From webhook-mailer at python.org Wed Mar 1 04:49:32 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 01 Mar 2023 09:49:32 -0000 Subject: [Python-checkins] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives in tkinter module (#102319) Message-ID: https://github.com/python/cpython/commit/f91846ba390f4437bcd525dfe6ed4355a894e159 commit: f91846ba390f4437bcd525dfe6ed4355a894e159 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-01T09:49:23Z summary: gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives in tkinter module (#102319) files: M Modules/_tkinter.c diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index d4a129058702..1608939766ff 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -321,8 +321,6 @@ static PyObject *Tkinter_TclError; static int quitMainLoop = 0; static int errorInCmd = 0; static PyObject *excInCmd; -static PyObject *valInCmd; -static PyObject *trbInCmd; #ifdef TKINTER_PROTECT_LOADTK static int tk_load_failed = 0; @@ -1222,7 +1220,7 @@ typedef struct Tkapp_CallEvent { PyObject *args; int flags; PyObject **res; - PyObject **exc_type, **exc_value, **exc_tb; + PyObject **exc; Tcl_Condition *done; } Tkapp_CallEvent; @@ -1339,7 +1337,7 @@ Tkapp_CallProc(Tkapp_CallEvent *e, int flags) ENTER_PYTHON objv = Tkapp_CallArgs(e->args, objStore, &objc); if (!objv) { - PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb); + *(e->exc) = PyErr_GetRaisedException(); *(e->res) = NULL; } LEAVE_PYTHON @@ -1354,7 +1352,7 @@ Tkapp_CallProc(Tkapp_CallEvent *e, int flags) *(e->res) = Tkapp_ObjectResult(e->self); } if (*(e->res) == NULL) { - PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb); + *(e->exc) = PyErr_GetRaisedException(); } LEAVE_PYTHON @@ -1401,7 +1399,7 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) marshal the parameters to the interpreter thread. */ Tkapp_CallEvent *ev; Tcl_Condition cond = NULL; - PyObject *exc_type, *exc_value, *exc_tb; + PyObject *exc; if (!WaitForMainloop(self)) return NULL; ev = (Tkapp_CallEvent*)attemptckalloc(sizeof(Tkapp_CallEvent)); @@ -1413,18 +1411,18 @@ Tkapp_Call(PyObject *selfptr, PyObject *args) ev->self = self; ev->args = args; ev->res = &res; - ev->exc_type = &exc_type; - ev->exc_value = &exc_value; - ev->exc_tb = &exc_tb; + ev->exc = &exc; ev->done = &cond; Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &call_mutex); if (res == NULL) { - if (exc_type) - PyErr_Restore(exc_type, exc_value, exc_tb); - else - PyErr_SetObject(Tkinter_TclError, exc_value); + if (exc) { + PyErr_SetRaisedException(exc); + } + else { + PyErr_SetObject(Tkinter_TclError, exc); + } } Tcl_ConditionFinalize(&cond); } @@ -1578,8 +1576,7 @@ typedef struct VarEvent { int flags; EventFunc func; PyObject **res; - PyObject **exc_type; - PyObject **exc_val; + PyObject **exc; Tcl_Condition *cond; } VarEvent; @@ -1643,12 +1640,7 @@ var_perform(VarEvent *ev) { *(ev->res) = ev->func(ev->self, ev->args, ev->flags); if (!*(ev->res)) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - PyErr_NormalizeException(&exc, &val, &tb); - *(ev->exc_type) = exc; - *(ev->exc_val) = val; - Py_XDECREF(tb); + *(ev->exc) = PyErr_GetRaisedException();; } } @@ -1672,7 +1664,7 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) TkappObject *self = (TkappObject*)selfptr; if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { VarEvent *ev; - PyObject *res, *exc_type, *exc_val; + PyObject *res, *exc; Tcl_Condition cond = NULL; /* The current thread is not the interpreter thread. Marshal @@ -1691,16 +1683,14 @@ var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) ev->flags = flags; ev->func = func; ev->res = &res; - ev->exc_type = &exc_type; - ev->exc_val = &exc_val; + ev->exc = &exc; ev->cond = &cond; ev->ev.proc = (Tcl_EventProc*)var_proc; Tkapp_ThreadSend(self, (Tcl_Event*)ev, &cond, &var_mutex); Tcl_ConditionFinalize(&cond); if (!res) { - PyErr_SetObject(exc_type, exc_val); - Py_DECREF(exc_type); - Py_DECREF(exc_val); + PyErr_SetObject((PyObject*)Py_TYPE(exc), exc); + Py_DECREF(exc); return NULL; } return res; @@ -2188,7 +2178,7 @@ static int PythonCmd_Error(Tcl_Interp *interp) { errorInCmd = 1; - PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + excInCmd = PyErr_GetRaisedException(); LEAVE_PYTHON return TCL_ERROR; } @@ -2458,7 +2448,7 @@ FileHandler(ClientData clientData, int mask) res = PyObject_CallFunction(func, "Oi", file, mask); if (res == NULL) { errorInCmd = 1; - PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + excInCmd = PyErr_GetRaisedException(); } Py_XDECREF(res); LEAVE_PYTHON @@ -2628,7 +2618,7 @@ TimerHandler(ClientData clientData) if (res == NULL) { errorInCmd = 1; - PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + excInCmd = PyErr_GetRaisedException(); } else Py_DECREF(res); @@ -2725,8 +2715,8 @@ _tkinter_tkapp_mainloop_impl(TkappObject *self, int threshold) if (errorInCmd) { errorInCmd = 0; - PyErr_Restore(excInCmd, valInCmd, trbInCmd); - excInCmd = valInCmd = trbInCmd = NULL; + PyErr_SetRaisedException(excInCmd); + excInCmd = NULL; return NULL; } Py_RETURN_NONE; @@ -3187,8 +3177,8 @@ EventHook(void) #endif if (errorInCmd) { errorInCmd = 0; - PyErr_Restore(excInCmd, valInCmd, trbInCmd); - excInCmd = valInCmd = trbInCmd = NULL; + PyErr_SetRaisedException(excInCmd); + excInCmd = NULL; PyErr_Print(); } PyEval_SaveThread(); From webhook-mailer at python.org Wed Mar 1 07:01:47 2023 From: webhook-mailer at python.org (zooba) Date: Wed, 01 Mar 2023 12:01:47 -0000 Subject: [Python-checkins] gh-102336: Ensure CancelIoEx result is not ignored (GH-102347) Message-ID: https://github.com/python/cpython/commit/d3d20743ee1ae7e0be17bacd278985cffa864816 commit: d3d20743ee1ae7e0be17bacd278985cffa864816 branch: main author: Max Bachmann committer: zooba date: 2023-03-01T12:01:39Z summary: gh-102336: Ensure CancelIoEx result is not ignored (GH-102347) fix ignored return value files: M Modules/_winapi.c diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 8c4c725b9df2..eefc2571ee82 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -288,7 +288,7 @@ _winapi_Overlapped_cancel_impl(OverlappedObject *self) if (self->pending) { Py_BEGIN_ALLOW_THREADS - CancelIoEx(self->handle, &self->overlapped); + res = CancelIoEx(self->handle, &self->overlapped); Py_END_ALLOW_THREADS } From webhook-mailer at python.org Wed Mar 1 09:50:50 2023 From: webhook-mailer at python.org (zooba) Date: Wed, 01 Mar 2023 14:50:50 -0000 Subject: [Python-checkins] gh-102344: Reimplement winreg QueryValue / SetValue using QueryValueEx / SetValueEx (GH-102345) Message-ID: https://github.com/python/cpython/commit/c1748ed59dc30ab99fe69c22bdbab54f93baa57c commit: c1748ed59dc30ab99fe69c22bdbab54f93baa57c branch: main author: Max Bachmann committer: zooba date: 2023-03-01T14:50:38Z summary: gh-102344: Reimplement winreg QueryValue / SetValue using QueryValueEx / SetValueEx (GH-102345) The newer APIs are more widely available than the old ones, and are called in a way to preserve functionality. files: A Misc/NEWS.d/next/Windows/2023-03-01-01-36-39.gh-issue-102344.Dgfux4.rst M PC/winreg.c diff --git a/Misc/NEWS.d/next/Windows/2023-03-01-01-36-39.gh-issue-102344.Dgfux4.rst b/Misc/NEWS.d/next/Windows/2023-03-01-01-36-39.gh-issue-102344.Dgfux4.rst new file mode 100644 index 000000000000..4804212be818 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-03-01-01-36-39.gh-issue-102344.Dgfux4.rst @@ -0,0 +1,2 @@ +Implement ``winreg.QueryValue`` using ``QueryValueEx`` and +``winreg.SetValue`` using ``SetValueEx``. Patch by Max Bachmann. diff --git a/PC/winreg.c b/PC/winreg.c index 63b37be526ab..86efed09855b 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -561,7 +561,7 @@ Py2Reg(PyObject *value, DWORD typ, BYTE **retDataBuf, DWORD *retDataSize) { Py_ssize_t i,j; switch (typ) { - case REG_DWORD: + case REG_DWORD: { if (value != Py_None && !PyLong_Check(value)) { return FALSE; @@ -585,7 +585,7 @@ Py2Reg(PyObject *value, DWORD typ, BYTE **retDataBuf, DWORD *retDataSize) *retDataSize = sizeof(DWORD); break; } - case REG_QWORD: + case REG_QWORD: { if (value != Py_None && !PyLong_Check(value)) { return FALSE; @@ -1488,53 +1488,77 @@ static PyObject * winreg_QueryValue_impl(PyObject *module, HKEY key, const Py_UNICODE *sub_key) /*[clinic end generated code: output=c655810ae50c63a9 input=41cafbbf423b21d6]*/ { - long rc; - PyObject *retStr; - wchar_t *retBuf; - DWORD bufSize = 0; - DWORD retSize = 0; - wchar_t *tmp; + LONG rc; + HKEY childKey = key; + WCHAR buf[256], *pbuf = buf; + DWORD size = sizeof(buf); + DWORD type; + Py_ssize_t length; + PyObject *result = NULL; if (PySys_Audit("winreg.QueryValue", "nuu", - (Py_ssize_t)key, sub_key, NULL) < 0) { + (Py_ssize_t)key, sub_key, NULL) < 0) + { return NULL; } - rc = RegQueryValueW(key, sub_key, NULL, &retSize); - if (rc == ERROR_MORE_DATA) - retSize = 256; - else if (rc != ERROR_SUCCESS) - return PyErr_SetFromWindowsErrWithFunction(rc, + + if (key == HKEY_PERFORMANCE_DATA) { + return PyErr_SetFromWindowsErrWithFunction(ERROR_INVALID_HANDLE, "RegQueryValue"); + } - bufSize = retSize; - retBuf = (wchar_t *) PyMem_Malloc(bufSize); - if (retBuf == NULL) - return PyErr_NoMemory(); + if (sub_key && sub_key[0]) { + Py_BEGIN_ALLOW_THREADS + rc = RegOpenKeyExW(key, sub_key, 0, KEY_QUERY_VALUE, &childKey); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) { + return PyErr_SetFromWindowsErrWithFunction(rc, "RegOpenKeyEx"); + } + } while (1) { - retSize = bufSize; - rc = RegQueryValueW(key, sub_key, retBuf, &retSize); - if (rc != ERROR_MORE_DATA) + Py_BEGIN_ALLOW_THREADS + rc = RegQueryValueExW(childKey, NULL, NULL, &type, (LPBYTE)pbuf, + &size); + Py_END_ALLOW_THREADS + if (rc != ERROR_MORE_DATA) { break; - - bufSize *= 2; - tmp = (wchar_t *) PyMem_Realloc(retBuf, bufSize); + } + void *tmp = PyMem_Realloc(pbuf != buf ? pbuf : NULL, size); if (tmp == NULL) { - PyMem_Free(retBuf); - return PyErr_NoMemory(); + PyErr_NoMemory(); + goto exit; } - retBuf = tmp; + pbuf = tmp; } - if (rc != ERROR_SUCCESS) { - PyMem_Free(retBuf); - return PyErr_SetFromWindowsErrWithFunction(rc, - "RegQueryValue"); + if (rc == ERROR_SUCCESS) { + if (type != REG_SZ) { + PyErr_SetFromWindowsErrWithFunction(ERROR_INVALID_DATA, + "RegQueryValue"); + goto exit; + } + length = wcsnlen(pbuf, size / sizeof(WCHAR)); + } + else if (rc == ERROR_FILE_NOT_FOUND) { + // Return an empty string if there's no default value. + length = 0; + } + else { + PyErr_SetFromWindowsErrWithFunction(rc, "RegQueryValueEx"); + goto exit; } - retStr = PyUnicode_FromWideChar(retBuf, wcslen(retBuf)); - PyMem_Free(retBuf); - return retStr; + result = PyUnicode_FromWideChar(pbuf, length); + +exit: + if (pbuf != buf) { + PyMem_Free(pbuf); + } + if (childKey != key) { + RegCloseKey(childKey); + } + return result; } @@ -1687,38 +1711,69 @@ winreg_SetValue_impl(PyObject *module, HKEY key, const Py_UNICODE *sub_key, DWORD type, PyObject *value_obj) /*[clinic end generated code: output=d4773dc9c372311a input=bf088494ae2d24fd]*/ { - Py_ssize_t value_length; - long rc; + LONG rc; + HKEY childKey = key; + LPWSTR value; + Py_ssize_t size; + Py_ssize_t length; + PyObject *result = NULL; if (type != REG_SZ) { PyErr_SetString(PyExc_TypeError, "type must be winreg.REG_SZ"); return NULL; } - wchar_t *value = PyUnicode_AsWideCharString(value_obj, &value_length); + value = PyUnicode_AsWideCharString(value_obj, &length); if (value == NULL) { return NULL; } - if ((Py_ssize_t)(DWORD)value_length != value_length) { + + size = (length + 1) * sizeof(WCHAR); + if ((Py_ssize_t)(DWORD)size != size) { PyErr_SetString(PyExc_OverflowError, "value is too long"); - PyMem_Free(value); - return NULL; + goto exit; } if (PySys_Audit("winreg.SetValue", "nunu#", (Py_ssize_t)key, sub_key, (Py_ssize_t)type, - value, value_length) < 0) { - PyMem_Free(value); - return NULL; + value, length) < 0) + { + goto exit; + } + + if (key == HKEY_PERFORMANCE_DATA) { + PyErr_SetFromWindowsErrWithFunction(ERROR_INVALID_HANDLE, + "RegSetValue"); + goto exit; + } + + if (sub_key && sub_key[0]) { + Py_BEGIN_ALLOW_THREADS + rc = RegCreateKeyExW(key, sub_key, 0, NULL, 0, KEY_SET_VALUE, NULL, + &childKey, NULL); + Py_END_ALLOW_THREADS + if (rc != ERROR_SUCCESS) { + PyErr_SetFromWindowsErrWithFunction(rc, "RegCreateKeyEx"); + goto exit; + } } Py_BEGIN_ALLOW_THREADS - rc = RegSetValueW(key, sub_key, REG_SZ, value, (DWORD)(value_length + 1)); + rc = RegSetValueExW(childKey, NULL, 0, REG_SZ, (LPBYTE)value, (DWORD)size); Py_END_ALLOW_THREADS + if (rc == ERROR_SUCCESS) { + result = Py_NewRef(Py_None); + } + else { + PyErr_SetFromWindowsErrWithFunction(rc, "RegSetValueEx"); + } + +exit: PyMem_Free(value); - if (rc != ERROR_SUCCESS) - return PyErr_SetFromWindowsErrWithFunction(rc, "RegSetValue"); - Py_RETURN_NONE; + if (childKey != key) { + RegCloseKey(childKey); + } + return result; } /*[clinic input] @@ -1771,32 +1826,39 @@ winreg_SetValueEx_impl(PyObject *module, HKEY key, DWORD type, PyObject *value) /*[clinic end generated code: output=811b769a66ae11b7 input=900a9e3990bfb196]*/ { - BYTE *data; - DWORD len; - LONG rc; + BYTE *data = NULL; + DWORD size; + PyObject *result = NULL; - if (!Py2Reg(value, type, &data, &len)) + if (!Py2Reg(value, type, &data, &size)) { - if (!PyErr_Occurred()) + if (!PyErr_Occurred()) { PyErr_SetString(PyExc_ValueError, "Could not convert the data to the specified type."); + } return NULL; } if (PySys_Audit("winreg.SetValue", "nunO", (Py_ssize_t)key, value_name, (Py_ssize_t)type, - value) < 0) { - PyMem_Free(data); - return NULL; + value) < 0) + { + goto exit; } + Py_BEGIN_ALLOW_THREADS - rc = RegSetValueExW(key, value_name, 0, type, data, len); + rc = RegSetValueExW(key, value_name, 0, type, data, size); Py_END_ALLOW_THREADS + if (rc == ERROR_SUCCESS) { + result = Py_NewRef(Py_None); + } + else { + PyErr_SetFromWindowsErrWithFunction(rc, "RegSetValueEx"); + } + +exit: PyMem_Free(data); - if (rc != ERROR_SUCCESS) - return PyErr_SetFromWindowsErrWithFunction(rc, - "RegSetValueEx"); - Py_RETURN_NONE; + return result; } /*[clinic input] From webhook-mailer at python.org Wed Mar 1 09:56:26 2023 From: webhook-mailer at python.org (corona10) Date: Wed, 01 Mar 2023 14:56:26 -0000 Subject: [Python-checkins] gh-95672 skip fcntl when pipesize is smaller than pagesize (gh-102163) Message-ID: https://github.com/python/cpython/commit/2f62a5da949cd368a9498e6a03e700f4629fa97f commit: 2f62a5da949cd368a9498e6a03e700f4629fa97f branch: main author: Hyunkyun Moon committer: corona10 date: 2023-03-01T23:56:19+09:00 summary: gh-95672 skip fcntl when pipesize is smaller than pagesize (gh-102163) files: M Doc/library/test.rst M Lib/test/support/__init__.py M Lib/test/test_fcntl.py M Lib/test/test_subprocess.py diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 8199a27d7d9c..3c759648e4e6 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -536,6 +536,13 @@ The :mod:`test.support` module defines the following functions: :func:`doctest.testmod`. +.. function:: get_pagesize() + + Get size of a page in bytes. + + .. versionadded:: 3.12 + + .. function:: setswitchinterval(interval) Set the :func:`sys.setswitchinterval` to the given *interval*. Defines diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 4a22ccdd4db4..c309fd7910e0 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -51,6 +51,8 @@ # sys "is_jython", "is_android", "is_emscripten", "is_wasi", "check_impl_detail", "unix_shell", "setswitchinterval", + # os + "get_pagesize", # network "open_urlresource", # processes @@ -1893,6 +1895,18 @@ def setswitchinterval(interval): return sys.setswitchinterval(interval) +def get_pagesize(): + """Get size of a page in bytes.""" + try: + page_size = os.sysconf('SC_PAGESIZE') + except (ValueError, AttributeError): + try: + page_size = os.sysconf('SC_PAGE_SIZE') + except (ValueError, AttributeError): + page_size = 4096 + return page_size + + @contextlib.contextmanager def disable_faulthandler(): import faulthandler diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py index 26de67d92427..5da75615b41d 100644 --- a/Lib/test/test_fcntl.py +++ b/Lib/test/test_fcntl.py @@ -6,7 +6,7 @@ import struct import sys import unittest -from test.support import verbose, cpython_only +from test.support import verbose, cpython_only, get_pagesize from test.support.import_helper import import_module from test.support.os_helper import TESTFN, unlink @@ -201,7 +201,8 @@ def test_fcntl_f_pipesize(self): # Get the default pipesize with F_GETPIPE_SZ pipesize_default = fcntl.fcntl(test_pipe_w, fcntl.F_GETPIPE_SZ) pipesize = pipesize_default // 2 # A new value to detect change. - if pipesize < 512: # the POSIX minimum + pagesize_default = get_pagesize() + if pipesize < pagesize_default: # the POSIX minimum raise unittest.SkipTest( 'default pipesize too small to perform test.') fcntl.fcntl(test_pipe_w, fcntl.F_SETPIPE_SZ, pipesize) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 727b0e6dc578..3880125807f2 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -717,7 +717,8 @@ def test_pipesizes(self): os.close(test_pipe_r) os.close(test_pipe_w) pipesize = pipesize_default // 2 - if pipesize < 512: # the POSIX minimum + pagesize_default = support.get_pagesize() + if pipesize < pagesize_default: # the POSIX minimum raise unittest.SkipTest( 'default pipesize too small to perform test.') p = subprocess.Popen( From webhook-mailer at python.org Wed Mar 1 22:16:47 2023 From: webhook-mailer at python.org (rhettinger) Date: Thu, 02 Mar 2023 03:16:47 -0000 Subject: [Python-checkins] gh-102088 Optimize iter_index itertools recipe (GH-102360) Message-ID: https://github.com/python/cpython/commit/eaae563b6878aa050b4ad406b67728b6b066220e commit: eaae563b6878aa050b4ad406b67728b6b066220e branch: main author: Stefan Pochmann <609905+pochmann at users.noreply.github.com> committer: rhettinger date: 2023-03-01T21:16:23-06:00 summary: gh-102088 Optimize iter_index itertools recipe (GH-102360) files: M Doc/library/itertools.rst M Lib/test/test_operator.py diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 95da7166842e..d85a17effb04 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -886,9 +886,12 @@ which incur interpreter overhead. except AttributeError: # Slow path for general iterables it = islice(iterable, start, None) - for i, element in enumerate(it, start): - if element is value or element == value: - yield i + i = start - 1 + try: + while True: + yield (i := i + operator.indexOf(it, value) + 1) + except ValueError: + pass else: # Fast path for sequences i = start - 1 diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py index b7e38c233498..1db738d228b1 100644 --- a/Lib/test/test_operator.py +++ b/Lib/test/test_operator.py @@ -208,6 +208,9 @@ def test_indexOf(self): nan = float("nan") self.assertEqual(operator.indexOf([nan, nan, 21], nan), 0) self.assertEqual(operator.indexOf([{}, 1, {}, 2], {}), 0) + it = iter('leave the iterator at exactly the position after the match') + self.assertEqual(operator.indexOf(it, 'a'), 2) + self.assertEqual(next(it), 'v') def test_invert(self): operator = self.module From webhook-mailer at python.org Wed Mar 1 22:53:11 2023 From: webhook-mailer at python.org (rhettinger) Date: Thu, 02 Mar 2023 03:53:11 -0000 Subject: [Python-checkins] [3.11] gh-102088 Optimize iter_index itertools recipe (GH-102360) (GH-102363) Message-ID: https://github.com/python/cpython/commit/3effccee48c4e324e6f0e8fe20dc03950166bb5c commit: 3effccee48c4e324e6f0e8fe20dc03950166bb5c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: rhettinger date: 2023-03-01T21:52:37-06:00 summary: [3.11] gh-102088 Optimize iter_index itertools recipe (GH-102360) (GH-102363) files: M Doc/library/itertools.rst M Lib/test/test_operator.py diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 2fd30db0587f..5fe93fd3e0e5 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -875,9 +875,12 @@ which incur interpreter overhead. except AttributeError: # Slow path for general iterables it = islice(iterable, start, None) - for i, element in enumerate(it, start): - if element is value or element == value: - yield i + i = start - 1 + try: + while True: + yield (i := i + operator.indexOf(it, value) + 1) + except ValueError: + pass else: # Fast path for sequences i = start - 1 diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py index b7e38c233498..1db738d228b1 100644 --- a/Lib/test/test_operator.py +++ b/Lib/test/test_operator.py @@ -208,6 +208,9 @@ def test_indexOf(self): nan = float("nan") self.assertEqual(operator.indexOf([nan, nan, 21], nan), 0) self.assertEqual(operator.indexOf([{}, 1, {}, 2], {}), 0) + it = iter('leave the iterator at exactly the position after the match') + self.assertEqual(operator.indexOf(it, 'a'), 2) + self.assertEqual(next(it), 'v') def test_invert(self): operator = self.module From webhook-mailer at python.org Thu Mar 2 00:43:54 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 02 Mar 2023 05:43:54 -0000 Subject: [Python-checkins] [3.11] gh-90744: Fix erroneous doc links in the sys module (GH-101319) (#102321) Message-ID: https://github.com/python/cpython/commit/9a5f2e8562a4349bfb1b00465f75ee270592744e commit: 9a5f2e8562a4349bfb1b00465f75ee270592744e branch: 3.11 author: Hugo van Kemenade committer: hugovk date: 2023-03-02T07:43:44+02:00 summary: [3.11] gh-90744: Fix erroneous doc links in the sys module (GH-101319) (#102321) Co-authored-by: Hugo van Kemenade Co-authored-by: Brad Wolfe Co-authored-by: Furkan Onder Fix erroneous doc links in the sys module (#101319) files: M Doc/library/sys.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index b458040c876b..36155d632363 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -568,49 +568,55 @@ always available. .. tabularcolumns:: |l|l|L| - +---------------------+----------------+--------------------------------------------------+ - | attribute | float.h macro | explanation | - +=====================+================+==================================================+ - | :const:`epsilon` | DBL_EPSILON | difference between 1.0 and the least value | - | | | greater than 1.0 that is representable as a float| - | | | | - | | | See also :func:`math.ulp`. | - +---------------------+----------------+--------------------------------------------------+ - | :const:`dig` | DBL_DIG | maximum number of decimal digits that can be | - | | | faithfully represented in a float; see below | - +---------------------+----------------+--------------------------------------------------+ - | :const:`mant_dig` | DBL_MANT_DIG | float precision: the number of base-``radix`` | - | | | digits in the significand of a float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`max` | DBL_MAX | maximum representable positive finite float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`max_exp` | DBL_MAX_EXP | maximum integer *e* such that ``radix**(e-1)`` is| - | | | a representable finite float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`max_10_exp` | DBL_MAX_10_EXP | maximum integer *e* such that ``10**e`` is in the| - | | | range of representable finite floats | - +---------------------+----------------+--------------------------------------------------+ - | :const:`min` | DBL_MIN | minimum representable positive *normalized* float| - | | | | - | | | Use :func:`math.ulp(0.0) ` to get the | - | | | smallest positive *denormalized* representable | - | | | float. | - +---------------------+----------------+--------------------------------------------------+ - | :const:`min_exp` | DBL_MIN_EXP | minimum integer *e* such that ``radix**(e-1)`` is| - | | | a normalized float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`min_10_exp` | DBL_MIN_10_EXP | minimum integer *e* such that ``10**e`` is a | - | | | normalized float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`radix` | FLT_RADIX | radix of exponent representation | - +---------------------+----------------+--------------------------------------------------+ - | :const:`rounds` | FLT_ROUNDS | integer constant representing the rounding mode | - | | | used for arithmetic operations. This reflects | - | | | the value of the system FLT_ROUNDS macro at | - | | | interpreter startup time. See section 5.2.4.2.2 | - | | | of the C99 standard for an explanation of the | - | | | possible values and their meanings. | - +---------------------+----------------+--------------------------------------------------+ + +---------------------+---------------------+--------------------------------------------------+ + | attribute | float.h macro | explanation | + +=====================+=====================+==================================================+ + | ``epsilon`` | ``DBL_EPSILON`` | difference between 1.0 and the least value | + | | | greater than 1.0 that is representable as a float| + | | | | + | | | See also :func:`math.ulp`. | + +---------------------+---------------------+--------------------------------------------------+ + | ``dig`` | ``DBL_DIG`` | maximum number of decimal digits that can be | + | | | faithfully represented in a float; see below | + +---------------------+---------------------+--------------------------------------------------+ + | ``mant_dig`` | ``DBL_MANT_DIG`` | float precision: the number of base-``radix`` | + | | | digits in the significand of a float | + +---------------------+---------------------+--------------------------------------------------+ + | ``max`` | ``DBL_MAX`` | maximum representable positive finite float | + +---------------------+---------------------+--------------------------------------------------+ + | ``max_exp`` | ``DBL_MAX_EXP`` | maximum integer *e* such that ``radix**(e-1)`` is| + | | | a representable finite float | + +---------------------+---------------------+--------------------------------------------------+ + | ``max_10_exp`` | ``DBL_MAX_10_EXP`` | maximum integer *e* such that ``10**e`` is in the| + | | | range of representable finite floats | + +---------------------+---------------------+--------------------------------------------------+ + | ``min`` | ``DBL_MIN`` | minimum representable positive *normalized* float| + | | | | + | | | Use :func:`math.ulp(0.0) ` to get the | + | | | smallest positive *denormalized* representable | + | | | float. | + +---------------------+---------------------+--------------------------------------------------+ + | ``min_exp`` | ``DBL_MIN_EXP`` | minimum integer *e* such that ``radix**(e-1)`` is| + | | | a normalized float | + +---------------------+---------------------+--------------------------------------------------+ + | ``min_10_exp`` | ``DBL_MIN_10_EXP`` | minimum integer *e* such that ``10**e`` is a | + | | | normalized float | + +---------------------+---------------------+--------------------------------------------------+ + | ``radix`` | ``FLT_RADIX`` | radix of exponent representation | + +---------------------+---------------------+--------------------------------------------------+ + | ``rounds`` | ``FLT_ROUNDS`` | integer representing the rounding mode for | + | | | floating-point arithmetic. This reflects the | + | | | value of the system ``FLT_ROUNDS`` macro at | + | | | interpreter startup time: | + | | | ``-1`` indeterminable, | + | | | ``0`` toward zero, | + | | | ``1`` to nearest, | + | | | ``2`` toward positive infinity, | + | | | ``3`` toward negative infinity | + | | | | + | | | All other values for ``FLT_ROUNDS`` characterize | + | | | implementation-defined rounding behavior. | + +---------------------+---------------------+--------------------------------------------------+ The attribute :attr:`sys.float_info.dig` needs further explanation. If ``s`` is any string representing a decimal number with at most From webhook-mailer at python.org Thu Mar 2 00:43:57 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 02 Mar 2023 05:43:57 -0000 Subject: [Python-checkins] [3.10] gh-90744: Fix erroneous doc links in the sys module (GH-101319) (#102322) Message-ID: https://github.com/python/cpython/commit/a8f9a82881cf925107b39d2bd452ab9dacc99157 commit: a8f9a82881cf925107b39d2bd452ab9dacc99157 branch: 3.10 author: Hugo van Kemenade committer: hugovk date: 2023-03-02T07:43:50+02:00 summary: [3.10] gh-90744: Fix erroneous doc links in the sys module (GH-101319) (#102322) Co-authored-by: Hugo van Kemenade Co-authored-by: Brad Wolfe Co-authored-by: Furkan Onder Fix erroneous doc links in the sys module (#101319) files: M Doc/library/sys.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index c4658424c9cf..315e570416b6 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -522,49 +522,55 @@ always available. .. tabularcolumns:: |l|l|L| - +---------------------+----------------+--------------------------------------------------+ - | attribute | float.h macro | explanation | - +=====================+================+==================================================+ - | :const:`epsilon` | DBL_EPSILON | difference between 1.0 and the least value | - | | | greater than 1.0 that is representable as a float| - | | | | - | | | See also :func:`math.ulp`. | - +---------------------+----------------+--------------------------------------------------+ - | :const:`dig` | DBL_DIG | maximum number of decimal digits that can be | - | | | faithfully represented in a float; see below | - +---------------------+----------------+--------------------------------------------------+ - | :const:`mant_dig` | DBL_MANT_DIG | float precision: the number of base-``radix`` | - | | | digits in the significand of a float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`max` | DBL_MAX | maximum representable positive finite float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`max_exp` | DBL_MAX_EXP | maximum integer *e* such that ``radix**(e-1)`` is| - | | | a representable finite float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`max_10_exp` | DBL_MAX_10_EXP | maximum integer *e* such that ``10**e`` is in the| - | | | range of representable finite floats | - +---------------------+----------------+--------------------------------------------------+ - | :const:`min` | DBL_MIN | minimum representable positive *normalized* float| - | | | | - | | | Use :func:`math.ulp(0.0) ` to get the | - | | | smallest positive *denormalized* representable | - | | | float. | - +---------------------+----------------+--------------------------------------------------+ - | :const:`min_exp` | DBL_MIN_EXP | minimum integer *e* such that ``radix**(e-1)`` is| - | | | a normalized float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`min_10_exp` | DBL_MIN_10_EXP | minimum integer *e* such that ``10**e`` is a | - | | | normalized float | - +---------------------+----------------+--------------------------------------------------+ - | :const:`radix` | FLT_RADIX | radix of exponent representation | - +---------------------+----------------+--------------------------------------------------+ - | :const:`rounds` | FLT_ROUNDS | integer constant representing the rounding mode | - | | | used for arithmetic operations. This reflects | - | | | the value of the system FLT_ROUNDS macro at | - | | | interpreter startup time. See section 5.2.4.2.2 | - | | | of the C99 standard for an explanation of the | - | | | possible values and their meanings. | - +---------------------+----------------+--------------------------------------------------+ + +---------------------+---------------------+--------------------------------------------------+ + | attribute | float.h macro | explanation | + +=====================+=====================+==================================================+ + | ``epsilon`` | ``DBL_EPSILON`` | difference between 1.0 and the least value | + | | | greater than 1.0 that is representable as a float| + | | | | + | | | See also :func:`math.ulp`. | + +---------------------+---------------------+--------------------------------------------------+ + | ``dig`` | ``DBL_DIG`` | maximum number of decimal digits that can be | + | | | faithfully represented in a float; see below | + +---------------------+---------------------+--------------------------------------------------+ + | ``mant_dig`` | ``DBL_MANT_DIG`` | float precision: the number of base-``radix`` | + | | | digits in the significand of a float | + +---------------------+---------------------+--------------------------------------------------+ + | ``max`` | ``DBL_MAX`` | maximum representable positive finite float | + +---------------------+---------------------+--------------------------------------------------+ + | ``max_exp`` | ``DBL_MAX_EXP`` | maximum integer *e* such that ``radix**(e-1)`` is| + | | | a representable finite float | + +---------------------+---------------------+--------------------------------------------------+ + | ``max_10_exp`` | ``DBL_MAX_10_EXP`` | maximum integer *e* such that ``10**e`` is in the| + | | | range of representable finite floats | + +---------------------+---------------------+--------------------------------------------------+ + | ``min`` | ``DBL_MIN`` | minimum representable positive *normalized* float| + | | | | + | | | Use :func:`math.ulp(0.0) ` to get the | + | | | smallest positive *denormalized* representable | + | | | float. | + +---------------------+---------------------+--------------------------------------------------+ + | ``min_exp`` | ``DBL_MIN_EXP`` | minimum integer *e* such that ``radix**(e-1)`` is| + | | | a normalized float | + +---------------------+---------------------+--------------------------------------------------+ + | ``min_10_exp`` | ``DBL_MIN_10_EXP`` | minimum integer *e* such that ``10**e`` is a | + | | | normalized float | + +---------------------+---------------------+--------------------------------------------------+ + | ``radix`` | ``FLT_RADIX`` | radix of exponent representation | + +---------------------+---------------------+--------------------------------------------------+ + | ``rounds`` | ``FLT_ROUNDS`` | integer representing the rounding mode for | + | | | floating-point arithmetic. This reflects the | + | | | value of the system ``FLT_ROUNDS`` macro at | + | | | interpreter startup time: | + | | | ``-1`` indeterminable, | + | | | ``0`` toward zero, | + | | | ``1`` to nearest, | + | | | ``2`` toward positive infinity, | + | | | ``3`` toward negative infinity | + | | | | + | | | All other values for ``FLT_ROUNDS`` characterize | + | | | implementation-defined rounding behavior. | + +---------------------+---------------------+--------------------------------------------------+ The attribute :attr:`sys.float_info.dig` needs further explanation. If ``s`` is any string representing a decimal number with at most From webhook-mailer at python.org Thu Mar 2 06:10:19 2023 From: webhook-mailer at python.org (corona10) Date: Thu, 02 Mar 2023 11:10:19 -0000 Subject: [Python-checkins] gh-95672: Update memory_watchdog to use test.support.get_pagesize (gh-102365) Message-ID: https://github.com/python/cpython/commit/60597439ef482a840f8ffc76eb6c27f3ba773d9c commit: 60597439ef482a840f8ffc76eb6c27f3ba773d9c branch: main author: Hyunkyun Moon committer: corona10 date: 2023-03-02T20:10:08+09:00 summary: gh-95672: Update memory_watchdog to use test.support.get_pagesize (gh-102365) files: M Lib/test/memory_watchdog.py diff --git a/Lib/test/memory_watchdog.py b/Lib/test/memory_watchdog.py index 88cca8d323a6..fee062ecc9b3 100644 --- a/Lib/test/memory_watchdog.py +++ b/Lib/test/memory_watchdog.py @@ -5,20 +5,13 @@ # If the process crashes, reading from the /proc entry will fail with ESRCH. -import os import sys import time +from test.support import get_pagesize -try: - page_size = os.sysconf('SC_PAGESIZE') -except (ValueError, AttributeError): - try: - page_size = os.sysconf('SC_PAGE_SIZE') - except (ValueError, AttributeError): - page_size = 4096 - while True: + page_size = get_pagesize() sys.stdin.seek(0) statm = sys.stdin.read() data = int(statm.split()[5]) From webhook-mailer at python.org Thu Mar 2 06:32:47 2023 From: webhook-mailer at python.org (corona10) Date: Thu, 02 Mar 2023 11:32:47 -0000 Subject: [Python-checkins] gh-101101: Fix test_code_extra to reset value for refleak test (gh-102350) Message-ID: https://github.com/python/cpython/commit/ed55c69ebd74178115cd8b080f7f8e7588cd5fda commit: ed55c69ebd74178115cd8b080f7f8e7588cd5fda branch: main author: Dong-hee Na committer: corona10 date: 2023-03-02T20:32:05+09:00 summary: gh-101101: Fix test_code_extra to reset value for refleak test (gh-102350) files: M Modules/_testcapi/code.c diff --git a/Modules/_testcapi/code.c b/Modules/_testcapi/code.c index 588dc67971ea..84c668cd6b3b 100644 --- a/Modules/_testcapi/code.c +++ b/Modules/_testcapi/code.c @@ -92,7 +92,11 @@ test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable)) goto finally; } assert ((uintptr_t)extra == 77); - + // Revert to initial code extra value. + res = PyUnstable_Code_SetExtra(test_func_code, code_extra_index, NULL); + if (res < 0) { + goto finally; + } result = Py_NewRef(Py_None); finally: Py_XDECREF(test_module); From webhook-mailer at python.org Thu Mar 2 10:26:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 02 Mar 2023 15:26:56 -0000 Subject: [Python-checkins] Fix typos in documentation and comments (GH-102374) Message-ID: https://github.com/python/cpython/commit/73250000ac7d6a5e41917e8bcea7234444cbde78 commit: 73250000ac7d6a5e41917e8bcea7234444cbde78 branch: main author: Michael K committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-02T07:26:49-08:00 summary: Fix typos in documentation and comments (GH-102374) Found some duplicate `to`s in the documentation and some code comments and fixed them. [Misc/NEWS.d/3.12.0a1.rst](https://github.com/python/cpython/blob/ed55c69ebd74178115cd8b080f7f8e7588cd5fda/Misc/NEWS.d/3.12.0a1.rst) also contains two duplicate `to`s, but I wasn't sure if it's ok to touch that file. Looks auto generated. I'm happy to amend the PR if requested. :) Automerge-Triggered-By: GH:AlexWaygood files: M Doc/library/sqlite3.rst M Doc/library/typing.rst M Lib/zoneinfo/_zoneinfo.py M Objects/typeobject.c diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 18d0a5e630f6..ff036ad56acb 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -72,7 +72,7 @@ including `cursors`_ and `transactions`_. First, we need to create a new database and open a database connection to allow :mod:`!sqlite3` to work with it. -Call :func:`sqlite3.connect` to to create a connection to +Call :func:`sqlite3.connect` to create a connection to the database :file:`tutorial.db` in the current working directory, implicitly creating it if it does not exist: diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 3395e4bfb95c..80a969e6335a 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1345,7 +1345,7 @@ These are not used in annotations. They are building blocks for creating generic x: Ts # Not valid x: tuple[Ts] # Not valid - x: tuple[*Ts] # The correct way to to do it + x: tuple[*Ts] # The correct way to do it Type variable tuples can be used in the same contexts as normal type variables. For example, in class definitions, arguments, and return types:: diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index de68380792f1..eede15b82710 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -302,7 +302,7 @@ def _utcoff_to_dstoff(trans_idx, utcoffsets, isdsts): # difference between utcoffset() and the "standard" offset, but # the "base offset" and "DST offset" are not encoded in the file; # we can infer what they are from the isdst flag, but it is not - # sufficient to to just look at the last standard offset, because + # sufficient to just look at the last standard offset, because # occasionally countries will shift both DST offset and base offset. typecnt = len(isdsts) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b3f1429debc5..54f1974c6ae3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3822,11 +3822,11 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, res->ht_qualname = Py_NewRef(ht_name); res->ht_name = ht_name; - ht_name = NULL; // Give our reference to to the type + ht_name = NULL; // Give our reference to the type type->tp_name = _ht_tpname; res->_ht_tpname = _ht_tpname; - _ht_tpname = NULL; // Give ownership to to the type + _ht_tpname = NULL; // Give ownership to the type /* Copy the sizes */ From webhook-mailer at python.org Thu Mar 2 11:00:16 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 02 Mar 2023 16:00:16 -0000 Subject: [Python-checkins] [3.11] Fix typos in documentation and comments (GH-102374) (#102376) Message-ID: https://github.com/python/cpython/commit/3b1201daf6fa1fb6aac96868f489e2e17b28d356 commit: 3b1201daf6fa1fb6aac96868f489e2e17b28d356 branch: 3.11 author: Alex Waygood committer: AlexWaygood date: 2023-03-02T16:00:06Z summary: [3.11] Fix typos in documentation and comments (GH-102374) (#102376) [3.11] Fix typos in documentation and comments (GH-102374) Found some duplicate `to`s in the documentation and some code comments and fixed them. [Misc/NEWS.d/3.12.0a1.rst](https://github.com/python/cpython/blob/ed55c69ebd74178115cd8b080f7f8e7588cd5fda/Misc/NEWS.d/3.12.0a1.rst) also contains two duplicate `to`s, but I wasn't sure if it's ok to touch that file. Looks auto generated. I'm happy to amend the PR if requested. :) Automerge-Triggered-By: GH:AlexWaygood Co-authored-by: Michael K files: M Doc/library/sqlite3.rst M Doc/library/typing.rst M Lib/zoneinfo/_zoneinfo.py diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index fd8a032aff73..b5351a8feae8 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -72,7 +72,7 @@ including `cursors`_ and `transactions`_. First, we need to create a new database and open a database connection to allow :mod:`!sqlite3` to work with it. -Call :func:`sqlite3.connect` to to create a connection to +Call :func:`sqlite3.connect` to create a connection to the database :file:`tutorial.db` in the current working directory, implicitly creating it if it does not exist: diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 02c3e0336d34..8db9a3f2c609 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1343,7 +1343,7 @@ These are not used in annotations. They are building blocks for creating generic x: Ts # Not valid x: tuple[Ts] # Not valid - x: tuple[*Ts] # The correct way to to do it + x: tuple[*Ts] # The correct way to do it Type variable tuples can be used in the same contexts as normal type variables. For example, in class definitions, arguments, and return types:: diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index de68380792f1..eede15b82710 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -302,7 +302,7 @@ def _utcoff_to_dstoff(trans_idx, utcoffsets, isdsts): # difference between utcoffset() and the "standard" offset, but # the "base offset" and "DST offset" are not encoded in the file; # we can infer what they are from the isdst flag, but it is not - # sufficient to to just look at the last standard offset, because + # sufficient to just look at the last standard offset, because # occasionally countries will shift both DST offset and base offset. typecnt = len(isdsts) From webhook-mailer at python.org Thu Mar 2 11:45:12 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 02 Mar 2023 16:45:12 -0000 Subject: [Python-checkins] [3.10] Fix typos in documentation and comments (GH-102374) (#102377) Message-ID: https://github.com/python/cpython/commit/47cc6fac4b871f97a9fab30cea4b6465571db2fb commit: 47cc6fac4b871f97a9fab30cea4b6465571db2fb branch: 3.10 author: Alex Waygood committer: AlexWaygood date: 2023-03-02T16:45:01Z summary: [3.10] Fix typos in documentation and comments (GH-102374) (#102377) Fix typos in documentation and comments (GH-102374) Found some duplicate `to`s in the documentation and some code comments and fixed them. [Misc/NEWS.d/3.12.0a1.rst](https://github.com/python/cpython/blob/ed55c69ebd74178115cd8b080f7f8e7588cd5fda/Misc/NEWS.d/3.12.0a1.rst) also contains two duplicate `to`s, but I wasn't sure if it's ok to touch that file. Looks auto generated. I'm happy to amend the PR if requested. :) Automerge-Triggered-By: GH:AlexWaygood Co-authored-by: Michael K files: M Doc/library/sqlite3.rst M Lib/zoneinfo/_zoneinfo.py diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index dc8a48b0c05c..509c4a8277eb 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -72,7 +72,7 @@ including `cursors`_ and `transactions`_. First, we need to create a new database and open a database connection to allow :mod:`!sqlite3` to work with it. -Call :func:`sqlite3.connect` to to create a connection to +Call :func:`sqlite3.connect` to create a connection to the database :file:`tutorial.db` in the current working directory, implicitly creating it if it does not exist: diff --git a/Lib/zoneinfo/_zoneinfo.py b/Lib/zoneinfo/_zoneinfo.py index de68380792f1..eede15b82710 100644 --- a/Lib/zoneinfo/_zoneinfo.py +++ b/Lib/zoneinfo/_zoneinfo.py @@ -302,7 +302,7 @@ def _utcoff_to_dstoff(trans_idx, utcoffsets, isdsts): # difference between utcoffset() and the "standard" offset, but # the "base offset" and "DST offset" are not encoded in the file; # we can infer what they are from the isdst flag, but it is not - # sufficient to to just look at the last standard offset, because + # sufficient to just look at the last standard offset, because # occasionally countries will shift both DST offset and base offset. typecnt = len(isdsts) From webhook-mailer at python.org Thu Mar 2 13:39:08 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 02 Mar 2023 18:39:08 -0000 Subject: [Python-checkins] gh-102371: move _Py_Mangle from compile.c to symtable.c (#102372) Message-ID: https://github.com/python/cpython/commit/71db5dbcd714b2e1297c43538188dd69715feb9a commit: 71db5dbcd714b2e1297c43538188dd69715feb9a branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-02T18:38:22Z summary: gh-102371: move _Py_Mangle from compile.c to symtable.c (#102372) files: M Include/internal/pycore_compile.h M Include/internal/pycore_symtable.h M Objects/typeobject.c M Python/compile.c M Python/symtable.c diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index 967fe92a5bc2..511f0689c938 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -19,12 +19,6 @@ PyAPI_FUNC(PyCodeObject*) _PyAST_Compile( int optimize, struct _arena *arena); -int _PyFuture_FromAST( - struct _mod * mod, - PyObject *filename, - PyFutureFeatures* futures); - -extern PyObject* _Py_Mangle(PyObject *p, PyObject *name); typedef struct { int optimize; diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h index 8532646ce7d9..512c4c931f73 100644 --- a/Include/internal/pycore_symtable.h +++ b/Include/internal/pycore_symtable.h @@ -90,6 +90,8 @@ PyAPI_FUNC(PySTEntryObject *) PySymtable_Lookup(struct symtable *, void *); extern void _PySymtable_Free(struct symtable *); +extern PyObject* _Py_Mangle(PyObject *p, PyObject *name); + /* Flags for def-use information */ #define DEF_GLOBAL 1 /* global stmt */ @@ -128,6 +130,11 @@ extern struct symtable* _Py_SymtableStringObjectFlags( int start, PyCompilerFlags *flags); +int _PyFuture_FromAST( + struct _mod * mod, + PyObject *filename, + PyFutureFeatures* futures); + #ifdef __cplusplus } #endif diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 54f1974c6ae3..981930f58417 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3,7 +3,7 @@ #include "Python.h" #include "pycore_call.h" #include "pycore_code.h" // CO_FAST_FREE -#include "pycore_compile.h" // _Py_Mangle() +#include "pycore_symtable.h" // _Py_Mangle() #include "pycore_dict.h" // _PyDict_KeysSize() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_moduleobject.h" // _PyModule_GetDef() diff --git a/Python/compile.c b/Python/compile.c index b14c637210ff..2e60a8157533 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -29,12 +29,12 @@ #include "Python.h" #include "pycore_ast.h" // _PyAST_GetDocString() #include "pycore_code.h" // _PyCode_New() -#include "pycore_compile.h" // _PyFuture_FromAST() +#include "pycore_compile.h" #include "pycore_intrinsics.h" #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_opcode.h" // _PyOpcode_Caches #include "pycore_pymem.h" // _PyMem_IsPtrFreed() -#include "pycore_symtable.h" // PySTEntryObject +#include "pycore_symtable.h" // PySTEntryObject, _PyFuture_FromAST() #include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed @@ -569,72 +569,6 @@ static PyCodeObject *assemble(struct compiler *, int addNone); #define CAPSULE_NAME "compile.c compiler unit" -PyObject * -_Py_Mangle(PyObject *privateobj, PyObject *ident) -{ - /* Name mangling: __private becomes _classname__private. - This is independent from how the name is used. */ - PyObject *result; - size_t nlen, plen, ipriv; - Py_UCS4 maxchar; - if (privateobj == NULL || !PyUnicode_Check(privateobj) || - PyUnicode_READ_CHAR(ident, 0) != '_' || - PyUnicode_READ_CHAR(ident, 1) != '_') { - return Py_NewRef(ident); - } - nlen = PyUnicode_GET_LENGTH(ident); - plen = PyUnicode_GET_LENGTH(privateobj); - /* Don't mangle __id__ or names with dots. - - The only time a name with a dot can occur is when - we are compiling an import statement that has a - package name. - - TODO(jhylton): Decide whether we want to support - mangling of the module name, e.g. __M.X. - */ - if ((PyUnicode_READ_CHAR(ident, nlen-1) == '_' && - PyUnicode_READ_CHAR(ident, nlen-2) == '_') || - PyUnicode_FindChar(ident, '.', 0, nlen, 1) != -1) { - return Py_NewRef(ident); /* Don't mangle __whatever__ */ - } - /* Strip leading underscores from class name */ - ipriv = 0; - while (PyUnicode_READ_CHAR(privateobj, ipriv) == '_') - ipriv++; - if (ipriv == plen) { - return Py_NewRef(ident); /* Don't mangle if class is just underscores */ - } - plen -= ipriv; - - if (plen + nlen >= PY_SSIZE_T_MAX - 1) { - PyErr_SetString(PyExc_OverflowError, - "private identifier too large to be mangled"); - return NULL; - } - - maxchar = PyUnicode_MAX_CHAR_VALUE(ident); - if (PyUnicode_MAX_CHAR_VALUE(privateobj) > maxchar) - maxchar = PyUnicode_MAX_CHAR_VALUE(privateobj); - - result = PyUnicode_New(1 + nlen + plen, maxchar); - if (!result) { - return NULL; - } - /* ident = "_" + priv[ipriv:] + ident # i.e. 1+plen+nlen bytes */ - PyUnicode_WRITE(PyUnicode_KIND(result), PyUnicode_DATA(result), 0, '_'); - if (PyUnicode_CopyCharacters(result, 1, privateobj, ipriv, plen) < 0) { - Py_DECREF(result); - return NULL; - } - if (PyUnicode_CopyCharacters(result, plen+1, ident, 0, nlen) < 0) { - Py_DECREF(result); - return NULL; - } - assert(_PyUnicode_CheckConsistency(result, 1)); - return result; -} - static int compiler_setup(struct compiler *c, mod_ty mod, PyObject *filename, diff --git a/Python/symtable.c b/Python/symtable.c index 89a2bc437dfa..df7473943f3f 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1,6 +1,5 @@ #include "Python.h" #include "pycore_ast.h" // identifier, stmt_ty -#include "pycore_compile.h" // _Py_Mangle(), _PyFuture_FromAST() #include "pycore_parser.h" // _PyParser_ASTFromString() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_symtable.h" // PySTEntryObject @@ -2152,3 +2151,69 @@ _Py_SymtableStringObjectFlags(const char *str, PyObject *filename, _PyArena_Free(arena); return st; } + +PyObject * +_Py_Mangle(PyObject *privateobj, PyObject *ident) +{ + /* Name mangling: __private becomes _classname__private. + This is independent from how the name is used. */ + if (privateobj == NULL || !PyUnicode_Check(privateobj) || + PyUnicode_READ_CHAR(ident, 0) != '_' || + PyUnicode_READ_CHAR(ident, 1) != '_') { + return Py_NewRef(ident); + } + size_t nlen = PyUnicode_GET_LENGTH(ident); + size_t plen = PyUnicode_GET_LENGTH(privateobj); + /* Don't mangle __id__ or names with dots. + + The only time a name with a dot can occur is when + we are compiling an import statement that has a + package name. + + TODO(jhylton): Decide whether we want to support + mangling of the module name, e.g. __M.X. + */ + if ((PyUnicode_READ_CHAR(ident, nlen-1) == '_' && + PyUnicode_READ_CHAR(ident, nlen-2) == '_') || + PyUnicode_FindChar(ident, '.', 0, nlen, 1) != -1) { + return Py_NewRef(ident); /* Don't mangle __whatever__ */ + } + /* Strip leading underscores from class name */ + size_t ipriv = 0; + while (PyUnicode_READ_CHAR(privateobj, ipriv) == '_') { + ipriv++; + } + if (ipriv == plen) { + return Py_NewRef(ident); /* Don't mangle if class is just underscores */ + } + plen -= ipriv; + + if (plen + nlen >= PY_SSIZE_T_MAX - 1) { + PyErr_SetString(PyExc_OverflowError, + "private identifier too large to be mangled"); + return NULL; + } + + Py_UCS4 maxchar = PyUnicode_MAX_CHAR_VALUE(ident); + if (PyUnicode_MAX_CHAR_VALUE(privateobj) > maxchar) { + maxchar = PyUnicode_MAX_CHAR_VALUE(privateobj); + } + + PyObject *result = PyUnicode_New(1 + nlen + plen, maxchar); + if (!result) { + return NULL; + } + /* ident = "_" + priv[ipriv:] + ident # i.e. 1+plen+nlen bytes */ + PyUnicode_WRITE(PyUnicode_KIND(result), PyUnicode_DATA(result), 0, '_'); + if (PyUnicode_CopyCharacters(result, 1, privateobj, ipriv, plen) < 0) { + Py_DECREF(result); + return NULL; + } + if (PyUnicode_CopyCharacters(result, plen+1, ident, 0, nlen) < 0) { + Py_DECREF(result); + return NULL; + } + assert(_PyUnicode_CheckConsistency(result, 1)); + return result; +} + From webhook-mailer at python.org Thu Mar 2 22:59:44 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Fri, 03 Mar 2023 03:59:44 -0000 Subject: [Python-checkins] gh-102324: Improve tests of `typing.override` (#102325) Message-ID: https://github.com/python/cpython/commit/12011dd8bafa6867f2b4a8a9e8e54cb0fbf006e4 commit: 12011dd8bafa6867f2b4a8a9e8e54cb0fbf006e4 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2023-03-02T19:59:05-08:00 summary: gh-102324: Improve tests of `typing.override` (#102325) Fixes #101564 files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index d61dc6e2fbd7..96496ec9279e 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4171,38 +4171,129 @@ class OverrideDecoratorTests(BaseTestCase): def test_override(self): class Base: def normal_method(self): ... + @classmethod + def class_method_good_order(cls): ... + @classmethod + def class_method_bad_order(cls): ... @staticmethod def static_method_good_order(): ... @staticmethod def static_method_bad_order(): ... - @staticmethod - def decorator_with_slots(): ... class Derived(Base): @override def normal_method(self): return 42 + @classmethod + @override + def class_method_good_order(cls): + return 42 + @override + @classmethod + def class_method_bad_order(cls): + return 42 + @staticmethod @override def static_method_good_order(): return 42 - @override @staticmethod def static_method_bad_order(): return 42 - self.assertIsSubclass(Derived, Base) instance = Derived() self.assertEqual(instance.normal_method(), 42) + self.assertIs(True, Derived.normal_method.__override__) self.assertIs(True, instance.normal_method.__override__) + + self.assertEqual(Derived.class_method_good_order(), 42) + self.assertIs(True, Derived.class_method_good_order.__override__) + self.assertEqual(Derived.class_method_bad_order(), 42) + self.assertIs(False, hasattr(Derived.class_method_bad_order, "__override__")) + self.assertEqual(Derived.static_method_good_order(), 42) self.assertIs(True, Derived.static_method_good_order.__override__) self.assertEqual(Derived.static_method_bad_order(), 42) self.assertIs(False, hasattr(Derived.static_method_bad_order, "__override__")) + # Base object is not changed: + self.assertIs(False, hasattr(Base.normal_method, "__override__")) + self.assertIs(False, hasattr(Base.class_method_good_order, "__override__")) + self.assertIs(False, hasattr(Base.class_method_bad_order, "__override__")) + self.assertIs(False, hasattr(Base.static_method_good_order, "__override__")) + self.assertIs(False, hasattr(Base.static_method_bad_order, "__override__")) + + def test_property(self): + class Base: + @property + def correct(self) -> int: + return 1 + @property + def wrong(self) -> int: + return 1 + + class Child(Base): + @property + @override + def correct(self) -> int: + return 2 + @override + @property + def wrong(self) -> int: + return 2 + + instance = Child() + self.assertEqual(instance.correct, 2) + self.assertTrue(Child.correct.fget.__override__) + self.assertEqual(instance.wrong, 2) + self.assertFalse(hasattr(Child.wrong, "__override__")) + self.assertFalse(hasattr(Child.wrong.fset, "__override__")) + + def test_silent_failure(self): + class CustomProp: + __slots__ = ('fget',) + def __init__(self, fget): + self.fget = fget + def __get__(self, obj, objtype=None): + return self.fget(obj) + + class WithOverride: + @override # must not fail on object with `__slots__` + @CustomProp + def some(self): + return 1 + + self.assertEqual(WithOverride.some, 1) + self.assertFalse(hasattr(WithOverride.some, "__override__")) + + def test_multiple_decorators(self): + import functools + + def with_wraps(f): # similar to `lru_cache` definition + @functools.wraps(f) + def wrapper(*args, **kwargs): + return f(*args, **kwargs) + return wrapper + + class WithOverride: + @override + @with_wraps + def on_top(self, a: int) -> int: + return a + 1 + @with_wraps + @override + def on_bottom(self, a: int) -> int: + return a + 2 + + instance = WithOverride() + self.assertEqual(instance.on_top(1), 2) + self.assertTrue(instance.on_top.__override__) + self.assertEqual(instance.on_bottom(1), 3) + self.assertTrue(instance.on_bottom.__override__) + class CastTests(BaseTestCase): From webhook-mailer at python.org Fri Mar 3 05:51:44 2023 From: webhook-mailer at python.org (zooba) Date: Fri, 03 Mar 2023 10:51:44 -0000 Subject: [Python-checkins] gh-101754: Document that Windows converts keys in `os.environ` to uppercase (GH-101840) Message-ID: https://github.com/python/cpython/commit/4e7c0cbf59595714848cf9827f6e5b40c3985924 commit: 4e7c0cbf59595714848cf9827f6e5b40c3985924 branch: main author: Owain Davies <116417456+OTheDev at users.noreply.github.com> committer: zooba date: 2023-03-03T10:51:32Z summary: gh-101754: Document that Windows converts keys in `os.environ` to uppercase (GH-101840) files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 85924d0e4836..23ce98785bed 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -201,6 +201,11 @@ process and user. ``'surrogateescape'`` error handler. Use :data:`environb` if you would like to use a different encoding. + On Windows, the keys are converted to uppercase. This also applies when + getting, setting, or deleting an item. For example, + ``environ['monty'] = 'python'`` maps the key ``'MONTY'`` to the value + ``'python'``. + .. note:: Calling :func:`putenv` directly does not change :data:`os.environ`, so it's better From webhook-mailer at python.org Fri Mar 3 05:58:37 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 03 Mar 2023 10:58:37 -0000 Subject: [Python-checkins] gh-101754: Document that Windows converts keys in `os.environ` to uppercase (GH-101840) Message-ID: https://github.com/python/cpython/commit/3d88b4e51a08d20c9325491226763a70eff164f8 commit: 3d88b4e51a08d20c9325491226763a70eff164f8 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-03T02:58:30-08:00 summary: gh-101754: Document that Windows converts keys in `os.environ` to uppercase (GH-101840) (cherry picked from commit 4e7c0cbf59595714848cf9827f6e5b40c3985924) Co-authored-by: Owain Davies <116417456+OTheDev at users.noreply.github.com> files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index e5fc63afdcf5..1f1e2fd31454 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -188,6 +188,11 @@ process and user. ``'surrogateescape'`` error handler. Use :data:`environb` if you would like to use a different encoding. + On Windows, the keys are converted to uppercase. This also applies when + getting, setting, or deleting an item. For example, + ``environ['monty'] = 'python'`` maps the key ``'MONTY'`` to the value + ``'python'``. + .. note:: Calling :func:`putenv` directly does not change :data:`os.environ`, so it's better From webhook-mailer at python.org Fri Mar 3 06:00:13 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 03 Mar 2023 11:00:13 -0000 Subject: [Python-checkins] gh-101754: Document that Windows converts keys in `os.environ` to uppercase (GH-101840) Message-ID: https://github.com/python/cpython/commit/32a738e5b3b54b667bfbe3f8d7cb1f51230e95a0 commit: 32a738e5b3b54b667bfbe3f8d7cb1f51230e95a0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-03T03:00:06-08:00 summary: gh-101754: Document that Windows converts keys in `os.environ` to uppercase (GH-101840) (cherry picked from commit 4e7c0cbf59595714848cf9827f6e5b40c3985924) Co-authored-by: Owain Davies <116417456+OTheDev at users.noreply.github.com> files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 759064a6e52e..e3e20510f809 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -201,6 +201,11 @@ process and user. ``'surrogateescape'`` error handler. Use :data:`environb` if you would like to use a different encoding. + On Windows, the keys are converted to uppercase. This also applies when + getting, setting, or deleting an item. For example, + ``environ['monty'] = 'python'`` maps the key ``'MONTY'`` to the value + ``'python'``. + .. note:: Calling :func:`putenv` directly does not change :data:`os.environ`, so it's better From webhook-mailer at python.org Fri Mar 3 08:14:41 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 03 Mar 2023 13:14:41 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E10=5D_GH-102126=3A_fix_deadlo?= =?utf-8?q?ck_at_shutdown_when_clearing_thread_state=E2=80=A6_=28=23102235?= =?utf-8?q?=29?= Message-ID: https://github.com/python/cpython/commit/6c2e052ee07f10a6336bb4de1cef71dbe7d30ee6 commit: 6c2e052ee07f10a6336bb4de1cef71dbe7d30ee6 branch: 3.10 author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-03T18:44:30+05:30 summary: [3.10] GH-102126: fix deadlock at shutdown when clearing thread state? (#102235) [3.10] GH-102126: fix deadlock at shutdown when clearing thread states (GH-102222). (cherry picked from commit 5f11478ce7fda826d399530af4c5ca96c592f144) files: A Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst M Python/pystate.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst new file mode 100644 index 000000000000..68c43688c3df --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst @@ -0,0 +1 @@ +Fix deadlock at shutdown when clearing thread states if any finalizer tries to acquire the runtime head lock. Patch by Kumar Aditya. diff --git a/Python/pystate.c b/Python/pystate.c index df98eb11bb0a..c7a6af5da893 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -293,11 +293,19 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) _PyErr_Clear(tstate); } + // Clear the current/main thread state last. HEAD_LOCK(runtime); - for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) { + PyThreadState *p = interp->tstate_head; + HEAD_UNLOCK(runtime); + while (p != NULL) { + // See https://github.com/python/cpython/issues/102126 + // Must be called without HEAD_LOCK held as it can deadlock + // if any finalizer tries to acquire that lock. PyThreadState_Clear(p); + HEAD_LOCK(runtime); + p = p->next; + HEAD_UNLOCK(runtime); } - HEAD_UNLOCK(runtime); Py_CLEAR(interp->audit_hooks); From webhook-mailer at python.org Fri Mar 3 12:16:58 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 03 Mar 2023 17:16:58 -0000 Subject: [Python-checkins] gh-102383: [docs] Arguments of `PyObject_CopyData` are `PyObject *` (#102390) Message-ID: https://github.com/python/cpython/commit/7b9132057d8f176cb9c40e8324f5122a3132ee58 commit: 7b9132057d8f176cb9c40e8324f5122a3132ee58 branch: main author: Nikita Sobolev committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-03T22:46:50+05:30 summary: gh-102383: [docs] Arguments of `PyObject_CopyData` are `PyObject *` (#102390) files: M Doc/c-api/buffer.rst diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index a04062fb2a68..91d1edd9b2ec 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -499,7 +499,7 @@ Buffer-related functions This function fails if *len* != *src->len*. -.. c:function:: int PyObject_CopyData(Py_buffer *dest, Py_buffer *src) +.. c:function:: int PyObject_CopyData(PyObject *dest, PyObject *src) Copy data from *src* to *dest* buffer. Can convert between C-style and or Fortran-style buffers. From webhook-mailer at python.org Fri Mar 3 12:25:39 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 03 Mar 2023 17:25:39 -0000 Subject: [Python-checkins] Add import of `unittest.mock.Mock` in documentation (#102346) Message-ID: https://github.com/python/cpython/commit/cb944d0be869dfb1189265467ec8a986176cc104 commit: cb944d0be869dfb1189265467ec8a986176cc104 branch: main author: Wagner Alberto committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-03T22:55:31+05:30 summary: Add import of `unittest.mock.Mock` in documentation (#102346) files: M Doc/library/unittest.mock.rst diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst index d6d8e5e9557d..6c4d801f69f5 100644 --- a/Doc/library/unittest.mock.rst +++ b/Doc/library/unittest.mock.rst @@ -72,6 +72,7 @@ available, and then make assertions about how they have been used: :attr:`side_effect` allows you to perform side effects, including raising an exception when a mock is called: + >>> from unittest.mock import Mock >>> mock = Mock(side_effect=KeyError('foo')) >>> mock() Traceback (most recent call last): From webhook-mailer at python.org Fri Mar 3 12:27:27 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 03 Mar 2023 17:27:27 -0000 Subject: [Python-checkins] gh-102383: [docs] Arguments of `PyObject_CopyData` are `PyObject *` (GH-102390) Message-ID: https://github.com/python/cpython/commit/00791f23b78cc61d732ef4a6386c9ce255113c3e commit: 00791f23b78cc61d732ef4a6386c9ce255113c3e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-03T09:27:20-08:00 summary: gh-102383: [docs] Arguments of `PyObject_CopyData` are `PyObject *` (GH-102390) (cherry picked from commit 7b9132057d8f176cb9c40e8324f5122a3132ee58) Co-authored-by: Nikita Sobolev files: M Doc/c-api/buffer.rst diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index a04062fb2a68..91d1edd9b2ec 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -499,7 +499,7 @@ Buffer-related functions This function fails if *len* != *src->len*. -.. c:function:: int PyObject_CopyData(Py_buffer *dest, Py_buffer *src) +.. c:function:: int PyObject_CopyData(PyObject *dest, PyObject *src) Copy data from *src* to *dest* buffer. Can convert between C-style and or Fortran-style buffers. From webhook-mailer at python.org Fri Mar 3 23:59:40 2023 From: webhook-mailer at python.org (gvanrossum) Date: Sat, 04 Mar 2023 04:59:40 -0000 Subject: [Python-checkins] gh-102021 : Allow multiple input files for interpreter loop generator (#102022) Message-ID: https://github.com/python/cpython/commit/8de59c1bb9fdcea69ff6e6357972ef1b75b71721 commit: 8de59c1bb9fdcea69ff6e6357972ef1b75b71721 branch: main author: Jacob Bower <1978924+jbower-fb at users.noreply.github.com> committer: gvanrossum date: 2023-03-03T20:59:21-08:00 summary: gh-102021 : Allow multiple input files for interpreter loop generator (#102022) The input files no longer use `-i`. files: M Makefile.pre.in M Python/generated_cases.c.h M Python/opcode_metadata.h M Tools/cases_generator/generate_cases.py M Tools/cases_generator/lexer.py M Tools/cases_generator/parser.py diff --git a/Makefile.pre.in b/Makefile.pre.in index b12a1bc060af..1a1853bf3d78 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1485,9 +1485,9 @@ regen-cases: PYTHONPATH=$(srcdir)/Tools/cases_generator \ $(PYTHON_FOR_REGEN) \ $(srcdir)/Tools/cases_generator/generate_cases.py \ - -i $(srcdir)/Python/bytecodes.c \ -o $(srcdir)/Python/generated_cases.c.h.new \ - -m $(srcdir)/Python/opcode_metadata.h.new + -m $(srcdir)/Python/opcode_metadata.h.new \ + $(srcdir)/Python/bytecodes.c $(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new $(UPDATE_FILE) $(srcdir)/Python/opcode_metadata.h $(srcdir)/Python/opcode_metadata.h.new diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index f59f7c17451c..82e18505b0d4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1,5 +1,6 @@ // This file is generated by Tools/cases_generator/generate_cases.py -// from Python/bytecodes.c +// from: +// Python/bytecodes.c // Do not edit! TARGET(NOP) { diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index f27906a3e349..67cb0088c3b7 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -1,5 +1,6 @@ -// This file is generated by Tools/cases_generator/generate_cases.py --metadata -// from Python/bytecodes.c +// This file is generated by Tools/cases_generator/generate_cases.py +// from: +// Python/bytecodes.c // Do not edit! #ifndef NEED_OPCODE_TABLES diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index b760172974c8..25cf75e4c1c4 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -37,15 +37,15 @@ description="Generate the code for the interpreter switch.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) -arg_parser.add_argument( - "-i", "--input", type=str, help="Instruction definitions", default=DEFAULT_INPUT -) arg_parser.add_argument( "-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT ) arg_parser.add_argument( "-m", "--metadata", type=str, help="Generated metadata", default=DEFAULT_METADATA_OUTPUT ) +arg_parser.add_argument( + "input", nargs=argparse.REMAINDER, help="Instruction definition file(s)" +) def effect_size(effect: StackEffect) -> tuple[int, str]: @@ -485,6 +485,11 @@ class MacroInstruction(SuperOrMacroInstruction): parts: list[Component | parser.CacheEffect] + at dataclasses.dataclass +class OverriddenInstructionPlaceHolder: + name: str + + AnyInstruction = Instruction | SuperInstruction | MacroInstruction INSTR_FMT_PREFIX = "INSTR_FMT_" @@ -492,32 +497,33 @@ class MacroInstruction(SuperOrMacroInstruction): class Analyzer: """Parse input, analyze it, and write to output.""" - filename: str + input_filenames: list[str] output_filename: str metadata_filename: str - src: str errors: int = 0 - def __init__(self, filename: str, output_filename: str, metadata_filename: str): + def __init__(self, input_filenames: list[str], output_filename: str, metadata_filename: str): """Read the input file.""" - self.filename = filename + self.input_filenames = input_filenames self.output_filename = output_filename self.metadata_filename = metadata_filename - with open(filename) as f: - self.src = f.read() def error(self, msg: str, node: parser.Node) -> None: lineno = 0 + filename = "" if context := node.context: + filename = context.owner.filename # Use line number of first non-comment in the node for token in context.owner.tokens[context.begin : context.end]: lineno = token.line if token.kind != "COMMENT": break - print(f"{self.filename}:{lineno}: {msg}", file=sys.stderr) + print(f"{filename}:{lineno}: {msg}", file=sys.stderr) self.errors += 1 - everything: list[parser.InstDef | parser.Super | parser.Macro] + everything: list[ + parser.InstDef | parser.Super | parser.Macro | OverriddenInstructionPlaceHolder + ] instrs: dict[str, Instruction] # Includes ops supers: dict[str, parser.Super] super_instrs: dict[str, SuperInstruction] @@ -531,7 +537,31 @@ def parse(self) -> None: We only want the parser to see the stuff between the begin and end markers. """ - psr = parser.Parser(self.src, filename=self.filename) + + self.everything = [] + self.instrs = {} + self.supers = {} + self.macros = {} + self.families = {} + + instrs_idx: dict[str, int] = dict() + + for filename in self.input_filenames: + self.parse_file(filename, instrs_idx) + + files = " + ".join(self.input_filenames) + print( + f"Read {len(self.instrs)} instructions/ops, " + f"{len(self.supers)} supers, {len(self.macros)} macros, " + f"and {len(self.families)} families from {files}", + file=sys.stderr, + ) + + def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: + with open(filename) as file: + src = file.read() + + psr = parser.Parser(src, filename=filename) # Skip until begin marker while tkn := psr.next(raw=True): @@ -551,16 +581,27 @@ def parse(self) -> None: # Parse from start psr.setpos(start) - self.everything = [] - self.instrs = {} - self.supers = {} - self.macros = {} - self.families = {} thing: parser.InstDef | parser.Super | parser.Macro | parser.Family | None + thing_first_token = psr.peek() while thing := psr.definition(): match thing: case parser.InstDef(name=name): + if name in self.instrs: + if not thing.override: + raise psr.make_syntax_error( + f"Duplicate definition of '{name}' @ {thing.context} " + f"previous definition @ {self.instrs[name].inst.context}", + thing_first_token, + ) + self.everything[instrs_idx[name]] = OverriddenInstructionPlaceHolder(name=name) + if name not in self.instrs and thing.override: + raise psr.make_syntax_error( + f"Definition of '{name}' @ {thing.context} is supposed to be " + "an override but no previous definition exists.", + thing_first_token, + ) self.instrs[name] = Instruction(thing) + instrs_idx[name] = len(self.everything) self.everything.append(thing) case parser.Super(name): self.supers[name] = thing @@ -573,14 +614,7 @@ def parse(self) -> None: case _: typing.assert_never(thing) if not psr.eof(): - raise psr.make_syntax_error("Extra stuff at the end") - - print( - f"Read {len(self.instrs)} instructions/ops, " - f"{len(self.supers)} supers, {len(self.macros)} macros, " - f"and {len(self.families)} families from {self.filename}", - file=sys.stderr, - ) + raise psr.make_syntax_error(f"Extra stuff at the end of {filename}") def analyze(self) -> None: """Analyze the inputs. @@ -879,6 +913,8 @@ def write_stack_effect_functions(self) -> None: popped_data: list[tuple[AnyInstruction, str]] = [] pushed_data: list[tuple[AnyInstruction, str]] = [] for thing in self.everything: + if isinstance(thing, OverriddenInstructionPlaceHolder): + continue instr, popped, pushed = self.get_stack_effect_info(thing) if instr is not None: popped_data.append((instr, popped)) @@ -907,6 +943,13 @@ def write_function( write_function("pushed", pushed_data) self.out.emit("") + def from_source_files(self) -> str: + paths = "\n// ".join( + os.path.relpath(filename, ROOT).replace(os.path.sep, posixpath.sep) + for filename in self.input_filenames + ) + return f"// from:\n// {paths}\n" + def write_metadata(self) -> None: """Write instruction metadata to output file.""" @@ -914,6 +957,8 @@ def write_metadata(self) -> None: all_formats: set[str] = set() for thing in self.everything: match thing: + case OverriddenInstructionPlaceHolder(): + continue case parser.InstDef(): format = self.instrs[thing.name].instr_fmt case parser.Super(): @@ -928,8 +973,8 @@ def write_metadata(self) -> None: with open(self.metadata_filename, "w") as f: # Write provenance header - f.write(f"// This file is generated by {THIS} --metadata\n") - f.write(f"// from {os.path.relpath(self.filename, ROOT).replace(os.path.sep, posixpath.sep)}\n") + f.write(f"// This file is generated by {THIS}\n") + f.write(self.from_source_files()) f.write(f"// Do not edit!\n") # Create formatter; the rest of the code uses this @@ -959,6 +1004,8 @@ def write_metadata(self) -> None: # Write metadata for each instruction for thing in self.everything: match thing: + case OverriddenInstructionPlaceHolder(): + continue case parser.InstDef(): if thing.kind != "op": self.write_metadata_for_inst(self.instrs[thing.name]) @@ -1008,7 +1055,7 @@ def write_instructions(self) -> None: with open(self.output_filename, "w") as f: # Write provenance header f.write(f"// This file is generated by {THIS}\n") - f.write(f"// from {os.path.relpath(self.filename, ROOT).replace(os.path.sep, posixpath.sep)}\n") + f.write(self.from_source_files()) f.write(f"// Do not edit!\n") # Create formatter; the rest of the code uses this @@ -1020,6 +1067,8 @@ def write_instructions(self) -> None: n_macros = 0 for thing in self.everything: match thing: + case OverriddenInstructionPlaceHolder(): + self.write_overridden_instr_place_holder(thing) case parser.InstDef(): if thing.kind != "op": n_instrs += 1 @@ -1039,9 +1088,17 @@ def write_instructions(self) -> None: file=sys.stderr, ) + def write_overridden_instr_place_holder(self, + place_holder: OverriddenInstructionPlaceHolder) -> None: + self.out.emit("") + self.out.emit( + f"// TARGET({place_holder.name}) overridden by later definition") + def write_instr(self, instr: Instruction) -> None: name = instr.name self.out.emit("") + if instr.inst.override: + self.out.emit("// Override") with self.out.block(f"TARGET({name})"): if instr.predicted: self.out.emit(f"PREDICTED({name});") @@ -1190,6 +1247,8 @@ def variable_used(node: parser.Node, name: str) -> bool: def main(): """Parse command line, parse input, analyze, write output.""" args = arg_parser.parse_args() # Prints message and sys.exit(2) on error + if len(args.input) == 0: + args.input.append(DEFAULT_INPUT) a = Analyzer(args.input, args.output, args.metadata) # Raises OSError if input unreadable a.parse() # Raises SyntaxError on failure a.analyze() # Prints messages and sets a.errors on failure diff --git a/Tools/cases_generator/lexer.py b/Tools/cases_generator/lexer.py index 39b6a212a67b..1c70d1c4089e 100644 --- a/Tools/cases_generator/lexer.py +++ b/Tools/cases_generator/lexer.py @@ -119,7 +119,7 @@ def choice(*opts): kwds = ( 'AUTO', 'BREAK', 'CASE', 'CHAR', 'CONST', 'CONTINUE', 'DEFAULT', 'DO', 'DOUBLE', 'ELSE', 'ENUM', 'EXTERN', - 'FLOAT', 'FOR', 'GOTO', 'IF', 'INLINE', 'INT', 'LONG', + 'FLOAT', 'FOR', 'GOTO', 'IF', 'INLINE', 'INT', 'LONG', 'OVERRIDE', 'REGISTER', 'OFFSETOF', 'RESTRICT', 'RETURN', 'SHORT', 'SIGNED', 'SIZEOF', 'STATIC', 'STRUCT', 'SWITCH', 'TYPEDEF', 'UNION', 'UNSIGNED', 'VOID', diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index c7c8d8af6b73..7bf45a350bc8 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -33,7 +33,7 @@ class Context(NamedTuple): owner: PLexer def __repr__(self): - return f"<{self.begin}-{self.end}>" + return f"<{self.owner.filename}: {self.begin}-{self.end}>" @dataclass @@ -99,6 +99,7 @@ class OpName(Node): @dataclass class InstHeader(Node): + override: bool register: bool kind: Literal["inst", "op", "legacy"] # Legacy means no (inputs -- outputs) name: str @@ -108,6 +109,7 @@ class InstHeader(Node): @dataclass class InstDef(Node): + override: bool register: bool kind: Literal["inst", "op", "legacy"] name: str @@ -152,17 +154,18 @@ def inst_def(self) -> InstDef | None: if hdr := self.inst_header(): if block := self.block(): return InstDef( - hdr.register, hdr.kind, hdr.name, hdr.inputs, hdr.outputs, block + hdr.override, hdr.register, hdr.kind, hdr.name, hdr.inputs, hdr.outputs, block ) raise self.make_syntax_error("Expected block") return None @contextual def inst_header(self) -> InstHeader | None: - # inst(NAME) - # | [register] inst(NAME, (inputs -- outputs)) - # | [register] op(NAME, (inputs -- outputs)) + # [override] inst(NAME) + # | [override] [register] inst(NAME, (inputs -- outputs)) + # | [override] [register] op(NAME, (inputs -- outputs)) # TODO: Make INST a keyword in the lexer. + override = bool(self.expect(lx.OVERRIDE)) register = bool(self.expect(lx.REGISTER)) if (tkn := self.expect(lx.IDENTIFIER)) and (kind := tkn.text) in ("inst", "op"): if self.expect(lx.LPAREN) and (tkn := self.expect(lx.IDENTIFIER)): @@ -171,10 +174,10 @@ def inst_header(self) -> InstHeader | None: inp, outp = self.io_effect() if self.expect(lx.RPAREN): if (tkn := self.peek()) and tkn.kind == lx.LBRACE: - return InstHeader(register, kind, name, inp, outp) + return InstHeader(override, register, kind, name, inp, outp) elif self.expect(lx.RPAREN) and kind == "inst": # No legacy stack effect if kind is "op". - return InstHeader(register, "legacy", name, [], []) + return InstHeader(override, register, "legacy", name, [], []) return None def io_effect(self) -> tuple[list[InputEffect], list[OutputEffect]]: From webhook-mailer at python.org Sat Mar 4 07:20:30 2023 From: webhook-mailer at python.org (mdickinson) Date: Sat, 04 Mar 2023 12:20:30 -0000 Subject: [Python-checkins] Remove unused internal macros (#102415) Message-ID: https://github.com/python/cpython/commit/b022250e67449e0bc49a3c982fe9e6a2d6a7b71a commit: b022250e67449e0bc49a3c982fe9e6a2d6a7b71a branch: main author: Mark Dickinson committer: mdickinson date: 2023-03-04T12:20:14Z summary: Remove unused internal macros (#102415) Since #101826 was merged, the internal macro `_Py_InIntegralTypeRange` is unused, as are its supporting macros `_Py_IntegralTypeMax` and `_Py_IntegralTypeMin`. This PR removes them. Note that `_Py_InIntegralTypeRange` doesn't actually work as advertised - it's not a safe way to avoid undefined behaviour in an integer to double conversion. files: M Include/internal/pycore_pymath.h diff --git a/Include/internal/pycore_pymath.h b/Include/internal/pycore_pymath.h index 5f3afe4df686..7a4e1c1eb714 100644 --- a/Include/internal/pycore_pymath.h +++ b/Include/internal/pycore_pymath.h @@ -56,21 +56,6 @@ static inline void _Py_ADJUST_ERANGE2(double x, double y) } } -// Return the maximum value of integral type *type*. -#define _Py_IntegralTypeMax(type) \ - (_Py_IS_TYPE_SIGNED(type) ? (((((type)1 << (sizeof(type)*CHAR_BIT - 2)) - 1) << 1) + 1) : ~(type)0) - -// Return the minimum value of integral type *type*. -#define _Py_IntegralTypeMin(type) \ - (_Py_IS_TYPE_SIGNED(type) ? -_Py_IntegralTypeMax(type) - 1 : 0) - -// Check whether *v* is in the range of integral type *type*. This is most -// useful if *v* is floating-point, since demoting a floating-point *v* to an -// integral type that cannot represent *v*'s integral part is undefined -// behavior. -#define _Py_InIntegralTypeRange(type, v) \ - (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type)) - //--- HAVE_PY_SET_53BIT_PRECISION macro ------------------------------------ // From webhook-mailer at python.org Sat Mar 4 09:21:36 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sat, 04 Mar 2023 14:21:36 -0000 Subject: [Python-checkins] gh-101892: Fix `SystemError` when a callable iterator call exhausts the iterator (#101896) Message-ID: https://github.com/python/cpython/commit/705487c6557c3d8866622b4d32528bf7fc2e4204 commit: 705487c6557c3d8866622b4d32528bf7fc2e4204 branch: main author: Raj <51259329+workingpayload at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-04T19:51:29+05:30 summary: gh-101892: Fix `SystemError` when a callable iterator call exhausts the iterator (#101896) Co-authored-by: Oleg Iarygin files: A Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst M Lib/test/test_iter.py M Objects/iterobject.c diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py index 6ab9b7a72303..30aedb0db3bb 100644 --- a/Lib/test/test_iter.py +++ b/Lib/test/test_iter.py @@ -348,6 +348,31 @@ def spam(state=[0]): return i self.check_iterator(iter(spam, 20), list(range(10)), pickle=False) + def test_iter_function_concealing_reentrant_exhaustion(self): + # gh-101892: Test two-argument iter() with a function that + # exhausts its associated iterator but forgets to either return + # a sentinel value or raise StopIteration. + HAS_MORE = 1 + NO_MORE = 2 + + def exhaust(iterator): + """Exhaust an iterator without raising StopIteration.""" + list(iterator) + + def spam(): + # Touching the iterator with exhaust() below will call + # spam() once again so protect against recursion. + if spam.is_recursive_call: + return NO_MORE + spam.is_recursive_call = True + exhaust(spam.iterator) + return HAS_MORE + + spam.is_recursive_call = False + spam.iterator = iter(spam, NO_MORE) + with self.assertRaises(StopIteration): + next(spam.iterator) + # Test exception propagation through function iterator def test_exception_function(self): def spam(state=[0]): diff --git a/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst b/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst new file mode 100644 index 000000000000..d586779b3a8a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst @@ -0,0 +1,3 @@ +Callable iterators no longer raise :class:`SystemError` when the +callable object exhausts the iterator but forgets to either return a +sentinel value or raise :class:`StopIteration`. diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 149b701b68e9..7cb17a6ca4ab 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -219,7 +219,7 @@ calliter_iternext(calliterobject *it) } result = _PyObject_CallNoArgs(it->it_callable); - if (result != NULL) { + if (result != NULL && it->it_sentinel != NULL){ int ok; ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ); @@ -227,7 +227,6 @@ calliter_iternext(calliterobject *it) return result; /* Common case, fast path */ } - Py_DECREF(result); if (ok > 0) { Py_CLEAR(it->it_callable); Py_CLEAR(it->it_sentinel); @@ -238,6 +237,7 @@ calliter_iternext(calliterobject *it) Py_CLEAR(it->it_callable); Py_CLEAR(it->it_sentinel); } + Py_XDECREF(result); return NULL; } From webhook-mailer at python.org Sat Mar 4 09:24:15 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sat, 04 Mar 2023 14:24:15 -0000 Subject: [Python-checkins] gh-102179: Fix `os.dup2` error reporting for negative fds (#102180) Message-ID: https://github.com/python/cpython/commit/c2bd55d26f8eb2850eb9f9026b5d7f0ed1420b65 commit: c2bd55d26f8eb2850eb9f9026b5d7f0ed1420b65 branch: main author: Alexey Izbyshev committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-04T19:54:08+05:30 summary: gh-102179: Fix `os.dup2` error reporting for negative fds (#102180) files: A Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst M Lib/test/test_os.py M Modules/posixmodule.c diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index deea207bfdad..792794ca1094 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2221,6 +2221,26 @@ def test_closerange(self): def test_dup2(self): self.check(os.dup2, 20) + @unittest.skipUnless(hasattr(os, 'dup2'), 'test needs os.dup2()') + @unittest.skipIf( + support.is_emscripten, + "dup2() with negative fds is broken on Emscripten (see gh-102179)" + ) + def test_dup2_negative_fd(self): + valid_fd = os.open(__file__, os.O_RDONLY) + self.addCleanup(os.close, valid_fd) + fds = [ + valid_fd, + -1, + -2**31, + ] + for fd, fd2 in itertools.product(fds, repeat=2): + if fd != fd2: + with self.subTest(fd=fd, fd2=fd2): + with self.assertRaises(OSError) as ctx: + os.dup2(fd, fd2) + self.assertEqual(ctx.exception.errno, errno.EBADF) + @unittest.skipUnless(hasattr(os, 'fchmod'), 'test needs os.fchmod()') def test_fchmod(self): self.check(os.fchmod, 0) diff --git a/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst b/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst new file mode 100644 index 000000000000..f77493e267ac --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst @@ -0,0 +1 @@ +Fix :func:`os.dup2` error message for negative fds. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 937233a3bd07..7beb2cee64a0 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9795,11 +9795,6 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) static int dup3_works = -1; #endif - if (fd < 0 || fd2 < 0) { - posix_error(); - return -1; - } - /* dup2() can fail with EINTR if the target FD is already open, because it * then has to be closed. See os_close_impl() for why we don't handle EINTR * upon close(), and therefore below. From webhook-mailer at python.org Sat Mar 4 09:46:24 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 04 Mar 2023 14:46:24 -0000 Subject: [Python-checkins] gh-101892: Fix `SystemError` when a callable iterator call exhausts the iterator (GH-101896) Message-ID: https://github.com/python/cpython/commit/06a3bb8c9416a53018ea23414d6018764a9e2845 commit: 06a3bb8c9416a53018ea23414d6018764a9e2845 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-04T06:46:17-08:00 summary: gh-101892: Fix `SystemError` when a callable iterator call exhausts the iterator (GH-101896) (cherry picked from commit 705487c6557c3d8866622b4d32528bf7fc2e4204) Co-authored-by: Raj <51259329+workingpayload at users.noreply.github.com> Co-authored-by: Oleg Iarygin files: A Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst M Lib/test/test_iter.py M Objects/iterobject.c diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py index 6ab9b7a72303..30aedb0db3bb 100644 --- a/Lib/test/test_iter.py +++ b/Lib/test/test_iter.py @@ -348,6 +348,31 @@ def spam(state=[0]): return i self.check_iterator(iter(spam, 20), list(range(10)), pickle=False) + def test_iter_function_concealing_reentrant_exhaustion(self): + # gh-101892: Test two-argument iter() with a function that + # exhausts its associated iterator but forgets to either return + # a sentinel value or raise StopIteration. + HAS_MORE = 1 + NO_MORE = 2 + + def exhaust(iterator): + """Exhaust an iterator without raising StopIteration.""" + list(iterator) + + def spam(): + # Touching the iterator with exhaust() below will call + # spam() once again so protect against recursion. + if spam.is_recursive_call: + return NO_MORE + spam.is_recursive_call = True + exhaust(spam.iterator) + return HAS_MORE + + spam.is_recursive_call = False + spam.iterator = iter(spam, NO_MORE) + with self.assertRaises(StopIteration): + next(spam.iterator) + # Test exception propagation through function iterator def test_exception_function(self): def spam(state=[0]): diff --git a/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst b/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst new file mode 100644 index 000000000000..d586779b3a8a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst @@ -0,0 +1,3 @@ +Callable iterators no longer raise :class:`SystemError` when the +callable object exhausts the iterator but forgets to either return a +sentinel value or raise :class:`StopIteration`. diff --git a/Objects/iterobject.c b/Objects/iterobject.c index ae09d2c0570e..822f9e293e27 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -222,7 +222,7 @@ calliter_iternext(calliterobject *it) } result = _PyObject_CallNoArgs(it->it_callable); - if (result != NULL) { + if (result != NULL && it->it_sentinel != NULL){ int ok; ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ); @@ -230,7 +230,6 @@ calliter_iternext(calliterobject *it) return result; /* Common case, fast path */ } - Py_DECREF(result); if (ok > 0) { Py_CLEAR(it->it_callable); Py_CLEAR(it->it_sentinel); @@ -241,6 +240,7 @@ calliter_iternext(calliterobject *it) Py_CLEAR(it->it_callable); Py_CLEAR(it->it_sentinel); } + Py_XDECREF(result); return NULL; } From webhook-mailer at python.org Sat Mar 4 09:55:09 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 04 Mar 2023 14:55:09 -0000 Subject: [Python-checkins] gh-102179: Fix `os.dup2` error reporting for negative fds (GH-102180) Message-ID: https://github.com/python/cpython/commit/cc6ce90206a84888659c2e088e3c046e87d9d5b8 commit: cc6ce90206a84888659c2e088e3c046e87d9d5b8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-04T06:55:02-08:00 summary: gh-102179: Fix `os.dup2` error reporting for negative fds (GH-102180) (cherry picked from commit c2bd55d26f8eb2850eb9f9026b5d7f0ed1420b65) Co-authored-by: Alexey Izbyshev files: A Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst M Lib/test/test_os.py M Modules/posixmodule.c diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 9970b234b483..58e83f658c44 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2176,6 +2176,26 @@ def test_closerange(self): def test_dup2(self): self.check(os.dup2, 20) + @unittest.skipUnless(hasattr(os, 'dup2'), 'test needs os.dup2()') + @unittest.skipIf( + support.is_emscripten, + "dup2() with negative fds is broken on Emscripten (see gh-102179)" + ) + def test_dup2_negative_fd(self): + valid_fd = os.open(__file__, os.O_RDONLY) + self.addCleanup(os.close, valid_fd) + fds = [ + valid_fd, + -1, + -2**31, + ] + for fd, fd2 in itertools.product(fds, repeat=2): + if fd != fd2: + with self.subTest(fd=fd, fd2=fd2): + with self.assertRaises(OSError) as ctx: + os.dup2(fd, fd2) + self.assertEqual(ctx.exception.errno, errno.EBADF) + @unittest.skipUnless(hasattr(os, 'fchmod'), 'test needs os.fchmod()') def test_fchmod(self): self.check(os.fchmod, 0) diff --git a/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst b/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst new file mode 100644 index 000000000000..f77493e267ac --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst @@ -0,0 +1 @@ +Fix :func:`os.dup2` error message for negative fds. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 150bb78cb41c..613b86f09c9e 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9387,11 +9387,6 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) static int dup3_works = -1; #endif - if (fd < 0 || fd2 < 0) { - posix_error(); - return -1; - } - /* dup2() can fail with EINTR if the target FD is already open, because it * then has to be closed. See os_close_impl() for why we don't handle EINTR * upon close(), and therefore below. From webhook-mailer at python.org Sat Mar 4 10:09:04 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 04 Mar 2023 15:09:04 -0000 Subject: [Python-checkins] gh-102302 Micro-optimize `inspect.Parameter.__hash__` (#102303) Message-ID: https://github.com/python/cpython/commit/90801e48fdd2a57c5c5a5e202ff76c3a7dc42a50 commit: 90801e48fdd2a57c5c5a5e202ff76c3a7dc42a50 branch: main author: Gouvernathor <44340603+Gouvernathor at users.noreply.github.com> committer: AlexWaygood date: 2023-03-04T15:08:57Z summary: gh-102302 Micro-optimize `inspect.Parameter.__hash__` (#102303) files: A Misc/NEWS.d/next/Library/2023-03-04-14-46-47.gh-issue-102302.-b_s6Z.rst M Lib/inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 8bb3a375735a..166667c62cdc 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2805,7 +2805,7 @@ def __repr__(self): return '<{} "{}">'.format(self.__class__.__name__, self) def __hash__(self): - return hash((self.name, self.kind, self.annotation, self.default)) + return hash((self._name, self._kind, self._annotation, self._default)) def __eq__(self, other): if self is other: diff --git a/Misc/NEWS.d/next/Library/2023-03-04-14-46-47.gh-issue-102302.-b_s6Z.rst b/Misc/NEWS.d/next/Library/2023-03-04-14-46-47.gh-issue-102302.-b_s6Z.rst new file mode 100644 index 000000000000..aaf4e62069ca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-04-14-46-47.gh-issue-102302.-b_s6Z.rst @@ -0,0 +1 @@ +Micro-optimise hashing of :class:`inspect.Parameter`, reducing the time it takes to hash an instance by around 40%. From webhook-mailer at python.org Sat Mar 4 10:26:18 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sat, 04 Mar 2023 15:26:18 -0000 Subject: [Python-checkins] [3.10] gh-101892: Fix `SystemError` when a callable iterator call exhausts the iterator (GH-101896) (#102422) Message-ID: https://github.com/python/cpython/commit/fe36778968a0fdddada282fbd7e28e8ccd0debe0 commit: fe36778968a0fdddada282fbd7e28e8ccd0debe0 branch: 3.10 author: Oleg Iarygin committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-04T20:56:12+05:30 summary: [3.10] gh-101892: Fix `SystemError` when a callable iterator call exhausts the iterator (GH-101896) (#102422) gh-101892: Fix `SystemError` when a callable iterator call exhausts the iterator (#101896) Co-authored-by: Oleg Iarygin (cherry picked from commit 705487c6557c3d8866622b4d32528bf7fc2e4204) Co-authored-by: Raj <51259329+workingpayload at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst M Lib/test/test_iter.py M Objects/iterobject.c diff --git a/Lib/test/test_iter.py b/Lib/test/test_iter.py index 3130ec5410c9..f9935d6f921a 100644 --- a/Lib/test/test_iter.py +++ b/Lib/test/test_iter.py @@ -346,6 +346,31 @@ def spam(state=[0]): return i self.check_iterator(iter(spam, 20), list(range(10)), pickle=False) + def test_iter_function_concealing_reentrant_exhaustion(self): + # gh-101892: Test two-argument iter() with a function that + # exhausts its associated iterator but forgets to either return + # a sentinel value or raise StopIteration. + HAS_MORE = 1 + NO_MORE = 2 + + def exhaust(iterator): + """Exhaust an iterator without raising StopIteration.""" + list(iterator) + + def spam(): + # Touching the iterator with exhaust() below will call + # spam() once again so protect against recursion. + if spam.is_recursive_call: + return NO_MORE + spam.is_recursive_call = True + exhaust(spam.iterator) + return HAS_MORE + + spam.is_recursive_call = False + spam.iterator = iter(spam, NO_MORE) + with self.assertRaises(StopIteration): + next(spam.iterator) + # Test exception propagation through function iterator def test_exception_function(self): def spam(state=[0]): diff --git a/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst b/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst new file mode 100644 index 000000000000..d586779b3a8a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst @@ -0,0 +1,3 @@ +Callable iterators no longer raise :class:`SystemError` when the +callable object exhausts the iterator but forgets to either return a +sentinel value or raise :class:`StopIteration`. diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 980c04bd1154..ffea1293c9f8 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -223,7 +223,7 @@ calliter_iternext(calliterobject *it) } result = _PyObject_CallNoArg(it->it_callable); - if (result != NULL) { + if (result != NULL && it->it_sentinel != NULL){ int ok; ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ); @@ -231,7 +231,6 @@ calliter_iternext(calliterobject *it) return result; /* Common case, fast path */ } - Py_DECREF(result); if (ok > 0) { Py_CLEAR(it->it_callable); Py_CLEAR(it->it_sentinel); @@ -242,6 +241,7 @@ calliter_iternext(calliterobject *it) Py_CLEAR(it->it_callable); Py_CLEAR(it->it_sentinel); } + Py_XDECREF(result); return NULL; } From webhook-mailer at python.org Sat Mar 4 10:27:39 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sat, 04 Mar 2023 15:27:39 -0000 Subject: [Python-checkins] [3.10] gh-102179: Fix `os.dup2` error reporting for negative fds (GH-102180) (#102419) Message-ID: https://github.com/python/cpython/commit/925ebfbfd22ac2ba3315ff427b9739d1e1907664 commit: 925ebfbfd22ac2ba3315ff427b9739d1e1907664 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-04T20:57:32+05:30 summary: [3.10] gh-102179: Fix `os.dup2` error reporting for negative fds (GH-102180) (#102419) * gh-102179: Fix `os.dup2` error reporting for negative fds (GH-102180) (cherry picked from commit c2bd55d26f8eb2850eb9f9026b5d7f0ed1420b65) Co-authored-by: Alexey Izbyshev Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> files: A Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst M Lib/test/test_os.py M Modules/posixmodule.c diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 1243b575dcaf..6b443c48f8fc 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2143,6 +2143,22 @@ def test_closerange(self): def test_dup2(self): self.check(os.dup2, 20) + @unittest.skipUnless(hasattr(os, 'dup2'), 'test needs os.dup2()') + def test_dup2_negative_fd(self): + valid_fd = os.open(__file__, os.O_RDONLY) + self.addCleanup(os.close, valid_fd) + fds = [ + valid_fd, + -1, + -2**31, + ] + for fd, fd2 in itertools.product(fds, repeat=2): + if fd != fd2: + with self.subTest(fd=fd, fd2=fd2): + with self.assertRaises(OSError) as ctx: + os.dup2(fd, fd2) + self.assertEqual(ctx.exception.errno, errno.EBADF) + @unittest.skipUnless(hasattr(os, 'fchmod'), 'test needs os.fchmod()') def test_fchmod(self): self.check(os.fchmod, 0) diff --git a/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst b/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst new file mode 100644 index 000000000000..f77493e267ac --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst @@ -0,0 +1 @@ +Fix :func:`os.dup2` error message for negative fds. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 62b81a16e806..c0421a94c173 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -9282,11 +9282,6 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable) static int dup3_works = -1; #endif - if (fd < 0 || fd2 < 0) { - posix_error(); - return -1; - } - /* dup2() can fail with EINTR if the target FD is already open, because it * then has to be closed. See os_close_impl() for why we don't handle EINTR * upon close(), and therefore below. From webhook-mailer at python.org Sat Mar 4 11:02:10 2023 From: webhook-mailer at python.org (corona10) Date: Sat, 04 Mar 2023 16:02:10 -0000 Subject: [Python-checkins] gh-101863: Fix wrong comments in EUC-KR codec (gh-102417) Message-ID: https://github.com/python/cpython/commit/77a3196b7cc17d90a8aae5629aa71ff183b9266a commit: 77a3196b7cc17d90a8aae5629aa71ff183b9266a branch: main author: Byeongmin Choi committer: corona10 date: 2023-03-05T01:01:54+09:00 summary: gh-101863: Fix wrong comments in EUC-KR codec (gh-102417) files: M Misc/ACKS M Modules/cjkcodecs/_codecs_kr.c diff --git a/Misc/ACKS b/Misc/ACKS index 2da3d0ab29b8..c591cd3bfe4b 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -322,6 +322,7 @@ Adal Chiriliuc Matt Chisholm Lita Cho Kit Yan Choi +Byeongmin Choi Sayan Chowdhury Yuan-Chao Chou Anders Chrigstr?m diff --git a/Modules/cjkcodecs/_codecs_kr.c b/Modules/cjkcodecs/_codecs_kr.c index 6d6acb5c4be4..72641e495af0 100644 --- a/Modules/cjkcodecs/_codecs_kr.c +++ b/Modules/cjkcodecs/_codecs_kr.c @@ -60,7 +60,7 @@ ENCODER(euc_kr) } else { /* Mapping is found in CP949 extension, - but we encode it in KS X 1001:1998 Annex 3, + but we encode it in KS X 1001:1998, make-up sequence for EUC-KR. */ REQUIRE_OUTBUF(8); @@ -120,7 +120,7 @@ DECODER(euc_kr) if (c == EUCKR_JAMO_FIRSTBYTE && INBYTE2 == EUCKR_JAMO_FILLER) { - /* KS X 1001:1998 Annex 3 make-up sequence */ + /* KS X 1001:1998 make-up sequence */ DBCHAR cho, jung, jong; REQUIRE_INBUF(8); From webhook-mailer at python.org Sat Mar 4 16:07:45 2023 From: webhook-mailer at python.org (ned-deily) Date: Sat, 04 Mar 2023 21:07:45 -0000 Subject: [Python-checkins] [3.8] GH-102306 Avoid GHA CI macOS test_posix failure by using the appropriate macOS SDK (GH-102307) Message-ID: https://github.com/python/cpython/commit/4812813fc6f2b509910af42cbc1da9a51aa6aa7e commit: 4812813fc6f2b509910af42cbc1da9a51aa6aa7e branch: 3.8 author: Ned Deily committer: ned-deily date: 2023-03-04T16:07:35-05:00 summary: [3.8] GH-102306 Avoid GHA CI macOS test_posix failure by using the appropriate macOS SDK (GH-102307) [3.8] Avoid GHA CI macOS test_posix failure by using the appropriate macOS SDK. files: A Misc/NEWS.d/next/Build/2023-02-27-18-55-32.gh-issue-102306.bkokFL.rst M .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e019e8992887..c25df8136df7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -129,7 +129,7 @@ jobs: steps: - uses: actions/checkout at v2 - name: Configure CPython - run: ./configure --with-pydebug --with-openssl=/usr/local/opt/openssl --prefix=/opt/python-dev + run: SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX12.sdk ./configure --with-pydebug --with-openssl=/usr/local/opt/openssl --prefix=/opt/python-dev - name: Build CPython run: make -j4 - name: Display build info diff --git a/Misc/NEWS.d/next/Build/2023-02-27-18-55-32.gh-issue-102306.bkokFL.rst b/Misc/NEWS.d/next/Build/2023-02-27-18-55-32.gh-issue-102306.bkokFL.rst new file mode 100644 index 000000000000..c51319bee4c1 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-02-27-18-55-32.gh-issue-102306.bkokFL.rst @@ -0,0 +1,2 @@ +[3.8] Avoid GHA CI macOS test_posix failure by using the appropriate macOS +SDK. From webhook-mailer at python.org Sat Mar 4 16:32:20 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 04 Mar 2023 21:32:20 -0000 Subject: [Python-checkins] gh-63301: Set exit code when tabnanny CLI exits on error (#7699) Message-ID: https://github.com/python/cpython/commit/81763341ede99ea5ae8993a57b8e3b71b46b2d72 commit: 81763341ede99ea5ae8993a57b8e3b71b46b2d72 branch: main author: Jaysinh Shukla committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-04T13:32:13-08:00 summary: gh-63301: Set exit code when tabnanny CLI exits on error (#7699) Co-authored-by: Erlend E. Aasland files: A Misc/NEWS.d/next/Library/2023-02-01-10-42-16.gh-issue-63301.XNxSFh.rst M Lib/tabnanny.py M Lib/test/test_tabnanny.py diff --git a/Lib/tabnanny.py b/Lib/tabnanny.py index a47f5a96b897..9d2df59d36ff 100755 --- a/Lib/tabnanny.py +++ b/Lib/tabnanny.py @@ -35,6 +35,7 @@ def errprint(*args): sys.stderr.write(sep + str(arg)) sep = " " sys.stderr.write("\n") + sys.exit(1) def main(): import getopt @@ -44,7 +45,6 @@ def main(): opts, args = getopt.getopt(sys.argv[1:], "qv") except getopt.error as msg: errprint(msg) - return for o, a in opts: if o == '-q': filename_only = filename_only + 1 @@ -52,7 +52,6 @@ def main(): verbose = verbose + 1 if not args: errprint("Usage:", sys.argv[0], "[-v] file_or_directory ...") - return for arg in args: check(arg) diff --git a/Lib/test/test_tabnanny.py b/Lib/test/test_tabnanny.py index e0a82e95c486..afb8da719b0e 100644 --- a/Lib/test/test_tabnanny.py +++ b/Lib/test/test_tabnanny.py @@ -110,9 +110,10 @@ def test_errprint(self): for args, expected in tests: with self.subTest(arguments=args, expected=expected): - with captured_stderr() as stderr: - tabnanny.errprint(*args) - self.assertEqual(stderr.getvalue() , expected) + with self.assertRaises(SystemExit): + with captured_stderr() as stderr: + tabnanny.errprint(*args) + self.assertEqual(stderr.getvalue() , expected) class TestNannyNag(TestCase): @@ -203,14 +204,16 @@ def test_when_wrong_indented(self): err = ('unindent does not match any outer indentation level' ' (, line 3)\n') err = f"{file_path!r}: Indentation Error: {err}" - self.verify_tabnanny_check(file_path, err=err) + with self.assertRaises(SystemExit): + self.verify_tabnanny_check(file_path, err=err) def test_when_tokenize_tokenerror(self): """A python source code file eligible for raising 'tokenize.TokenError'.""" with TemporaryPyFile(SOURCE_CODES["incomplete_expression"]) as file_path: err = "('EOF in multi-line statement', (7, 0))\n" err = f"{file_path!r}: Token Error: {err}" - self.verify_tabnanny_check(file_path, err=err) + with self.assertRaises(SystemExit): + self.verify_tabnanny_check(file_path, err=err) def test_when_nannynag_error_verbose(self): """A python source code file eligible for raising `tabnanny.NannyNag`. @@ -236,7 +239,8 @@ def test_when_no_file(self): path = 'no_file.py' err = (f"{path!r}: I/O Error: [Errno {errno.ENOENT}] " f"{os.strerror(errno.ENOENT)}: {path!r}\n") - self.verify_tabnanny_check(path, err=err) + with self.assertRaises(SystemExit): + self.verify_tabnanny_check(path, err=err) def test_errored_directory(self): """Directory containing wrongly indented python source code files.""" @@ -251,7 +255,8 @@ def test_errored_directory(self): err = ('unindent does not match any outer indentation level' ' (, line 3)\n') err = f"{e_file!r}: Indentation Error: {err}" - self.verify_tabnanny_check(tmp_dir, err=err) + with self.assertRaises(SystemExit): + self.verify_tabnanny_check(tmp_dir, err=err) class TestProcessTokens(TestCase): @@ -287,9 +292,12 @@ def test_with_errored_codes_samples(self): class TestCommandLine(TestCase): """Tests command line interface of `tabnanny`.""" - def validate_cmd(self, *args, stdout="", stderr="", partial=False): + def validate_cmd(self, *args, stdout="", stderr="", partial=False, expect_failure=False): """Common function to assert the behaviour of command line interface.""" - _, out, err = script_helper.assert_python_ok('-m', 'tabnanny', *args) + if expect_failure: + _, out, err = script_helper.assert_python_failure('-m', 'tabnanny', *args) + else: + _, out, err = script_helper.assert_python_ok('-m', 'tabnanny', *args) # Note: The `splitlines()` will solve the problem of CRLF(\r) added # by OS Windows. out = os.fsdecode(out) @@ -310,7 +318,7 @@ def test_with_errored_file(self): stderr = f"{file_path!r}: Indentation Error: " stderr += ('unindent does not match any outer indentation level' ' (, line 3)') - self.validate_cmd(file_path, stderr=stderr) + self.validate_cmd(file_path, stderr=stderr, expect_failure=True) def test_with_error_free_file(self): """Should not display anything if python file is correctly indented.""" @@ -321,7 +329,7 @@ def test_command_usage(self): """Should display usage on no arguments.""" path = findfile('tabnanny.py') stderr = f"Usage: {path} [-v] file_or_directory ..." - self.validate_cmd(stderr=stderr) + self.validate_cmd(stderr=stderr, expect_failure=True) def test_quiet_flag(self): """Should display less when quite mode is on.""" diff --git a/Misc/NEWS.d/next/Library/2023-02-01-10-42-16.gh-issue-63301.XNxSFh.rst b/Misc/NEWS.d/next/Library/2023-02-01-10-42-16.gh-issue-63301.XNxSFh.rst new file mode 100644 index 000000000000..e00e71fb8554 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-01-10-42-16.gh-issue-63301.XNxSFh.rst @@ -0,0 +1 @@ +Set exit code when :mod:`tabnanny` CLI exits on error. From webhook-mailer at python.org Sat Mar 4 16:35:31 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 04 Mar 2023 21:35:31 -0000 Subject: [Python-checkins] gh-101992: update pstlib module documentation (#102133) Message-ID: https://github.com/python/cpython/commit/e4609cbe4ca2d3d4fc07c19a7d0bdec52f054c63 commit: e4609cbe4ca2d3d4fc07c19a7d0bdec52f054c63 branch: main author: Dustin Rodrigues committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-04T13:35:25-08:00 summary: gh-101992: update pstlib module documentation (#102133) files: M Lib/plistlib.py diff --git a/Lib/plistlib.py b/Lib/plistlib.py index 30f3f673ada5..3292c30d5fb2 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -21,6 +21,9 @@ Generate Plist example: + import datetime + import plistlib + pl = dict( aString = "Doodah", aList = ["A", "B", 12, 32.1, [1, 2, 3]], @@ -28,22 +31,28 @@ anInt = 728, aDict = dict( anotherString = "", - aUnicodeValue = "M\xe4ssig, Ma\xdf", + aThirdString = "M\xe4ssig, Ma\xdf", aTrueValue = True, aFalseValue = False, ), someData = b"", someMoreData = b"" * 10, - aDate = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())), + aDate = datetime.datetime.now() ) - with open(fileName, 'wb') as fp: - dump(pl, fp) + print(plistlib.dumps(pl).decode()) Parse Plist example: - with open(fileName, 'rb') as fp: - pl = load(fp) - print(pl["aKey"]) + import plistlib + + plist = b''' + + foo + bar + + ''' + pl = plistlib.loads(plist) + print(pl["foo"]) """ __all__ = [ "InvalidFileException", "FMT_XML", "FMT_BINARY", "load", "dump", "loads", "dumps", "UID" From webhook-mailer at python.org Sat Mar 4 16:36:49 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 04 Mar 2023 21:36:49 -0000 Subject: [Python-checkins] [3.11] Clarify re docs for byte pattern group names (GH-99308) (#101001) Message-ID: https://github.com/python/cpython/commit/cda1d52ab810abbee3805fb5a333c957106f4b54 commit: cda1d52ab810abbee3805fb5a333c957106f4b54 branch: 3.11 author: Ilya Kulakov committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-04T13:36:42-08:00 summary: [3.11] Clarify re docs for byte pattern group names (GH-99308) (#101001) Fix wording of the deprecation notice in re for 3.11 files: M Doc/library/re.rst diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 7d8920169207..1f42cd28e65e 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -419,7 +419,8 @@ The special characters are: +---------------------------------------+----------------------------------+ .. deprecated:: 3.11 - Group names containing non-ASCII characters in bytes patterns. + Group *name* containing characters outside the ASCII range + (``b'\x00'``-``b'\x7f'``) in :class:`bytes` patterns. .. index:: single: (?P=; in regular expressions @@ -495,6 +496,8 @@ The special characters are: .. deprecated:: 3.11 Group *id* containing anything except ASCII digits. + Group *name* containing characters outside the ASCII range + (``b'\x00'``-``b'\x7f'``) in :class:`bytes` replacement strings. The special sequences consist of ``'\'`` and a character from the list below. @@ -1016,7 +1019,8 @@ Functions .. deprecated:: 3.11 Group *id* containing anything except ASCII digits. - Group names containing non-ASCII characters in bytes replacement strings. + Group *name* containing characters outside the ASCII range + (``b'\x00'``-``b'\x7f'``) in :class:`bytes` replacement strings. .. function:: subn(pattern, repl, string, count=0, flags=0) From webhook-mailer at python.org Sat Mar 4 16:39:59 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 04 Mar 2023 21:39:59 -0000 Subject: [Python-checkins] gh-96821: Add config option `--with-strict-overflow` (#96823) Message-ID: https://github.com/python/cpython/commit/eff9f43924fc836970b2378d58523388d9246194 commit: eff9f43924fc836970b2378d58523388d9246194 branch: main author: Matthias G?rgens committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-04T13:39:52-08:00 summary: gh-96821: Add config option `--with-strict-overflow` (#96823) Co-authored-by: C.A.M. Gerlach Co-authored-by: Erlend E. Aasland Co-authored-by: Adam Turner <9087854+AA-Turner at users.noreply.github.com> Co-authored-by: Shantanu files: A Misc/NEWS.d/next/Build/2022-09-14-10-38-15.gh-issue-96821.Zk2a9c.rst M Doc/using/configure.rst M configure M configure.ac diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 8fa8d250d533..8936bd381c9d 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -326,6 +326,11 @@ also be used to improve performance. Enable C-level code profiling with ``gprof`` (disabled by default). +.. cmdoption:: --with-strict-overflow + + Add ``-fstrict-overflow`` to the C compiler flags (by default we add + ``-fno-strict-overflow`` instead). + .. _debug-build: diff --git a/Misc/NEWS.d/next/Build/2022-09-14-10-38-15.gh-issue-96821.Zk2a9c.rst b/Misc/NEWS.d/next/Build/2022-09-14-10-38-15.gh-issue-96821.Zk2a9c.rst new file mode 100644 index 000000000000..865cfde8b063 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2022-09-14-10-38-15.gh-issue-96821.Zk2a9c.rst @@ -0,0 +1,3 @@ +Explicitly mark C extension modules that need defined signed integer overflow, +and add a configure option :option:`--with-strict-overflow`. +Patch by Matthias G?rgens and Shantanu Jain. diff --git a/configure b/configure index 557519ad86e0..9e99352f589f 100755 --- a/configure +++ b/configure @@ -1054,6 +1054,7 @@ with_assertions enable_optimizations with_lto enable_bolt +with_strict_overflow with_dsymutil with_address_sanitizer with_memory_sanitizer @@ -1825,6 +1826,8 @@ Optional Packages: --with-lto=[full|thin|no|yes] enable Link-Time-Optimization in any build (default is no) + --with-strict-overflow if 'yes', add -fstrict-overflow to CFLAGS, else add + -fno-strict-overflow (default is no) --with-dsymutil link debug information into final executable with dsymutil in macOS (default is no) --with-address-sanitizer @@ -8376,6 +8379,64 @@ case $CC in fi esac +save_CFLAGS=$CFLAGS +CFLAGS="-fstrict-overflow -fno-strict-overflow" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports -fstrict-overflow and -fno-strict-overflow" >&5 +$as_echo_n "checking if $CC supports -fstrict-overflow and -fno-strict-overflow... " >&6; } +if ${ac_cv_cc_supports_fstrict_overflow+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_cc_supports_fstrict_overflow=yes +else + ac_cv_cc_supports_fstrict_overflow=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cc_supports_fstrict_overflow" >&5 +$as_echo "$ac_cv_cc_supports_fstrict_overflow" >&6; } +CFLAGS=$save_CFLAGS + +if test "x$ac_cv_cc_supports_fstrict_overflow" = xyes; then : + STRICT_OVERFLOW_CFLAGS="-fstrict-overflow" + NO_STRICT_OVERFLOW_CFLAGS="-fno-strict-overflow" +else + STRICT_OVERFLOW_CFLAGS="" + NO_STRICT_OVERFLOW_CFLAGS="" +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-strict-overflow" >&5 +$as_echo_n "checking for --with-strict-overflow... " >&6; } + +# Check whether --with-strict-overflow was given. +if test "${with_strict_overflow+set}" = set; then : + withval=$with_strict_overflow; + if test "x$ac_cv_cc_supports_fstrict_overflow" = xno; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with-strict-overflow=yes requires a compiler that supports -fstrict-overflow" >&5 +$as_echo "$as_me: WARNING: --with-strict-overflow=yes requires a compiler that supports -fstrict-overflow" >&2;} +fi + +else + with_strict_overflow=no + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_strict_overflow" >&5 +$as_echo "$with_strict_overflow" >&6; } + # Check if CC supports -Og optimization level save_CFLAGS=$CFLAGS CFLAGS="-Og" @@ -8428,15 +8489,8 @@ if test "${OPT-unset}" = "unset" then case $GCC in yes) - # For gcc 4.x we need to use -fwrapv so lets check if its supported - if "$CC" -v --help 2>/dev/null |grep -- -fwrapv > /dev/null; then - WRAP="-fwrapv" - fi - if test -n "${cc_is_clang}" then - # Clang also needs -fwrapv - WRAP="-fwrapv" # bpo-30104: disable strict aliasing to compile correctly dtoa.c, # see Makefile.pre.in for more information CFLAGS_ALIASING="-fno-strict-aliasing" @@ -8447,7 +8501,7 @@ then if test "$Py_DEBUG" = 'true' ; then OPT="-g $PYDEBUG_CFLAGS -Wall" else - OPT="-g $WRAP -O3 -Wall" + OPT="-g -O3 -Wall" fi ;; *) @@ -8580,6 +8634,12 @@ UNIVERSAL_ARCH_FLAGS= # tweak BASECFLAGS based on compiler and platform +if test "x$with_strict_overflow" = xyes; then : + BASECFLAGS="$BASECFLAGS $STRICT_OVERFLOW_CFLAGS" +else + BASECFLAGS="$BASECFLAGS $NO_STRICT_OVERFLOW_CFLAGS" +fi + case $GCC in yes) CFLAGS_NODIST="$CFLAGS_NODIST -std=c11" @@ -27049,7 +27109,7 @@ fi as_fn_append MODULE_BLOCK "MODULE__CTYPES_STATE=$py_cv_module__ctypes$as_nl" if test "x$py_cv_module__ctypes" = xyes; then : - as_fn_append MODULE_BLOCK "MODULE__CTYPES_CFLAGS=$LIBFFI_CFLAGS$as_nl" + as_fn_append MODULE_BLOCK "MODULE__CTYPES_CFLAGS=$NO_STRICT_OVERFLOW_CFLAGS $LIBFFI_CFLAGS$as_nl" as_fn_append MODULE_BLOCK "MODULE__CTYPES_LDFLAGS=$LIBFFI_LIBS$as_nl" fi diff --git a/configure.ac b/configure.ac index 982f669acbcf..31b7a2157a2b 100644 --- a/configure.ac +++ b/configure.ac @@ -2073,6 +2073,45 @@ case $CC in fi esac +dnl Historically, some of our code assumed that signed integer overflow +dnl is defined behaviour via twos-complement. +dnl Set STRICT_OVERFLOW_CFLAGS and NO_STRICT_OVERFLOW_CFLAGS depending on compiler support. +dnl Pass the latter to modules that depend on such behaviour. +_SAVE_VAR([CFLAGS]) +CFLAGS="-fstrict-overflow -fno-strict-overflow" +AC_CACHE_CHECK([if $CC supports -fstrict-overflow and -fno-strict-overflow], + [ac_cv_cc_supports_fstrict_overflow], + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[]], [[]])], + [ac_cv_cc_supports_fstrict_overflow=yes], + [ac_cv_cc_supports_fstrict_overflow=no] + ) +) +_RESTORE_VAR([CFLAGS]) + +AS_VAR_IF([ac_cv_cc_supports_fstrict_overflow], [yes], + [STRICT_OVERFLOW_CFLAGS="-fstrict-overflow" + NO_STRICT_OVERFLOW_CFLAGS="-fno-strict-overflow"], + [STRICT_OVERFLOW_CFLAGS="" + NO_STRICT_OVERFLOW_CFLAGS=""]) + +AC_MSG_CHECKING([for --with-strict-overflow]) +AC_ARG_WITH([strict-overflow], + AS_HELP_STRING( + [--with-strict-overflow], + [if 'yes', add -fstrict-overflow to CFLAGS, else add -fno-strict-overflow (default is no)] + ), + [ + AS_VAR_IF( + [ac_cv_cc_supports_fstrict_overflow], [no], + [AC_MSG_WARN([--with-strict-overflow=yes requires a compiler that supports -fstrict-overflow])], + [] + ) + ], + [with_strict_overflow=no] +) +AC_MSG_RESULT([$with_strict_overflow]) + # Check if CC supports -Og optimization level _SAVE_VAR([CFLAGS]) CFLAGS="-Og" @@ -2103,15 +2142,8 @@ if test "${OPT-unset}" = "unset" then case $GCC in yes) - # For gcc 4.x we need to use -fwrapv so lets check if its supported - if "$CC" -v --help 2>/dev/null |grep -- -fwrapv > /dev/null; then - WRAP="-fwrapv" - fi - if test -n "${cc_is_clang}" then - # Clang also needs -fwrapv - WRAP="-fwrapv" # bpo-30104: disable strict aliasing to compile correctly dtoa.c, # see Makefile.pre.in for more information CFLAGS_ALIASING="-fno-strict-aliasing" @@ -2122,7 +2154,7 @@ then if test "$Py_DEBUG" = 'true' ; then OPT="-g $PYDEBUG_CFLAGS -Wall" else - OPT="-g $WRAP -O3 -Wall" + OPT="-g -O3 -Wall" fi ;; *) @@ -2237,6 +2269,10 @@ AC_DEFUN([PY_CHECK_CC_WARNING], [ ]) # tweak BASECFLAGS based on compiler and platform +AS_VAR_IF([with_strict_overflow], [yes], + [BASECFLAGS="$BASECFLAGS $STRICT_OVERFLOW_CFLAGS"], + [BASECFLAGS="$BASECFLAGS $NO_STRICT_OVERFLOW_CFLAGS"]) + case $GCC in yes) CFLAGS_NODIST="$CFLAGS_NODIST -std=c11" @@ -7213,7 +7249,7 @@ PY_STDLIB_MOD([_crypt], [$LIBCRYPT_CFLAGS], [$LIBCRYPT_LIBS]) PY_STDLIB_MOD([_ctypes], [], [test "$have_libffi" = yes], - [$LIBFFI_CFLAGS], [$LIBFFI_LIBS]) + [$NO_STRICT_OVERFLOW_CFLAGS $LIBFFI_CFLAGS], [$LIBFFI_LIBS]) PY_STDLIB_MOD([_curses], [], [test "$have_curses" != "no"], [$CURSES_CFLAGS], [$CURSES_LIBS] From webhook-mailer at python.org Sun Mar 5 01:36:19 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 06:36:19 -0000 Subject: [Python-checkins] gh-101992: update pstlib module documentation (GH-102133) Message-ID: https://github.com/python/cpython/commit/d4992c7315c1b92a73eec30407ed0cf3b673194a commit: d4992c7315c1b92a73eec30407ed0cf3b673194a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-04T22:36:07-08:00 summary: gh-101992: update pstlib module documentation (GH-102133) (cherry picked from commit e4609cbe4ca2d3d4fc07c19a7d0bdec52f054c63) Co-authored-by: Dustin Rodrigues files: M Lib/plistlib.py diff --git a/Lib/plistlib.py b/Lib/plistlib.py index bc8e4c8a7d70..d6c997efe9c5 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -21,6 +21,9 @@ Generate Plist example: + import datetime + import plistlib + pl = dict( aString = "Doodah", aList = ["A", "B", 12, 32.1, [1, 2, 3]], @@ -28,22 +31,28 @@ anInt = 728, aDict = dict( anotherString = "", - aUnicodeValue = "M\xe4ssig, Ma\xdf", + aThirdString = "M\xe4ssig, Ma\xdf", aTrueValue = True, aFalseValue = False, ), someData = b"", someMoreData = b"" * 10, - aDate = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())), + aDate = datetime.datetime.now() ) - with open(fileName, 'wb') as fp: - dump(pl, fp) + print(plistlib.dumps(pl).decode()) Parse Plist example: - with open(fileName, 'rb') as fp: - pl = load(fp) - print(pl["aKey"]) + import plistlib + + plist = b''' + + foo + bar + + ''' + pl = plistlib.loads(plist) + print(pl["foo"]) """ __all__ = [ "InvalidFileException", "FMT_XML", "FMT_BINARY", "load", "dump", "loads", "dumps", "UID" From webhook-mailer at python.org Sun Mar 5 01:36:19 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 06:36:19 -0000 Subject: [Python-checkins] gh-101992: update pstlib module documentation (GH-102133) Message-ID: https://github.com/python/cpython/commit/f96907a67ca1e21455fcec09447f0ffcc2dc1243 commit: f96907a67ca1e21455fcec09447f0ffcc2dc1243 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-04T22:36:00-08:00 summary: gh-101992: update pstlib module documentation (GH-102133) (cherry picked from commit e4609cbe4ca2d3d4fc07c19a7d0bdec52f054c63) Co-authored-by: Dustin Rodrigues files: M Lib/plistlib.py diff --git a/Lib/plistlib.py b/Lib/plistlib.py index 664890d25252..53e718f063b3 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -21,6 +21,9 @@ Generate Plist example: + import datetime + import plistlib + pl = dict( aString = "Doodah", aList = ["A", "B", 12, 32.1, [1, 2, 3]], @@ -28,22 +31,28 @@ anInt = 728, aDict = dict( anotherString = "", - aUnicodeValue = "M\xe4ssig, Ma\xdf", + aThirdString = "M\xe4ssig, Ma\xdf", aTrueValue = True, aFalseValue = False, ), someData = b"", someMoreData = b"" * 10, - aDate = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())), + aDate = datetime.datetime.now() ) - with open(fileName, 'wb') as fp: - dump(pl, fp) + print(plistlib.dumps(pl).decode()) Parse Plist example: - with open(fileName, 'rb') as fp: - pl = load(fp) - print(pl["aKey"]) + import plistlib + + plist = b''' + + foo + bar + + ''' + pl = plistlib.loads(plist) + print(pl["foo"]) """ __all__ = [ "InvalidFileException", "FMT_XML", "FMT_BINARY", "load", "dump", "loads", "dumps", "UID" From webhook-mailer at python.org Sun Mar 5 01:45:29 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sun, 05 Mar 2023 06:45:29 -0000 Subject: [Python-checkins] GH-97546: fix flaky asyncio `test_wait_for_race_condition` test (#102421) Message-ID: https://github.com/python/cpython/commit/a74cd3ba5de1aad1a1e1ee57328b54c22be47f77 commit: a74cd3ba5de1aad1a1e1ee57328b54c22be47f77 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-05T12:15:22+05:30 summary: GH-97546: fix flaky asyncio `test_wait_for_race_condition` test (#102421) files: M Lib/test/test_asyncio/test_waitfor.py diff --git a/Lib/test/test_asyncio/test_waitfor.py b/Lib/test/test_asyncio/test_waitfor.py index ed80540b2b38..d5c02ba4a01d 100644 --- a/Lib/test/test_asyncio/test_waitfor.py +++ b/Lib/test/test_asyncio/test_waitfor.py @@ -159,7 +159,7 @@ async def test_wait_for_race_condition(self): fut = loop.create_future() task = asyncio.wait_for(fut, timeout=0.2) - loop.call_later(0.1, fut.set_result, "ok") + loop.call_soon(fut.set_result, "ok") res = await task self.assertEqual(res, "ok") From webhook-mailer at python.org Sun Mar 5 04:32:03 2023 From: webhook-mailer at python.org (mdickinson) Date: Sun, 05 Mar 2023 09:32:03 -0000 Subject: [Python-checkins] Move around example in to_bytes() to avoid confusion (#101595) Message-ID: https://github.com/python/cpython/commit/5da379ca7dff44b321450800252be01041b3320b commit: 5da379ca7dff44b321450800252be01041b3320b branch: main author: Sergey B Kirpichev committer: mdickinson date: 2023-03-05T09:31:56Z summary: Move around example in to_bytes() to avoid confusion (#101595) Moves an example to be closer to the sentence that refers to it. files: M Doc/library/stdtypes.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 1240f80b0f11..550f808a16df 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -530,12 +530,14 @@ class`. In addition, it provides a few more methods: is ``False``. The default values can be used to conveniently turn an integer into a - single byte object. However, when using the default arguments, don't try - to convert a value greater than 255 or you'll get an :exc:`OverflowError`:: + single byte object:: >>> (65).to_bytes() b'A' + However, when using the default arguments, don't try + to convert a value greater than 255 or you'll get an :exc:`OverflowError`. + Equivalent to:: def to_bytes(n, length=1, byteorder='big', signed=False): From webhook-mailer at python.org Sun Mar 5 04:42:45 2023 From: webhook-mailer at python.org (mdickinson) Date: Sun, 05 Mar 2023 09:42:45 -0000 Subject: [Python-checkins] [3.11] Move around example in to_bytes() to avoid confusion (GH-101595) (#102434) Message-ID: https://github.com/python/cpython/commit/caff048cb35c9498e95c1e64c507e0c6b7783d7e commit: caff048cb35c9498e95c1e64c507e0c6b7783d7e branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: mdickinson date: 2023-03-05T09:42:36Z summary: [3.11] Move around example in to_bytes() to avoid confusion (GH-101595) (#102434) Move around example in to_bytes() to avoid confusion (GH-101595) Moves an example to be closer to the sentence that refers to it. (cherry picked from commit 5da379ca7dff44b321450800252be01041b3320b) Co-authored-by: Sergey B Kirpichev files: M Doc/library/stdtypes.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 608e15453be8..1fb3931902e4 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -530,12 +530,14 @@ class`. In addition, it provides a few more methods: is ``False``. The default values can be used to conveniently turn an integer into a - single byte object. However, when using the default arguments, don't try - to convert a value greater than 255 or you'll get an :exc:`OverflowError`:: + single byte object:: >>> (65).to_bytes() b'A' + However, when using the default arguments, don't try + to convert a value greater than 255 or you'll get an :exc:`OverflowError`. + Equivalent to:: def to_bytes(n, length=1, byteorder='big', signed=False): From webhook-mailer at python.org Sun Mar 5 06:00:48 2023 From: webhook-mailer at python.org (pablogsal) Date: Sun, 05 Mar 2023 11:00:48 -0000 Subject: [Python-checkins] gh-102356: Add thrashcan macros to filter object dealloc (#102426) Message-ID: https://github.com/python/cpython/commit/66aa78cbe604a7c5731f074b869f92174a8e3b64 commit: 66aa78cbe604a7c5731f074b869f92174a8e3b64 branch: main author: Marta G?mez Mac?as committer: pablogsal date: 2023-03-05T12:00:41+01:00 summary: gh-102356: Add thrashcan macros to filter object dealloc (#102426) Add thrashcan macros to the deallocator of the filter objects to protect against deeply nested destruction of chains of nested filters. files: A Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst M Lib/test/test_builtin.py M Misc/ACKS M Python/bltinmodule.c diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 9e19af0ae90f..e7a79bc13b7f 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -926,6 +926,16 @@ def test_filter_pickle(self): f2 = filter(filter_char, "abcdeabcde") self.check_iter_pickle(f1, list(f2), proto) + def test_filter_dealloc(self): + # Tests recursive deallocation of nested filter objects using the + # thrashcan mechanism. See gh-102356 for more details. + max_iters = 1000000 + i = filter(bool, range(max_iters)) + for _ in range(max_iters): + i = filter(bool, i) + del i + gc.collect() + def test_getattr(self): self.assertTrue(getattr(sys, 'stdout') is sys.stdout) self.assertRaises(TypeError, getattr) diff --git a/Misc/ACKS b/Misc/ACKS index c591cd3bfe4b..7bbde3af9978 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -637,6 +637,7 @@ Tim Golden Yonatan Goldschmidt Mark Gollahon Mikhail Golubev +Marta G?mez Mac?as Guilherme Gon?alves Tiago Gon?alves Chris Gonnerman diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst new file mode 100644 index 000000000000..c03fd5266bc3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst @@ -0,0 +1,2 @@ +Fix a bug that caused a crash when deallocating deeply nested filter +objects. Patch by Marta G?mez Mac?as. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 53439ab16040..12ca0ba6c487 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -553,9 +553,11 @@ static void filter_dealloc(filterobject *lz) { PyObject_GC_UnTrack(lz); + Py_TRASHCAN_BEGIN(lz, filter_dealloc) Py_XDECREF(lz->func); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); + Py_TRASHCAN_END } static int From webhook-mailer at python.org Sun Mar 5 06:20:55 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 11:20:55 -0000 Subject: [Python-checkins] gh-102356: Add thrashcan macros to filter object dealloc (GH-102426) Message-ID: https://github.com/python/cpython/commit/d4a04e55d8bd8eaa307f3e4aa8b443301a0d996a commit: d4a04e55d8bd8eaa307f3e4aa8b443301a0d996a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T03:20:41-08:00 summary: gh-102356: Add thrashcan macros to filter object dealloc (GH-102426) Add thrashcan macros to the deallocator of the filter objects to protect against deeply nested destruction of chains of nested filters. (cherry picked from commit 66aa78cbe604a7c5731f074b869f92174a8e3b64) Co-authored-by: Marta G?mez Mac?as files: A Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst M Lib/test/test_builtin.py M Misc/ACKS M Python/bltinmodule.c diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index aabf0ab5a92a..f31ab72c0209 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -799,6 +799,16 @@ def test_filter_pickle(self): f2 = filter(filter_char, "abcdeabcde") self.check_iter_pickle(f1, list(f2), proto) + def test_filter_dealloc(self): + # Tests recursive deallocation of nested filter objects using the + # thrashcan mechanism. See gh-102356 for more details. + max_iters = 1000000 + i = filter(bool, range(max_iters)) + for _ in range(max_iters): + i = filter(bool, i) + del i + gc.collect() + def test_getattr(self): self.assertTrue(getattr(sys, 'stdout') is sys.stdout) self.assertRaises(TypeError, getattr, sys, 1) diff --git a/Misc/ACKS b/Misc/ACKS index b4be8af3d99f..de1fb148e926 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -627,6 +627,7 @@ Tim Golden Yonatan Goldschmidt Mark Gollahon Mikhail Golubev +Marta G?mez Mac?as Guilherme Gon?alves Tiago Gon?alves Chris Gonnerman diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst new file mode 100644 index 000000000000..c03fd5266bc3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst @@ -0,0 +1,2 @@ +Fix a bug that caused a crash when deallocating deeply nested filter +objects. Patch by Marta G?mez Mac?as. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 659b78edc3de..6ea20bfc5f7c 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -567,9 +567,11 @@ static void filter_dealloc(filterobject *lz) { PyObject_GC_UnTrack(lz); + Py_TRASHCAN_BEGIN(lz, filter_dealloc) Py_XDECREF(lz->func); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); + Py_TRASHCAN_END } static int From webhook-mailer at python.org Sun Mar 5 06:25:55 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 11:25:55 -0000 Subject: [Python-checkins] gh-102356: Add thrashcan macros to filter object dealloc (GH-102426) Message-ID: https://github.com/python/cpython/commit/63fd95410038d1333da8b514adffdd0f4736aa27 commit: 63fd95410038d1333da8b514adffdd0f4736aa27 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T03:25:48-08:00 summary: gh-102356: Add thrashcan macros to filter object dealloc (GH-102426) Add thrashcan macros to the deallocator of the filter objects to protect against deeply nested destruction of chains of nested filters. (cherry picked from commit 66aa78cbe604a7c5731f074b869f92174a8e3b64) Co-authored-by: Marta G?mez Mac?as files: A Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst M Lib/test/test_builtin.py M Misc/ACKS M Python/bltinmodule.c diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 6cd72eda774c..0f6d2db0ecb6 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -919,6 +919,16 @@ def test_filter_pickle(self): f2 = filter(filter_char, "abcdeabcde") self.check_iter_pickle(f1, list(f2), proto) + def test_filter_dealloc(self): + # Tests recursive deallocation of nested filter objects using the + # thrashcan mechanism. See gh-102356 for more details. + max_iters = 1000000 + i = filter(bool, range(max_iters)) + for _ in range(max_iters): + i = filter(bool, i) + del i + gc.collect() + def test_getattr(self): self.assertTrue(getattr(sys, 'stdout') is sys.stdout) self.assertRaises(TypeError, getattr) diff --git a/Misc/ACKS b/Misc/ACKS index 22df1b998fb1..afe86d37b0a7 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -631,6 +631,7 @@ Tim Golden Yonatan Goldschmidt Mark Gollahon Mikhail Golubev +Marta G?mez Mac?as Guilherme Gon?alves Tiago Gon?alves Chris Gonnerman diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst new file mode 100644 index 000000000000..c03fd5266bc3 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst @@ -0,0 +1,2 @@ +Fix a bug that caused a crash when deallocating deeply nested filter +objects. Patch by Marta G?mez Mac?as. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index a3fdb394a136..6c8725f98231 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -556,9 +556,11 @@ static void filter_dealloc(filterobject *lz) { PyObject_GC_UnTrack(lz); + Py_TRASHCAN_BEGIN(lz, filter_dealloc) Py_XDECREF(lz->func); Py_XDECREF(lz->it); Py_TYPE(lz)->tp_free(lz); + Py_TRASHCAN_END } static int From webhook-mailer at python.org Sun Mar 5 09:54:40 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Sun, 05 Mar 2023 14:54:40 -0000 Subject: [Python-checkins] gh-101979: argparse: fix a bug where parentheses in metavar argument of add_argument() were dropped (#102318) Message-ID: https://github.com/python/cpython/commit/9a478be1a4314734c697dda7a7b0e633a6fb0751 commit: 9a478be1a4314734c697dda7a7b0e633a6fb0751 branch: main author: Yeojin Kim committer: JelleZijlstra date: 2023-03-05T06:54:33-08:00 summary: gh-101979: argparse: fix a bug where parentheses in metavar argument of add_argument() were dropped (#102318) files: A Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst M Lib/argparse.py M Lib/test/test_argparse.py diff --git a/Lib/argparse.py b/Lib/argparse.py index 240625ff0108..a819d2650e85 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -403,10 +403,18 @@ def _format_actions_usage(self, actions, groups): except ValueError: continue else: - end = start + len(group._group_actions) + group_action_count = len(group._group_actions) + end = start + group_action_count if actions[start:end] == group._group_actions: + + suppressed_actions_count = 0 for action in group._group_actions: group_actions.add(action) + if action.help is SUPPRESS: + suppressed_actions_count += 1 + + exposed_actions_count = group_action_count - suppressed_actions_count + if not group.required: if start in inserts: inserts[start] += ' [' @@ -416,7 +424,7 @@ def _format_actions_usage(self, actions, groups): inserts[end] += ']' else: inserts[end] = ']' - else: + elif exposed_actions_count > 1: if start in inserts: inserts[start] += ' (' else: @@ -490,7 +498,6 @@ def _format_actions_usage(self, actions, groups): text = _re.sub(r'(%s) ' % open, r'\1', text) text = _re.sub(r' (%s)' % close, r'\1', text) text = _re.sub(r'%s *%s' % (open, close), r'', text) - text = _re.sub(r'\(([^|]*)\)', r'\1', text) text = text.strip() # return the text diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index cabb2f837693..861da2326d12 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -3764,6 +3764,28 @@ class TestHelpUsage(HelpTestCase): version = '' +class TestHelpUsageWithParentheses(HelpTestCase): + parser_signature = Sig(prog='PROG') + argument_signatures = [ + Sig('positional', metavar='(example) positional'), + Sig('-p', '--optional', metavar='{1 (option A), 2 (option B)}'), + ] + + usage = '''\ + usage: PROG [-h] [-p {1 (option A), 2 (option B)}] (example) positional + ''' + help = usage + '''\ + + positional arguments: + (example) positional + + options: + -h, --help show this help message and exit + -p {1 (option A), 2 (option B)}, --optional {1 (option A), 2 (option B)} + ''' + version = '' + + class TestHelpOnlyUserGroups(HelpTestCase): """Test basic usage messages""" diff --git a/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst b/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst new file mode 100644 index 000000000000..1efe72439b3a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst @@ -0,0 +1,2 @@ +Fix a bug where parentheses in the ``metavar`` argument to :meth:`argparse.ArgumentParser.add_argument` were +dropped. Patch by Yeojin Kim. From webhook-mailer at python.org Sun Mar 5 10:07:51 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 15:07:51 -0000 Subject: [Python-checkins] Fix unused classes in a typing test (GH-102437) Message-ID: https://github.com/python/cpython/commit/7894bbe94ba319eb650f383cb5196424c77b2cfd commit: 7894bbe94ba319eb650f383cb5196424c77b2cfd branch: main author: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T07:07:44-08:00 summary: Fix unused classes in a typing test (GH-102437) As part of investigation issue https://github.com/python/cpython/issues/102433, I discovered what I believe to be an error where two classes `CI` and `DI` are not being used. The assertions beneath them act on `C` and `D`, duplicating existing assertions in this test. Automerge-Triggered-By: GH:AlexWaygood files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 96496ec9279e..2eeaf91d78d8 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2921,8 +2921,8 @@ class DI: def __init__(self): self.x = None - self.assertIsInstance(C(), P) - self.assertIsInstance(D(), P) + self.assertIsInstance(CI(), P) + self.assertIsInstance(DI(), P) def test_protocols_in_unions(self): class P(Protocol): From webhook-mailer at python.org Sun Mar 5 10:16:21 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 15:16:21 -0000 Subject: [Python-checkins] gh-101979: argparse: fix a bug where parentheses in metavar argument of add_argument() were dropped (GH-102318) Message-ID: https://github.com/python/cpython/commit/2a062f275970b3775b055c2c82f31b766271ae18 commit: 2a062f275970b3775b055c2c82f31b766271ae18 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T07:16:14-08:00 summary: gh-101979: argparse: fix a bug where parentheses in metavar argument of add_argument() were dropped (GH-102318) (cherry picked from commit 9a478be1a4314734c697dda7a7b0e633a6fb0751) Co-authored-by: Yeojin Kim files: A Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst M Lib/argparse.py M Lib/test/test_argparse.py diff --git a/Lib/argparse.py b/Lib/argparse.py index fb042a86b47c..736bf5ab21a5 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -400,10 +400,18 @@ def _format_actions_usage(self, actions, groups): except ValueError: continue else: - end = start + len(group._group_actions) + group_action_count = len(group._group_actions) + end = start + group_action_count if actions[start:end] == group._group_actions: + + suppressed_actions_count = 0 for action in group._group_actions: group_actions.add(action) + if action.help is SUPPRESS: + suppressed_actions_count += 1 + + exposed_actions_count = group_action_count - suppressed_actions_count + if not group.required: if start in inserts: inserts[start] += ' [' @@ -413,7 +421,7 @@ def _format_actions_usage(self, actions, groups): inserts[end] += ']' else: inserts[end] = ']' - else: + elif exposed_actions_count > 1: if start in inserts: inserts[start] += ' (' else: @@ -487,7 +495,6 @@ def _format_actions_usage(self, actions, groups): text = _re.sub(r'(%s) ' % open, r'\1', text) text = _re.sub(r' (%s)' % close, r'\1', text) text = _re.sub(r'%s *%s' % (open, close), r'', text) - text = _re.sub(r'\(([^|]*)\)', r'\1', text) text = text.strip() # return the text diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 4d43e3310d49..5df6f3263075 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -3729,6 +3729,28 @@ class TestHelpUsage(HelpTestCase): version = '' +class TestHelpUsageWithParentheses(HelpTestCase): + parser_signature = Sig(prog='PROG') + argument_signatures = [ + Sig('positional', metavar='(example) positional'), + Sig('-p', '--optional', metavar='{1 (option A), 2 (option B)}'), + ] + + usage = '''\ + usage: PROG [-h] [-p {1 (option A), 2 (option B)}] (example) positional + ''' + help = usage + '''\ + + positional arguments: + (example) positional + + options: + -h, --help show this help message and exit + -p {1 (option A), 2 (option B)}, --optional {1 (option A), 2 (option B)} + ''' + version = '' + + class TestHelpOnlyUserGroups(HelpTestCase): """Test basic usage messages""" diff --git a/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst b/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst new file mode 100644 index 000000000000..1efe72439b3a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst @@ -0,0 +1,2 @@ +Fix a bug where parentheses in the ``metavar`` argument to :meth:`argparse.ArgumentParser.add_argument` were +dropped. Patch by Yeojin Kim. From webhook-mailer at python.org Sun Mar 5 10:18:40 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 15:18:40 -0000 Subject: [Python-checkins] gh-101979: argparse: fix a bug where parentheses in metavar argument of add_argument() were dropped (GH-102318) Message-ID: https://github.com/python/cpython/commit/e748f9e2704c173c830c48c069bb566aaeee06e5 commit: e748f9e2704c173c830c48c069bb566aaeee06e5 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T07:18:34-08:00 summary: gh-101979: argparse: fix a bug where parentheses in metavar argument of add_argument() were dropped (GH-102318) (cherry picked from commit 9a478be1a4314734c697dda7a7b0e633a6fb0751) Co-authored-by: Yeojin Kim files: A Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst M Lib/argparse.py M Lib/test/test_argparse.py diff --git a/Lib/argparse.py b/Lib/argparse.py index 77619088614e..96617464966f 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -403,10 +403,18 @@ def _format_actions_usage(self, actions, groups): except ValueError: continue else: - end = start + len(group._group_actions) + group_action_count = len(group._group_actions) + end = start + group_action_count if actions[start:end] == group._group_actions: + + suppressed_actions_count = 0 for action in group._group_actions: group_actions.add(action) + if action.help is SUPPRESS: + suppressed_actions_count += 1 + + exposed_actions_count = group_action_count - suppressed_actions_count + if not group.required: if start in inserts: inserts[start] += ' [' @@ -416,7 +424,7 @@ def _format_actions_usage(self, actions, groups): inserts[end] += ']' else: inserts[end] = ']' - else: + elif exposed_actions_count > 1: if start in inserts: inserts[start] += ' (' else: @@ -490,7 +498,6 @@ def _format_actions_usage(self, actions, groups): text = _re.sub(r'(%s) ' % open, r'\1', text) text = _re.sub(r' (%s)' % close, r'\1', text) text = _re.sub(r'%s *%s' % (open, close), r'', text) - text = _re.sub(r'\(([^|]*)\)', r'\1', text) text = text.strip() # return the text diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 1acecbb8abaa..3fb88e5c6371 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -3753,6 +3753,28 @@ class TestHelpUsage(HelpTestCase): version = '' +class TestHelpUsageWithParentheses(HelpTestCase): + parser_signature = Sig(prog='PROG') + argument_signatures = [ + Sig('positional', metavar='(example) positional'), + Sig('-p', '--optional', metavar='{1 (option A), 2 (option B)}'), + ] + + usage = '''\ + usage: PROG [-h] [-p {1 (option A), 2 (option B)}] (example) positional + ''' + help = usage + '''\ + + positional arguments: + (example) positional + + options: + -h, --help show this help message and exit + -p {1 (option A), 2 (option B)}, --optional {1 (option A), 2 (option B)} + ''' + version = '' + + class TestHelpOnlyUserGroups(HelpTestCase): """Test basic usage messages""" diff --git a/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst b/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst new file mode 100644 index 000000000000..1efe72439b3a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst @@ -0,0 +1,2 @@ +Fix a bug where parentheses in the ``metavar`` argument to :meth:`argparse.ArgumentParser.add_argument` were +dropped. Patch by Yeojin Kim. From webhook-mailer at python.org Sun Mar 5 10:31:49 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 15:31:49 -0000 Subject: [Python-checkins] Fix unused classes in a typing test (GH-102437) Message-ID: https://github.com/python/cpython/commit/c957128b480445079b462b23b5ba3162c032f098 commit: c957128b480445079b462b23b5ba3162c032f098 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T07:31:42-08:00 summary: Fix unused classes in a typing test (GH-102437) As part of investigation issue https://github.com/python/cpython/issues/102433, I discovered what I believe to be an error where two classes `CI` and `DI` are not being used. The assertions beneath them act on `C` and `D`, duplicating existing assertions in this test. (cherry picked from commit 7894bbe94ba319eb650f383cb5196424c77b2cfd) Co-authored-by: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> Automerge-Triggered-By: GH:AlexWaygood files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 276f95bacfcf..4fe17a655dfd 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2916,8 +2916,8 @@ class DI: def __init__(self): self.x = None - self.assertIsInstance(C(), P) - self.assertIsInstance(D(), P) + self.assertIsInstance(CI(), P) + self.assertIsInstance(DI(), P) def test_protocols_in_unions(self): class P(Protocol): From webhook-mailer at python.org Sun Mar 5 10:37:41 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 15:37:41 -0000 Subject: [Python-checkins] Fix unused classes in a typing test (GH-102437) Message-ID: https://github.com/python/cpython/commit/94e08e174d8828298e51501e505ab567cd80ef25 commit: 94e08e174d8828298e51501e505ab567cd80ef25 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T07:37:33-08:00 summary: Fix unused classes in a typing test (GH-102437) As part of investigation issue https://github.com/python/cpython/issues/102433, I discovered what I believe to be an error where two classes `CI` and `DI` are not being used. The assertions beneath them act on `C` and `D`, duplicating existing assertions in this test. (cherry picked from commit 7894bbe94ba319eb650f383cb5196424c77b2cfd) Co-authored-by: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> Automerge-Triggered-By: GH:AlexWaygood files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 7e033c02c40e..2be4195b8565 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1528,8 +1528,8 @@ class DI: def __init__(self): self.x = None - self.assertIsInstance(C(), P) - self.assertIsInstance(D(), P) + self.assertIsInstance(CI(), P) + self.assertIsInstance(DI(), P) def test_protocols_in_unions(self): class P(Protocol): From webhook-mailer at python.org Sun Mar 5 12:31:33 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 05 Mar 2023 17:31:33 -0000 Subject: [Python-checkins] GH-102341: Improve the test function for pow (#102342) Message-ID: https://github.com/python/cpython/commit/32220543e2db36c6146ff2704ed1714a6adecc1b commit: 32220543e2db36c6146ff2704ed1714a6adecc1b branch: main author: Partha P. Mukherjee committer: terryjreedy date: 2023-03-05T12:31:26-05:00 summary: GH-102341: Improve the test function for pow (#102342) Co-authored-by: Terry Jan Reedy files: M Lib/test/test_pow.py diff --git a/Lib/test/test_pow.py b/Lib/test/test_pow.py index 5cea9ceb20f5..eeb482ec4b27 100644 --- a/Lib/test/test_pow.py +++ b/Lib/test/test_pow.py @@ -19,12 +19,11 @@ def powtest(self, type): self.assertEqual(pow(2, i), pow2) if i != 30 : pow2 = pow2*2 - for othertype in (int,): - for i in list(range(-10, 0)) + list(range(1, 10)): - ii = type(i) - for j in range(1, 11): - jj = -othertype(j) - pow(ii, jj) + for i in list(range(-10, 0)) + list(range(1, 10)): + ii = type(i) + inv = pow(ii, -1) # inverse of ii + for jj in range(-10, 0): + self.assertAlmostEqual(pow(ii, jj), pow(inv, -jj)) for othertype in int, float: for i in range(1, 100): From webhook-mailer at python.org Sun Mar 5 12:53:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 17:53:56 -0000 Subject: [Python-checkins] GH-102341: Improve the test function for pow (GH-102342) Message-ID: https://github.com/python/cpython/commit/9cec6022e438a28a66bc775b497f97d8bbad9610 commit: 9cec6022e438a28a66bc775b497f97d8bbad9610 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T09:53:50-08:00 summary: GH-102341: Improve the test function for pow (GH-102342) (cherry picked from commit 32220543e2db36c6146ff2704ed1714a6adecc1b) Co-authored-by: Partha P. Mukherjee Co-authored-by: Terry Jan Reedy files: M Lib/test/test_pow.py diff --git a/Lib/test/test_pow.py b/Lib/test/test_pow.py index 660ff80bbf52..6395fb15ea06 100644 --- a/Lib/test/test_pow.py +++ b/Lib/test/test_pow.py @@ -19,12 +19,11 @@ def powtest(self, type): self.assertEqual(pow(2, i), pow2) if i != 30 : pow2 = pow2*2 - for othertype in (int,): - for i in list(range(-10, 0)) + list(range(1, 10)): - ii = type(i) - for j in range(1, 11): - jj = -othertype(j) - pow(ii, jj) + for i in list(range(-10, 0)) + list(range(1, 10)): + ii = type(i) + inv = pow(ii, -1) # inverse of ii + for jj in range(-10, 0): + self.assertAlmostEqual(pow(ii, jj), pow(inv, -jj)) for othertype in int, float: for i in range(1, 100): From webhook-mailer at python.org Sun Mar 5 12:55:24 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 17:55:24 -0000 Subject: [Python-checkins] GH-102341: Improve the test function for pow (GH-102342) Message-ID: https://github.com/python/cpython/commit/db8d10beb3ab4c64a671d7334707359b7f968743 commit: db8d10beb3ab4c64a671d7334707359b7f968743 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T09:55:18-08:00 summary: GH-102341: Improve the test function for pow (GH-102342) (cherry picked from commit 32220543e2db36c6146ff2704ed1714a6adecc1b) Co-authored-by: Partha P. Mukherjee Co-authored-by: Terry Jan Reedy files: M Lib/test/test_pow.py diff --git a/Lib/test/test_pow.py b/Lib/test/test_pow.py index 5cea9ceb20f5..eeb482ec4b27 100644 --- a/Lib/test/test_pow.py +++ b/Lib/test/test_pow.py @@ -19,12 +19,11 @@ def powtest(self, type): self.assertEqual(pow(2, i), pow2) if i != 30 : pow2 = pow2*2 - for othertype in (int,): - for i in list(range(-10, 0)) + list(range(1, 10)): - ii = type(i) - for j in range(1, 11): - jj = -othertype(j) - pow(ii, jj) + for i in list(range(-10, 0)) + list(range(1, 10)): + ii = type(i) + inv = pow(ii, -1) # inverse of ii + for jj in range(-10, 0): + self.assertAlmostEqual(pow(ii, jj), pow(inv, -jj)) for othertype in int, float: for i in range(1, 100): From webhook-mailer at python.org Sun Mar 5 16:38:08 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 05 Mar 2023 21:38:08 -0000 Subject: [Python-checkins] gh-102444: Fix minor bugs in `test_typing` highlighted by pyflakes (#102445) Message-ID: https://github.com/python/cpython/commit/96e10229292145012bc462a6ab3ce1626c8acf71 commit: 96e10229292145012bc462a6ab3ce1626c8acf71 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-03-05T21:37:29Z summary: gh-102444: Fix minor bugs in `test_typing` highlighted by pyflakes (#102445) files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 2eeaf91d78d8..0483ca3aa42f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -473,7 +473,6 @@ def test_var_substitution(self): def test_bad_var_substitution(self): T = TypeVar('T') - P = ParamSpec("P") bad_args = ( (), (int, str), Union, Generic, Generic[T], Protocol, Protocol[T], @@ -1037,8 +1036,6 @@ class G2(Generic[Unpack[Ts]]): pass def test_repr_is_correct(self): Ts = TypeVarTuple('Ts') - T = TypeVar('T') - T2 = TypeVar('T2') class G1(Generic[*Ts]): pass class G2(Generic[Unpack[Ts]]): pass @@ -1307,7 +1304,7 @@ def test_callable_args_are_correct(self): i = Callable[[None], *Ts] j = Callable[[None], Unpack[Ts]] self.assertEqual(i.__args__, (type(None), *Ts)) - self.assertEqual(i.__args__, (type(None), Unpack[Ts])) + self.assertEqual(j.__args__, (type(None), Unpack[Ts])) k = Callable[[None], tuple[int, *Ts]] l = Callable[[None], Tuple[int, Unpack[Ts]]] @@ -1435,8 +1432,6 @@ def g(*args: *Ts): pass self.assertEqual(g.__annotations__, {'args': (*Ts,)[0]}) def test_variadic_args_with_ellipsis_annotations_are_correct(self): - Ts = TypeVarTuple('Ts') - def a(*args: *tuple[int, ...]): pass self.assertEqual(a.__annotations__, {'args': (*tuple[int, ...],)[0]}) @@ -4918,7 +4913,6 @@ def test_overload_registry_repeated(self): # Definitions needed for features introduced in Python 3.6 from test import ann_module, ann_module2, ann_module3, ann_module5, ann_module6 -import asyncio T_a = TypeVar('T_a') @@ -7077,16 +7071,6 @@ class C: self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int]) self.assertEqual(get_type_hints(C, globals())['const'], Final[int]) - def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) - self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} - ) - def test_cannot_subclass(self): with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"): class C(Annotated): @@ -7515,7 +7499,6 @@ class Y(Generic[P, T]): self.assertEqual(B.__args__, ((int, str,), Tuple[bytes, float])) def test_var_substitution(self): - T = TypeVar("T") P = ParamSpec("P") subst = P.__typing_subst__ self.assertEqual(subst((int, str)), (int, str)) @@ -7835,7 +7818,7 @@ def test_special_attrs2(self): self.assertEqual(fr.__module__, 'typing') # Forward refs are currently unpicklable. for proto in range(pickle.HIGHEST_PROTOCOL + 1): - with self.assertRaises(TypeError) as exc: + with self.assertRaises(TypeError): pickle.dumps(fr, proto) self.assertEqual(SpecialAttrsTests.TypeName.__name__, 'TypeName') From webhook-mailer at python.org Sun Mar 5 17:01:02 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 05 Mar 2023 22:01:02 -0000 Subject: [Python-checkins] GH-101362: Call join() only when >1 argument supplied to pathlib.PurePath() (#101665) Message-ID: https://github.com/python/cpython/commit/3572c861d8e8f03c34793608e7e2221e116aaec0 commit: 3572c861d8e8f03c34793608e7e2221e116aaec0 branch: main author: Barney Gale committer: AlexWaygood date: 2023-03-05T22:00:56Z summary: GH-101362: Call join() only when >1 argument supplied to pathlib.PurePath() (#101665) GH-101362: Call join() only when >1 argument supplied to pathlib.PurePath This reduces the time taken to run `PurePath("foo")` by ~15% files: A Misc/NEWS.d/next/Library/2023-02-07-21-16-41.gh-issue-101362.KMQllM.rst M Lib/pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index dde573592fdd..ed0f2cc73dfa 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -275,9 +275,12 @@ def __reduce__(self): def _parse_parts(cls, parts): if not parts: return '', '', [] + elif len(parts) == 1: + path = os.fspath(parts[0]) + else: + path = cls._flavour.join(*parts) sep = cls._flavour.sep altsep = cls._flavour.altsep - path = cls._flavour.join(*parts) if altsep: path = path.replace(altsep, sep) drv, root, rel = cls._flavour.splitroot(path) diff --git a/Misc/NEWS.d/next/Library/2023-02-07-21-16-41.gh-issue-101362.KMQllM.rst b/Misc/NEWS.d/next/Library/2023-02-07-21-16-41.gh-issue-101362.KMQllM.rst new file mode 100644 index 000000000000..af4ee9ad9048 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-07-21-16-41.gh-issue-101362.KMQllM.rst @@ -0,0 +1,2 @@ +Speed up :class:`pathlib.PurePath` construction by calling +:func:`os.path.join` only when two or more arguments are given. From webhook-mailer at python.org Sun Mar 5 17:01:02 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 22:01:02 -0000 Subject: [Python-checkins] gh-102444: Fix minor bugs in `test_typing` highlighted by pyflakes (GH-102445) Message-ID: https://github.com/python/cpython/commit/a7ec32e7d407f6d86c89a78d91502fa412681536 commit: a7ec32e7d407f6d86c89a78d91502fa412681536 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T14:00:56-08:00 summary: gh-102444: Fix minor bugs in `test_typing` highlighted by pyflakes (GH-102445) (cherry picked from commit 96e10229292145012bc462a6ab3ce1626c8acf71) Co-authored-by: Alex Waygood files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 4fe17a655dfd..c222df41e90b 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -469,7 +469,6 @@ def test_var_substitution(self): def test_bad_var_substitution(self): T = TypeVar('T') - P = ParamSpec("P") bad_args = ( (), (int, str), Union, Generic, Generic[T], Protocol, Protocol[T], @@ -1033,8 +1032,6 @@ class G2(Generic[Unpack[Ts]]): pass def test_repr_is_correct(self): Ts = TypeVarTuple('Ts') - T = TypeVar('T') - T2 = TypeVar('T2') class G1(Generic[*Ts]): pass class G2(Generic[Unpack[Ts]]): pass @@ -1304,7 +1301,7 @@ def test_callable_args_are_correct(self): i = Callable[[None], *Ts] j = Callable[[None], Unpack[Ts]] self.assertEqual(i.__args__, (type(None), *Ts)) - self.assertEqual(i.__args__, (type(None), Unpack[Ts])) + self.assertEqual(j.__args__, (type(None), Unpack[Ts])) k = Callable[[None], tuple[int, *Ts]] l = Callable[[None], Tuple[int, Unpack[Ts]]] @@ -1432,8 +1429,6 @@ def g(*args: *Ts): pass self.assertEqual(g.__annotations__, {'args': (*Ts,)[0]}) def test_variadic_args_with_ellipsis_annotations_are_correct(self): - Ts = TypeVarTuple('Ts') - def a(*args: *tuple[int, ...]): pass self.assertEqual(a.__annotations__, {'args': (*tuple[int, ...],)[0]}) @@ -4769,7 +4764,6 @@ def test_overload_registry_repeated(self): # Definitions needed for features introduced in Python 3.6 from test import ann_module, ann_module2, ann_module3, ann_module5, ann_module6 -import asyncio T_a = TypeVar('T_a') @@ -6898,16 +6892,6 @@ class C: self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int]) self.assertEqual(get_type_hints(C, globals())['const'], Final[int]) - def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) - self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} - ) - def test_cannot_subclass(self): with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"): class C(Annotated): @@ -7335,7 +7319,6 @@ class Y(Generic[P, T]): self.assertEqual(B.__args__, ((int, str,), Tuple[bytes, float])) def test_var_substitution(self): - T = TypeVar("T") P = ParamSpec("P") subst = P.__typing_subst__ self.assertEqual(subst((int, str)), (int, str)) @@ -7628,7 +7611,7 @@ def test_special_attrs2(self): self.assertEqual(fr.__module__, 'typing') # Forward refs are currently unpicklable. for proto in range(pickle.HIGHEST_PROTOCOL + 1): - with self.assertRaises(TypeError) as exc: + with self.assertRaises(TypeError): pickle.dumps(fr, proto) self.assertEqual(SpecialAttrsTests.TypeName.__name__, 'TypeName') From webhook-mailer at python.org Sun Mar 5 17:16:14 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 05 Mar 2023 22:16:14 -0000 Subject: [Python-checkins] [3.10] gh-102444: Fix minor bugs in `test_typing` highlighted by pyflakes (#102445) (#102452) Message-ID: https://github.com/python/cpython/commit/f5280e2ed8a673bc01adf86e4019e3ea1a150f5a commit: f5280e2ed8a673bc01adf86e4019e3ea1a150f5a branch: 3.10 author: Alex Waygood committer: AlexWaygood date: 2023-03-05T22:16:08Z summary: [3.10] gh-102444: Fix minor bugs in `test_typing` highlighted by pyflakes (#102445) (#102452) (cherry picked from commit 96e1022) files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 2be4195b8565..4e0a4f51fd07 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -4752,16 +4752,6 @@ class C: self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int]) self.assertEqual(get_type_hints(C, globals())['const'], Final[int]) - def test_hash_eq(self): - self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4]) - self.assertNotEqual(Annotated[int, 4, 5], Annotated[str, 4, 5]) - self.assertNotEqual(Annotated[int, 4], Annotated[int, 4, 4]) - self.assertEqual( - {Annotated[int, 4, 5], Annotated[int, 4, 5], Annotated[T, 4, 5]}, - {Annotated[int, 4, 5], Annotated[T, 4, 5]} - ) - def test_cannot_subclass(self): with self.assertRaisesRegex(TypeError, "Cannot subclass .*Annotated"): class C(Annotated): @@ -5309,7 +5299,7 @@ def test_special_attrs2(self): self.assertEqual(fr.__module__, 'typing') # Forward refs are currently unpicklable. for proto in range(pickle.HIGHEST_PROTOCOL + 1): - with self.assertRaises(TypeError) as exc: + with self.assertRaises(TypeError): pickle.dumps(fr, proto) self.assertEqual(SpecialAttrsTests.TypeName.__name__, 'TypeName') From webhook-mailer at python.org Sun Mar 5 17:46:51 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 22:46:51 -0000 Subject: [Python-checkins] GH-101362: Check pathlib.Path flavour compatibility at import time (GH-101664) Message-ID: https://github.com/python/cpython/commit/3e60e0213e9d884a2f4cef4df96956c5d4adde0a commit: 3e60e0213e9d884a2f4cef4df96956c5d4adde0a branch: main author: Barney Gale committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T14:46:45-08:00 summary: GH-101362: Check pathlib.Path flavour compatibility at import time (GH-101664) This saves a comparison in `pathlib.Path.__new__()` and reduces the time taken to run `Path()` by ~5%. Automerge-Triggered-By: GH:AlexWaygood files: A Misc/NEWS.d/next/Library/2023-02-07-20-46-08.gh-issue-101362.2ckZ6R.rst M Lib/pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index ed0f2cc73dfa..c37ff21c0352 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -707,11 +707,7 @@ def __new__(cls, *args, **kwargs): warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14)) if cls is Path: cls = WindowsPath if os.name == 'nt' else PosixPath - self = cls._from_parts(args) - if self._flavour is not os.path: - raise NotImplementedError("cannot instantiate %r on your system" - % (cls.__name__,)) - return self + return cls._from_parts(args) def _make_child_relpath(self, part): # This is an optimization used for dir walking. `part` must be @@ -1261,9 +1257,19 @@ class PosixPath(Path, PurePosixPath): """ __slots__ = () + if os.name == 'nt': + def __new__(cls, *args, **kwargs): + raise NotImplementedError( + f"cannot instantiate {cls.__name__!r} on your system") + class WindowsPath(Path, PureWindowsPath): """Path subclass for Windows systems. On a Windows system, instantiating a Path should return this object. """ __slots__ = () + + if os.name != 'nt': + def __new__(cls, *args, **kwargs): + raise NotImplementedError( + f"cannot instantiate {cls.__name__!r} on your system") diff --git a/Misc/NEWS.d/next/Library/2023-02-07-20-46-08.gh-issue-101362.2ckZ6R.rst b/Misc/NEWS.d/next/Library/2023-02-07-20-46-08.gh-issue-101362.2ckZ6R.rst new file mode 100644 index 000000000000..8421466cdbb3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-07-20-46-08.gh-issue-101362.2ckZ6R.rst @@ -0,0 +1,2 @@ +Speed up :class:`pathlib.Path` construction by running the path flavour +compatibility check only when pathlib is imported. From webhook-mailer at python.org Sun Mar 5 18:50:29 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 05 Mar 2023 23:50:29 -0000 Subject: [Python-checkins] GH-101362: Optimise PurePath(PurePath(...)) (GH-101667) Message-ID: https://github.com/python/cpython/commit/6716254e71eeb4666fd6d1a13857832caad7b19f commit: 6716254e71eeb4666fd6d1a13857832caad7b19f branch: main author: Barney Gale committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-05T15:50:21-08:00 summary: GH-101362: Optimise PurePath(PurePath(...)) (GH-101667) The previous `_parse_args()` method pulled the `_parts` out of any supplied `PurePath` objects; these were subsequently joined in `_from_parts()` using `os.path.join()`. This is actually a slower form of joining than calling `fspath()` on the path object, because it doesn't take advantage of the fact that the contents of `_parts` is normalized! This reduces the time taken to run `PurePath("foo", "bar")` by ~20%, and the time taken to run `PurePath(p, "cheese")`, where `p = PurePath("/foo", "bar", "baz")`, by ~40%. Automerge-Triggered-By: GH:AlexWaygood files: A Misc/NEWS.d/next/Library/2023-02-07-22-20-32.gh-issue-101362.Jlk6mt.rst M Doc/library/pathlib.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index c8a734ecad8e..8e91936680fa 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -105,8 +105,9 @@ we also call *flavours*: PurePosixPath('setup.py') Each element of *pathsegments* can be either a string representing a - path segment, an object implementing the :class:`os.PathLike` interface - which returns a string, or another path object:: + path segment, or an object implementing the :class:`os.PathLike` interface + where the :meth:`~os.PathLike.__fspath__` method returns a string, + such as another path object:: >>> PurePath('foo', 'some/path', 'bar') PurePosixPath('foo/some/path/bar') diff --git a/Lib/pathlib.py b/Lib/pathlib.py index c37ff21c0352..d375529ff5f7 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -281,6 +281,14 @@ def _parse_parts(cls, parts): path = cls._flavour.join(*parts) sep = cls._flavour.sep altsep = cls._flavour.altsep + if isinstance(path, str): + # Force-cast str subclasses to str (issue #21127) + path = str(path) + else: + raise TypeError( + "argument should be a str or an os.PathLike " + "object where __fspath__ returns a str, " + f"not {type(path).__name__!r}") if altsep: path = path.replace(altsep, sep) drv, root, rel = cls._flavour.splitroot(path) @@ -291,32 +299,10 @@ def _parse_parts(cls, parts): parsed = [sys.intern(x) for x in unfiltered_parsed if x and x != '.'] return drv, root, parsed - @classmethod - def _parse_args(cls, args): - # This is useful when you don't want to create an instance, just - # canonicalize some constructor arguments. - parts = [] - for a in args: - if isinstance(a, PurePath): - parts += a._parts - else: - a = os.fspath(a) - if isinstance(a, str): - # Force-cast str subclasses to str (issue #21127) - parts.append(str(a)) - else: - raise TypeError( - "argument should be a str object or an os.PathLike " - "object returning str, not %r" - % type(a)) - return cls._parse_parts(parts) - @classmethod def _from_parts(cls, args): - # We need to call _parse_args on the instance, so as to get the - # right flavour. self = object.__new__(cls) - drv, root, parts = self._parse_args(args) + drv, root, parts = self._parse_parts(args) self._drv = drv self._root = root self._parts = parts @@ -575,7 +561,7 @@ def joinpath(self, *args): anchored). """ drv1, root1, parts1 = self._drv, self._root, self._parts - drv2, root2, parts2 = self._parse_args(args) + drv2, root2, parts2 = self._parse_parts(args) if root2: if not drv2 and drv1: return self._from_parsed_parts(drv1, root2, [drv1 + root2] + parts2[1:]) @@ -662,7 +648,7 @@ def match(self, path_pattern): return True # Can't subclass os.PathLike from PurePath and keep the constructor -# optimizations in PurePath._parse_args(). +# optimizations in PurePath.__slots__. os.PathLike.register(PurePath) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 4de91d52c6d1..df9c1f6ba65d 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -166,6 +166,33 @@ def test_constructor_common(self): self.assertEqual(P(P('a'), P('b')), P('a/b')) self.assertEqual(P(P('a'), P('b'), P('c')), P(FakePath("a/b/c"))) + def test_bytes(self): + P = self.cls + message = (r"argument should be a str or an os\.PathLike object " + r"where __fspath__ returns a str, not 'bytes'") + with self.assertRaisesRegex(TypeError, message): + P(b'a') + with self.assertRaises(TypeError): + P(b'a', 'b') + with self.assertRaises(TypeError): + P('a', b'b') + with self.assertRaises(TypeError): + P('a').joinpath(b'b') + with self.assertRaises(TypeError): + P('a') / b'b' + with self.assertRaises(TypeError): + b'a' / P('b') + with self.assertRaises(TypeError): + P('a').match(b'b') + with self.assertRaises(TypeError): + P('a').relative_to(b'b') + with self.assertRaises(TypeError): + P('a').with_name(b'b') + with self.assertRaises(TypeError): + P('a').with_stem(b'b') + with self.assertRaises(TypeError): + P('a').with_suffix(b'b') + def _check_str_subclass(self, *args): # Issue #21127: it should be possible to construct a PurePath object # from a str subclass instance, and it then gets converted to diff --git a/Misc/NEWS.d/next/Library/2023-02-07-22-20-32.gh-issue-101362.Jlk6mt.rst b/Misc/NEWS.d/next/Library/2023-02-07-22-20-32.gh-issue-101362.Jlk6mt.rst new file mode 100644 index 000000000000..c05f92ae699d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-07-22-20-32.gh-issue-101362.Jlk6mt.rst @@ -0,0 +1,4 @@ +Speed up :class:`pathlib.PurePath` construction by handling arguments more +uniformly. When a :class:`pathlib.Path` argument is supplied, +we use its string representation rather than joining its parts +with :func:`os.path.join`. From webhook-mailer at python.org Mon Mar 6 08:42:00 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 06 Mar 2023 13:42:00 -0000 Subject: [Python-checkins] gh-102416: Do not memoize incorrectly loop rules in the parser (#102467) Message-ID: https://github.com/python/cpython/commit/f533f216e6aaba3f36639ae27210420e7dcf9de1 commit: f533f216e6aaba3f36639ae27210420e7dcf9de1 branch: main author: Pablo Galindo Salgado committer: pablogsal date: 2023-03-06T14:41:53+01:00 summary: gh-102416: Do not memoize incorrectly loop rules in the parser (#102467) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst M Parser/parser.c M Tools/peg_generator/pegen/c_generator.py diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst new file mode 100644 index 000000000000..9ffc67cfb7ed --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst @@ -0,0 +1 @@ +Do not memoize incorrectly automatically generated loop rules in the parser. Patch by Pablo Galindo. diff --git a/Parser/parser.c b/Parser/parser.c index 845c1739d63a..e0a88a9cc72c 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -23777,7 +23777,6 @@ _loop0_1_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23828,7 +23827,6 @@ _loop0_1_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_1_type, _seq); p->level--; return _seq; } @@ -23847,7 +23845,6 @@ _loop0_2_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23898,7 +23895,6 @@ _loop0_2_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_2_type, _seq); p->level--; return _seq; } @@ -23917,7 +23913,6 @@ _loop1_3_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23973,7 +23968,6 @@ _loop1_3_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_3_type, _seq); p->level--; return _seq; } @@ -23992,7 +23986,6 @@ _loop0_5_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24052,7 +24045,6 @@ _loop0_5_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_5_type, _seq); p->level--; return _seq; } @@ -24585,7 +24577,6 @@ _loop1_14_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24641,7 +24632,6 @@ _loop1_14_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_14_type, _seq); p->level--; return _seq; } @@ -24823,7 +24813,6 @@ _loop0_19_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24883,7 +24872,6 @@ _loop0_19_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_19_type, _seq); p->level--; return _seq; } @@ -24944,7 +24932,6 @@ _loop0_21_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25004,7 +24991,6 @@ _loop0_21_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_21_type, _seq); p->level--; return _seq; } @@ -25170,7 +25156,6 @@ _loop0_24_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25221,7 +25206,6 @@ _loop0_24_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_24_type, _seq); p->level--; return _seq; } @@ -25240,7 +25224,6 @@ _loop1_25_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25296,7 +25279,6 @@ _loop1_25_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_25_type, _seq); p->level--; return _seq; } @@ -25315,7 +25297,6 @@ _loop0_27_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25375,7 +25356,6 @@ _loop0_27_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_27_type, _seq); p->level--; return _seq; } @@ -25483,7 +25463,6 @@ _loop0_30_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25543,7 +25522,6 @@ _loop0_30_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_30_type, _seq); p->level--; return _seq; } @@ -25651,7 +25629,6 @@ _loop1_32_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25707,7 +25684,6 @@ _loop1_32_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_32_type, _seq); p->level--; return _seq; } @@ -25870,7 +25846,6 @@ _loop0_36_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25921,7 +25896,6 @@ _loop0_36_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_36_type, _seq); p->level--; return _seq; } @@ -25940,7 +25914,6 @@ _loop0_37_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25991,7 +25964,6 @@ _loop0_37_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_37_type, _seq); p->level--; return _seq; } @@ -26010,7 +25982,6 @@ _loop0_38_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26061,7 +26032,6 @@ _loop0_38_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_38_type, _seq); p->level--; return _seq; } @@ -26080,7 +26050,6 @@ _loop1_39_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26136,7 +26105,6 @@ _loop1_39_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_39_type, _seq); p->level--; return _seq; } @@ -26155,7 +26123,6 @@ _loop0_40_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26206,7 +26173,6 @@ _loop0_40_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_40_type, _seq); p->level--; return _seq; } @@ -26225,7 +26191,6 @@ _loop1_41_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26281,7 +26246,6 @@ _loop1_41_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_41_type, _seq); p->level--; return _seq; } @@ -26300,7 +26264,6 @@ _loop1_42_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26356,7 +26319,6 @@ _loop1_42_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_42_type, _seq); p->level--; return _seq; } @@ -26375,7 +26337,6 @@ _loop1_43_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26431,7 +26392,6 @@ _loop1_43_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_43_type, _seq); p->level--; return _seq; } @@ -26450,7 +26410,6 @@ _loop0_44_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26501,7 +26460,6 @@ _loop0_44_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_44_type, _seq); p->level--; return _seq; } @@ -26520,7 +26478,6 @@ _loop1_45_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26576,7 +26533,6 @@ _loop1_45_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_45_type, _seq); p->level--; return _seq; } @@ -26595,7 +26551,6 @@ _loop0_46_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26646,7 +26601,6 @@ _loop0_46_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_46_type, _seq); p->level--; return _seq; } @@ -26665,7 +26619,6 @@ _loop1_47_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26721,7 +26674,6 @@ _loop1_47_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_47_type, _seq); p->level--; return _seq; } @@ -26740,7 +26692,6 @@ _loop0_48_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26791,7 +26742,6 @@ _loop0_48_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_48_type, _seq); p->level--; return _seq; } @@ -26810,7 +26760,6 @@ _loop0_49_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26861,7 +26810,6 @@ _loop0_49_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_49_type, _seq); p->level--; return _seq; } @@ -26880,7 +26828,6 @@ _loop1_50_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26936,7 +26883,6 @@ _loop1_50_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_50_type, _seq); p->level--; return _seq; } @@ -26955,7 +26901,6 @@ _loop0_52_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27015,7 +26960,6 @@ _loop0_52_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_52_type, _seq); p->level--; return _seq; } @@ -27076,7 +27020,6 @@ _loop0_54_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27136,7 +27079,6 @@ _loop0_54_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_54_type, _seq); p->level--; return _seq; } @@ -27197,7 +27139,6 @@ _loop0_56_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27257,7 +27198,6 @@ _loop0_56_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_56_type, _seq); p->level--; return _seq; } @@ -27318,7 +27258,6 @@ _loop0_58_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27378,7 +27317,6 @@ _loop0_58_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_58_type, _seq); p->level--; return _seq; } @@ -27516,7 +27454,6 @@ _loop1_60_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27572,7 +27509,6 @@ _loop1_60_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_60_type, _seq); p->level--; return _seq; } @@ -27591,7 +27527,6 @@ _loop1_61_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27647,7 +27582,6 @@ _loop1_61_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_61_type, _seq); p->level--; return _seq; } @@ -27760,7 +27694,6 @@ _loop1_64_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27816,7 +27749,6 @@ _loop1_64_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_64_type, _seq); p->level--; return _seq; } @@ -27835,7 +27767,6 @@ _loop0_66_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27895,7 +27826,6 @@ _loop0_66_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_66_type, _seq); p->level--; return _seq; } @@ -28226,7 +28156,6 @@ _loop0_72_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28286,7 +28215,6 @@ _loop0_72_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_72_type, _seq); p->level--; return _seq; } @@ -28347,7 +28275,6 @@ _loop0_74_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28407,7 +28334,6 @@ _loop0_74_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_74_type, _seq); p->level--; return _seq; } @@ -28526,7 +28452,6 @@ _loop0_77_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28586,7 +28511,6 @@ _loop0_77_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_77_type, _seq); p->level--; return _seq; } @@ -28647,7 +28571,6 @@ _loop0_79_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28707,7 +28630,6 @@ _loop0_79_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_79_type, _seq); p->level--; return _seq; } @@ -28768,7 +28690,6 @@ _loop1_80_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28824,7 +28745,6 @@ _loop1_80_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_80_type, _seq); p->level--; return _seq; } @@ -28843,7 +28763,6 @@ _loop1_81_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28899,7 +28818,6 @@ _loop1_81_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_81_type, _seq); p->level--; return _seq; } @@ -28918,7 +28836,6 @@ _loop0_83_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28978,7 +28895,6 @@ _loop0_83_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_83_type, _seq); p->level--; return _seq; } @@ -29039,7 +28955,6 @@ _loop1_84_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29095,7 +29010,6 @@ _loop1_84_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_84_type, _seq); p->level--; return _seq; } @@ -29114,7 +29028,6 @@ _loop1_85_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29170,7 +29083,6 @@ _loop1_85_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_85_type, _seq); p->level--; return _seq; } @@ -29189,7 +29101,6 @@ _loop1_86_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29245,7 +29156,6 @@ _loop1_86_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_86_type, _seq); p->level--; return _seq; } @@ -29308,7 +29218,6 @@ _loop0_89_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29368,7 +29277,6 @@ _loop0_89_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_89_type, _seq); p->level--; return _seq; } @@ -29765,7 +29673,6 @@ _loop0_95_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29816,7 +29723,6 @@ _loop0_95_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_95_type, _seq); p->level--; return _seq; } @@ -29835,7 +29741,6 @@ _loop0_96_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29886,7 +29791,6 @@ _loop0_96_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_96_type, _seq); p->level--; return _seq; } @@ -29905,7 +29809,6 @@ _loop0_97_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29956,7 +29859,6 @@ _loop0_97_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_97_type, _seq); p->level--; return _seq; } @@ -29975,7 +29877,6 @@ _loop1_98_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30031,7 +29932,6 @@ _loop1_98_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_98_type, _seq); p->level--; return _seq; } @@ -30050,7 +29950,6 @@ _loop0_99_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30101,7 +30000,6 @@ _loop0_99_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_99_type, _seq); p->level--; return _seq; } @@ -30120,7 +30018,6 @@ _loop1_100_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30176,7 +30073,6 @@ _loop1_100_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_100_type, _seq); p->level--; return _seq; } @@ -30195,7 +30091,6 @@ _loop1_101_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30251,7 +30146,6 @@ _loop1_101_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_101_type, _seq); p->level--; return _seq; } @@ -30270,7 +30164,6 @@ _loop1_102_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30326,7 +30219,6 @@ _loop1_102_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_102_type, _seq); p->level--; return _seq; } @@ -30345,7 +30237,6 @@ _loop0_103_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30396,7 +30287,6 @@ _loop0_103_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_103_type, _seq); p->level--; return _seq; } @@ -30415,7 +30305,6 @@ _loop1_104_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30471,7 +30360,6 @@ _loop1_104_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_104_type, _seq); p->level--; return _seq; } @@ -30490,7 +30378,6 @@ _loop0_105_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30541,7 +30428,6 @@ _loop0_105_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_105_type, _seq); p->level--; return _seq; } @@ -30560,7 +30446,6 @@ _loop1_106_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30616,7 +30501,6 @@ _loop1_106_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_106_type, _seq); p->level--; return _seq; } @@ -30635,7 +30519,6 @@ _loop0_107_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30686,7 +30569,6 @@ _loop0_107_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_107_type, _seq); p->level--; return _seq; } @@ -30705,7 +30587,6 @@ _loop1_108_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30761,7 +30642,6 @@ _loop1_108_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_108_type, _seq); p->level--; return _seq; } @@ -30780,7 +30660,6 @@ _loop1_109_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30836,7 +30715,6 @@ _loop1_109_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_109_type, _seq); p->level--; return _seq; } @@ -30905,7 +30783,6 @@ _loop0_112_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30965,7 +30842,6 @@ _loop0_112_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_112_type, _seq); p->level--; return _seq; } @@ -31026,7 +30902,6 @@ _loop1_113_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31082,7 +30957,6 @@ _loop1_113_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_113_type, _seq); p->level--; return _seq; } @@ -31101,7 +30975,6 @@ _loop0_114_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31152,7 +31025,6 @@ _loop0_114_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_114_type, _seq); p->level--; return _seq; } @@ -31171,7 +31043,6 @@ _loop0_115_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31222,7 +31093,6 @@ _loop0_115_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_115_type, _seq); p->level--; return _seq; } @@ -31301,7 +31171,6 @@ _loop0_118_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31361,7 +31230,6 @@ _loop0_118_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_118_type, _seq); p->level--; return _seq; } @@ -31470,7 +31338,6 @@ _loop0_121_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31530,7 +31397,6 @@ _loop0_121_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_121_type, _seq); p->level--; return _seq; } @@ -31591,7 +31457,6 @@ _loop0_123_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31651,7 +31516,6 @@ _loop0_123_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_123_type, _seq); p->level--; return _seq; } @@ -31712,7 +31576,6 @@ _loop0_125_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31772,7 +31635,6 @@ _loop0_125_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_125_type, _seq); p->level--; return _seq; } @@ -31833,7 +31695,6 @@ _loop0_127_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31893,7 +31754,6 @@ _loop0_127_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_127_type, _seq); p->level--; return _seq; } @@ -31954,7 +31814,6 @@ _loop0_128_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32005,7 +31864,6 @@ _loop0_128_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_128_type, _seq); p->level--; return _seq; } @@ -32024,7 +31882,6 @@ _loop0_130_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32084,7 +31941,6 @@ _loop0_130_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_130_type, _seq); p->level--; return _seq; } @@ -32145,7 +32001,6 @@ _loop1_131_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32201,7 +32056,6 @@ _loop1_131_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_131_type, _seq); p->level--; return _seq; } @@ -32261,7 +32115,6 @@ _loop0_134_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32321,7 +32174,6 @@ _loop0_134_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_134_type, _seq); p->level--; return _seq; } @@ -32382,7 +32234,6 @@ _loop0_136_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32442,7 +32293,6 @@ _loop0_136_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_136_type, _seq); p->level--; return _seq; } @@ -32503,7 +32353,6 @@ _loop0_138_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32563,7 +32412,6 @@ _loop0_138_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_138_type, _seq); p->level--; return _seq; } @@ -32624,7 +32472,6 @@ _loop0_140_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32684,7 +32531,6 @@ _loop0_140_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_140_type, _seq); p->level--; return _seq; } @@ -32745,7 +32591,6 @@ _loop0_142_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32805,7 +32650,6 @@ _loop0_142_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_142_type, _seq); p->level--; return _seq; } @@ -33557,7 +33401,6 @@ _loop0_154_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33608,7 +33451,6 @@ _loop0_154_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_154_type, _seq); p->level--; return _seq; } @@ -33627,7 +33469,6 @@ _loop0_155_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33678,7 +33519,6 @@ _loop0_155_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_155_type, _seq); p->level--; return _seq; } @@ -33697,7 +33537,6 @@ _loop0_156_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33748,7 +33587,6 @@ _loop0_156_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_156_type, _seq); p->level--; return _seq; } @@ -34076,7 +33914,6 @@ _loop0_162_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34127,7 +33964,6 @@ _loop0_162_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_162_type, _seq); p->level--; return _seq; } @@ -34146,7 +33982,6 @@ _loop0_163_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34197,7 +34032,6 @@ _loop0_163_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_163_type, _seq); p->level--; return _seq; } @@ -34216,7 +34050,6 @@ _loop0_164_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34267,7 +34100,6 @@ _loop0_164_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_164_type, _seq); p->level--; return _seq; } @@ -34286,7 +34118,6 @@ _loop1_165_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34342,7 +34173,6 @@ _loop1_165_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_165_type, _seq); p->level--; return _seq; } @@ -34419,7 +34249,6 @@ _loop0_167_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34470,7 +34299,6 @@ _loop0_167_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_167_type, _seq); p->level--; return _seq; } @@ -34547,7 +34375,6 @@ _loop0_169_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34598,7 +34425,6 @@ _loop0_169_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_169_type, _seq); p->level--; return _seq; } @@ -34617,7 +34443,6 @@ _loop1_170_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34673,7 +34498,6 @@ _loop1_170_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_170_type, _seq); p->level--; return _seq; } @@ -34869,7 +34693,6 @@ _loop0_174_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34920,7 +34743,6 @@ _loop0_174_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_174_type, _seq); p->level--; return _seq; } @@ -35074,7 +34896,6 @@ _loop1_177_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35130,7 +34951,6 @@ _loop1_177_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_177_type, _seq); p->level--; return _seq; } @@ -35207,7 +35027,6 @@ _loop0_179_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35258,7 +35077,6 @@ _loop0_179_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_179_type, _seq); p->level--; return _seq; } @@ -35277,7 +35095,6 @@ _loop0_180_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35328,7 +35145,6 @@ _loop0_180_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_180_type, _seq); p->level--; return _seq; } @@ -35347,7 +35163,6 @@ _loop0_181_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35398,7 +35213,6 @@ _loop0_181_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_181_type, _seq); p->level--; return _seq; } @@ -35417,7 +35231,6 @@ _loop0_183_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35477,7 +35290,6 @@ _loop0_183_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_183_type, _seq); p->level--; return _seq; } @@ -35596,7 +35408,6 @@ _loop0_185_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35647,7 +35458,6 @@ _loop0_185_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_185_type, _seq); p->level--; return _seq; } @@ -35724,7 +35534,6 @@ _loop0_187_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35775,7 +35584,6 @@ _loop0_187_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_187_type, _seq); p->level--; return _seq; } @@ -35794,7 +35602,6 @@ _loop1_188_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35850,7 +35657,6 @@ _loop1_188_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_188_type, _seq); p->level--; return _seq; } @@ -35869,7 +35675,6 @@ _loop1_189_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35925,7 +35730,6 @@ _loop1_189_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_189_type, _seq); p->level--; return _seq; } @@ -36063,7 +35867,6 @@ _loop0_192_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36114,7 +35917,6 @@ _loop0_192_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_192_type, _seq); p->level--; return _seq; } @@ -36345,7 +36147,6 @@ _loop0_197_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36405,7 +36206,6 @@ _loop0_197_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_197_type, _seq); p->level--; return _seq; } @@ -36466,7 +36266,6 @@ _loop0_199_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36526,7 +36325,6 @@ _loop0_199_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_199_type, _seq); p->level--; return _seq; } @@ -36587,7 +36385,6 @@ _loop0_201_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36647,7 +36444,6 @@ _loop0_201_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_201_type, _seq); p->level--; return _seq; } @@ -36708,7 +36504,6 @@ _loop0_203_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36768,7 +36563,6 @@ _loop0_203_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_203_type, _seq); p->level--; return _seq; } @@ -36887,7 +36681,6 @@ _loop0_205_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36938,7 +36731,6 @@ _loop0_205_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_205_type, _seq); p->level--; return _seq; } @@ -36957,7 +36749,6 @@ _loop1_206_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -37013,7 +36804,6 @@ _loop1_206_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_206_type, _seq); p->level--; return _seq; } @@ -37074,7 +36864,6 @@ _loop0_208_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -37125,7 +36914,6 @@ _loop0_208_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_208_type, _seq); p->level--; return _seq; } @@ -37144,7 +36932,6 @@ _loop1_209_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -37200,7 +36987,6 @@ _loop1_209_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_209_type, _seq); p->level--; return _seq; } @@ -37664,7 +37450,6 @@ _loop0_221_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -37724,7 +37509,6 @@ _loop0_221_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_221_type, _seq); p->level--; return _seq; } diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py index c41d87b74d1c..e72ce7afdc47 100644 --- a/Tools/peg_generator/pegen/c_generator.py +++ b/Tools/peg_generator/pegen/c_generator.py @@ -619,7 +619,8 @@ def _handle_loop_rule_body(self, node: Rule, rhs: Rhs) -> None: self.add_return("_res") self.print("}") self.print("int _mark = p->mark;") - self.print("int _start_mark = p->mark;") + if memoize: + self.print("int _start_mark = p->mark;") self.print("void **_children = PyMem_Malloc(sizeof(void *));") self.out_of_memory_return(f"!_children") self.print("Py_ssize_t _children_capacity = 1;") @@ -642,7 +643,7 @@ def _handle_loop_rule_body(self, node: Rule, rhs: Rhs) -> None: self.out_of_memory_return(f"!_seq", cleanup_code="PyMem_Free(_children);") self.print("for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]);") self.print("PyMem_Free(_children);") - if node.name: + if memoize and node.name: self.print(f"_PyPegen_insert_memo(p, _start_mark, {node.name}_type, _seq);") self.add_return("_seq") From webhook-mailer at python.org Mon Mar 6 08:56:27 2023 From: webhook-mailer at python.org (corona10) Date: Mon, 06 Mar 2023 13:56:27 -0000 Subject: [Python-checkins] gh-95672: Fix versionadded indentation of get_pagesize in test.rst (gh-102455) Message-ID: https://github.com/python/cpython/commit/d3ca042c99b2e86a2bb927a877fdfcbacdc22f89 commit: d3ca042c99b2e86a2bb927a877fdfcbacdc22f89 branch: main author: Hyunkyun Moon committer: corona10 date: 2023-03-06T22:56:19+09:00 summary: gh-95672: Fix versionadded indentation of get_pagesize in test.rst (gh-102455) files: M Doc/library/test.rst diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 3c759648e4e6..c60b4da75d1a 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -540,7 +540,7 @@ The :mod:`test.support` module defines the following functions: Get size of a page in bytes. - .. versionadded:: 3.12 + .. versionadded:: 3.12 .. function:: setswitchinterval(interval) From webhook-mailer at python.org Mon Mar 6 11:59:25 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 06 Mar 2023 16:59:25 -0000 Subject: [Python-checkins] [3.10] gh-102416: Do not memoize incorrectly loop rules in the parser (GH-102467). (#102474) Message-ID: https://github.com/python/cpython/commit/6b49cc64a44bdf86e9c7ed1e58ed4033ac32e906 commit: 6b49cc64a44bdf86e9c7ed1e58ed4033ac32e906 branch: 3.10 author: Pablo Galindo Salgado committer: pablogsal date: 2023-03-06T16:59:16Z summary: [3.10] gh-102416: Do not memoize incorrectly loop rules in the parser (GH-102467). (#102474) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst M Parser/parser.c M Tools/peg_generator/pegen/c_generator.py diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst new file mode 100644 index 000000000000..9ffc67cfb7ed --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst @@ -0,0 +1 @@ +Do not memoize incorrectly automatically generated loop rules in the parser. Patch by Pablo Galindo. diff --git a/Parser/parser.c b/Parser/parser.c index a2104afb41cb..b1d842776109 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -22039,7 +22039,6 @@ _loop0_1_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -22090,7 +22089,6 @@ _loop0_1_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_1_type, _seq); p->level--; return _seq; } @@ -22109,7 +22107,6 @@ _loop0_2_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -22160,7 +22157,6 @@ _loop0_2_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_2_type, _seq); p->level--; return _seq; } @@ -22179,7 +22175,6 @@ _loop0_4_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -22239,7 +22234,6 @@ _loop0_4_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_4_type, _seq); p->level--; return _seq; } @@ -22300,7 +22294,6 @@ _loop0_6_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -22360,7 +22353,6 @@ _loop0_6_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_6_type, _seq); p->level--; return _seq; } @@ -22421,7 +22413,6 @@ _loop0_8_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -22481,7 +22472,6 @@ _loop0_8_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_8_type, _seq); p->level--; return _seq; } @@ -22542,7 +22532,6 @@ _loop0_10_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -22602,7 +22591,6 @@ _loop0_10_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_10_type, _seq); p->level--; return _seq; } @@ -22663,7 +22651,6 @@ _loop1_11_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -22719,7 +22706,6 @@ _loop1_11_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_11_type, _seq); p->level--; return _seq; } @@ -22738,7 +22724,6 @@ _loop0_13_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -22798,7 +22783,6 @@ _loop0_13_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_13_type, _seq); p->level--; return _seq; } @@ -23331,7 +23315,6 @@ _loop1_22_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23387,7 +23370,6 @@ _loop1_22_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_22_type, _seq); p->level--; return _seq; } @@ -23522,7 +23504,6 @@ _loop0_26_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23582,7 +23563,6 @@ _loop0_26_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_26_type, _seq); p->level--; return _seq; } @@ -23643,7 +23623,6 @@ _loop0_28_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23703,7 +23682,6 @@ _loop0_28_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_28_type, _seq); p->level--; return _seq; } @@ -23869,7 +23847,6 @@ _loop0_31_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23920,7 +23897,6 @@ _loop0_31_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_31_type, _seq); p->level--; return _seq; } @@ -23939,7 +23915,6 @@ _loop1_32_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23995,7 +23970,6 @@ _loop1_32_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_32_type, _seq); p->level--; return _seq; } @@ -24014,7 +23988,6 @@ _loop0_34_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24074,7 +24047,6 @@ _loop0_34_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_34_type, _seq); p->level--; return _seq; } @@ -24182,7 +24154,6 @@ _loop0_37_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24242,7 +24213,6 @@ _loop0_37_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_37_type, _seq); p->level--; return _seq; } @@ -24350,7 +24320,6 @@ _loop0_40_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24410,7 +24379,6 @@ _loop0_40_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_40_type, _seq); p->level--; return _seq; } @@ -24471,7 +24439,6 @@ _loop0_42_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24531,7 +24498,6 @@ _loop0_42_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_42_type, _seq); p->level--; return _seq; } @@ -24592,7 +24558,6 @@ _loop0_44_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24652,7 +24617,6 @@ _loop0_44_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_44_type, _seq); p->level--; return _seq; } @@ -24713,7 +24677,6 @@ _loop0_46_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24773,7 +24736,6 @@ _loop0_46_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_46_type, _seq); p->level--; return _seq; } @@ -24911,7 +24873,6 @@ _loop1_48_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24967,7 +24928,6 @@ _loop1_48_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_48_type, _seq); p->level--; return _seq; } @@ -25033,7 +24993,6 @@ _loop1_50_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25089,7 +25048,6 @@ _loop1_50_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_50_type, _seq); p->level--; return _seq; } @@ -25108,7 +25066,6 @@ _loop0_52_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25168,7 +25125,6 @@ _loop0_52_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_52_type, _seq); p->level--; return _seq; } @@ -25499,7 +25455,6 @@ _loop0_58_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25559,7 +25514,6 @@ _loop0_58_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_58_type, _seq); p->level--; return _seq; } @@ -25620,7 +25574,6 @@ _loop0_60_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25680,7 +25633,6 @@ _loop0_60_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_60_type, _seq); p->level--; return _seq; } @@ -25799,7 +25751,6 @@ _loop0_63_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25859,7 +25810,6 @@ _loop0_63_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_63_type, _seq); p->level--; return _seq; } @@ -25920,7 +25870,6 @@ _loop0_65_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25980,7 +25929,6 @@ _loop0_65_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_65_type, _seq); p->level--; return _seq; } @@ -26224,7 +26172,6 @@ _loop0_70_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26275,7 +26222,6 @@ _loop0_70_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_70_type, _seq); p->level--; return _seq; } @@ -26294,7 +26240,6 @@ _loop0_71_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26345,7 +26290,6 @@ _loop0_71_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_71_type, _seq); p->level--; return _seq; } @@ -26364,7 +26308,6 @@ _loop0_72_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26415,7 +26358,6 @@ _loop0_72_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_72_type, _seq); p->level--; return _seq; } @@ -26434,7 +26376,6 @@ _loop1_73_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26490,7 +26431,6 @@ _loop1_73_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_73_type, _seq); p->level--; return _seq; } @@ -26509,7 +26449,6 @@ _loop0_74_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26560,7 +26499,6 @@ _loop0_74_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_74_type, _seq); p->level--; return _seq; } @@ -26579,7 +26517,6 @@ _loop1_75_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26635,7 +26572,6 @@ _loop1_75_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_75_type, _seq); p->level--; return _seq; } @@ -26654,7 +26590,6 @@ _loop1_76_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26710,7 +26645,6 @@ _loop1_76_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_76_type, _seq); p->level--; return _seq; } @@ -26729,7 +26663,6 @@ _loop1_77_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26785,7 +26718,6 @@ _loop1_77_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_77_type, _seq); p->level--; return _seq; } @@ -26804,7 +26736,6 @@ _loop0_78_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26855,7 +26786,6 @@ _loop0_78_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_78_type, _seq); p->level--; return _seq; } @@ -26874,7 +26804,6 @@ _loop1_79_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26930,7 +26859,6 @@ _loop1_79_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_79_type, _seq); p->level--; return _seq; } @@ -26949,7 +26877,6 @@ _loop0_80_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27000,7 +26927,6 @@ _loop0_80_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_80_type, _seq); p->level--; return _seq; } @@ -27019,7 +26945,6 @@ _loop1_81_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27075,7 +27000,6 @@ _loop1_81_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_81_type, _seq); p->level--; return _seq; } @@ -27094,7 +27018,6 @@ _loop0_82_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27145,7 +27068,6 @@ _loop0_82_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_82_type, _seq); p->level--; return _seq; } @@ -27164,7 +27086,6 @@ _loop1_83_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27220,7 +27141,6 @@ _loop1_83_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_83_type, _seq); p->level--; return _seq; } @@ -27239,7 +27159,6 @@ _loop1_84_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27295,7 +27214,6 @@ _loop1_84_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_84_type, _seq); p->level--; return _seq; } @@ -27364,7 +27282,6 @@ _loop1_86_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27420,7 +27337,6 @@ _loop1_86_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_86_type, _seq); p->level--; return _seq; } @@ -27439,7 +27355,6 @@ _loop0_88_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27499,7 +27414,6 @@ _loop0_88_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_88_type, _seq); p->level--; return _seq; } @@ -27560,7 +27474,6 @@ _loop1_89_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27616,7 +27529,6 @@ _loop1_89_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_89_type, _seq); p->level--; return _seq; } @@ -27635,7 +27547,6 @@ _loop0_90_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27686,7 +27597,6 @@ _loop0_90_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_90_type, _seq); p->level--; return _seq; } @@ -27705,7 +27615,6 @@ _loop0_91_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27756,7 +27665,6 @@ _loop0_91_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_91_type, _seq); p->level--; return _seq; } @@ -27775,7 +27683,6 @@ _loop0_92_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27826,7 +27733,6 @@ _loop0_92_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_92_type, _seq); p->level--; return _seq; } @@ -27845,7 +27751,6 @@ _loop1_93_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27901,7 +27806,6 @@ _loop1_93_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_93_type, _seq); p->level--; return _seq; } @@ -27920,7 +27824,6 @@ _loop0_94_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27971,7 +27874,6 @@ _loop0_94_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_94_type, _seq); p->level--; return _seq; } @@ -27990,7 +27892,6 @@ _loop1_95_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28046,7 +27947,6 @@ _loop1_95_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_95_type, _seq); p->level--; return _seq; } @@ -28065,7 +27965,6 @@ _loop1_96_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28121,7 +28020,6 @@ _loop1_96_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_96_type, _seq); p->level--; return _seq; } @@ -28140,7 +28038,6 @@ _loop1_97_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28196,7 +28093,6 @@ _loop1_97_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_97_type, _seq); p->level--; return _seq; } @@ -28215,7 +28111,6 @@ _loop0_98_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28266,7 +28161,6 @@ _loop0_98_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_98_type, _seq); p->level--; return _seq; } @@ -28285,7 +28179,6 @@ _loop1_99_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28341,7 +28234,6 @@ _loop1_99_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_99_type, _seq); p->level--; return _seq; } @@ -28360,7 +28252,6 @@ _loop0_100_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28411,7 +28302,6 @@ _loop0_100_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_100_type, _seq); p->level--; return _seq; } @@ -28430,7 +28320,6 @@ _loop1_101_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28486,7 +28375,6 @@ _loop1_101_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_101_type, _seq); p->level--; return _seq; } @@ -28505,7 +28393,6 @@ _loop0_102_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28556,7 +28443,6 @@ _loop0_102_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_102_type, _seq); p->level--; return _seq; } @@ -28575,7 +28461,6 @@ _loop1_103_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28631,7 +28516,6 @@ _loop1_103_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_103_type, _seq); p->level--; return _seq; } @@ -28650,7 +28534,6 @@ _loop1_104_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28706,7 +28589,6 @@ _loop1_104_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_104_type, _seq); p->level--; return _seq; } @@ -28725,7 +28607,6 @@ _loop1_105_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28781,7 +28662,6 @@ _loop1_105_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_105_type, _seq); p->level--; return _seq; } @@ -28800,7 +28680,6 @@ _loop1_106_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28856,7 +28735,6 @@ _loop1_106_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_106_type, _seq); p->level--; return _seq; } @@ -28919,7 +28797,6 @@ _loop0_109_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28979,7 +28856,6 @@ _loop0_109_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_109_type, _seq); p->level--; return _seq; } @@ -29318,7 +29194,6 @@ _loop1_114_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29374,7 +29249,6 @@ _loop1_114_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_114_type, _seq); p->level--; return _seq; } @@ -29561,7 +29435,6 @@ _loop0_119_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29621,7 +29494,6 @@ _loop0_119_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_119_type, _seq); p->level--; return _seq; } @@ -29682,7 +29554,6 @@ _loop1_120_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29738,7 +29609,6 @@ _loop1_120_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_120_type, _seq); p->level--; return _seq; } @@ -29757,7 +29627,6 @@ _loop0_121_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29808,7 +29677,6 @@ _loop0_121_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_121_type, _seq); p->level--; return _seq; } @@ -29827,7 +29695,6 @@ _loop0_122_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29878,7 +29745,6 @@ _loop0_122_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_122_type, _seq); p->level--; return _seq; } @@ -29897,7 +29763,6 @@ _loop0_124_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29957,7 +29822,6 @@ _loop0_124_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_124_type, _seq); p->level--; return _seq; } @@ -30066,7 +29930,6 @@ _loop0_127_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30126,7 +29989,6 @@ _loop0_127_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_127_type, _seq); p->level--; return _seq; } @@ -30187,7 +30049,6 @@ _loop0_129_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30247,7 +30108,6 @@ _loop0_129_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_129_type, _seq); p->level--; return _seq; } @@ -30308,7 +30168,6 @@ _loop0_131_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30368,7 +30227,6 @@ _loop0_131_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_131_type, _seq); p->level--; return _seq; } @@ -30429,7 +30287,6 @@ _loop0_133_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30489,7 +30346,6 @@ _loop0_133_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_133_type, _seq); p->level--; return _seq; } @@ -30550,7 +30406,6 @@ _loop0_134_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30601,7 +30456,6 @@ _loop0_134_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_134_type, _seq); p->level--; return _seq; } @@ -30620,7 +30474,6 @@ _loop0_136_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30680,7 +30533,6 @@ _loop0_136_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_136_type, _seq); p->level--; return _seq; } @@ -30741,7 +30593,6 @@ _loop1_137_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30797,7 +30648,6 @@ _loop1_137_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_137_type, _seq); p->level--; return _seq; } @@ -30857,7 +30707,6 @@ _loop0_140_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30917,7 +30766,6 @@ _loop0_140_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_140_type, _seq); p->level--; return _seq; } @@ -31527,7 +31375,6 @@ _loop0_149_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31578,7 +31425,6 @@ _loop0_149_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_149_type, _seq); p->level--; return _seq; } @@ -31597,7 +31443,6 @@ _loop0_150_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31648,7 +31493,6 @@ _loop0_150_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_150_type, _seq); p->level--; return _seq; } @@ -31667,7 +31511,6 @@ _loop0_151_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31718,7 +31561,6 @@ _loop0_151_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_151_type, _seq); p->level--; return _seq; } @@ -31988,7 +31830,6 @@ _loop0_156_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32039,7 +31880,6 @@ _loop0_156_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_156_type, _seq); p->level--; return _seq; } @@ -32058,7 +31898,6 @@ _loop1_157_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32114,7 +31953,6 @@ _loop1_157_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_157_type, _seq); p->level--; return _seq; } @@ -32133,7 +31971,6 @@ _loop0_158_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32184,7 +32021,6 @@ _loop0_158_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_158_type, _seq); p->level--; return _seq; } @@ -32203,7 +32039,6 @@ _loop1_159_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32259,7 +32094,6 @@ _loop1_159_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_159_type, _seq); p->level--; return _seq; } @@ -32477,7 +32311,6 @@ _loop0_164_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32537,7 +32370,6 @@ _loop0_164_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_164_type, _seq); p->level--; return _seq; } @@ -32598,7 +32430,6 @@ _loop0_166_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32658,7 +32489,6 @@ _loop0_166_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_166_type, _seq); p->level--; return _seq; } @@ -32719,7 +32549,6 @@ _loop0_168_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32779,7 +32608,6 @@ _loop0_168_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_168_type, _seq); p->level--; return _seq; } @@ -32840,7 +32668,6 @@ _loop0_170_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32900,7 +32727,6 @@ _loop0_170_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_170_type, _seq); p->level--; return _seq; } @@ -33321,7 +33147,6 @@ _loop0_180_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33381,7 +33206,6 @@ _loop0_180_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_180_type, _seq); p->level--; return _seq; } diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py index 4a93693e6143..6b8ab69c8c81 100644 --- a/Tools/peg_generator/pegen/c_generator.py +++ b/Tools/peg_generator/pegen/c_generator.py @@ -604,7 +604,8 @@ def _handle_loop_rule_body(self, node: Rule, rhs: Rhs) -> None: self.add_return("_res") self.print("}") self.print("int _mark = p->mark;") - self.print("int _start_mark = p->mark;") + if memoize: + self.print("int _start_mark = p->mark;") self.print("void **_children = PyMem_Malloc(sizeof(void *));") self.out_of_memory_return(f"!_children") self.print("Py_ssize_t _children_capacity = 1;") @@ -624,7 +625,7 @@ def _handle_loop_rule_body(self, node: Rule, rhs: Rhs) -> None: self.out_of_memory_return(f"!_seq", cleanup_code="PyMem_Free(_children);") self.print("for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]);") self.print("PyMem_Free(_children);") - if node.name: + if memoize and node.name: self.print(f"_PyPegen_insert_memo(p, _start_mark, {node.name}_type, _seq);") self.add_return("_seq") From webhook-mailer at python.org Mon Mar 6 12:13:59 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 06 Mar 2023 17:13:59 -0000 Subject: [Python-checkins] [3.11] gh-102416: Do not memoize incorrectly loop rules in the parser (GH-102467). (#102473) Message-ID: https://github.com/python/cpython/commit/58de2eb26bb53d6447741de5f232940ec1555115 commit: 58de2eb26bb53d6447741de5f232940ec1555115 branch: 3.11 author: Pablo Galindo Salgado committer: pablogsal date: 2023-03-06T17:13:28Z summary: [3.11] gh-102416: Do not memoize incorrectly loop rules in the parser (GH-102467). (#102473) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst M Parser/parser.c M Tools/peg_generator/pegen/c_generator.py diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst new file mode 100644 index 000000000000..9ffc67cfb7ed --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst @@ -0,0 +1 @@ +Do not memoize incorrectly automatically generated loop rules in the parser. Patch by Pablo Galindo. diff --git a/Parser/parser.c b/Parser/parser.c index f5aecbc42dcd..b2c0cfe3c2b9 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -23549,7 +23549,6 @@ _loop0_1_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23600,7 +23599,6 @@ _loop0_1_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_1_type, _seq); p->level--; return _seq; } @@ -23619,7 +23617,6 @@ _loop0_2_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23670,7 +23667,6 @@ _loop0_2_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_2_type, _seq); p->level--; return _seq; } @@ -23689,7 +23685,6 @@ _loop1_3_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23745,7 +23740,6 @@ _loop1_3_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_3_type, _seq); p->level--; return _seq; } @@ -23764,7 +23758,6 @@ _loop0_5_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -23824,7 +23817,6 @@ _loop0_5_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_5_type, _seq); p->level--; return _seq; } @@ -24357,7 +24349,6 @@ _loop1_14_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24413,7 +24404,6 @@ _loop1_14_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_14_type, _seq); p->level--; return _seq; } @@ -24595,7 +24585,6 @@ _loop0_19_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24655,7 +24644,6 @@ _loop0_19_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_19_type, _seq); p->level--; return _seq; } @@ -24716,7 +24704,6 @@ _loop0_21_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24776,7 +24763,6 @@ _loop0_21_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_21_type, _seq); p->level--; return _seq; } @@ -24942,7 +24928,6 @@ _loop0_24_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -24993,7 +24978,6 @@ _loop0_24_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_24_type, _seq); p->level--; return _seq; } @@ -25012,7 +24996,6 @@ _loop1_25_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25068,7 +25051,6 @@ _loop1_25_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_25_type, _seq); p->level--; return _seq; } @@ -25087,7 +25069,6 @@ _loop0_27_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25147,7 +25128,6 @@ _loop0_27_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_27_type, _seq); p->level--; return _seq; } @@ -25255,7 +25235,6 @@ _loop0_30_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25315,7 +25294,6 @@ _loop0_30_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_30_type, _seq); p->level--; return _seq; } @@ -25423,7 +25401,6 @@ _loop1_32_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25479,7 +25456,6 @@ _loop1_32_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_32_type, _seq); p->level--; return _seq; } @@ -25642,7 +25618,6 @@ _loop0_36_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25693,7 +25668,6 @@ _loop0_36_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_36_type, _seq); p->level--; return _seq; } @@ -25712,7 +25686,6 @@ _loop0_37_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25763,7 +25736,6 @@ _loop0_37_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_37_type, _seq); p->level--; return _seq; } @@ -25782,7 +25754,6 @@ _loop0_38_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25833,7 +25804,6 @@ _loop0_38_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_38_type, _seq); p->level--; return _seq; } @@ -25852,7 +25822,6 @@ _loop1_39_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25908,7 +25877,6 @@ _loop1_39_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_39_type, _seq); p->level--; return _seq; } @@ -25927,7 +25895,6 @@ _loop0_40_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -25978,7 +25945,6 @@ _loop0_40_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_40_type, _seq); p->level--; return _seq; } @@ -25997,7 +25963,6 @@ _loop1_41_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26053,7 +26018,6 @@ _loop1_41_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_41_type, _seq); p->level--; return _seq; } @@ -26072,7 +26036,6 @@ _loop1_42_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26128,7 +26091,6 @@ _loop1_42_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_42_type, _seq); p->level--; return _seq; } @@ -26147,7 +26109,6 @@ _loop1_43_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26203,7 +26164,6 @@ _loop1_43_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_43_type, _seq); p->level--; return _seq; } @@ -26222,7 +26182,6 @@ _loop0_44_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26273,7 +26232,6 @@ _loop0_44_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_44_type, _seq); p->level--; return _seq; } @@ -26292,7 +26250,6 @@ _loop1_45_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26348,7 +26305,6 @@ _loop1_45_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_45_type, _seq); p->level--; return _seq; } @@ -26367,7 +26323,6 @@ _loop0_46_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26418,7 +26373,6 @@ _loop0_46_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_46_type, _seq); p->level--; return _seq; } @@ -26437,7 +26391,6 @@ _loop1_47_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26493,7 +26446,6 @@ _loop1_47_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_47_type, _seq); p->level--; return _seq; } @@ -26512,7 +26464,6 @@ _loop0_48_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26563,7 +26514,6 @@ _loop0_48_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_48_type, _seq); p->level--; return _seq; } @@ -26582,7 +26532,6 @@ _loop0_49_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26633,7 +26582,6 @@ _loop0_49_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_49_type, _seq); p->level--; return _seq; } @@ -26652,7 +26600,6 @@ _loop1_50_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26708,7 +26655,6 @@ _loop1_50_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_50_type, _seq); p->level--; return _seq; } @@ -26727,7 +26673,6 @@ _loop0_52_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26787,7 +26732,6 @@ _loop0_52_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_52_type, _seq); p->level--; return _seq; } @@ -26848,7 +26792,6 @@ _loop0_54_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -26908,7 +26851,6 @@ _loop0_54_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_54_type, _seq); p->level--; return _seq; } @@ -26969,7 +26911,6 @@ _loop0_56_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27029,7 +26970,6 @@ _loop0_56_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_56_type, _seq); p->level--; return _seq; } @@ -27090,7 +27030,6 @@ _loop0_58_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27150,7 +27089,6 @@ _loop0_58_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_58_type, _seq); p->level--; return _seq; } @@ -27288,7 +27226,6 @@ _loop1_60_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27344,7 +27281,6 @@ _loop1_60_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_60_type, _seq); p->level--; return _seq; } @@ -27363,7 +27299,6 @@ _loop1_61_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27419,7 +27354,6 @@ _loop1_61_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_61_type, _seq); p->level--; return _seq; } @@ -27532,7 +27466,6 @@ _loop1_64_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27588,7 +27521,6 @@ _loop1_64_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_64_type, _seq); p->level--; return _seq; } @@ -27607,7 +27539,6 @@ _loop0_66_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -27667,7 +27598,6 @@ _loop0_66_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_66_type, _seq); p->level--; return _seq; } @@ -27998,7 +27928,6 @@ _loop0_72_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28058,7 +27987,6 @@ _loop0_72_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_72_type, _seq); p->level--; return _seq; } @@ -28119,7 +28047,6 @@ _loop0_74_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28179,7 +28106,6 @@ _loop0_74_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_74_type, _seq); p->level--; return _seq; } @@ -28298,7 +28224,6 @@ _loop0_77_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28358,7 +28283,6 @@ _loop0_77_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_77_type, _seq); p->level--; return _seq; } @@ -28419,7 +28343,6 @@ _loop0_79_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28479,7 +28402,6 @@ _loop0_79_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_79_type, _seq); p->level--; return _seq; } @@ -28540,7 +28462,6 @@ _loop1_80_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28596,7 +28517,6 @@ _loop1_80_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_80_type, _seq); p->level--; return _seq; } @@ -28615,7 +28535,6 @@ _loop1_81_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28671,7 +28590,6 @@ _loop1_81_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_81_type, _seq); p->level--; return _seq; } @@ -28690,7 +28608,6 @@ _loop0_83_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28750,7 +28667,6 @@ _loop0_83_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_83_type, _seq); p->level--; return _seq; } @@ -28811,7 +28727,6 @@ _loop1_84_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28867,7 +28782,6 @@ _loop1_84_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_84_type, _seq); p->level--; return _seq; } @@ -28886,7 +28800,6 @@ _loop1_85_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -28942,7 +28855,6 @@ _loop1_85_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_85_type, _seq); p->level--; return _seq; } @@ -28961,7 +28873,6 @@ _loop1_86_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29017,7 +28928,6 @@ _loop1_86_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_86_type, _seq); p->level--; return _seq; } @@ -29080,7 +28990,6 @@ _loop0_89_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29140,7 +29049,6 @@ _loop0_89_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_89_type, _seq); p->level--; return _seq; } @@ -29537,7 +29445,6 @@ _loop0_95_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29588,7 +29495,6 @@ _loop0_95_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_95_type, _seq); p->level--; return _seq; } @@ -29607,7 +29513,6 @@ _loop0_96_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29658,7 +29563,6 @@ _loop0_96_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_96_type, _seq); p->level--; return _seq; } @@ -29677,7 +29581,6 @@ _loop0_97_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29728,7 +29631,6 @@ _loop0_97_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_97_type, _seq); p->level--; return _seq; } @@ -29747,7 +29649,6 @@ _loop1_98_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29803,7 +29704,6 @@ _loop1_98_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_98_type, _seq); p->level--; return _seq; } @@ -29822,7 +29722,6 @@ _loop0_99_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29873,7 +29772,6 @@ _loop0_99_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_99_type, _seq); p->level--; return _seq; } @@ -29892,7 +29790,6 @@ _loop1_100_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -29948,7 +29845,6 @@ _loop1_100_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_100_type, _seq); p->level--; return _seq; } @@ -29967,7 +29863,6 @@ _loop1_101_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30023,7 +29918,6 @@ _loop1_101_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_101_type, _seq); p->level--; return _seq; } @@ -30042,7 +29936,6 @@ _loop1_102_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30098,7 +29991,6 @@ _loop1_102_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_102_type, _seq); p->level--; return _seq; } @@ -30117,7 +30009,6 @@ _loop0_103_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30168,7 +30059,6 @@ _loop0_103_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_103_type, _seq); p->level--; return _seq; } @@ -30187,7 +30077,6 @@ _loop1_104_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30243,7 +30132,6 @@ _loop1_104_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_104_type, _seq); p->level--; return _seq; } @@ -30262,7 +30150,6 @@ _loop0_105_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30313,7 +30200,6 @@ _loop0_105_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_105_type, _seq); p->level--; return _seq; } @@ -30332,7 +30218,6 @@ _loop1_106_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30388,7 +30273,6 @@ _loop1_106_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_106_type, _seq); p->level--; return _seq; } @@ -30407,7 +30291,6 @@ _loop0_107_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30458,7 +30341,6 @@ _loop0_107_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_107_type, _seq); p->level--; return _seq; } @@ -30477,7 +30359,6 @@ _loop1_108_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30533,7 +30414,6 @@ _loop1_108_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_108_type, _seq); p->level--; return _seq; } @@ -30552,7 +30432,6 @@ _loop1_109_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30608,7 +30487,6 @@ _loop1_109_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_109_type, _seq); p->level--; return _seq; } @@ -30677,7 +30555,6 @@ _loop0_112_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30737,7 +30614,6 @@ _loop0_112_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_112_type, _seq); p->level--; return _seq; } @@ -30798,7 +30674,6 @@ _loop1_113_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30854,7 +30729,6 @@ _loop1_113_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_113_type, _seq); p->level--; return _seq; } @@ -30873,7 +30747,6 @@ _loop0_114_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30924,7 +30797,6 @@ _loop0_114_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_114_type, _seq); p->level--; return _seq; } @@ -30943,7 +30815,6 @@ _loop0_115_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -30994,7 +30865,6 @@ _loop0_115_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_115_type, _seq); p->level--; return _seq; } @@ -31073,7 +30943,6 @@ _loop0_118_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31133,7 +31002,6 @@ _loop0_118_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_118_type, _seq); p->level--; return _seq; } @@ -31242,7 +31110,6 @@ _loop0_121_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31302,7 +31169,6 @@ _loop0_121_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_121_type, _seq); p->level--; return _seq; } @@ -31363,7 +31229,6 @@ _loop0_123_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31423,7 +31288,6 @@ _loop0_123_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_123_type, _seq); p->level--; return _seq; } @@ -31484,7 +31348,6 @@ _loop0_125_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31544,7 +31407,6 @@ _loop0_125_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_125_type, _seq); p->level--; return _seq; } @@ -31605,7 +31467,6 @@ _loop0_127_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31665,7 +31526,6 @@ _loop0_127_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_127_type, _seq); p->level--; return _seq; } @@ -31726,7 +31586,6 @@ _loop0_128_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31777,7 +31636,6 @@ _loop0_128_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_128_type, _seq); p->level--; return _seq; } @@ -31796,7 +31654,6 @@ _loop0_130_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31856,7 +31713,6 @@ _loop0_130_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_130_type, _seq); p->level--; return _seq; } @@ -31917,7 +31773,6 @@ _loop1_131_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -31973,7 +31828,6 @@ _loop1_131_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_131_type, _seq); p->level--; return _seq; } @@ -32033,7 +31887,6 @@ _loop0_134_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32093,7 +31946,6 @@ _loop0_134_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_134_type, _seq); p->level--; return _seq; } @@ -32154,7 +32006,6 @@ _loop0_136_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32214,7 +32065,6 @@ _loop0_136_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_136_type, _seq); p->level--; return _seq; } @@ -32275,7 +32125,6 @@ _loop0_138_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32335,7 +32184,6 @@ _loop0_138_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_138_type, _seq); p->level--; return _seq; } @@ -32396,7 +32244,6 @@ _loop0_140_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32456,7 +32303,6 @@ _loop0_140_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_140_type, _seq); p->level--; return _seq; } @@ -32517,7 +32363,6 @@ _loop0_142_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -32577,7 +32422,6 @@ _loop0_142_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_142_type, _seq); p->level--; return _seq; } @@ -33229,7 +33073,6 @@ _loop0_152_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33280,7 +33123,6 @@ _loop0_152_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_152_type, _seq); p->level--; return _seq; } @@ -33299,7 +33141,6 @@ _loop0_153_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33350,7 +33191,6 @@ _loop0_153_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_153_type, _seq); p->level--; return _seq; } @@ -33369,7 +33209,6 @@ _loop0_154_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33420,7 +33259,6 @@ _loop0_154_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_154_type, _seq); p->level--; return _seq; } @@ -33690,7 +33528,6 @@ _loop0_159_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33741,7 +33578,6 @@ _loop0_159_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_159_type, _seq); p->level--; return _seq; } @@ -33760,7 +33596,6 @@ _loop0_160_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33811,7 +33646,6 @@ _loop0_160_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_160_type, _seq); p->level--; return _seq; } @@ -33830,7 +33664,6 @@ _loop1_161_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -33886,7 +33719,6 @@ _loop1_161_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_161_type, _seq); p->level--; return _seq; } @@ -33963,7 +33795,6 @@ _loop0_163_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34014,7 +33845,6 @@ _loop0_163_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_163_type, _seq); p->level--; return _seq; } @@ -34091,7 +33921,6 @@ _loop0_165_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34142,7 +33971,6 @@ _loop0_165_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_165_type, _seq); p->level--; return _seq; } @@ -34219,7 +34047,6 @@ _loop0_167_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34270,7 +34097,6 @@ _loop0_167_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_167_type, _seq); p->level--; return _seq; } @@ -34289,7 +34115,6 @@ _loop1_168_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34345,7 +34170,6 @@ _loop1_168_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_168_type, _seq); p->level--; return _seq; } @@ -34541,7 +34365,6 @@ _loop0_172_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34592,7 +34415,6 @@ _loop0_172_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_172_type, _seq); p->level--; return _seq; } @@ -34746,7 +34568,6 @@ _loop1_175_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34802,7 +34623,6 @@ _loop1_175_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_175_type, _seq); p->level--; return _seq; } @@ -34821,7 +34641,6 @@ _loop0_176_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34872,7 +34691,6 @@ _loop0_176_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_176_type, _seq); p->level--; return _seq; } @@ -34891,7 +34709,6 @@ _loop0_177_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -34942,7 +34759,6 @@ _loop0_177_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_177_type, _seq); p->level--; return _seq; } @@ -34961,7 +34777,6 @@ _loop0_179_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35021,7 +34836,6 @@ _loop0_179_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_179_type, _seq); p->level--; return _seq; } @@ -35140,7 +34954,6 @@ _loop0_181_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35191,7 +35004,6 @@ _loop0_181_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_181_type, _seq); p->level--; return _seq; } @@ -35268,7 +35080,6 @@ _loop0_183_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35319,7 +35130,6 @@ _loop0_183_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_183_type, _seq); p->level--; return _seq; } @@ -35396,7 +35206,6 @@ _loop0_185_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35447,7 +35256,6 @@ _loop0_185_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_185_type, _seq); p->level--; return _seq; } @@ -35466,7 +35274,6 @@ _loop1_186_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35522,7 +35329,6 @@ _loop1_186_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_186_type, _seq); p->level--; return _seq; } @@ -35541,7 +35347,6 @@ _loop1_187_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35597,7 +35402,6 @@ _loop1_187_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_187_type, _seq); p->level--; return _seq; } @@ -35735,7 +35539,6 @@ _loop0_190_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -35786,7 +35589,6 @@ _loop0_190_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_190_type, _seq); p->level--; return _seq; } @@ -36017,7 +35819,6 @@ _loop0_195_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36077,7 +35878,6 @@ _loop0_195_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_195_type, _seq); p->level--; return _seq; } @@ -36138,7 +35938,6 @@ _loop0_197_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36198,7 +35997,6 @@ _loop0_197_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_197_type, _seq); p->level--; return _seq; } @@ -36259,7 +36057,6 @@ _loop0_199_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36319,7 +36116,6 @@ _loop0_199_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_199_type, _seq); p->level--; return _seq; } @@ -36380,7 +36176,6 @@ _loop0_201_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36440,7 +36235,6 @@ _loop0_201_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_201_type, _seq); p->level--; return _seq; } @@ -36559,7 +36353,6 @@ _loop0_203_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36610,7 +36403,6 @@ _loop0_203_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_203_type, _seq); p->level--; return _seq; } @@ -36629,7 +36421,6 @@ _loop1_204_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36685,7 +36476,6 @@ _loop1_204_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_204_type, _seq); p->level--; return _seq; } @@ -36746,7 +36536,6 @@ _loop0_206_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36797,7 +36586,6 @@ _loop0_206_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_206_type, _seq); p->level--; return _seq; } @@ -36816,7 +36604,6 @@ _loop1_207_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -36872,7 +36659,6 @@ _loop1_207_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop1_207_type, _seq); p->level--; return _seq; } @@ -37336,7 +37122,6 @@ _loop0_219_rule(Parser *p) } void *_res = NULL; int _mark = p->mark; - int _start_mark = p->mark; void **_children = PyMem_Malloc(sizeof(void *)); if (!_children) { p->error_indicator = 1; @@ -37396,7 +37181,6 @@ _loop0_219_rule(Parser *p) } for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); PyMem_Free(_children); - _PyPegen_insert_memo(p, _start_mark, _loop0_219_type, _seq); p->level--; return _seq; } diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py index 295bc1f83e8d..cb4f8c4f66ac 100644 --- a/Tools/peg_generator/pegen/c_generator.py +++ b/Tools/peg_generator/pegen/c_generator.py @@ -619,7 +619,8 @@ def _handle_loop_rule_body(self, node: Rule, rhs: Rhs) -> None: self.add_return("_res") self.print("}") self.print("int _mark = p->mark;") - self.print("int _start_mark = p->mark;") + if memoize: + self.print("int _start_mark = p->mark;") self.print("void **_children = PyMem_Malloc(sizeof(void *));") self.out_of_memory_return(f"!_children") self.print("Py_ssize_t _children_capacity = 1;") @@ -642,7 +643,7 @@ def _handle_loop_rule_body(self, node: Rule, rhs: Rhs) -> None: self.out_of_memory_return(f"!_seq", cleanup_code="PyMem_Free(_children);") self.print("for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]);") self.print("PyMem_Free(_children);") - if node.name: + if memoize and node.name: self.print(f"_PyPegen_insert_memo(p, _start_mark, {node.name}_type, _seq);") self.add_return("_seq") From webhook-mailer at python.org Mon Mar 6 12:50:11 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 06 Mar 2023 17:50:11 -0000 Subject: [Python-checkins] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives in sub interpreters module (#102472) Message-ID: https://github.com/python/cpython/commit/f105fe4f0a704bedee21d95f1a08bc14a1fcea2a commit: f105fe4f0a704bedee21d95f1a08bc14a1fcea2a branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-06T17:49:31Z summary: gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives in sub interpreters module (#102472) files: M Modules/_xxsubinterpretersmodule.c diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 461c505c092c..79dbe3474ba9 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -61,9 +61,9 @@ add_new_exception(PyObject *mod, const char *name, PyObject *base) static int _release_xid_data(_PyCrossInterpreterData *data, int ignoreexc) { - PyObject *exctype, *excval, *exctb; + PyObject *exc; if (ignoreexc) { - PyErr_Fetch(&exctype, &excval, &exctb); + exc = PyErr_GetRaisedException(); } int res = _PyCrossInterpreterData_Release(data); if (res < 0) { @@ -84,7 +84,7 @@ _release_xid_data(_PyCrossInterpreterData *data, int ignoreexc) } } if (ignoreexc) { - PyErr_Restore(exctype, excval, exctb); + PyErr_SetRaisedException(exc); } return res; } @@ -294,9 +294,9 @@ _sharedexception_free(_sharedexception *exc) } static _sharedexception * -_sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb) +_sharedexception_bind(PyObject *exc) { - assert(exctype != NULL); + assert(exc != NULL); char *failure = NULL; _sharedexception *err = _sharedexception_new(); @@ -304,7 +304,7 @@ _sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb) goto finally; } - PyObject *name = PyUnicode_FromFormat("%S", exctype); + PyObject *name = PyUnicode_FromFormat("%S", Py_TYPE(exc)); if (name == NULL) { failure = "unable to format exception type name"; goto finally; @@ -432,10 +432,7 @@ static int _run_script(PyInterpreterState *interp, const char *codestr, _sharedns *shared, _sharedexception **exc) { - PyObject *exctype = NULL; PyObject *excval = NULL; - PyObject *tb = NULL; - PyObject *main_mod = _PyInterpreterState_GetMainModule(interp); if (main_mod == NULL) { goto error; @@ -469,12 +466,9 @@ _run_script(PyInterpreterState *interp, const char *codestr, return 0; error: - PyErr_Fetch(&exctype, &excval, &tb); - - _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb); - Py_XDECREF(exctype); + excval = PyErr_GetRaisedException(); + _sharedexception *sharedexc = _sharedexception_bind(excval); Py_XDECREF(excval); - Py_XDECREF(tb); if (sharedexc == NULL) { fprintf(stderr, "RunFailedError: script raised an uncaught exception"); PyErr_Clear(); From webhook-mailer at python.org Mon Mar 6 16:21:00 2023 From: webhook-mailer at python.org (hugovk) Date: Mon, 06 Mar 2023 21:21:00 -0000 Subject: [Python-checkins] Add gettext support to tools/extensions/c_annotations.py (#101989) Message-ID: https://github.com/python/cpython/commit/d959bcd4a0393a120fa12c034de4041037d171c3 commit: d959bcd4a0393a120fa12c034de4041037d171c3 branch: main author: R?mi Lapeyre committer: hugovk date: 2023-03-06T23:20:52+02:00 summary: Add gettext support to tools/extensions/c_annotations.py (#101989) files: M Doc/tools/extensions/c_annotations.py M Doc/tools/templates/dummy.html diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index e5dc82cf0dc2..5af56433f415 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -24,6 +24,7 @@ from docutils.parsers.rst import directives from docutils.parsers.rst import Directive from docutils.statemachine import StringList +from sphinx.locale import _ as sphinx_gettext import csv from sphinx import addnodes @@ -168,11 +169,11 @@ def add_annotations(self, app, doctree): elif not entry.result_type.endswith("Object*"): continue if entry.result_refs is None: - rc = 'Return value: Always NULL.' + rc = sphinx_gettext('Return value: Always NULL.') elif entry.result_refs: - rc = 'Return value: New reference.' + rc = sphinx_gettext('Return value: New reference.') else: - rc = 'Return value: Borrowed reference.' + rc = sphinx_gettext('Return value: Borrowed reference.') node.insert(0, nodes.emphasis(rc, rc, classes=['refcount'])) diff --git a/Doc/tools/templates/dummy.html b/Doc/tools/templates/dummy.html index 3438b44377fc..bab4aaeb4604 100644 --- a/Doc/tools/templates/dummy.html +++ b/Doc/tools/templates/dummy.html @@ -7,6 +7,11 @@ {% trans %}Deprecated since version {deprecated}, will be removed in version {removed}{% endtrans %} {% trans %}Deprecated since version {deprecated}, removed in version {removed}{% endtrans %} +In extensions/c_annotations.py: + +{% trans %}Return value: Always NULL.{% endtrans %} +{% trans %}Return value: New reference.{% endtrans %} +{% trans %}Return value: Borrowed reference.{% endtrans %} In docsbuild-scripts, when rewriting indexsidebar.html with actual versions: From webhook-mailer at python.org Mon Mar 6 16:53:32 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 06 Mar 2023 21:53:32 -0000 Subject: [Python-checkins] Add gettext support to tools/extensions/c_annotations.py (GH-101989) Message-ID: https://github.com/python/cpython/commit/4248c24b416151ae85720ba49049452ae292a303 commit: 4248c24b416151ae85720ba49049452ae292a303 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-06T13:53:24-08:00 summary: Add gettext support to tools/extensions/c_annotations.py (GH-101989) (cherry picked from commit d959bcd4a0393a120fa12c034de4041037d171c3) Co-authored-by: R?mi Lapeyre files: M Doc/tools/extensions/c_annotations.py M Doc/tools/templates/dummy.html diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index 9defb24a0331..a845ef46c0ba 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -24,6 +24,7 @@ from docutils.parsers.rst import directives from docutils.parsers.rst import Directive from docutils.statemachine import StringList +from sphinx.locale import _ as sphinx_gettext import csv from sphinx import addnodes @@ -152,11 +153,11 @@ def add_annotations(self, app, doctree): elif not entry.result_type.endswith("Object*"): continue if entry.result_refs is None: - rc = 'Return value: Always NULL.' + rc = sphinx_gettext('Return value: Always NULL.') elif entry.result_refs: - rc = 'Return value: New reference.' + rc = sphinx_gettext('Return value: New reference.') else: - rc = 'Return value: Borrowed reference.' + rc = sphinx_gettext('Return value: Borrowed reference.') node.insert(0, nodes.emphasis(rc, rc, classes=['refcount'])) diff --git a/Doc/tools/templates/dummy.html b/Doc/tools/templates/dummy.html index 3438b44377fc..bab4aaeb4604 100644 --- a/Doc/tools/templates/dummy.html +++ b/Doc/tools/templates/dummy.html @@ -7,6 +7,11 @@ {% trans %}Deprecated since version {deprecated}, will be removed in version {removed}{% endtrans %} {% trans %}Deprecated since version {deprecated}, removed in version {removed}{% endtrans %} +In extensions/c_annotations.py: + +{% trans %}Return value: Always NULL.{% endtrans %} +{% trans %}Return value: New reference.{% endtrans %} +{% trans %}Return value: Borrowed reference.{% endtrans %} In docsbuild-scripts, when rewriting indexsidebar.html with actual versions: From webhook-mailer at python.org Mon Mar 6 16:53:54 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 06 Mar 2023 21:53:54 -0000 Subject: [Python-checkins] Add gettext support to tools/extensions/c_annotations.py (GH-101989) Message-ID: https://github.com/python/cpython/commit/280b975c3f18674eca1dfbed33fc13330535b241 commit: 280b975c3f18674eca1dfbed33fc13330535b241 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-06T13:53:47-08:00 summary: Add gettext support to tools/extensions/c_annotations.py (GH-101989) (cherry picked from commit d959bcd4a0393a120fa12c034de4041037d171c3) Co-authored-by: R?mi Lapeyre files: M Doc/tools/extensions/c_annotations.py M Doc/tools/templates/dummy.html diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py index 9defb24a0331..a845ef46c0ba 100644 --- a/Doc/tools/extensions/c_annotations.py +++ b/Doc/tools/extensions/c_annotations.py @@ -24,6 +24,7 @@ from docutils.parsers.rst import directives from docutils.parsers.rst import Directive from docutils.statemachine import StringList +from sphinx.locale import _ as sphinx_gettext import csv from sphinx import addnodes @@ -152,11 +153,11 @@ def add_annotations(self, app, doctree): elif not entry.result_type.endswith("Object*"): continue if entry.result_refs is None: - rc = 'Return value: Always NULL.' + rc = sphinx_gettext('Return value: Always NULL.') elif entry.result_refs: - rc = 'Return value: New reference.' + rc = sphinx_gettext('Return value: New reference.') else: - rc = 'Return value: Borrowed reference.' + rc = sphinx_gettext('Return value: Borrowed reference.') node.insert(0, nodes.emphasis(rc, rc, classes=['refcount'])) diff --git a/Doc/tools/templates/dummy.html b/Doc/tools/templates/dummy.html index 3438b44377fc..bab4aaeb4604 100644 --- a/Doc/tools/templates/dummy.html +++ b/Doc/tools/templates/dummy.html @@ -7,6 +7,11 @@ {% trans %}Deprecated since version {deprecated}, will be removed in version {removed}{% endtrans %} {% trans %}Deprecated since version {deprecated}, removed in version {removed}{% endtrans %} +In extensions/c_annotations.py: + +{% trans %}Return value: Always NULL.{% endtrans %} +{% trans %}Return value: New reference.{% endtrans %} +{% trans %}Return value: Borrowed reference.{% endtrans %} In docsbuild-scripts, when rewriting indexsidebar.html with actual versions: From webhook-mailer at python.org Mon Mar 6 17:02:27 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 06 Mar 2023 22:02:27 -0000 Subject: [Python-checkins] Remove unused import of `warnings` from `unittest.loader` (#102479) Message-ID: https://github.com/python/cpython/commit/c84e6f32df989908685ea8b6cd49ddde9f428524 commit: c84e6f32df989908685ea8b6cd49ddde9f428524 branch: main author: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> committer: AlexWaygood date: 2023-03-06T22:02:19Z summary: Remove unused import of `warnings` from `unittest.loader` (#102479) files: M Lib/unittest/loader.py diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py index 80d4fbdd8e36..b989284a640e 100644 --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -6,7 +6,6 @@ import traceback import types import functools -import warnings from fnmatch import fnmatch, fnmatchcase From webhook-mailer at python.org Mon Mar 6 20:02:32 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 07 Mar 2023 01:02:32 -0000 Subject: [Python-checkins] gh-101759: Update macOS installer SQLite 3.40.1 checksum (gh-102485) Message-ID: https://github.com/python/cpython/commit/f9cdeb7b99d408a2e884101ede576952510bcc9b commit: f9cdeb7b99d408a2e884101ede576952510bcc9b branch: main author: Ned Deily committer: ned-deily date: 2023-03-06T20:02:24-05:00 summary: gh-101759: Update macOS installer SQLite 3.40.1 checksum (gh-102485) files: M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 5ea2cfc5183e..63fa21b2b33d 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -361,7 +361,7 @@ def library_recipes(): dict( name="SQLite 3.40.1", url="https://sqlite.org/2022/sqlite-autoconf-3400100.tar.gz", - checksum="5498af3a357753d473ee713e363fa5b7", + checksum="42175b1a1d23529cb133bbd2b5900afd", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' From webhook-mailer at python.org Mon Mar 6 20:31:55 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 07 Mar 2023 01:31:55 -0000 Subject: [Python-checkins] [3.11] gh-101759: Update macOS installer SQLite 3.40.1 checksum (gh-102485) (GH-102488) Message-ID: https://github.com/python/cpython/commit/b6fd4e69c46551209059ad6674369ab158cf4662 commit: b6fd4e69c46551209059ad6674369ab158cf4662 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily date: 2023-03-06T20:31:48-05:00 summary: [3.11] gh-101759: Update macOS installer SQLite 3.40.1 checksum (gh-102485) (GH-102488) (cherry picked from commit f9cdeb7b99d408a2e884101ede576952510bcc9b) Co-authored-by: Ned Deily files: M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 01e06013f3d1..334e10e7060f 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -360,7 +360,7 @@ def library_recipes(): dict( name="SQLite 3.40.1", url="https://sqlite.org/2022/sqlite-autoconf-3400100.tar.gz", - checksum="5498af3a357753d473ee713e363fa5b7", + checksum="42175b1a1d23529cb133bbd2b5900afd", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' From webhook-mailer at python.org Mon Mar 6 20:32:59 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 07 Mar 2023 01:32:59 -0000 Subject: [Python-checkins] [3.10] gh-101759: Update macOS installer SQLite 3.40.1 checksum (gh-102485) (GH-102489) Message-ID: https://github.com/python/cpython/commit/5e6351c1fb193b742e8d05bbf2135c318ff8bb65 commit: 5e6351c1fb193b742e8d05bbf2135c318ff8bb65 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily date: 2023-03-06T20:32:53-05:00 summary: [3.10] gh-101759: Update macOS installer SQLite 3.40.1 checksum (gh-102485) (GH-102489) (cherry picked from commit f9cdeb7b99d408a2e884101ede576952510bcc9b) Co-authored-by: Ned Deily files: M Mac/BuildScript/build-installer.py diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 7daead587c22..114cc1005d4d 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -360,7 +360,7 @@ def library_recipes(): dict( name="SQLite 3.40.1", url="https://sqlite.org/2022/sqlite-autoconf-3400100.tar.gz", - checksum="5498af3a357753d473ee713e363fa5b7", + checksum="42175b1a1d23529cb133bbd2b5900afd", extra_cflags=('-Os ' '-DSQLITE_ENABLE_FTS5 ' '-DSQLITE_ENABLE_FTS4 ' From webhook-mailer at python.org Mon Mar 6 21:40:16 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 07 Mar 2023 02:40:16 -0000 Subject: [Python-checkins] gh-90110: Fix the c-analyzer Tool (#102483) Message-ID: https://github.com/python/cpython/commit/8606697f49dc58ff7e18147401ac65a09c38cf57 commit: 8606697f49dc58ff7e18147401ac65a09c38cf57 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-06T19:40:09-07:00 summary: gh-90110: Fix the c-analyzer Tool (#102483) Some incompatible changes had gone in, and the "ignore" lists weren't properly undated. This change fixes that. It's necessary prior to enabling test_check_c_globals, which I hope to do soon. Note that this does include moving last_resort_memory_error to PyInterpreterState. https://github.com/python/cpython/issues/90110 files: M Include/internal/pycore_global_objects.h M Include/internal/pycore_intrinsics.h M Include/internal/pycore_runtime_init.h M Objects/exceptions.c M Python/intrinsics.c M Tools/c-analyzer/c_parser/parser/_common.py M Tools/c-analyzer/c_parser/parser/_func_body.py M Tools/c-analyzer/c_parser/preprocessor/gcc.py M Tools/c-analyzer/cpython/_parser.py M Tools/c-analyzer/cpython/globals-to-fix.tsv M Tools/c-analyzer/cpython/ignored.tsv diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 30c7c4e3bbd0..9957da1fc5f2 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -86,6 +86,7 @@ struct _Py_interp_static_objects { // hamt_empty is here instead of global because of its weakreflist. _PyGC_Head_UNUSED _hamt_empty_gc_not_used; PyHamtObject hamt_empty; + PyBaseExceptionObject last_resort_memory_error; } singletons; }; diff --git a/Include/internal/pycore_intrinsics.h b/Include/internal/pycore_intrinsics.h index deac145fff76..46a52740eb8a 100644 --- a/Include/internal/pycore_intrinsics.h +++ b/Include/internal/pycore_intrinsics.h @@ -21,6 +21,6 @@ typedef PyObject *(*instrinsic_func1)(PyThreadState* tstate, PyObject *value); typedef PyObject *(*instrinsic_func2)(PyThreadState* tstate, PyObject *value1, PyObject *value2); -extern instrinsic_func1 _PyIntrinsics_UnaryFunctions[]; -extern instrinsic_func2 _PyIntrinsics_BinaryFunctions[]; +extern const instrinsic_func1 _PyIntrinsics_UnaryFunctions[]; +extern const instrinsic_func2 _PyIntrinsics_BinaryFunctions[]; diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index b54adf04761d..a2cc7c87c2f3 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -14,6 +14,9 @@ extern "C" { #include "pycore_obmalloc_init.h" +extern PyTypeObject _PyExc_MemoryError; + + /* The static initializers defined here should only be used in the runtime init code (in pystate.c and pylifecycle.c). */ @@ -120,6 +123,9 @@ extern "C" { .ob_base = _PyObject_IMMORTAL_INIT(&_PyHamt_Type), \ .h_root = (PyHamtNode*)&_Py_SINGLETON(hamt_bitmap_node_empty), \ }, \ + .last_resort_memory_error = { \ + _PyObject_IMMORTAL_INIT(&_PyExc_MemoryError), \ + }, \ }, \ }, \ ._initial_thread = _PyThreadState_INIT, \ diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 976f84dbf63c..a473cbdfeda7 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3207,8 +3207,6 @@ SimpleExtendsException(PyExc_Exception, ReferenceError, #define MEMERRORS_SAVE 16 -static PyBaseExceptionObject last_resort_memory_error; - static PyObject * get_memory_error(int allow_allocation, PyObject *args, PyObject *kwds) { @@ -3216,7 +3214,9 @@ get_memory_error(int allow_allocation, PyObject *args, PyObject *kwds) struct _Py_exc_state *state = get_exc_state(); if (state->memerrors_freelist == NULL) { if (!allow_allocation) { - return Py_NewRef(&last_resort_memory_error); + PyInterpreterState *interp = _PyInterpreterState_GET(); + return Py_NewRef( + &_Py_INTERP_SINGLETON(interp, last_resort_memory_error)); } PyObject *result = BaseException_new((PyTypeObject *)PyExc_MemoryError, args, kwds); return result; @@ -3239,8 +3239,6 @@ get_memory_error(int allow_allocation, PyObject *args, PyObject *kwds) return (PyObject *)self; } -static PyBaseExceptionObject last_resort_memory_error; - static PyObject * MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -3325,7 +3323,7 @@ free_preallocated_memerrors(struct _Py_exc_state *state) } -static PyTypeObject _PyExc_MemoryError = { +PyTypeObject _PyExc_MemoryError = { PyVarObject_HEAD_INIT(NULL, 0) "MemoryError", sizeof(PyBaseExceptionObject), @@ -3339,9 +3337,6 @@ static PyTypeObject _PyExc_MemoryError = { }; PyObject *PyExc_MemoryError = (PyObject *) &_PyExc_MemoryError; -static PyBaseExceptionObject last_resort_memory_error = { - _PyObject_IMMORTAL_INIT(&_PyExc_MemoryError) -}; /* * BufferError extends Exception diff --git a/Python/intrinsics.c b/Python/intrinsics.c index 9e90ef32130f..cca29d859902 100644 --- a/Python/intrinsics.c +++ b/Python/intrinsics.c @@ -199,7 +199,7 @@ list_to_tuple(PyThreadState* unused, PyObject *v) return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v)); } -instrinsic_func1 +const instrinsic_func1 _PyIntrinsics_UnaryFunctions[] = { [0] = no_intrinsic, [INTRINSIC_PRINT] = print_expr, @@ -221,7 +221,7 @@ prep_reraise_star(PyThreadState* unused, PyObject *orig, PyObject *excs) return _PyExc_PrepReraiseStar(orig, excs); } -instrinsic_func2 +const instrinsic_func2 _PyIntrinsics_BinaryFunctions[] = { [INTRINSIC_PREP_RERAISE_STAR] = prep_reraise_star, }; diff --git a/Tools/c-analyzer/c_parser/parser/_common.py b/Tools/c-analyzer/c_parser/parser/_common.py index d468d5442a93..2eacace2c001 100644 --- a/Tools/c-analyzer/c_parser/parser/_common.py +++ b/Tools/c-analyzer/c_parser/parser/_common.py @@ -7,13 +7,25 @@ ) -def log_match(group, m): +def log_match(group, m, depth_before=None, depth_after=None): from . import _logger - text = m.group(0) - if text.startswith(('(', ')')) or text.endswith(('(', ')')): - _logger.debug(f'matched <{group}> ({text!r})') + + if m is not None: + text = m.group(0) + if text.startswith(('(', ')')) or text.endswith(('(', ')')): + _logger.debug(f'matched <{group}> ({text!r})') + else: + _logger.debug(f'matched <{group}> ({text})') + + elif depth_before is not None or depth_after is not None: + if depth_before is None: + depth_before = '???' + elif depth_after is None: + depth_after = '???' + _logger.log(1, f'depth: %s -> %s', depth_before, depth_after) + else: - _logger.debug(f'matched <{group}> ({text})') + raise NotImplementedError('this should not have been hit') ############################# diff --git a/Tools/c-analyzer/c_parser/parser/_func_body.py b/Tools/c-analyzer/c_parser/parser/_func_body.py index 42fd459e111d..25f2f5807ae8 100644 --- a/Tools/c-analyzer/c_parser/parser/_func_body.py +++ b/Tools/c-analyzer/c_parser/parser/_func_body.py @@ -65,11 +65,11 @@ def parse_function_body(name, text, resolve, source, anon_name, parent): ) = m.groups() if empty: - log_match('', m) + log_match('', m, depth) resolve(None, None, None, text) yield None, text elif inline_kind: - log_match('', m) + log_match('', m, depth) kind = inline_kind name = inline_name or anon_name('inline-') data = [] # members @@ -92,7 +92,7 @@ def parse_function_body(name, text, resolve, source, anon_name, parent): # XXX Should "parent" really be None for inline type decls? yield resolve(kind, data, name, text, None), text elif block_close: - log_match('', m) + log_match('', m, depth) depth -= 1 resolve(None, None, None, text) # XXX This isn't great. Calling resolve() should have @@ -101,13 +101,13 @@ def parse_function_body(name, text, resolve, source, anon_name, parent): # needs to be fixed. yield None, text elif compound_bare: - log_match('', m) + log_match('', m, depth) yield resolve('statement', compound_bare, None, text, parent), text elif compound_labeled: - log_match('', m) + log_match('', m, depth) yield resolve('statement', compound_labeled, None, text, parent), text elif compound_paren: - log_match('', m) + log_match('', m, depth) try: pos = match_paren(text) except ValueError: @@ -132,7 +132,7 @@ def parse_function_body(name, text, resolve, source, anon_name, parent): } yield resolve('statement', data, None, text, parent), text elif block_open: - log_match('', m) + log_match('', m, depth) depth += 1 if block_leading: # An inline block: the last evaluated expression is used @@ -144,10 +144,10 @@ def parse_function_body(name, text, resolve, source, anon_name, parent): resolve(None, None, None, text) yield None, text elif simple_ending: - log_match('', m) + log_match('', m, depth) yield resolve('statement', simple_stmt, None, text, parent), text elif var_ending: - log_match('', m) + log_match('', m, depth) kind = 'variable' _, name, vartype = parse_var_decl(decl) data = { @@ -220,7 +220,7 @@ def _parse_next_local_static(m, srcinfo, anon_name, func, depth): remainder = srcinfo.text[m.end():] if inline_kind: - log_match('func inline', m) + log_match('func inline', m, depth, depth) kind = inline_kind name = inline_name or anon_name('inline-') # Immediately emit a forward declaration. @@ -249,7 +249,7 @@ def parse_body(source): yield parse_body, depth elif static_decl: - log_match('local variable', m) + log_match('local variable', m, depth, depth) _, name, data = parse_var_decl(static_decl) yield srcinfo.resolve('variable', data, name, parent=func), depth @@ -266,10 +266,13 @@ def parse_body(source): else: log_match('func other', m) if block_open: + log_match('func other', None, depth, depth + 1) depth += 1 elif block_close: + log_match('func other', None, depth, depth - 1) depth -= 1 elif stmt_end: + log_match('func other', None, depth, depth) pass else: # This should be unreachable. diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 770802253792..7ef1a8afc3b1 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -29,7 +29,7 @@ [^()]* )* ) # - ( [)] [)] )? # + ( [)] [)] ) # ''', re.VERBOSE) POST_ARGS = ( @@ -156,6 +156,7 @@ def _iter_top_include_lines(lines, topfile, cwd, if name != 'pragma': raise Exception(line) else: + line = re.sub(r'__inline__', 'inline', line) if not raw: line, partial = _strip_directives(line, partial=partial) yield _common.SourceLine( diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index ab1d6257f1b1..e7764165d36c 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -105,9 +105,14 @@ def clean_lines(text): * ./Include * ./Include/internal +Modules/_decimal/**/*.c Modules/_decimal/libmpdec +Modules/_hacl/*.c Modules/_hacl/include +Modules/_hacl/*.h Modules/_hacl/include Modules/_tkinter.c /usr/include/tcl8.6 +Modules/md5module.c Modules/_hacl/include +Modules/sha1module.c Modules/_hacl/include +Modules/sha2module.c Modules/_hacl/include Modules/tkappinit.c /usr/include/tcl -Modules/_decimal/**/*.c Modules/_decimal/libmpdec Objects/stringlib/*.h Objects # @end=tsv@ @@ -173,6 +178,7 @@ def clean_lines(text): Modules/_functoolsmodule.c Py_BUILD_CORE 1 Modules/_heapqmodule.c Py_BUILD_CORE 1 Modules/_io/*.c Py_BUILD_CORE 1 +Modules/_io/*.h Py_BUILD_CORE 1 Modules/_localemodule.c Py_BUILD_CORE 1 Modules/_operator.c Py_BUILD_CORE 1 Modules/_posixsubprocess.c Py_BUILD_CORE 1 @@ -296,6 +302,7 @@ def clean_lines(text): # First match wins. _abs('Modules/_ctypes/ctypes.h'): (5_000, 500), _abs('Modules/_datetimemodule.c'): (20_000, 300), + _abs('Modules/_hacl/*.c'): (200_000, 500), _abs('Modules/posixmodule.c'): (20_000, 500), _abs('Modules/termios.c'): (10_000, 800), _abs('Modules/_testcapimodule.c'): (20_000, 400), diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 2e28c50c6ff6..57b8542fb464 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -539,7 +539,7 @@ Modules/_tkinter.c - command_mutex - Modules/_tkinter.c - HeadFHCD - Modules/_tkinter.c - stdin_ready - Modules/_tkinter.c - event_tstate - -Modules/_xxsubinterpretersmodule.c - _globals - +Modules/_xxinterpchannelsmodule.c - _globals - Modules/readline.c - completer_word_break_characters - Modules/readline.c - _history_length - Modules/readline.c - should_auto_add_history - diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 849e20a1b0f4..700ddf285183 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -206,6 +206,10 @@ Modules/_decimal/_decimal.c - invalid_signals_err - Modules/_decimal/_decimal.c - signal_map - Modules/_decimal/_decimal.c - ssize_constants - Modules/_elementtree.c - ExpatMemoryHandler - +Modules/_hashopenssl.c - py_hashes - +Modules/_hacl/Hacl_Hash_SHA1.c - _h0 - +Modules/_hacl/Hacl_Hash_MD5.c - _h0 - +Modules/_hacl/Hacl_Hash_MD5.c - _t - Modules/_io/_iomodule.c - static_types - Modules/_io/textio.c - encodefuncs - Modules/_io/winconsoleio.c - _PyWindowsConsoleIO_Type - @@ -218,9 +222,10 @@ Modules/_sre/sre_targets.h - sre_targets - Modules/_sre.c pattern_repr flag_names - Modules/_struct.c - bigendian_table - Modules/_struct.c - lilendian_table - +Modules/_struct.c - native_table - Modules/_tkinter.c - state_key - -Modules/_xxsubinterpretersmodule.c - _channelid_end_recv - -Modules/_xxsubinterpretersmodule.c - _channelid_end_send - +Modules/_xxinterpchannelsmodule.c - _channelid_end_recv - +Modules/_xxinterpchannelsmodule.c - _channelid_end_send - Modules/_zoneinfo.c - DAYS_BEFORE_MONTH - Modules/_zoneinfo.c - DAYS_IN_MONTH - Modules/arraymodule.c - descriptors - @@ -332,12 +337,15 @@ Python/frozen.c - _PyImport_FrozenTest - Python/getopt.c - longopts - Python/import.c - _PyImport_Inittab - Python/import.c - _PySys_ImplCacheTag - +Python/intrinsics.c - _PyIntrinsics_UnaryFunctions - +Python/intrinsics.c - _PyIntrinsics_BinaryFunctions - Python/opcode_targets.h - opcode_targets - Python/perf_trampoline.c - _Py_perfmap_callbacks - Python/pyhash.c - PyHash_Func - Python/pylifecycle.c - _C_LOCALE_WARNING - Python/pylifecycle.c - _PyOS_mystrnicmp_hack - Python/pylifecycle.c - _TARGET_LOCALES - +Python/pylifecycle.c - INTERPRETER_TRAMPOLINE_CODEDEF - Python/pystate.c - initial - Python/specialize.c - adaptive_opcodes - Python/specialize.c - cache_requirements - @@ -392,8 +400,23 @@ Modules/_testbuffer.c ndarray_memoryview_from_buffer strides - Modules/_testbuffer.c ndarray_memoryview_from_buffer suboffsets - Modules/_testbuffer.c ndarray_push kwlist - Modules/_testbuffer.c staticarray_init kwlist - +Modules/_testcapi/code.c get_code_extra_index key - +Modules/_testcapi/datetime.c - test_run_counter - +Modules/_testcapi/exceptions.c - PyRecursingInfinitelyError_Type - Modules/_testcapi/heaptype.c - _testcapimodule - +Modules/_testcapi/mem.c - FmData - +Modules/_testcapi/mem.c - FmHook - +Modules/_testcapi/structmember.c - test_structmembersType_OldAPI - Modules/_testcapi/unicode.c - _testcapimodule - +Modules/_testcapi/watchers.c - g_dict_watch_events - +Modules/_testcapi/watchers.c - g_dict_watchers_installed - +Modules/_testcapi/watchers.c - g_type_modified_events - +Modules/_testcapi/watchers.c - g_type_watchers_installed - +Modules/_testcapi/watchers.c - num_code_object_created_events - +Modules/_testcapi/watchers.c - num_code_object_destroyed_events - +Modules/_testcapi/watchers.c - pyfunc_watchers - +Modules/_testcapi/watchers.c - func_watcher_ids - +Modules/_testcapi/watchers.c - func_watcher_callbacks - Modules/_testcapimodule.c - ContainerNoGC_members - Modules/_testcapimodule.c - ContainerNoGC_type - Modules/_testcapimodule.c - FmData - @@ -460,11 +483,13 @@ Modules/_testcapimodule.c - meth_static_methods - Modules/_testcapimodule.c - ml - Modules/_testcapimodule.c - str1 - Modules/_testcapimodule.c - str2 - +Modules/_testcapimodule.c - test_c_thread - Modules/_testcapimodule.c - test_members - Modules/_testcapimodule.c - test_run_counter - Modules/_testcapimodule.c - test_structmembersType - Modules/_testcapimodule.c - thread_done - Modules/_testcapimodule.c - x - +Modules/_testcapimodule.c - wait_done - Modules/_testcapimodule.c getargs_keyword_only keywords - Modules/_testcapimodule.c getargs_keywords keywords - Modules/_testcapimodule.c getargs_positional_only_and_keywords keywords - @@ -526,6 +551,7 @@ Modules/_testmultiphase.c - slots_exec_unreported_exception - Modules/_testmultiphase.c - slots_nonmodule_with_exec_slots - Modules/_testmultiphase.c - testexport_methods - Modules/_testmultiphase.c - uninitialized_def - +Modules/_testsinglephase.c - global_state - Modules/_xxtestfuzz/_xxtestfuzz.c - _fuzzmodule - Modules/_xxtestfuzz/_xxtestfuzz.c - module_methods - Modules/_xxtestfuzz/fuzzer.c - SRE_FLAG_DEBUG - From webhook-mailer at python.org Mon Mar 6 21:46:01 2023 From: webhook-mailer at python.org (Fidget-Spinner) Date: Tue, 07 Mar 2023 02:46:01 -0000 Subject: [Python-checkins] gh-95913: Edit Faster CPython section in 3.11 WhatsNew (GH-98429) Message-ID: https://github.com/python/cpython/commit/80b19a30c0d5f9f8a8651e7f8847c0e68671c89a commit: 80b19a30c0d5f9f8a8651e7f8847c0e68671c89a branch: main author: C.A.M. Gerlach committer: Fidget-Spinner date: 2023-03-07T10:45:52+08:00 summary: gh-95913: Edit Faster CPython section in 3.11 WhatsNew (GH-98429) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index bffb8d03aa7c..391ea531281a 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1317,14 +1317,17 @@ This section covers specific optimizations independent of the Faster CPython ============== -CPython 3.11 is on average `25% faster `_ -than CPython 3.10 when measured with the +CPython 3.11 is an average of +`25% faster `_ +than CPython 3.10 as measured with the `pyperformance `_ benchmark suite, -and compiled with GCC on Ubuntu Linux. Depending on your workload, the speedup -could be up to 10-60% faster. +when compiled with GCC on Ubuntu Linux. +Depending on your workload, the overall speedup could be 10-60%. -This project focuses on two major areas in Python: faster startup and faster -runtime. Other optimizations not under this project are listed in `Optimizations`_. +This project focuses on two major areas in Python: +:ref:`whatsnew311-faster-startup` and :ref:`whatsnew311-faster-runtime`. +Optimizations not covered by this project are listed separately under +:ref:`whatsnew311-optimizations`. .. _whatsnew311-faster-startup: @@ -1337,8 +1340,8 @@ Faster Startup Frozen imports / Static code objects ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Python caches bytecode in the :ref:`__pycache__` directory to -speed up module loading. +Python caches :term:`bytecode` in the :ref:`__pycache__ ` +directory to speed up module loading. Previously in 3.10, Python module execution looked like this: @@ -1347,8 +1350,9 @@ Previously in 3.10, Python module execution looked like this: Read __pycache__ -> Unmarshal -> Heap allocated code object -> Evaluate In Python 3.11, the core modules essential for Python startup are "frozen". -This means that their code objects (and bytecode) are statically allocated -by the interpreter. This reduces the steps in module execution process to this: +This means that their :ref:`codeobjects` (and bytecode) +are statically allocated by the interpreter. +This reduces the steps in module execution process to: .. code-block:: text @@ -1357,7 +1361,7 @@ by the interpreter. This reduces the steps in module execution process to this: Interpreter startup is now 10-15% faster in Python 3.11. This has a big impact for short-running programs using Python. -(Contributed by Eric Snow, Guido van Rossum and Kumar Aditya in numerous issues.) +(Contributed by Eric Snow, Guido van Rossum and Kumar Aditya in many issues.) .. _whatsnew311-faster-runtime: @@ -1370,17 +1374,19 @@ Faster Runtime Cheaper, lazy Python frames ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Python frames are created whenever Python calls a Python function. This frame -holds execution information. The following are new frame optimizations: +Python frames, holding execution information, +are created whenever Python calls a Python function. +The following are new frame optimizations: - Streamlined the frame creation process. - Avoided memory allocation by generously re-using frame space on the C stack. - Streamlined the internal frame struct to contain only essential information. Frames previously held extra debugging and memory management information. -Old-style frame objects are now created only when requested by debuggers or -by Python introspection functions such as ``sys._getframe`` or -``inspect.currentframe``. For most user code, no frame objects are +Old-style :ref:`frame objects ` +are now created only when requested by debuggers +or by Python introspection functions such as :func:`sys._getframe` and +:func:`inspect.currentframe`. For most user code, no frame objects are created at all. As a result, nearly all Python functions calls have sped up significantly. We measured a 3-7% speedup in pyperformance. @@ -1401,10 +1407,11 @@ In 3.11, when CPython detects Python code calling another Python function, it sets up a new frame, and "jumps" to the new code inside the new frame. This avoids calling the C interpreting function altogether. -Most Python function calls now consume no C stack space. This speeds up -most of such calls. In simple recursive functions like fibonacci or -factorial, a 1.7x speedup was observed. This also means recursive functions -can recurse significantly deeper (if the user increases the recursion limit). +Most Python function calls now consume no C stack space, speeding them up. +In simple recursive functions like fibonacci or +factorial, we observed a 1.7x speedup. This also means recursive functions +can recurse significantly deeper +(if the user increases the recursion limit with :func:`sys.setrecursionlimit`). We measured a 1-3% improvement in pyperformance. (Contributed by Pablo Galindo and Mark Shannon in :issue:`45256`.) @@ -1415,7 +1422,7 @@ We measured a 1-3% improvement in pyperformance. PEP 659: Specializing Adaptive Interpreter ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:pep:`659` is one of the key parts of the faster CPython project. The general +:pep:`659` is one of the key parts of the Faster CPython project. The general idea is that while Python is a dynamic language, most code has regions where objects and types rarely change. This concept is known as *type stability*. @@ -1424,17 +1431,18 @@ in the executing code. Python will then replace the current operation with a more specialized one. This specialized operation uses fast paths available only to those use cases/types, which generally outperform their generic counterparts. This also brings in another concept called *inline caching*, where -Python caches the results of expensive operations directly in the bytecode. +Python caches the results of expensive operations directly in the +:term:`bytecode`. The specializer will also combine certain common instruction pairs into one -superinstruction. This reduces the overhead during execution. +superinstruction, reducing the overhead during execution. Python will only specialize when it sees code that is "hot" (executed multiple times). This prevents Python -from wasting time for run-once code. Python can also de-specialize when code is +from wasting time on run-once code. Python can also de-specialize when code is too dynamic or when the use changes. Specialization is attempted periodically, -and specialization attempts are not too expensive. This allows specialization -to adapt to new circumstances. +and specialization attempts are not too expensive, +allowing specialization to adapt to new circumstances. (PEP written by Mark Shannon, with ideas inspired by Stefan Brunthaler. See :pep:`659` for more information. Implementation by Mark Shannon and Brandt @@ -1447,32 +1455,32 @@ Bucher, with additional help from Irit Katriel and Dennis Sweeney.) | Operation | Form | Specialization | Operation speedup | Contributor(s) | | | | | (up to) | | +===============+====================+=======================================================+===================+===================+ -| Binary | ``x+x; x*x; x-x;`` | Binary add, multiply and subtract for common types | 10% | Mark Shannon, | -| operations | | such as ``int``, ``float``, and ``str`` take custom | | Dong-hee Na, | -| | | fast paths for their underlying types. | | Brandt Bucher, | +| Binary | ``x + x`` | Binary add, multiply and subtract for common types | 10% | Mark Shannon, | +| operations | | such as :class:`int`, :class:`float` and :class:`str` | | Dong-hee Na, | +| | ``x - x`` | take custom fast paths for their underlying types. | | Brandt Bucher, | | | | | | Dennis Sweeney | +| | ``x * x`` | | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -| Subscript | ``a[i]`` | Subscripting container types such as ``list``, | 10-25% | Irit Katriel, | -| | | ``tuple`` and ``dict`` directly index the underlying | | Mark Shannon | -| | | data structures. | | | +| Subscript | ``a[i]`` | Subscripting container types such as :class:`list`, | 10-25% | Irit Katriel, | +| | | :class:`tuple` and :class:`dict` directly index | | Mark Shannon | +| | | the underlying data structures. | | | | | | | | | -| | | Subscripting custom ``__getitem__`` | | | +| | | Subscripting custom :meth:`~object.__getitem__` | | | | | | is also inlined similar to :ref:`inline-calls`. | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ | Store | ``a[i] = z`` | Similar to subscripting specialization above. | 10-25% | Dennis Sweeney | | subscript | | | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ | Calls | ``f(arg)`` | Calls to common builtin (C) functions and types such | 20% | Mark Shannon, | -| | ``C(arg)`` | as ``len`` and ``str`` directly call their underlying | | Ken Jin | -| | | C version. This avoids going through the internal | | | -| | | calling convention. | | | -| | | | | | +| | | as :func:`len` and :class:`str` directly call their | | Ken Jin | +| | ``C(arg)`` | underlying C version. This avoids going through the | | | +| | | internal calling convention. | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -| Load | ``print`` | The object's index in the globals/builtins namespace | [1]_ | Mark Shannon | -| global | ``len`` | is cached. Loading globals and builtins require | | | -| variable | | zero namespace lookups. | | | +| Load | ``print`` | The object's index in the globals/builtins namespace | [#load-global]_ | Mark Shannon | +| global | | is cached. Loading globals and builtins require | | | +| variable | ``len`` | zero namespace lookups. | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -| Load | ``o.attr`` | Similar to loading global variables. The attribute's | [2]_ | Mark Shannon | +| Load | ``o.attr`` | Similar to loading global variables. The attribute's | [#load-attr]_ | Mark Shannon | | attribute | | index inside the class/object's namespace is cached. | | | | | | In most cases, attribute loading will require zero | | | | | | namespace lookups. | | | @@ -1484,14 +1492,15 @@ Bucher, with additional help from Irit Katriel and Dennis Sweeney.) | Store | ``o.attr = z`` | Similar to load attribute optimization. | 2% | Mark Shannon | | attribute | | | in pyperformance | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -| Unpack | ``*seq`` | Specialized for common containers such as ``list`` | 8% | Brandt Bucher | -| Sequence | | and ``tuple``. Avoids internal calling convention. | | | +| Unpack | ``*seq`` | Specialized for common containers such as | 8% | Brandt Bucher | +| Sequence | | :class:`list` and :class:`tuple`. | | | +| | | Avoids internal calling convention. | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -.. [1] A similar optimization already existed since Python 3.8. 3.11 - specializes for more forms and reduces some overhead. +.. [#load-global] A similar optimization already existed since Python 3.8. + 3.11 specializes for more forms and reduces some overhead. -.. [2] A similar optimization already existed since Python 3.10. +.. [#load-attr] A similar optimization already existed since Python 3.10. 3.11 specializes for more forms. Furthermore, all attribute loads should be sped up by :issue:`45947`. @@ -1501,49 +1510,72 @@ Bucher, with additional help from Irit Katriel and Dennis Sweeney.) Misc ---- -* Objects now require less memory due to lazily created object namespaces. Their - namespace dictionaries now also share keys more freely. +* Objects now require less memory due to lazily created object namespaces. + Their namespace dictionaries now also share keys more freely. (Contributed Mark Shannon in :issue:`45340` and :issue:`40116`.) +* "Zero-cost" exceptions are implemented, eliminating the cost + of :keyword:`try` statements when no exception is raised. + (Contributed by Mark Shannon in :issue:`40222`.) + * A more concise representation of exceptions in the interpreter reduced the time required for catching an exception by about 10%. (Contributed by Irit Katriel in :issue:`45711`.) +* :mod:`re`'s regular expression matching engine has been partially refactored, + and now uses computed gotos (or "threaded code") on supported platforms. As a + result, Python 3.11 executes the `pyperformance regular expression benchmarks + `_ up to 10% + faster than Python 3.10. + (Contributed by Brandt Bucher in :gh:`91404`.) + .. _whatsnew311-faster-cpython-faq: FAQ --- -| Q: How should I write my code to utilize these speedups? -| -| A: You don't have to change your code. Write Pythonic code that follows common - best practices. The Faster CPython project optimizes for common code - patterns we observe. -| -| -| Q: Will CPython 3.11 use more memory? -| -| A: Maybe not. We don't expect memory use to exceed 20% more than 3.10. - This is offset by memory optimizations for frame objects and object - dictionaries as mentioned above. -| -| -| Q: I don't see any speedups in my workload. Why? -| -| A: Certain code won't have noticeable benefits. If your code spends most of - its time on I/O operations, or already does most of its - computation in a C extension library like numpy, there won't be significant - speedup. This project currently benefits pure-Python workloads the most. -| -| Furthermore, the pyperformance figures are a geometric mean. Even within the - pyperformance benchmarks, certain benchmarks have slowed down slightly, while - others have sped up by nearly 2x! -| -| -| Q: Is there a JIT compiler? -| -| A: No. We're still exploring other optimizations. +.. _faster-cpython-faq-my-code: + +How should I write my code to utilize these speedups? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Write Pythonic code that follows common best practices; +you don't have to change your code. +The Faster CPython project optimizes for common code patterns we observe. + + +.. _faster-cpython-faq-memory: + +Will CPython 3.11 use more memory? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Maybe not; we don't expect memory use to exceed 20% higher than 3.10. +This is offset by memory optimizations for frame objects and object +dictionaries as mentioned above. + + +.. _faster-cpython-ymmv: + +I don't see any speedups in my workload. Why? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Certain code won't have noticeable benefits. If your code spends most of +its time on I/O operations, or already does most of its +computation in a C extension library like NumPy, there won't be significant +speedups. This project currently benefits pure-Python workloads the most. + +Furthermore, the pyperformance figures are a geometric mean. Even within the +pyperformance benchmarks, certain benchmarks have slowed down slightly, while +others have sped up by nearly 2x! + + +.. _faster-cpython-jit: + +Is there a JIT compiler? +^^^^^^^^^^^^^^^^^^^^^^^^ + +No. We're still exploring other optimizations. .. _whatsnew311-faster-cpython-about: From webhook-mailer at python.org Mon Mar 6 22:08:24 2023 From: webhook-mailer at python.org (Fidget-Spinner) Date: Tue, 07 Mar 2023 03:08:24 -0000 Subject: [Python-checkins] [3.11] gh-95913: Edit Faster CPython section in 3.11 WhatsNew (GH-98429) (GH-102490) Message-ID: https://github.com/python/cpython/commit/df3ed54e341ca592bdfc39ad755444ef0807577a commit: df3ed54e341ca592bdfc39ad755444ef0807577a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Fidget-Spinner date: 2023-03-07T11:08:14+08:00 summary: [3.11] gh-95913: Edit Faster CPython section in 3.11 WhatsNew (GH-98429) (GH-102490) gh-95913: Edit Faster CPython section in 3.11 WhatsNew (GH-98429) (cherry picked from commit 80b19a30c0d5f9f8a8651e7f8847c0e68671c89a) Co-authored-by: C.A.M. Gerlach files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 4244875f6c69..40a998c765c9 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1319,14 +1319,17 @@ This section covers specific optimizations independent of the Faster CPython ============== -CPython 3.11 is on average `25% faster `_ -than CPython 3.10 when measured with the +CPython 3.11 is an average of +`25% faster `_ +than CPython 3.10 as measured with the `pyperformance `_ benchmark suite, -and compiled with GCC on Ubuntu Linux. Depending on your workload, the speedup -could be up to 10-60% faster. +when compiled with GCC on Ubuntu Linux. +Depending on your workload, the overall speedup could be 10-60%. -This project focuses on two major areas in Python: faster startup and faster -runtime. Other optimizations not under this project are listed in `Optimizations`_. +This project focuses on two major areas in Python: +:ref:`whatsnew311-faster-startup` and :ref:`whatsnew311-faster-runtime`. +Optimizations not covered by this project are listed separately under +:ref:`whatsnew311-optimizations`. .. _whatsnew311-faster-startup: @@ -1339,8 +1342,8 @@ Faster Startup Frozen imports / Static code objects ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Python caches bytecode in the :ref:`__pycache__` directory to -speed up module loading. +Python caches :term:`bytecode` in the :ref:`__pycache__ ` +directory to speed up module loading. Previously in 3.10, Python module execution looked like this: @@ -1349,8 +1352,9 @@ Previously in 3.10, Python module execution looked like this: Read __pycache__ -> Unmarshal -> Heap allocated code object -> Evaluate In Python 3.11, the core modules essential for Python startup are "frozen". -This means that their code objects (and bytecode) are statically allocated -by the interpreter. This reduces the steps in module execution process to this: +This means that their :ref:`codeobjects` (and bytecode) +are statically allocated by the interpreter. +This reduces the steps in module execution process to: .. code-block:: text @@ -1359,7 +1363,7 @@ by the interpreter. This reduces the steps in module execution process to this: Interpreter startup is now 10-15% faster in Python 3.11. This has a big impact for short-running programs using Python. -(Contributed by Eric Snow, Guido van Rossum and Kumar Aditya in numerous issues.) +(Contributed by Eric Snow, Guido van Rossum and Kumar Aditya in many issues.) .. _whatsnew311-faster-runtime: @@ -1372,17 +1376,19 @@ Faster Runtime Cheaper, lazy Python frames ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Python frames are created whenever Python calls a Python function. This frame -holds execution information. The following are new frame optimizations: +Python frames, holding execution information, +are created whenever Python calls a Python function. +The following are new frame optimizations: - Streamlined the frame creation process. - Avoided memory allocation by generously re-using frame space on the C stack. - Streamlined the internal frame struct to contain only essential information. Frames previously held extra debugging and memory management information. -Old-style frame objects are now created only when requested by debuggers or -by Python introspection functions such as ``sys._getframe`` or -``inspect.currentframe``. For most user code, no frame objects are +Old-style :ref:`frame objects ` +are now created only when requested by debuggers +or by Python introspection functions such as :func:`sys._getframe` and +:func:`inspect.currentframe`. For most user code, no frame objects are created at all. As a result, nearly all Python functions calls have sped up significantly. We measured a 3-7% speedup in pyperformance. @@ -1403,10 +1409,11 @@ In 3.11, when CPython detects Python code calling another Python function, it sets up a new frame, and "jumps" to the new code inside the new frame. This avoids calling the C interpreting function altogether. -Most Python function calls now consume no C stack space. This speeds up -most of such calls. In simple recursive functions like fibonacci or -factorial, a 1.7x speedup was observed. This also means recursive functions -can recurse significantly deeper (if the user increases the recursion limit). +Most Python function calls now consume no C stack space, speeding them up. +In simple recursive functions like fibonacci or +factorial, we observed a 1.7x speedup. This also means recursive functions +can recurse significantly deeper +(if the user increases the recursion limit with :func:`sys.setrecursionlimit`). We measured a 1-3% improvement in pyperformance. (Contributed by Pablo Galindo and Mark Shannon in :issue:`45256`.) @@ -1417,7 +1424,7 @@ We measured a 1-3% improvement in pyperformance. PEP 659: Specializing Adaptive Interpreter ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:pep:`659` is one of the key parts of the faster CPython project. The general +:pep:`659` is one of the key parts of the Faster CPython project. The general idea is that while Python is a dynamic language, most code has regions where objects and types rarely change. This concept is known as *type stability*. @@ -1426,17 +1433,18 @@ in the executing code. Python will then replace the current operation with a more specialized one. This specialized operation uses fast paths available only to those use cases/types, which generally outperform their generic counterparts. This also brings in another concept called *inline caching*, where -Python caches the results of expensive operations directly in the bytecode. +Python caches the results of expensive operations directly in the +:term:`bytecode`. The specializer will also combine certain common instruction pairs into one -superinstruction. This reduces the overhead during execution. +superinstruction, reducing the overhead during execution. Python will only specialize when it sees code that is "hot" (executed multiple times). This prevents Python -from wasting time for run-once code. Python can also de-specialize when code is +from wasting time on run-once code. Python can also de-specialize when code is too dynamic or when the use changes. Specialization is attempted periodically, -and specialization attempts are not too expensive. This allows specialization -to adapt to new circumstances. +and specialization attempts are not too expensive, +allowing specialization to adapt to new circumstances. (PEP written by Mark Shannon, with ideas inspired by Stefan Brunthaler. See :pep:`659` for more information. Implementation by Mark Shannon and Brandt @@ -1449,32 +1457,32 @@ Bucher, with additional help from Irit Katriel and Dennis Sweeney.) | Operation | Form | Specialization | Operation speedup | Contributor(s) | | | | | (up to) | | +===============+====================+=======================================================+===================+===================+ -| Binary | ``x+x; x*x; x-x;`` | Binary add, multiply and subtract for common types | 10% | Mark Shannon, | -| operations | | such as ``int``, ``float``, and ``str`` take custom | | Dong-hee Na, | -| | | fast paths for their underlying types. | | Brandt Bucher, | +| Binary | ``x + x`` | Binary add, multiply and subtract for common types | 10% | Mark Shannon, | +| operations | | such as :class:`int`, :class:`float` and :class:`str` | | Dong-hee Na, | +| | ``x - x`` | take custom fast paths for their underlying types. | | Brandt Bucher, | | | | | | Dennis Sweeney | +| | ``x * x`` | | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -| Subscript | ``a[i]`` | Subscripting container types such as ``list``, | 10-25% | Irit Katriel, | -| | | ``tuple`` and ``dict`` directly index the underlying | | Mark Shannon | -| | | data structures. | | | +| Subscript | ``a[i]`` | Subscripting container types such as :class:`list`, | 10-25% | Irit Katriel, | +| | | :class:`tuple` and :class:`dict` directly index | | Mark Shannon | +| | | the underlying data structures. | | | | | | | | | -| | | Subscripting custom ``__getitem__`` | | | +| | | Subscripting custom :meth:`~object.__getitem__` | | | | | | is also inlined similar to :ref:`inline-calls`. | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ | Store | ``a[i] = z`` | Similar to subscripting specialization above. | 10-25% | Dennis Sweeney | | subscript | | | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ | Calls | ``f(arg)`` | Calls to common builtin (C) functions and types such | 20% | Mark Shannon, | -| | ``C(arg)`` | as ``len`` and ``str`` directly call their underlying | | Ken Jin | -| | | C version. This avoids going through the internal | | | -| | | calling convention. | | | -| | | | | | +| | | as :func:`len` and :class:`str` directly call their | | Ken Jin | +| | ``C(arg)`` | underlying C version. This avoids going through the | | | +| | | internal calling convention. | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -| Load | ``print`` | The object's index in the globals/builtins namespace | [1]_ | Mark Shannon | -| global | ``len`` | is cached. Loading globals and builtins require | | | -| variable | | zero namespace lookups. | | | +| Load | ``print`` | The object's index in the globals/builtins namespace | [#load-global]_ | Mark Shannon | +| global | | is cached. Loading globals and builtins require | | | +| variable | ``len`` | zero namespace lookups. | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -| Load | ``o.attr`` | Similar to loading global variables. The attribute's | [2]_ | Mark Shannon | +| Load | ``o.attr`` | Similar to loading global variables. The attribute's | [#load-attr]_ | Mark Shannon | | attribute | | index inside the class/object's namespace is cached. | | | | | | In most cases, attribute loading will require zero | | | | | | namespace lookups. | | | @@ -1486,14 +1494,15 @@ Bucher, with additional help from Irit Katriel and Dennis Sweeney.) | Store | ``o.attr = z`` | Similar to load attribute optimization. | 2% | Mark Shannon | | attribute | | | in pyperformance | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -| Unpack | ``*seq`` | Specialized for common containers such as ``list`` | 8% | Brandt Bucher | -| Sequence | | and ``tuple``. Avoids internal calling convention. | | | +| Unpack | ``*seq`` | Specialized for common containers such as | 8% | Brandt Bucher | +| Sequence | | :class:`list` and :class:`tuple`. | | | +| | | Avoids internal calling convention. | | | +---------------+--------------------+-------------------------------------------------------+-------------------+-------------------+ -.. [1] A similar optimization already existed since Python 3.8. 3.11 - specializes for more forms and reduces some overhead. +.. [#load-global] A similar optimization already existed since Python 3.8. + 3.11 specializes for more forms and reduces some overhead. -.. [2] A similar optimization already existed since Python 3.10. +.. [#load-attr] A similar optimization already existed since Python 3.10. 3.11 specializes for more forms. Furthermore, all attribute loads should be sped up by :issue:`45947`. @@ -1503,49 +1512,72 @@ Bucher, with additional help from Irit Katriel and Dennis Sweeney.) Misc ---- -* Objects now require less memory due to lazily created object namespaces. Their - namespace dictionaries now also share keys more freely. +* Objects now require less memory due to lazily created object namespaces. + Their namespace dictionaries now also share keys more freely. (Contributed Mark Shannon in :issue:`45340` and :issue:`40116`.) +* "Zero-cost" exceptions are implemented, eliminating the cost + of :keyword:`try` statements when no exception is raised. + (Contributed by Mark Shannon in :issue:`40222`.) + * A more concise representation of exceptions in the interpreter reduced the time required for catching an exception by about 10%. (Contributed by Irit Katriel in :issue:`45711`.) +* :mod:`re`'s regular expression matching engine has been partially refactored, + and now uses computed gotos (or "threaded code") on supported platforms. As a + result, Python 3.11 executes the `pyperformance regular expression benchmarks + `_ up to 10% + faster than Python 3.10. + (Contributed by Brandt Bucher in :gh:`91404`.) + .. _whatsnew311-faster-cpython-faq: FAQ --- -| Q: How should I write my code to utilize these speedups? -| -| A: You don't have to change your code. Write Pythonic code that follows common - best practices. The Faster CPython project optimizes for common code - patterns we observe. -| -| -| Q: Will CPython 3.11 use more memory? -| -| A: Maybe not. We don't expect memory use to exceed 20% more than 3.10. - This is offset by memory optimizations for frame objects and object - dictionaries as mentioned above. -| -| -| Q: I don't see any speedups in my workload. Why? -| -| A: Certain code won't have noticeable benefits. If your code spends most of - its time on I/O operations, or already does most of its - computation in a C extension library like numpy, there won't be significant - speedup. This project currently benefits pure-Python workloads the most. -| -| Furthermore, the pyperformance figures are a geometric mean. Even within the - pyperformance benchmarks, certain benchmarks have slowed down slightly, while - others have sped up by nearly 2x! -| -| -| Q: Is there a JIT compiler? -| -| A: No. We're still exploring other optimizations. +.. _faster-cpython-faq-my-code: + +How should I write my code to utilize these speedups? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Write Pythonic code that follows common best practices; +you don't have to change your code. +The Faster CPython project optimizes for common code patterns we observe. + + +.. _faster-cpython-faq-memory: + +Will CPython 3.11 use more memory? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Maybe not; we don't expect memory use to exceed 20% higher than 3.10. +This is offset by memory optimizations for frame objects and object +dictionaries as mentioned above. + + +.. _faster-cpython-ymmv: + +I don't see any speedups in my workload. Why? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Certain code won't have noticeable benefits. If your code spends most of +its time on I/O operations, or already does most of its +computation in a C extension library like NumPy, there won't be significant +speedups. This project currently benefits pure-Python workloads the most. + +Furthermore, the pyperformance figures are a geometric mean. Even within the +pyperformance benchmarks, certain benchmarks have slowed down slightly, while +others have sped up by nearly 2x! + + +.. _faster-cpython-jit: + +Is there a JIT compiler? +^^^^^^^^^^^^^^^^^^^^^^^^ + +No. We're still exploring other optimizations. .. _whatsnew311-faster-cpython-about: From webhook-mailer at python.org Mon Mar 6 22:15:03 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 07 Mar 2023 03:15:03 -0000 Subject: [Python-checkins] Remove redundant `_ensure_future` in favor of `ensure_future` in `asyncio` (#102398) Message-ID: https://github.com/python/cpython/commit/d8485d6c8bd7ad8191fde337d81c01f2192855eb commit: d8485d6c8bd7ad8191fde337d81c01f2192855eb branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-07T08:44:55+05:30 summary: Remove redundant `_ensure_future` in favor of `ensure_future` in `asyncio` (#102398) files: M Lib/asyncio/tasks.py diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index a2e06d5ef72f..1c20754b839b 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -630,10 +630,6 @@ def ensure_future(coro_or_future, *, loop=None): If the argument is a Future, it is returned directly. """ - return _ensure_future(coro_or_future, loop=loop) - - -def _ensure_future(coro_or_future, *, loop=None): if futures.isfuture(coro_or_future): if loop is not None and loop is not futures._get_loop(coro_or_future): raise ValueError('The future belongs to a different loop than ' @@ -798,7 +794,7 @@ def _done_callback(fut): outer = None # bpo-46672 for arg in coros_or_futures: if arg not in arg_to_fut: - fut = _ensure_future(arg, loop=loop) + fut = ensure_future(arg, loop=loop) if loop is None: loop = futures._get_loop(fut) if fut is not arg: @@ -855,7 +851,7 @@ def shield(arg): weak references to tasks. A task that isn't referenced elsewhere may get garbage collected at any time, even before it's done. """ - inner = _ensure_future(arg) + inner = ensure_future(arg) if inner.done(): # Shortcut. return inner From webhook-mailer at python.org Tue Mar 7 09:39:15 2023 From: webhook-mailer at python.org (encukou) Date: Tue, 07 Mar 2023 14:39:15 -0000 Subject: [Python-checkins] gh-95913: Consolidate build requirements changes in 3.11 WhatsNew (GH-98781) Message-ID: https://github.com/python/cpython/commit/4a3ea1fdd890e5e2ec26540dc3c958a52fba6556 commit: 4a3ea1fdd890e5e2ec26540dc3c958a52fba6556 branch: main author: C.A.M. Gerlach committer: encukou date: 2023-03-07T15:38:31+01:00 summary: gh-95913: Consolidate build requirements changes in 3.11 WhatsNew (GH-98781) Apply suggestion to combine build requirements changes in 3.11 WhatsNew Co-authored-by: Petr Viktorin files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 391ea531281a..10fcfb6a0b56 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -2114,30 +2114,22 @@ Build Changes and WASI contributed by Christian Heimes in :gh:`90473`; platforms promoted in :gh:`95085`) -* Building Python now requires: +* Building CPython now requires: - * A `C11 `_ compiler. + * A `C11 `_ compiler and standard library. `Optional C11 features `_ are not required. - (Contributed by Victor Stinner in :issue:`46656`.) + (Contributed by Victor Stinner in :issue:`46656`, + :issue:`45440` and :issue:`46640`.) * Support for `IEEE 754 `_ floating point numbers. (Contributed by Victor Stinner in :issue:`46917`.) - * Support for `floating point Not-a-Number (NaN) - `_, - as the :c:macro:`!Py_NO_NAN` macro has been removed. - (Contributed by Victor Stinner in :issue:`46656`.) - - * A `C99 `_ - ```` header file providing the - :c:func:`!copysign`, :c:func:`!hypot`, :c:func:`!isfinite`, - :c:func:`!isinf`, :c:func:`!isnan`, and :c:func:`!round` functions - (contributed by Victor Stinner in :issue:`45440`); - and a :c:data:`!NAN` constant or the :c:func:`!__builtin_nan` function - (Contributed by Victor Stinner in :issue:`46640`). +* The :c:macro:`!Py_NO_NAN` macro has been removed. + Since CPython now requires IEEE 754 floats, NaN values are always available. + (Contributed by Victor Stinner in :issue:`46656`.) * The :mod:`tkinter` package now requires `Tcl/Tk `_ version 8.5.12 or newer. From webhook-mailer at python.org Tue Mar 7 13:16:40 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 07 Mar 2023 18:16:40 -0000 Subject: [Python-checkins] gh-87092: compiler's CFG construction moved to after codegen stage (#102320) Message-ID: https://github.com/python/cpython/commit/54060ae91da2df44b3f6e6c698694d40284687e9 commit: 54060ae91da2df44b3f6e6c698694d40284687e9 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-07T18:16:32Z summary: gh-87092: compiler's CFG construction moved to after codegen stage (#102320) files: M Python/compile.c diff --git a/Python/compile.c b/Python/compile.c index 2e60a8157533..45c97b4f8ef0 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -175,19 +175,18 @@ static struct jump_target_label_ NO_LABEL = {-1}; #define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) #define NEW_JUMP_TARGET_LABEL(C, NAME) \ - jump_target_label NAME = cfg_new_label(CFG_BUILDER(C)); \ + jump_target_label NAME = instr_sequence_new_label(INSTR_SEQUENCE(C)); \ if (!IS_LABEL(NAME)) { \ return ERROR; \ } #define USE_LABEL(C, LBL) \ - RETURN_IF_ERROR(cfg_builder_use_label(CFG_BUILDER(C), LBL)) + RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id)) -struct instr { +struct cfg_instr { int i_opcode; int i_oparg; location i_loc; - /* The following fields should not be set by the front-end: */ struct basicblock_ *i_target; /* target block (if jump instruction) */ struct basicblock_ *i_except; /* target block when exception is raised */ }; @@ -196,7 +195,7 @@ struct instr { #define INSTR_SET_OP1(I, OP, ARG) \ do { \ assert(HAS_ARG(OP)); \ - struct instr *_instr__ptr_ = (I); \ + struct cfg_instr *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = (ARG); \ } while (0); @@ -205,7 +204,7 @@ struct instr { #define INSTR_SET_OP0(I, OP) \ do { \ assert(!HAS_ARG(OP)); \ - struct instr *_instr__ptr_ = (I); \ + struct cfg_instr *_instr__ptr_ = (I); \ _instr__ptr_->i_opcode = (OP); \ _instr__ptr_->i_oparg = 0; \ } while (0); @@ -235,25 +234,25 @@ is_bit_set_in_table(const uint32_t *table, int bitindex) { } static inline int -is_relative_jump(struct instr *i) +is_relative_jump(struct cfg_instr *i) { return is_bit_set_in_table(_PyOpcode_RelativeJump, i->i_opcode); } static inline int -is_block_push(struct instr *i) +is_block_push(struct cfg_instr *i) { return IS_BLOCK_PUSH_OPCODE(i->i_opcode); } static inline int -is_jump(struct instr *i) +is_jump(struct cfg_instr *i) { return IS_JUMP_OPCODE(i->i_opcode); } static int -instr_size(struct instr *instruction) +instr_size(struct cfg_instr *instruction) { int opcode = instruction->i_opcode; assert(!IS_PSEUDO_OPCODE(opcode)); @@ -265,7 +264,7 @@ instr_size(struct instr *instruction) } static void -write_instr(_Py_CODEUNIT *codestr, struct instr *instruction, int ilen) +write_instr(_Py_CODEUNIT *codestr, struct cfg_instr *instruction, int ilen) { int opcode = instruction->i_opcode; assert(!IS_PSEUDO_OPCODE(opcode)); @@ -313,7 +312,7 @@ typedef struct basicblock_ { /* Exception stack at start of block, used by assembler to create the exception handling table */ ExceptStack *b_exceptstack; /* pointer to an array of instructions, initially NULL */ - struct instr *b_instr; + struct cfg_instr *b_instr; /* If b_next is non-NULL, it is a pointer to the next block reached by normal control flow. */ struct basicblock_ *b_next; @@ -342,7 +341,7 @@ typedef struct basicblock_ { } basicblock; -static struct instr * +static struct cfg_instr * basicblock_last_instr(const basicblock *b) { assert(b->b_iused >= 0); if (b->b_iused > 0) { @@ -352,21 +351,15 @@ basicblock_last_instr(const basicblock *b) { return NULL; } -static inline int -basicblock_returns(const basicblock *b) { - struct instr *last = basicblock_last_instr(b); - return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST); -} - static inline int basicblock_exits_scope(const basicblock *b) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode); } static inline int basicblock_nofallthrough(const basicblock *b) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); return (last && (IS_SCOPE_EXIT_OPCODE(last->i_opcode) || IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode))); @@ -415,10 +408,208 @@ typedef struct cfg_builder_ { basicblock *g_curblock; /* label for the next instruction to be placed */ jump_target_label g_current_label; - /* next free label id */ - int g_next_free_label; } cfg_builder; +typedef struct { + int i_opcode; + int i_oparg; + location i_loc; +} instruction; + + +typedef struct instr_sequence_ { + instruction *s_instrs; + int s_allocated; + int s_used; + + int *s_labelmap; /* label id --> instr offset */ + int s_labelmap_size; + int s_next_free_label; /* next free label id */ +} instr_sequence; + +#define INITIAL_INSTR_SEQUENCE_SIZE 100 +#define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10 + +/* + * Resize the array if index is out of range. + * + * idx: the index we want to access + * arr: pointer to the array + * alloc: pointer to the capacity of the array + * default_alloc: initial number of items + * item_size: size of each item + * + */ +static int +ensure_array_large_enough(int idx, void **arr_, int *alloc, int default_alloc, size_t item_size) +{ + void *arr = *arr_; + if (arr == NULL) { + int new_alloc = default_alloc; + if (idx >= new_alloc) { + new_alloc = idx + default_alloc; + } + arr = PyObject_Calloc(new_alloc, item_size); + if (arr == NULL) { + PyErr_NoMemory(); + return ERROR; + } + *alloc = new_alloc; + } + else if (idx >= *alloc) { + size_t oldsize = *alloc * item_size; + int new_alloc = *alloc << 1; + if (idx >= new_alloc) { + new_alloc = idx + default_alloc; + } + size_t newsize = new_alloc * item_size; + + if (oldsize > (SIZE_MAX >> 1)) { + PyErr_NoMemory(); + return ERROR; + } + + assert(newsize > 0); + void *tmp = PyObject_Realloc(arr, newsize); + if (tmp == NULL) { + PyErr_NoMemory(); + return ERROR; + } + *alloc = new_alloc; + arr = tmp; + memset((char *)arr + oldsize, 0, newsize - oldsize); + } + + *arr_ = arr; + return SUCCESS; +} + +static int +instr_sequence_next_inst(instr_sequence *seq) { + assert(seq->s_instrs != NULL || seq->s_used == 0); + + RETURN_IF_ERROR( + ensure_array_large_enough(seq->s_used + 1, + (void**)&seq->s_instrs, + &seq->s_allocated, + INITIAL_INSTR_SEQUENCE_SIZE, + sizeof(instruction))); + assert(seq->s_used < seq->s_allocated); + return seq->s_used++; +} + +static jump_target_label +instr_sequence_new_label(instr_sequence *seq) +{ + jump_target_label lbl = {seq->s_next_free_label++}; + return lbl; +} + +static int +instr_sequence_use_label(instr_sequence *seq, int lbl) { + int old_size = seq->s_labelmap_size; + RETURN_IF_ERROR( + ensure_array_large_enough(lbl, + (void**)&seq->s_labelmap, + &seq->s_labelmap_size, + INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE, + sizeof(int))); + + for(int i = old_size; i < seq->s_labelmap_size; i++) { + seq->s_labelmap[i] = -111; /* something weird, for debugging */ + } + seq->s_labelmap[lbl] = seq->s_used; /* label refers to the next instruction */ + return SUCCESS; +} + +static int +instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc) +{ + assert(IS_WITHIN_OPCODE_RANGE(opcode)); + assert(!IS_ASSEMBLER_OPCODE(opcode)); + assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); + assert(0 <= oparg && oparg < (1 << 30)); + + int idx = instr_sequence_next_inst(seq); + RETURN_IF_ERROR(idx); + instruction *ci = &seq->s_instrs[idx]; + ci->i_opcode = opcode; + ci->i_oparg = oparg; + ci->i_loc = loc; + return SUCCESS; +} + +static int +instr_sequence_insert_instruction(instr_sequence *seq, int pos, + int opcode, int oparg, location loc) +{ + assert(pos >= 0 && pos <= seq->s_used); + int last_idx = instr_sequence_next_inst(seq); + RETURN_IF_ERROR(last_idx); + for (int i=last_idx-1; i >= pos; i--) { + seq->s_instrs[i+1] = seq->s_instrs[i]; + } + instruction *ci = &seq->s_instrs[pos]; + ci->i_opcode = opcode; + ci->i_oparg = oparg; + ci->i_loc = loc; + + /* fix the labels map */ + for(int lbl=0; lbl < seq->s_labelmap_size; lbl++) { + if (seq->s_labelmap[lbl] >= pos) { + seq->s_labelmap[lbl]++; + } + } + return SUCCESS; +} + +static void +instr_sequence_fini(instr_sequence *seq) { + PyObject_Free(seq->s_labelmap); + seq->s_labelmap = NULL; + + PyObject_Free(seq->s_instrs); + seq->s_instrs = NULL; +} + +static int basicblock_addop(basicblock *b, int opcode, int oparg, location loc); +static int cfg_builder_maybe_start_new_block(cfg_builder *g); + +static int +cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) +{ + g->g_current_label = lbl; + return cfg_builder_maybe_start_new_block(g); +} + +static int +cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) +{ + RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); + return basicblock_addop(g->g_curblock, opcode, oparg, loc); +} + +static int cfg_builder_init(cfg_builder *g); + +static int +instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { + memset(g, 0, sizeof(cfg_builder)); + RETURN_IF_ERROR(cfg_builder_init(g)); + /* Note: there can be more than one label for the same offset */ + for (int i = 0; i < seq->s_used; i++) { + for (int j=0; j < seq->s_labelmap_size; j++) { + if (seq->s_labelmap[j] == i) { + jump_target_label lbl = {j}; + RETURN_IF_ERROR(cfg_builder_use_label(g, lbl)); + } + } + instruction *instr = &seq->s_instrs[i]; + RETURN_IF_ERROR(cfg_builder_addop(g, instr->i_opcode, instr->i_oparg, instr->i_loc)); + } + return SUCCESS; +} + + /* The following items change on entry and exit of code blocks. They must be saved and restored when returning to a block. */ @@ -445,7 +636,7 @@ struct compiler_unit { Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */ Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */ - cfg_builder u_cfg_builder; /* The control flow graph */ + instr_sequence u_instr_sequence; /* codegen output */ int u_nfblocks; struct fblockinfo u_fblock[CO_MAXBLOCKS]; @@ -481,7 +672,7 @@ struct compiler { PyArena *c_arena; /* pointer to memory allocation arena */ }; -#define CFG_BUILDER(C) (&((C)->u->u_cfg_builder)) +#define INSTR_SEQUENCE(C) (&((C)->u->u_instr_sequence)) typedef struct { @@ -511,9 +702,7 @@ typedef struct { static int basicblock_next_instr(basicblock *); -static basicblock *cfg_builder_new_block(cfg_builder *g); -static int cfg_builder_maybe_start_new_block(cfg_builder *g); -static int cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc); +static int codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc); static void compiler_free(struct compiler *); static int compiler_error(struct compiler *, location loc, const char *, ...); @@ -744,7 +933,8 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset) return dest; } -static void +#ifndef NDEBUG +static bool cfg_builder_check(cfg_builder *g) { for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) { @@ -759,7 +949,11 @@ cfg_builder_check(cfg_builder *g) assert (block->b_ialloc == 0); } } + return true; } +#endif + +static basicblock *cfg_builder_new_block(cfg_builder *g); static int cfg_builder_init(cfg_builder *g) @@ -777,7 +971,7 @@ cfg_builder_init(cfg_builder *g) static void cfg_builder_fini(cfg_builder* g) { - cfg_builder_check(g); + assert(cfg_builder_check(g)); basicblock *b = g->g_block_list; while (b != NULL) { if (b->b_instr) { @@ -792,7 +986,7 @@ cfg_builder_fini(cfg_builder* g) static void compiler_unit_free(struct compiler_unit *u) { - cfg_builder_fini(&u->u_cfg_builder); + instr_sequence_fini(&u->u_instr_sequence); Py_CLEAR(u->u_ste); Py_CLEAR(u->u_name); Py_CLEAR(u->u_qualname); @@ -878,13 +1072,6 @@ compiler_set_qualname(struct compiler *c) return SUCCESS; } -static jump_target_label -cfg_new_label(cfg_builder *g) -{ - jump_target_label lbl = {g->g_next_free_label++}; - return lbl; -} - /* Allocate a new block and return a pointer to it. Returns NULL on error. */ @@ -912,13 +1099,6 @@ cfg_builder_use_next_block(cfg_builder *g, basicblock *block) return block; } -static int -cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) -{ - g->g_current_label = lbl; - return cfg_builder_maybe_start_new_block(g); -} - static inline int basicblock_append_instructions(basicblock *target, basicblock *source) { @@ -958,40 +1138,15 @@ static int basicblock_next_instr(basicblock *b) { assert(b != NULL); - if (b->b_instr == NULL) { - b->b_instr = (struct instr *)PyObject_Calloc( - DEFAULT_BLOCK_SIZE, sizeof(struct instr)); - if (b->b_instr == NULL) { - PyErr_NoMemory(); - return ERROR; - } - b->b_ialloc = DEFAULT_BLOCK_SIZE; - } - else if (b->b_iused == b->b_ialloc) { - struct instr *tmp; - size_t oldsize, newsize; - oldsize = b->b_ialloc * sizeof(struct instr); - newsize = oldsize << 1; - if (oldsize > (SIZE_MAX >> 1)) { - PyErr_NoMemory(); - return ERROR; - } + RETURN_IF_ERROR( + ensure_array_large_enough( + b->b_iused + 1, + (void**)&b->b_instr, + &b->b_ialloc, + DEFAULT_BLOCK_SIZE, + sizeof(struct cfg_instr))); - if (newsize == 0) { - PyErr_NoMemory(); - return ERROR; - } - b->b_ialloc <<= 1; - tmp = (struct instr *)PyObject_Realloc( - (void *)b->b_instr, newsize); - if (tmp == NULL) { - PyErr_NoMemory(); - return ERROR; - } - b->b_instr = tmp; - memset((char *)b->b_instr + oldsize, 0, newsize - oldsize); - } return b->b_iused++; } @@ -1100,7 +1255,7 @@ basicblock_addop(basicblock *b, int opcode, int oparg, location loc) if (off < 0) { return ERROR; } - struct instr *i = &b->b_instr[off]; + struct cfg_instr *i = &b->b_instr[off]; i->i_opcode = opcode; i->i_oparg = oparg; i->i_target = NULL; @@ -1115,7 +1270,7 @@ cfg_builder_current_block_is_terminated(cfg_builder *g) if (IS_LABEL(g->g_current_label)) { return true; } - struct instr *last = basicblock_last_instr(g->g_curblock); + struct cfg_instr *last = basicblock_last_instr(g->g_curblock); return last && IS_TERMINATOR_OPCODE(last->i_opcode); } @@ -1135,17 +1290,10 @@ cfg_builder_maybe_start_new_block(cfg_builder *g) } static int -cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) -{ - RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); - return basicblock_addop(g->g_curblock, opcode, oparg, loc); -} - -static int -cfg_builder_addop_noarg(cfg_builder *g, int opcode, location loc) +codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { assert(!HAS_ARG(opcode)); - return cfg_builder_addop(g, opcode, 0, loc); + return instr_sequence_addop(seq, opcode, 0, loc); } static Py_ssize_t @@ -1303,7 +1451,7 @@ compiler_addop_load_const(struct compiler *c, location loc, PyObject *o) if (arg < 0) { return ERROR; } - return cfg_builder_addop_i(CFG_BUILDER(c), LOAD_CONST, arg, loc); + return codegen_addop_i(INSTR_SEQUENCE(c), LOAD_CONST, arg, loc); } static int @@ -1314,7 +1462,7 @@ compiler_addop_o(struct compiler *c, location loc, if (arg < 0) { return ERROR; } - return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, loc); + return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc); } static int @@ -1340,12 +1488,12 @@ compiler_addop_name(struct compiler *c, location loc, arg <<= 1; arg |= 1; } - return cfg_builder_addop_i(CFG_BUILDER(c), opcode, arg, loc); + return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc); } /* Add an opcode with an integer argument */ static int -cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc) +codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc) { /* oparg value is unsigned, but a signed C int is usually used to store it in the C code (like Python/ceval.c). @@ -1356,23 +1504,23 @@ cfg_builder_addop_i(cfg_builder *g, int opcode, Py_ssize_t oparg, location loc) EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */ int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); - return cfg_builder_addop(g, opcode, oparg_, loc); + return instr_sequence_addop(seq, opcode, oparg_, loc); } static int -cfg_builder_addop_j(cfg_builder *g, location loc, +codegen_addop_j(instr_sequence *seq, location loc, int opcode, jump_target_label target) { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); - return cfg_builder_addop(g, opcode, target.id, loc); + return instr_sequence_addop(seq, opcode, target.id, loc); } #define ADDOP(C, LOC, OP) \ - RETURN_IF_ERROR(cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC))) + RETURN_IF_ERROR(codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC))) #define ADDOP_IN_SCOPE(C, LOC, OP) { \ - if (cfg_builder_addop_noarg(CFG_BUILDER(C), (OP), (LOC)) < 0) { \ + if (codegen_addop_noarg(INSTR_SEQUENCE(C), (OP), (LOC)) < 0) { \ compiler_exit_scope(C); \ return ERROR; \ } \ @@ -1407,10 +1555,10 @@ cfg_builder_addop_j(cfg_builder *g, location loc, RETURN_IF_ERROR(compiler_addop_name((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O))) #define ADDOP_I(C, LOC, OP, O) \ - RETURN_IF_ERROR(cfg_builder_addop_i(CFG_BUILDER(C), (OP), (O), (LOC))) + RETURN_IF_ERROR(codegen_addop_i(INSTR_SEQUENCE(C), (OP), (O), (LOC))) #define ADDOP_JUMP(C, LOC, OP, O) \ - RETURN_IF_ERROR(cfg_builder_addop_j(CFG_BUILDER(C), (LOC), (OP), (O))) + RETURN_IF_ERROR(codegen_addop_j(INSTR_SEQUENCE(C), (LOC), (OP), (O))) #define ADDOP_COMPARE(C, LOC, CMP) \ RETURN_IF_ERROR(compiler_addcompare((C), (LOC), (cmpop_ty)(CMP))) @@ -1546,9 +1694,6 @@ compiler_enter_scope(struct compiler *c, identifier name, c->c_nestlevel++; - cfg_builder *g = CFG_BUILDER(c); - RETURN_IF_ERROR(cfg_builder_init(g)); - if (u->u_scope_type == COMPILER_SCOPE_MODULE) { loc.lineno = 0; } @@ -1582,7 +1727,6 @@ compiler_exit_scope(struct compiler *c) _PyErr_WriteUnraisableMsg("on removing the last compiler " "stack item", NULL); } - cfg_builder_check(CFG_BUILDER(c)); } else { c->u = NULL; @@ -2321,7 +2465,7 @@ compiler_check_debug_args(struct compiler *c, arguments_ty args) } static inline int -insert_instruction(basicblock *block, int pos, struct instr *instr) { +insert_instruction(basicblock *block, int pos, struct cfg_instr *instr) { RETURN_IF_ERROR(basicblock_next_instr(block)); for (int i = block->b_iused - 1; i > pos; i--) { block->b_instr[i] = block->b_instr[i-1]; @@ -2336,14 +2480,10 @@ wrap_in_stopiteration_handler(struct compiler *c) NEW_JUMP_TARGET_LABEL(c, handler); /* Insert SETUP_CLEANUP at start */ - struct instr setup = { - .i_opcode = SETUP_CLEANUP, - .i_oparg = handler.id, - .i_loc = NO_LOCATION, - .i_target = NULL, - }; RETURN_IF_ERROR( - insert_instruction(c->u->u_cfg_builder.g_entryblock, 0, &setup)); + instr_sequence_insert_instruction( + INSTR_SEQUENCE(c), 0, + SETUP_CLEANUP, handler.id, NO_LOCATION)); ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); ADDOP(c, NO_LOCATION, RETURN_VALUE); @@ -4032,7 +4172,7 @@ compiler_nameop(struct compiler *c, location loc, if (op == LOAD_GLOBAL) { arg <<= 1; } - return cfg_builder_addop_i(CFG_BUILDER(c), op, arg, loc); + return codegen_addop_i(INSTR_SEQUENCE(c), op, arg, loc); } static int @@ -6051,7 +6191,7 @@ emit_and_reset_fail_pop(struct compiler *c, location loc, } while (--pc->fail_pop_size) { USE_LABEL(c, pc->fail_pop[pc->fail_pop_size]); - if (cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, loc) < 0) { + if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, loc) < 0) { pc->fail_pop_size = 0; PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; @@ -6491,7 +6631,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - if (cfg_builder_addop_i(CFG_BUILDER(c), COPY, 1, LOC(alt)) < 0 || + if (codegen_addop_i(INSTR_SEQUENCE(c), COPY, 1, LOC(alt)) < 0 || compiler_pattern(c, alt, pc) < 0) { goto error; } @@ -6554,7 +6694,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) } } assert(control); - if (cfg_builder_addop_j(CFG_BUILDER(c), LOC(alt), JUMP, end) < 0 || + if (codegen_addop_j(INSTR_SEQUENCE(c), LOC(alt), JUMP, end) < 0 || emit_and_reset_fail_pop(c, LOC(alt), pc) < 0) { goto error; @@ -6566,7 +6706,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // Need to NULL this for the PyObject_Free call in the error block. old_pc.fail_pop = NULL; // No match. Pop the remaining copy of the subject and fail: - if (cfg_builder_addop_noarg(CFG_BUILDER(c), POP_TOP, LOC(p)) < 0 || + if (codegen_addop_noarg(INSTR_SEQUENCE(c), POP_TOP, LOC(p)) < 0 || jump_to_fail_pop(c, LOC(p), pc, JUMP) < 0) { goto error; } @@ -6884,7 +7024,7 @@ stackdepth(basicblock *entryblock, int code_flags) assert(depth >= 0); basicblock *next = b->b_next; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; int effect = stack_effect(instr->i_opcode, instr->i_oparg, 0); if (effect == PY_INVALID_STACK_EFFECT) { PyErr_Format(PyExc_SystemError, @@ -6973,7 +7113,7 @@ blocksize(basicblock *b) } static basicblock * -push_except_block(ExceptStack *stack, struct instr *setup) { +push_except_block(ExceptStack *stack, struct cfg_instr *setup) { assert(is_block_push(setup)); int opcode = setup->i_opcode; basicblock * target = setup->i_target; @@ -7045,7 +7185,7 @@ label_exception_targets(basicblock *entryblock) { b->b_exceptstack = NULL; handler = except_stack_top(except_stack); for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_block_push(instr)) { if (!instr->i_target->b_visited) { ExceptStack *copy = copy_except_stack(except_stack); @@ -7123,7 +7263,7 @@ mark_except_handlers(basicblock *entryblock) { #endif for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i=0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_block_push(instr)) { instr->i_target->b_except_handler = 1; } @@ -7152,7 +7292,7 @@ mark_warm(basicblock *entryblock) { next->b_visited = 1; } for (int i=0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_jump(instr) && !instr->i_target->b_visited) { *sp++ = instr->i_target; instr->i_target->b_visited = 1; @@ -7197,7 +7337,7 @@ mark_cold(basicblock *entryblock) { } } for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_jump(instr)) { assert(i == b->b_iused - 1); basicblock *target = b->b_instr[i].i_target; @@ -7238,7 +7378,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { b->b_next = explicit_jump; /* set target */ - struct instr *last = basicblock_last_instr(explicit_jump); + struct cfg_instr *last = basicblock_last_instr(explicit_jump); last->i_target = explicit_jump->b_next; } } @@ -7293,7 +7433,7 @@ static void convert_exception_handlers_to_nops(basicblock *entryblock) { for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) { INSTR_SET_OP0(instr, NOP); } @@ -7372,7 +7512,7 @@ assemble_exception_table(struct assembler *a, basicblock *entryblock) for (b = entryblock; b != NULL; b = b->b_next) { ioffset = b->b_offset; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (instr->i_except != handler) { if (handler != NULL) { RETURN_IF_ERROR( @@ -7542,7 +7682,7 @@ assemble_emit_location(struct assembler* a, location loc, int isize) */ static int -assemble_emit(struct assembler *a, struct instr *i) +assemble_emit(struct assembler *a, struct cfg_instr *i) { Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); _Py_CODEUNIT *code; @@ -7562,7 +7702,7 @@ assemble_emit(struct assembler *a, struct instr *i) static int normalize_jumps_in_block(cfg_builder *g, basicblock *b) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last == NULL || !is_jump(last)) { return SUCCESS; } @@ -7663,7 +7803,7 @@ assemble_jump_offsets(basicblock *entryblock) for (basicblock *b = entryblock; b != NULL; b = b->b_next) { bsize = b->b_offset; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; int isize = instr_size(instr); /* Relative jumps are computed relative to the instruction pointer after fetching @@ -7735,7 +7875,7 @@ scan_block_for_locals(basicblock *b, basicblock ***sp) // bit i is set if local i is potentially uninitialized uint64_t unsafe_mask = b->b_unsafe_locals_mask; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; assert(instr->i_opcode != EXTENDED_ARG); assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); if (instr->i_except != NULL) { @@ -7768,7 +7908,7 @@ scan_block_for_locals(basicblock *b, basicblock ***sp) if (b->b_next && BB_HAS_FALLTHROUGH(b)) { maybe_push(b->b_next, unsafe_mask, sp); } - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last && is_jump(last)) { assert(last->i_target != NULL); maybe_push(last->i_target, unsafe_mask, sp); @@ -7791,7 +7931,7 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals) for (basicblock *b = entryblock; b != NULL; b = b->b_next) { blocknum++; for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; assert(instr->i_opcode != EXTENDED_ARG); assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); int arg = instr->i_oparg; @@ -8035,7 +8175,6 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, PyObject *consts = NULL; PyObject *localsplusnames = NULL; PyObject *localspluskinds = NULL; - names = dict_keys_inorder(c->u->u_names, 0); if (!names) { goto error; @@ -8121,7 +8260,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, /* For debugging purposes only */ #if 0 static void -dump_instr(struct instr *i) +dump_instr(struct cfg_instr *i) { const char *jrel = (is_relative_jump(i)) ? "jrel " : ""; const char *jabs = (is_jump(i) && !is_relative_jump(i))? "jabs " : ""; @@ -8139,6 +8278,12 @@ dump_instr(struct instr *i) i->i_loc.lineno, i->i_opcode, arg, jabs, jrel); } +static inline int +basicblock_returns(const basicblock *b) { + struct cfg_instr *last = basicblock_last_instr(b); + return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST); +} + static void dump_basicblock(const basicblock *b) { @@ -8211,14 +8356,14 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, /* Add the generator prefix instructions. */ if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { - struct instr make_gen = { + struct cfg_instr make_gen = { .i_opcode = RETURN_GENERATOR, .i_oparg = 0, .i_loc = LOCATION(c->u->u_firstlineno, c->u->u_firstlineno, -1, -1), .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, 0, &make_gen)); - struct instr pop_top = { + struct cfg_instr pop_top = { .i_opcode = POP_TOP, .i_oparg = 0, .i_loc = NO_LOCATION, @@ -8247,7 +8392,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, if (oldindex == -1) { continue; } - struct instr make_cell = { + struct cfg_instr make_cell = { .i_opcode = MAKE_CELL, // This will get fixed in offset_derefs(). .i_oparg = oldindex, @@ -8261,7 +8406,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, } if (nfreevars) { - struct instr copy_frees = { + struct cfg_instr copy_frees = { .i_opcode = COPY_FREE_VARS, .i_oparg = nfreevars, .i_loc = NO_LOCATION, @@ -8282,7 +8427,7 @@ guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) { int lineno = firstlineno; assert(lineno > 0); for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last == NULL) { continue; } @@ -8324,7 +8469,7 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap) // Then update offsets, either relative to locals or by cell2arg. for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct instr *inst = &b->b_instr[i]; + struct cfg_instr *inst = &b->b_instr[i]; // This is called before extended args are generated. assert(inst->i_opcode != EXTENDED_ARG); int oldoffset = inst->i_oparg; @@ -8364,7 +8509,7 @@ no_redundant_nops(cfg_builder *g) { static bool no_redundant_jumps(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last != NULL) { if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { assert(last->i_target != b->b_next); @@ -8382,7 +8527,7 @@ opcode_metadata_is_sane(cfg_builder *g) { bool result = true; for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; int opcode = instr->i_opcode; int oparg = instr->i_oparg; assert(opcode <= MAX_REAL_OPCODE); @@ -8426,7 +8571,7 @@ remove_redundant_jumps(cfg_builder *g) { */ assert(no_empty_basic_blocks(g)); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); assert(last != NULL); assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { @@ -8444,7 +8589,7 @@ remove_redundant_jumps(cfg_builder *g) { } static int -prepare_localsplus(struct compiler* c, int code_flags) +prepare_localsplus(struct compiler* c, cfg_builder *g, int code_flags) { assert(PyDict_GET_SIZE(c->u->u_varnames) < INT_MAX); assert(PyDict_GET_SIZE(c->u->u_cellvars) < INT_MAX); @@ -8460,7 +8605,6 @@ prepare_localsplus(struct compiler* c, int code_flags) return ERROR; } - cfg_builder* g = CFG_BUILDER(c); // This must be called before fix_cell_offsets(). if (insert_prefix_instructions(c, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { @@ -8474,20 +8618,21 @@ prepare_localsplus(struct compiler* c, int code_flags) if (numdropped < 0) { return ERROR; } + nlocalsplus -= numdropped; return nlocalsplus; } static int -add_return_at_end_of_block(struct compiler *c, int addNone) +add_return_at_end(struct compiler *c, int addNone) { - /* Make sure every block that falls off the end returns None. */ - if (!basicblock_returns(CFG_BUILDER(c)->g_curblock)) { - if (addNone) { - ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); - } - ADDOP(c, NO_LOCATION, RETURN_VALUE); + /* Make sure every instruction stream that falls off the end returns None. + * This also ensures that no jump target offsets are out of bounds. + */ + if (addNone) { + ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None); } + ADDOP(c, NO_LOCATION, RETURN_VALUE); return SUCCESS; } @@ -8496,6 +8641,8 @@ assemble(struct compiler *c, int addNone) { PyCodeObject *co = NULL; PyObject *consts = NULL; + cfg_builder g_; + cfg_builder *g = &g_; struct assembler a; memset(&a, 0, sizeof(struct assembler)); @@ -8504,12 +8651,18 @@ assemble(struct compiler *c, int addNone) return NULL; } - if (add_return_at_end_of_block(c, addNone) < 0) { + if (add_return_at_end(c, addNone) < 0) { return NULL; } + /** Preprocessing **/ + if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), g) < 0) { + goto error; + } + assert(cfg_builder_check(g)); + int nblocks = 0; - for (basicblock *b = CFG_BUILDER(c)->g_block_list; b != NULL; b = b->b_list) { + for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { nblocks++; } if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { @@ -8517,9 +8670,6 @@ assemble(struct compiler *c, int addNone) goto error; } - cfg_builder *g = CFG_BUILDER(c); - assert(g->g_entryblock != NULL); - /* Set firstlineno if it wasn't explicitly set. */ if (!c->u->u_firstlineno) { if (g->g_entryblock->b_instr && g->g_entryblock->b_instr->i_loc.lineno) { @@ -8530,9 +8680,8 @@ assemble(struct compiler *c, int addNone) } } - /** Preprocessing **/ /* Map labels to targets and mark exception handlers */ - if (translate_jump_labels_to_targets(g->g_entryblock)) { + if (translate_jump_labels_to_targets(g->g_entryblock) < 0) { goto error; } if (mark_except_handlers(g->g_entryblock) < 0) { @@ -8550,10 +8699,10 @@ assemble(struct compiler *c, int addNone) if (optimize_cfg(g, consts, c->c_const_cache)) { goto error; } - if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) { + if (remove_unused_consts(g->g_entryblock, consts) < 0) { goto error; } - if (remove_unused_consts(g->g_entryblock, consts) < 0) { + if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) { goto error; } @@ -8570,7 +8719,7 @@ assemble(struct compiler *c, int addNone) /** Assembly **/ - int nlocalsplus = prepare_localsplus(c, code_flags); + int nlocalsplus = prepare_localsplus(c, g, code_flags); if (nlocalsplus < 0) { goto error; } @@ -8587,7 +8736,6 @@ assemble(struct compiler *c, int addNone) if (normalize_jumps(g) < 0) { goto error; } - assert(no_redundant_jumps(g)); assert(opcode_metadata_is_sane(g)); @@ -8655,6 +8803,7 @@ assemble(struct compiler *c, int addNone) co = makecode(c, &a, consts, maxdepth, nlocalsplus, code_flags); error: Py_XDECREF(consts); + cfg_builder_fini(g); assemble_free(&a); return co; } @@ -8684,7 +8833,7 @@ get_const_value(int opcode, int oparg, PyObject *co_consts) */ static int fold_tuple_on_constants(PyObject *const_cache, - struct instr *inst, + struct cfg_instr *inst, int n, PyObject *consts) { /* Pre-conditions */ @@ -8753,7 +8902,7 @@ swaptimize(basicblock *block, int *ix) // NOTE: "./python -m test test_patma" serves as a good, quick stress test // for this function. Make sure to blow away cached *.pyc files first! assert(*ix < block->b_iused); - struct instr *instructions = &block->b_instr[*ix]; + struct cfg_instr *instructions = &block->b_instr[*ix]; // Find the length of the current sequence of SWAPs and NOPs, and record the // maximum depth of the stack manipulations: assert(instructions[0].i_opcode == SWAP); @@ -8854,7 +9003,7 @@ static int next_swappable_instruction(basicblock *block, int i, int lineno) { while (++i < block->b_iused) { - struct instr *instruction = &block->b_instr[i]; + struct cfg_instr *instruction = &block->b_instr[i]; if (0 <= lineno && instruction->i_loc.lineno != lineno) { // Optimizing across this instruction could cause user-visible // changes in the names bound between line tracing events! @@ -8880,7 +9029,7 @@ apply_static_swaps(basicblock *block, int i) // SWAPs are to our left, and potential swaperands are to our right: for (; 0 <= i; i--) { assert(i < block->b_iused); - struct instr *swap = &block->b_instr[i]; + struct cfg_instr *swap = &block->b_instr[i]; if (swap->i_opcode != SWAP) { if (swap->i_opcode == NOP || SWAPPABLE(swap->i_opcode)) { // Nope, but we know how to handle these. Keep looking: @@ -8903,7 +9052,7 @@ apply_static_swaps(basicblock *block, int i) } // Success! INSTR_SET_OP0(swap, NOP); - struct instr temp = block->b_instr[j]; + struct cfg_instr temp = block->b_instr[j]; block->b_instr[j] = block->b_instr[k]; block->b_instr[k] = temp; } @@ -8913,7 +9062,7 @@ apply_static_swaps(basicblock *block, int i) // target->i_target using the provided opcode. Return whether or not the // optimization was successful. static bool -jump_thread(struct instr *inst, struct instr *target, int opcode) +jump_thread(struct cfg_instr *inst, struct cfg_instr *target, int opcode) { assert(is_jump(inst)); assert(is_jump(target)); @@ -8938,11 +9087,11 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) { assert(PyDict_CheckExact(const_cache)); assert(PyList_CheckExact(consts)); - struct instr nop; + struct cfg_instr nop; INSTR_SET_OP0(&nop, NOP); - struct instr *target; + struct cfg_instr *target; for (int i = 0; i < bb->b_iused; i++) { - struct instr *inst = &bb->b_instr[i]; + struct cfg_instr *inst = &bb->b_instr[i]; int oparg = inst->i_oparg; int nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0; if (HAS_TARGET(inst->i_opcode)) { @@ -9179,7 +9328,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) */ static int inline_small_exit_blocks(basicblock *bb) { - struct instr *last = basicblock_last_instr(bb); + struct cfg_instr *last = basicblock_last_instr(bb); if (last == NULL) { return 0; } @@ -9287,7 +9436,7 @@ mark_reachable(basicblock *entryblock) { } for (int i = 0; i < b->b_iused; i++) { basicblock *target; - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (is_jump(instr) || is_block_push(instr)) { target = instr->i_target; if (!target->b_visited) { @@ -9318,7 +9467,7 @@ eliminate_empty_basic_blocks(cfg_builder *g) { for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { assert(b->b_iused > 0); for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; if (HAS_TARGET(instr->i_opcode)) { basicblock *target = instr->i_target; while (target->b_iused == 0) { @@ -9342,7 +9491,7 @@ eliminate_empty_basic_blocks(cfg_builder *g) { static void propagate_line_numbers(basicblock *entryblock) { for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); if (last == NULL) { continue; } @@ -9398,7 +9547,7 @@ translate_jump_labels_to_targets(basicblock *entryblock) } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; assert(instr->i_target == NULL); if (HAS_TARGET(instr->i_opcode)) { int lbl = instr->i_oparg; @@ -9584,7 +9733,7 @@ duplicate_exits_without_lineno(cfg_builder *g) */ basicblock *entryblock = g->g_entryblock; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); assert(last != NULL); if (is_jump(last)) { basicblock *target = last->i_target; @@ -9608,7 +9757,7 @@ duplicate_exits_without_lineno(cfg_builder *g) for (basicblock *b = entryblock; b != NULL; b = b->b_next) { if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) { if (is_exit_without_lineno(b->b_next)) { - struct instr *last = basicblock_last_instr(b); + struct cfg_instr *last = basicblock_last_instr(b); assert(last != NULL); b->b_next->b_instr[0].i_loc = last->i_loc; } @@ -9724,7 +9873,7 @@ cfg_to_instructions(cfg_builder *g) } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct instr *instr = &b->b_instr[i]; + struct cfg_instr *instr = &b->b_instr[i]; location loc = instr->i_loc; int arg = HAS_TARGET(instr->i_opcode) ? instr->i_target->b_label : instr->i_oparg; @@ -9783,16 +9932,19 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, goto finally; } - cfg_builder *g = CFG_BUILDER(c); - - if (translate_jump_labels_to_targets(g->g_entryblock) < 0) { + cfg_builder g; + if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), &g) < 0) { + goto finally; + } + if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { goto finally; } - res = cfg_to_instructions(g); + res = cfg_to_instructions(&g); finally: compiler_exit_scope(c); + cfg_builder_fini(&g); compiler_free(c); _PyArena_Free(arena); return res; @@ -9815,7 +9967,7 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) if (const_cache == NULL) { goto error; } - if (translate_jump_labels_to_targets(g.g_entryblock)) { + if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { goto error; } if (optimize_cfg(&g, consts, const_cache) < 0) { From webhook-mailer at python.org Tue Mar 7 16:27:53 2023 From: webhook-mailer at python.org (Yhg1s) Date: Tue, 07 Mar 2023 21:27:53 -0000 Subject: [Python-checkins] gh-102493: fix normalization in PyErr_SetObject (#102502) Message-ID: https://github.com/python/cpython/commit/a33ca2ad1fcf857817cba505a788e15cf9d6ed0c commit: a33ca2ad1fcf857817cba505a788e15cf9d6ed0c branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: Yhg1s date: 2023-03-07T13:27:46-08:00 summary: gh-102493: fix normalization in PyErr_SetObject (#102502) Co-authored-by: Jelle Zijlstra files: A Misc/NEWS.d/next/Core and Builtins/2023-03-07-16-56-28.gh-issue-102493.gTXrcD.rst M Lib/test/test_capi/test_exceptions.py M Modules/_testcapi/exceptions.c M Python/errors.c diff --git a/Lib/test/test_capi/test_exceptions.py b/Lib/test/test_capi/test_exceptions.py index b543a1a565a5..55f131699a25 100644 --- a/Lib/test/test_capi/test_exceptions.py +++ b/Lib/test/test_capi/test_exceptions.py @@ -140,6 +140,34 @@ def test_err_restore(self): self.assertEqual(1, v.args[0]) self.assertIs(tb, v.__traceback__.tb_next) + def test_set_object(self): + + # new exception as obj is not an exception + with self.assertRaises(ValueError) as e: + _testcapi.exc_set_object(ValueError, 42) + self.assertEqual(e.exception.args, (42,)) + + # wraps the exception because unrelated types + with self.assertRaises(ValueError) as e: + _testcapi.exc_set_object(ValueError, TypeError(1,2,3)) + wrapped = e.exception.args[0] + self.assertIsInstance(wrapped, TypeError) + self.assertEqual(wrapped.args, (1, 2, 3)) + + # is superclass, so does not wrap + with self.assertRaises(PermissionError) as e: + _testcapi.exc_set_object(OSError, PermissionError(24)) + self.assertEqual(e.exception.args, (24,)) + + class Meta(type): + def __subclasscheck__(cls, sub): + 1/0 + + class Broken(Exception, metaclass=Meta): + pass + + with self.assertRaises(ZeroDivisionError) as e: + _testcapi.exc_set_object(Broken, Broken()) if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-07-16-56-28.gh-issue-102493.gTXrcD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-07-16-56-28.gh-issue-102493.gTXrcD.rst new file mode 100644 index 000000000000..4c4e88ca4e7c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-07-16-56-28.gh-issue-102493.gTXrcD.rst @@ -0,0 +1 @@ +Fix regression in semantics of normalisation in ``PyErr_SetObject``. diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index 43b88ccf261d..a0575213987f 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -78,6 +78,20 @@ make_exception_with_doc(PyObject *self, PyObject *args, PyObject *kwargs) return PyErr_NewExceptionWithDoc(name, doc, base, dict); } +static PyObject * +exc_set_object(PyObject *self, PyObject *args) +{ + PyObject *exc; + PyObject *obj; + + if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) { + return NULL; + } + + PyErr_SetObject(exc, obj); + return NULL; +} + static PyObject * raise_exception(PyObject *self, PyObject *args) { @@ -247,6 +261,7 @@ static PyMethodDef test_methods[] = { PyDoc_STR("fatal_error(message, release_gil=False): call Py_FatalError(message)")}, {"make_exception_with_doc", _PyCFunction_CAST(make_exception_with_doc), METH_VARARGS | METH_KEYWORDS}, + {"exc_set_object", exc_set_object, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", raise_memoryerror, METH_NOARGS}, {"set_exc_info", test_set_exc_info, METH_VARARGS}, diff --git a/Python/errors.c b/Python/errors.c index f573bed3d63e..bbf6d397ce80 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -149,9 +149,16 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) exception); return; } - Py_XINCREF(value); /* Normalize the exception */ - if (value == NULL || (PyObject *)Py_TYPE(value) != exception) { + int is_subclass = 0; + if (value != NULL && PyExceptionInstance_Check(value)) { + is_subclass = PyObject_IsSubclass((PyObject *)Py_TYPE(value), exception); + if (is_subclass < 0) { + return; + } + } + Py_XINCREF(value); + if (!is_subclass) { /* We must normalize the value right now */ PyObject *fixed_value; @@ -206,9 +213,10 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) Py_DECREF(exc_value); } } - if (value != NULL && PyExceptionInstance_Check(value)) + assert(value != NULL); + if (PyExceptionInstance_Check(value)) tb = PyException_GetTraceback(value); - _PyErr_Restore(tstate, Py_XNewRef(exception), value, tb); + _PyErr_Restore(tstate, Py_NewRef(Py_TYPE(value)), value, tb); } void From webhook-mailer at python.org Tue Mar 7 18:01:29 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 07 Mar 2023 23:01:29 -0000 Subject: [Python-checkins] [3.9] gh-101726: Update the OpenSSL version to 1.1.1t (GH-101727) (GH-101751) Message-ID: https://github.com/python/cpython/commit/bf99e19b997b6c42c6cddd9a73e47add549f24c6 commit: bf99e19b997b6c42c6cddd9a73e47add549f24c6 branch: 3.9 author: Steve Dower committer: ned-deily date: 2023-03-07T18:01:22-05:00 summary: [3.9] gh-101726: Update the OpenSSL version to 1.1.1t (GH-101727) (GH-101751) Fixes CVE-2023-0286 (High) and a couple of Medium security issues. https://www.openssl.org/news/secadv/20230207.txt Co-authored-by: Gregory P. Smith Co-authored-by: Ned Deily files: A Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst M .azure-pipelines/ci.yml M .azure-pipelines/pr.yml M .github/workflows/build.yml M Mac/BuildScript/build-installer.py M PCbuild/get_externals.bat M PCbuild/python.props M PCbuild/readme.txt M Tools/ssl/multissltests.py diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index 39ad0e6b3ff7..92f3f41a31ad 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -57,7 +57,7 @@ jobs: variables: testRunTitle: '$(build.sourceBranchName)-linux' testRunPlatform: linux - openssl_version: 1.1.1n + openssl_version: 1.1.1t steps: - template: ./posix-steps.yml @@ -83,7 +83,7 @@ jobs: variables: testRunTitle: '$(Build.SourceBranchName)-linux-coverage' testRunPlatform: linux-coverage - openssl_version: 1.1.1n + openssl_version: 1.1.1t steps: - template: ./posix-steps.yml diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index 84d01806a452..654d32540c2a 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -57,7 +57,7 @@ jobs: variables: testRunTitle: '$(system.pullRequest.TargetBranch)-linux' testRunPlatform: linux - openssl_version: 1.1.1n + openssl_version: 1.1.1t steps: - template: ./posix-steps.yml @@ -83,7 +83,7 @@ jobs: variables: testRunTitle: '$(Build.SourceBranchName)-linux-coverage' testRunPlatform: linux-coverage - openssl_version: 1.1.1n + openssl_version: 1.1.1t steps: - template: ./posix-steps.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5a9659cede69..f21cc35b4800 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -165,7 +165,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: - OPENSSL_VER: 1.1.1n + OPENSSL_VER: 1.1.1t PYTHONSTRICTEXTENSIONBUILD: 1 steps: - uses: actions/checkout at v3 @@ -207,7 +207,7 @@ jobs: strategy: fail-fast: false matrix: - openssl_ver: [1.0.2u, 1.1.0l, 1.1.1n, 3.0.2] + openssl_ver: [1.0.2u, 1.1.0l, 1.1.1t, 3.0.8, 3.1.0-beta1] env: OPENSSL_VER: ${{ matrix.openssl_ver }} MULTISSL_DIR: ${{ github.workspace }}/multissl diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 9909679e0713..9a9237c493c3 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -244,9 +244,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 1.1.1n", - url="https://www.openssl.org/source/openssl-1.1.1n.tar.gz", - checksum='2aad5635f9bb338bc2c6b7d19cbc9676', + name="OpenSSL 1.1.1t", + url="https://www.openssl.org/source/openssl-1.1.1t.tar.gz", + checksum='1cfee919e0eac6be62c88c5ae8bcd91e', buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst b/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst new file mode 100644 index 000000000000..43acc82063fd --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst @@ -0,0 +1,4 @@ +Updated the OpenSSL version used in Windows and macOS binary release builds +to 1.1.1t to address CVE-2023-0286, CVE-2022-4303, and CVE-2022-4303 per +`the OpenSSL 2023-02-07 security advisory +`_. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index b17f37c4499f..09bfcd494131 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -53,7 +53,7 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.3.0 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1s +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1t set libraries=%libraries% sqlite-3.37.2.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.12.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.12.0 @@ -77,7 +77,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.3.0 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1s +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1t if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.12.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 diff --git a/PCbuild/python.props b/PCbuild/python.props index eeef39af637b..11c59ceb43b1 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -57,18 +57,25 @@ $(EXTERNALS_DIR) $([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`)) $(ExternalsDir)\ - $(ExternalsDir)sqlite-3.37.2.0\ - $(ExternalsDir)bzip2-1.0.8\ - $(ExternalsDir)xz-5.2.5\ - $(ExternalsDir)libffi-3.3.0\ - $(ExternalsDir)libffi-3.3.0\$(ArchName)\ - $(libffiOutDir)include - $(ExternalsDir)openssl-1.1.1s\ - $(ExternalsDir)openssl-bin-1.1.1s\$(ArchName)\ - $(opensslOutDir)include - $(ExternalsDir)\nasm-2.11.06\ - $(ExternalsDir)\zlib-1.2.12\ - + + + + + + $(ExternalsDir)sqlite-3.37.2.0\ + $(ExternalsDir)bzip2-1.0.8\ + $(ExternalsDir)xz-5.2.5\ + $(ExternalsDir)libffi-3.3.0\ + $(libffiDir)$(ArchName)\ + $(libffiOutDir)include + $(ExternalsDir)openssl-1.1.1t\ + $(ExternalsDir)openssl-bin-1.1.1t\$(ArchName)\ + $(opensslOutDir)include + $(ExternalsDir)\nasm-2.11.06\ + $(ExternalsDir)\zlib-1.2.12\ + + + _d diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 80b597cce3a7..db9dd352a84a 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -164,7 +164,7 @@ _lzma Homepage: https://tukaani.org/xz/ _ssl - Python wrapper for version 1.1.1k of the OpenSSL secure sockets + Python wrapper for version 1.1.1t of the OpenSSL secure sockets library, which is downloaded from our binaries repository at https://github.com/python/cpython-bin-deps. diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index 14c4918acc27..daf184358153 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -49,8 +49,8 @@ ] OPENSSL_RECENT_VERSIONS = [ - "1.1.1n", - "3.0.2" + "1.1.1t", + "3.0.8" ] LIBRESSL_OLD_VERSIONS = [ From webhook-mailer at python.org Tue Mar 7 18:03:14 2023 From: webhook-mailer at python.org (ned-deily) Date: Tue, 07 Mar 2023 23:03:14 -0000 Subject: [Python-checkins] [3.8] gh-101726: Update the OpenSSL version to 1.1.1t (GH-101727) (GH-101752) Message-ID: https://github.com/python/cpython/commit/ddd495e0552be409e3c8c280a6f7a69ed2e6425e commit: ddd495e0552be409e3c8c280a6f7a69ed2e6425e branch: 3.8 author: Steve Dower committer: ned-deily date: 2023-03-07T18:03:06-05:00 summary: [3.8] gh-101726: Update the OpenSSL version to 1.1.1t (GH-101727) (GH-101752) Fixes CVE-2023-0286 (High) and a couple of Medium security issues. https://www.openssl.org/news/secadv/20230207.txt Co-authored-by: Gregory P. Smith Co-authored-by: Ned Deily files: A Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst M .azure-pipelines/ci.yml M .azure-pipelines/pr.yml M .github/workflows/build.yml M Mac/BuildScript/build-installer.py M PCbuild/get_externals.bat M PCbuild/python.props M PCbuild/readme.txt M Tools/ssl/multissltests.py diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml index 39ad0e6b3ff7..92f3f41a31ad 100644 --- a/.azure-pipelines/ci.yml +++ b/.azure-pipelines/ci.yml @@ -57,7 +57,7 @@ jobs: variables: testRunTitle: '$(build.sourceBranchName)-linux' testRunPlatform: linux - openssl_version: 1.1.1n + openssl_version: 1.1.1t steps: - template: ./posix-steps.yml @@ -83,7 +83,7 @@ jobs: variables: testRunTitle: '$(Build.SourceBranchName)-linux-coverage' testRunPlatform: linux-coverage - openssl_version: 1.1.1n + openssl_version: 1.1.1t steps: - template: ./posix-steps.yml diff --git a/.azure-pipelines/pr.yml b/.azure-pipelines/pr.yml index 84d01806a452..654d32540c2a 100644 --- a/.azure-pipelines/pr.yml +++ b/.azure-pipelines/pr.yml @@ -57,7 +57,7 @@ jobs: variables: testRunTitle: '$(system.pullRequest.TargetBranch)-linux' testRunPlatform: linux - openssl_version: 1.1.1n + openssl_version: 1.1.1t steps: - template: ./posix-steps.yml @@ -83,7 +83,7 @@ jobs: variables: testRunTitle: '$(Build.SourceBranchName)-linux-coverage' testRunPlatform: linux-coverage - openssl_version: 1.1.1n + openssl_version: 1.1.1t steps: - template: ./posix-steps.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c25df8136df7..f34dc5d79344 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,7 +143,7 @@ jobs: needs: check_source if: needs.check_source.outputs.run_tests == 'true' env: - OPENSSL_VER: 1.1.1n + OPENSSL_VER: 1.1.1t steps: - uses: actions/checkout at v2 - name: Install Dependencies @@ -184,7 +184,7 @@ jobs: strategy: fail-fast: false matrix: - openssl_ver: [1.0.2u, 1.1.0l, 1.1.1l] + openssl_ver: [1.0.2u, 1.1.0l, 1.1.1t, 3.0.8, 3.1.0-beta1] env: OPENSSL_VER: ${{ matrix.openssl_ver }} MULTISSL_DIR: ${{ github.workspace }}/multissl diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py index 74c2c517d0ea..96a8587781de 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -242,9 +242,9 @@ def library_recipes(): result.extend([ dict( - name="OpenSSL 1.1.1n", - url="https://www.openssl.org/source/openssl-1.1.1n.tar.gz", - checksum='2aad5635f9bb338bc2c6b7d19cbc9676', + name="OpenSSL 1.1.1t", + url="https://www.openssl.org/source/openssl-1.1.1t.tar.gz", + checksum='1cfee919e0eac6be62c88c5ae8bcd91e', buildrecipe=build_universal_openssl, configure=None, install=None, diff --git a/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst b/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst new file mode 100644 index 000000000000..43acc82063fd --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst @@ -0,0 +1,4 @@ +Updated the OpenSSL version used in Windows and macOS binary release builds +to 1.1.1t to address CVE-2023-0286, CVE-2022-4303, and CVE-2022-4303 per +`the OpenSSL 2023-02-07 security advisory +`_. diff --git a/PCbuild/get_externals.bat b/PCbuild/get_externals.bat index 59ca66aa3601..995d3a3a8970 100644 --- a/PCbuild/get_externals.bat +++ b/PCbuild/get_externals.bat @@ -53,7 +53,7 @@ echo.Fetching external libraries... set libraries= set libraries=%libraries% bzip2-1.0.8 if NOT "%IncludeLibffiSrc%"=="false" set libraries=%libraries% libffi-3.3.0 -if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1s +if NOT "%IncludeSSLSrc%"=="false" set libraries=%libraries% openssl-1.1.1t set libraries=%libraries% sqlite-3.35.5.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tcl-core-8.6.9.0 if NOT "%IncludeTkinterSrc%"=="false" set libraries=%libraries% tk-8.6.9.0 @@ -77,7 +77,7 @@ echo.Fetching external binaries... set binaries= if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.3.0 -if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1s +if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-1.1.1t if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.9.0 if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06 diff --git a/PCbuild/python.props b/PCbuild/python.props index e9b491cac3ba..73e0a8008749 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -56,18 +56,25 @@ $(EXTERNALS_DIR) $([System.IO.Path]::GetFullPath(`$(PySourcePath)externals`)) $(ExternalsDir)\ - $(ExternalsDir)sqlite-3.35.5.0\ - $(ExternalsDir)bzip2-1.0.8\ - $(ExternalsDir)xz-5.2.2\ - $(ExternalsDir)libffi-3.3.0\ - $(ExternalsDir)libffi-3.3.0\$(ArchName)\ - $(libffiOutDir)include - $(ExternalsDir)openssl-1.1.1s\ - $(ExternalsDir)openssl-bin-1.1.1s\$(ArchName)\ - $(opensslOutDir)include - $(ExternalsDir)\nasm-2.11.06\ - $(ExternalsDir)\zlib-1.2.12\ - + + + + + + $(ExternalsDir)sqlite-3.35.5.0\ + $(ExternalsDir)bzip2-1.0.8\ + $(ExternalsDir)xz-5.2.2\ + $(ExternalsDir)libffi-3.3.0\ + $(libffiDir)$(ArchName)\ + $(libffiOutDir)include + $(ExternalsDir)openssl-1.1.1t\ + $(ExternalsDir)openssl-bin-1.1.1t\$(ArchName)\ + $(opensslOutDir)include + $(ExternalsDir)\nasm-2.11.06\ + $(ExternalsDir)\zlib-1.2.12\ + + + _d diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 6ad55ab922e1..aa600156b1a8 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -165,7 +165,7 @@ _lzma Homepage: http://tukaani.org/xz/ _ssl - Python wrapper for version 1.1.1k of the OpenSSL secure sockets + Python wrapper for version 1.1.1t of the OpenSSL secure sockets library, which is downloaded from our binaries repository at https://github.com/python/cpython-bin-deps. diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index 0e010b1deee0..d9df6c69aa85 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -49,8 +49,8 @@ ] OPENSSL_RECENT_VERSIONS = [ - "1.1.1n", - "3.0.1" + "1.1.1t", + "3.0.8" ] LIBRESSL_OLD_VERSIONS = [ From webhook-mailer at python.org Tue Mar 7 19:11:22 2023 From: webhook-mailer at python.org (carljm) Date: Wed, 08 Mar 2023 00:11:22 -0000 Subject: [Python-checkins] gh-102381: don't call watcher callback with dead object (#102382) Message-ID: https://github.com/python/cpython/commit/1e703a473343ed198c9a06a876b25d7d69d4bbd0 commit: 1e703a473343ed198c9a06a876b25d7d69d4bbd0 branch: main author: Carl Meyer committer: carljm date: 2023-03-07T17:10:58-07:00 summary: gh-102381: don't call watcher callback with dead object (#102382) Co-authored-by: T. Wouters files: M Doc/c-api/code.rst M Doc/c-api/dict.rst M Doc/c-api/function.rst M Include/cpython/code.h M Include/cpython/dictobject.h M Include/cpython/funcobject.h M Include/internal/pycore_dict.h M Lib/test/test_capi/test_watchers.py M Modules/_testcapi/watchers.c M Objects/codeobject.c M Objects/dictobject.c M Objects/funcobject.c diff --git a/Doc/c-api/code.rst b/Doc/c-api/code.rst index 062ef3a1fea9..a99de9904c07 100644 --- a/Doc/c-api/code.rst +++ b/Doc/c-api/code.rst @@ -172,6 +172,11 @@ bound into a function. before the destruction of *co* takes place, so the prior state of *co* can be inspected. + If *event* is ``PY_CODE_EVENT_DESTROY``, taking a reference in the callback + to the about-to-be-destroyed code object will resurrect it and prevent it + from being freed at this time. When the resurrected object is destroyed + later, any watcher callbacks active at that time will be called again. + Users of this API should not rely on internal runtime implementation details. Such details may include, but are not limited to, the exact order and timing of creation and destruction of code objects. While @@ -179,9 +184,15 @@ bound into a function. (including whether a callback is invoked or not), it does not change the semantics of the Python code being executed. - If the callback returns with an exception set, it must return ``-1``; this - exception will be printed as an unraisable exception using - :c:func:`PyErr_WriteUnraisable`. Otherwise it should return ``0``. + If the callback sets an exception, it must return ``-1``; this exception will + be printed as an unraisable exception using :c:func:`PyErr_WriteUnraisable`. + Otherwise it should return ``0``. + + There may already be a pending exception set on entry to the callback. In + this case, the callback should return ``0`` with the same exception still + set. This means the callback may not call any other API that can set an + exception unless it saves and clears the exception state first, and restores + it before returning. .. versionadded:: 3.12 diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 34106ee6b1f3..b9f84cea7856 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -298,13 +298,26 @@ Dictionary Objects dictionary. The callback may inspect but must not modify *dict*; doing so could have - unpredictable effects, including infinite recursion. + unpredictable effects, including infinite recursion. Do not trigger Python + code execution in the callback, as it could modify the dict as a side effect. + + If *event* is ``PyDict_EVENT_DEALLOCATED``, taking a new reference in the + callback to the about-to-be-destroyed dictionary will resurrect it and + prevent it from being freed at this time. When the resurrected object is + destroyed later, any watcher callbacks active at that time will be called + again. Callbacks occur before the notified modification to *dict* takes place, so the prior state of *dict* can be inspected. - If the callback returns with an exception set, it must return ``-1``; this - exception will be printed as an unraisable exception using - :c:func:`PyErr_WriteUnraisable`. Otherwise it should return ``0``. + If the callback sets an exception, it must return ``-1``; this exception will + be printed as an unraisable exception using :c:func:`PyErr_WriteUnraisable`. + Otherwise it should return ``0``. + + There may already be a pending exception set on entry to the callback. In + this case, the callback should return ``0`` with the same exception still + set. This means the callback may not call any other API that can set an + exception unless it saves and clears the exception state first, and restores + it before returning. .. versionadded:: 3.12 diff --git a/Doc/c-api/function.rst b/Doc/c-api/function.rst index bc7569d0add9..947ed7040408 100644 --- a/Doc/c-api/function.rst +++ b/Doc/c-api/function.rst @@ -173,8 +173,19 @@ There are a few functions specific to Python functions. runtime behavior depending on optimization decisions, it does not change the semantics of the Python code being executed. - If the callback returns with an exception set, it must return ``-1``; this - exception will be printed as an unraisable exception using - :c:func:`PyErr_WriteUnraisable`. Otherwise it should return ``0``. + If *event* is ``PyFunction_EVENT_DESTROY``, Taking a reference in the + callback to the about-to-be-destroyed function will resurrect it, preventing + it from being freed at this time. When the resurrected object is destroyed + later, any watcher callbacks active at that time will be called again. + + If the callback sets an exception, it must return ``-1``; this exception will + be printed as an unraisable exception using :c:func:`PyErr_WriteUnraisable`. + Otherwise it should return ``0``. + + There may already be a pending exception set on entry to the callback. In + this case, the callback should return ``0`` with the same exception still + set. This means the callback may not call any other API that can set an + exception unless it saves and clears the exception state first, and restores + it before returning. .. versionadded:: 3.12 diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 0e4bd8a58c16..abcf1250603d 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -224,9 +224,14 @@ PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int); PyAPI_FUNC(int) PyCode_Addr2Location(PyCodeObject *, int, int *, int *, int *, int *); -typedef enum PyCodeEvent { - PY_CODE_EVENT_CREATE, - PY_CODE_EVENT_DESTROY +#define PY_FOREACH_CODE_EVENT(V) \ + V(CREATE) \ + V(DESTROY) + +typedef enum { + #define PY_DEF_EVENT(op) PY_CODE_EVENT_##op, + PY_FOREACH_CODE_EVENT(PY_DEF_EVENT) + #undef PY_DEF_EVENT } PyCodeEvent; @@ -236,7 +241,7 @@ typedef enum PyCodeEvent { * The callback is invoked with a borrowed reference to co, after it is * created and before it is destroyed. * - * If the callback returns with an exception set, it must return -1. Otherwise + * If the callback sets an exception, it must return -1. Otherwise * it should return 0. */ typedef int (*PyCode_WatchCallback)( diff --git a/Include/cpython/dictobject.h b/Include/cpython/dictobject.h index 5001f3565447..ddada922020a 100644 --- a/Include/cpython/dictobject.h +++ b/Include/cpython/dictobject.h @@ -16,11 +16,11 @@ typedef struct { /* Dictionary version: globally unique, value change each time the dictionary is modified */ -#ifdef Py_BUILD_CORE +#ifdef Py_BUILD_CORE uint64_t ma_version_tag; #else Py_DEPRECATED(3.12) uint64_t ma_version_tag; -#endif +#endif PyDictKeysObject *ma_keys; @@ -90,13 +90,18 @@ PyAPI_FUNC(PyObject *) _PyDictView_Intersect(PyObject* self, PyObject *other); /* Dictionary watchers */ +#define PY_FOREACH_DICT_EVENT(V) \ + V(ADDED) \ + V(MODIFIED) \ + V(DELETED) \ + V(CLONED) \ + V(CLEARED) \ + V(DEALLOCATED) + typedef enum { - PyDict_EVENT_ADDED, - PyDict_EVENT_MODIFIED, - PyDict_EVENT_DELETED, - PyDict_EVENT_CLONED, - PyDict_EVENT_CLEARED, - PyDict_EVENT_DEALLOCATED, + #define PY_DEF_EVENT(EVENT) PyDict_EVENT_##EVENT, + PY_FOREACH_DICT_EVENT(PY_DEF_EVENT) + #undef PY_DEF_EVENT } PyDict_WatchEvent; // Callback to be invoked when a watched dict is cleared, dealloced, or modified. diff --git a/Include/cpython/funcobject.h b/Include/cpython/funcobject.h index 5979febc2e34..c716330cc3fb 100644 --- a/Include/cpython/funcobject.h +++ b/Include/cpython/funcobject.h @@ -131,17 +131,17 @@ PyAPI_DATA(PyTypeObject) PyStaticMethod_Type; PyAPI_FUNC(PyObject *) PyClassMethod_New(PyObject *); PyAPI_FUNC(PyObject *) PyStaticMethod_New(PyObject *); -#define FOREACH_FUNC_EVENT(V) \ - V(CREATE) \ - V(DESTROY) \ - V(MODIFY_CODE) \ - V(MODIFY_DEFAULTS) \ +#define PY_FOREACH_FUNC_EVENT(V) \ + V(CREATE) \ + V(DESTROY) \ + V(MODIFY_CODE) \ + V(MODIFY_DEFAULTS) \ V(MODIFY_KWDEFAULTS) typedef enum { - #define DEF_EVENT(EVENT) PyFunction_EVENT_##EVENT, - FOREACH_FUNC_EVENT(DEF_EVENT) - #undef DEF_EVENT + #define PY_DEF_EVENT(EVENT) PyFunction_EVENT_##EVENT, + PY_FOREACH_FUNC_EVENT(PY_DEF_EVENT) + #undef PY_DEF_EVENT } PyFunction_WatchEvent; /* diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index c74a34377130..1af5e59a677a 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -164,6 +164,7 @@ _PyDict_NotifyEvent(PyDict_WatchEvent event, PyObject *key, PyObject *value) { + assert(Py_REFCNT((PyObject*)mp) > 0); int watcher_bits = mp->ma_version_tag & DICT_VERSION_MASK; if (watcher_bits) { _PyDict_SendEvent(watcher_bits, event, mp, key, value); diff --git a/Lib/test/test_capi/test_watchers.py b/Lib/test/test_capi/test_watchers.py index 1922614ef605..93f6ef752d06 100644 --- a/Lib/test/test_capi/test_watchers.py +++ b/Lib/test/test_capi/test_watchers.py @@ -109,10 +109,21 @@ def test_error(self): self.watch(wid, d) with catch_unraisable_exception() as cm: d["foo"] = "bar" - self.assertIs(cm.unraisable.object, d) + self.assertIn( + "PyDict_EVENT_ADDED watcher callback for 0); PyInterpreterState *interp = _PyInterpreterState_GET(); assert(interp->_initialized); uint8_t bits = interp->active_code_watchers; @@ -25,7 +40,21 @@ notify_code_watchers(PyCodeEvent event, PyCodeObject *co) // callback must be non-null if the watcher bit is set assert(cb != NULL); if (cb(event, co) < 0) { - PyErr_WriteUnraisable((PyObject *) co); + // Don't risk resurrecting the object if an unraisablehook keeps + // a reference; pass a string as context. + PyObject *context = NULL; + PyObject *repr = code_repr(co); + if (repr) { + context = PyUnicode_FromFormat( + "%s watcher callback for %U", + code_event_name(event), repr); + Py_DECREF(repr); + } + if (context == NULL) { + context = Py_NewRef(Py_None); + } + PyErr_WriteUnraisable(context); + Py_DECREF(context); } } i++; @@ -1667,7 +1696,14 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount, static void code_dealloc(PyCodeObject *co) { + assert(Py_REFCNT(co) == 0); + Py_SET_REFCNT(co, 1); notify_code_watchers(PY_CODE_EVENT_DESTROY, co); + if (Py_REFCNT(co) > 1) { + Py_SET_REFCNT(co, Py_REFCNT(co) - 1); + return; + } + Py_SET_REFCNT(co, 0); if (co->co_extra != NULL) { PyInterpreterState *interp = _PyInterpreterState_GET(); diff --git a/Objects/dictobject.c b/Objects/dictobject.c index fc658ca2f4b7..e3795e75e3da 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2308,7 +2308,14 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) static void dict_dealloc(PyDictObject *mp) { + assert(Py_REFCNT(mp) == 0); + Py_SET_REFCNT(mp, 1); _PyDict_NotifyEvent(PyDict_EVENT_DEALLOCATED, mp, NULL, NULL); + if (Py_REFCNT(mp) > 1) { + Py_SET_REFCNT(mp, Py_REFCNT(mp) - 1); + return; + } + Py_SET_REFCNT(mp, 0); PyDictValues *values = mp->ma_values; PyDictKeysObject *keys = mp->ma_keys; Py_ssize_t i, n; @@ -5732,6 +5739,18 @@ PyDict_ClearWatcher(int watcher_id) return 0; } +static const char * +dict_event_name(PyDict_WatchEvent event) { + switch (event) { + #define CASE(op) \ + case PyDict_EVENT_##op: \ + return "PyDict_EVENT_" #op; + PY_FOREACH_DICT_EVENT(CASE) + #undef CASE + } + Py_UNREACHABLE(); +} + void _PyDict_SendEvent(int watcher_bits, PyDict_WatchEvent event, @@ -5744,9 +5763,18 @@ _PyDict_SendEvent(int watcher_bits, if (watcher_bits & 1) { PyDict_WatchCallback cb = interp->dict_state.watchers[i]; if (cb && (cb(event, (PyObject*)mp, key, value) < 0)) { - // some dict modification paths (e.g. PyDict_Clear) can't raise, so we - // can't propagate exceptions from dict watchers. - PyErr_WriteUnraisable((PyObject *)mp); + // We don't want to resurrect the dict by potentially having an + // unraisablehook keep a reference to it, so we don't pass the + // dict as context, just an informative string message. Dict + // repr can call arbitrary code, so we invent a simpler version. + PyObject *context = PyUnicode_FromFormat( + "%s watcher callback for ", + dict_event_name(event), mp); + if (context == NULL) { + context = Py_NewRef(Py_None); + } + PyErr_WriteUnraisable(context); + Py_DECREF(context); } } watcher_bits >>= 1; diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 91a6b3dd40a2..99048ea41c6c 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -8,6 +8,20 @@ #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "structmember.h" // PyMemberDef +static PyObject* func_repr(PyFunctionObject *op); + +static const char * +func_event_name(PyFunction_WatchEvent event) { + switch (event) { + #define CASE(op) \ + case PyFunction_EVENT_##op: \ + return "PyFunction_EVENT_" #op; + PY_FOREACH_FUNC_EVENT(CASE) + #undef CASE + } + Py_UNREACHABLE(); +} + static void notify_func_watchers(PyInterpreterState *interp, PyFunction_WatchEvent event, PyFunctionObject *func, PyObject *new_value) @@ -21,7 +35,21 @@ notify_func_watchers(PyInterpreterState *interp, PyFunction_WatchEvent event, // callback must be non-null if the watcher bit is set assert(cb != NULL); if (cb(event, func, new_value) < 0) { - PyErr_WriteUnraisable((PyObject *) func); + // Don't risk resurrecting the func if an unraisablehook keeps a + // reference; pass a string as context. + PyObject *context = NULL; + PyObject *repr = func_repr(func); + if (repr != NULL) { + context = PyUnicode_FromFormat( + "%s watcher callback for %U", + func_event_name(event), repr); + Py_DECREF(repr); + } + if (context == NULL) { + context = Py_NewRef(Py_None); + } + PyErr_WriteUnraisable(context); + Py_DECREF(context); } } i++; @@ -33,6 +61,7 @@ static inline void handle_func_event(PyFunction_WatchEvent event, PyFunctionObject *func, PyObject *new_value) { + assert(Py_REFCNT(func) > 0); PyInterpreterState *interp = _PyInterpreterState_GET(); assert(interp->_initialized); if (interp->active_func_watchers) { @@ -766,7 +795,14 @@ func_clear(PyFunctionObject *op) static void func_dealloc(PyFunctionObject *op) { + assert(Py_REFCNT(op) == 0); + Py_SET_REFCNT(op, 1); handle_func_event(PyFunction_EVENT_DESTROY, op, NULL); + if (Py_REFCNT(op) > 1) { + Py_SET_REFCNT(op, Py_REFCNT(op) - 1); + return; + } + Py_SET_REFCNT(op, 0); _PyObject_GC_UNTRACK(op); if (op->func_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *) op); From webhook-mailer at python.org Tue Mar 7 22:40:12 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Wed, 08 Mar 2023 03:40:12 -0000 Subject: [Python-checkins] fix typo in async generator code field name `ag_code` (#102448) Message-ID: https://github.com/python/cpython/commit/e499680100a9d4fa4b673cbcfebc32212b4f848a commit: e499680100a9d4fa4b673cbcfebc32212b4f848a branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-08T09:09:50+05:30 summary: fix typo in async generator code field name `ag_code` (#102448) files: M Objects/genobject.c diff --git a/Objects/genobject.c b/Objects/genobject.c index 4ab6581e12ab..be08a59ece6b 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1549,7 +1549,7 @@ ag_getframe(PyAsyncGenObject *ag, void *Py_UNUSED(ignored)) static PyObject * ag_getcode(PyGenObject *gen, void *Py_UNUSED(ignored)) { - return _gen_getcode(gen, "ag__code"); + return _gen_getcode(gen, "ag_code"); } static PyGetSetDef async_gen_getsetlist[] = { From webhook-mailer at python.org Tue Mar 7 23:06:58 2023 From: webhook-mailer at python.org (Yhg1s) Date: Wed, 08 Mar 2023 04:06:58 -0000 Subject: [Python-checkins] Python 3.12.0a6 Message-ID: https://github.com/python/cpython/commit/f9774e57d84162ff0cba0b17a3dcdb93dfbce45e commit: f9774e57d84162ff0cba0b17a3dcdb93dfbce45e branch: main author: Thomas Wouters committer: Yhg1s date: 2023-03-07T22:48:18+01:00 summary: Python 3.12.0a6 files: A Misc/NEWS.d/3.12.0a6.rst D Misc/NEWS.d/next/Build/2022-09-14-10-38-15.gh-issue-96821.Zk2a9c.rst D Misc/NEWS.d/next/Build/2022-12-18-08-33-28.gh-issue-100221.K94Ct3.rst D Misc/NEWS.d/next/Build/2022-12-20-01-06-17.gh-issue-99942.lbmzYj.rst D Misc/NEWS.d/next/Build/2023-01-12-00-49-16.gh-issue-99942.DUR8b4.rst D Misc/NEWS.d/next/C API/2022-04-21-17-25-22.gh-issue-91744.FgvaMi.rst D Misc/NEWS.d/next/C API/2023-02-06-16-14-30.gh-issue-101578.PW5fA9.rst D Misc/NEWS.d/next/C API/2023-02-09-10-38-20.gh-issue-99293.mFqfpp.rst D Misc/NEWS.d/next/C API/2023-02-14-15-53-01.gh-issue-101907.HgF1N2.rst D Misc/NEWS.d/next/Core and Builtins/2022-11-02-20-23-47.gh-issue-98627.VJkdRM.rst D Misc/NEWS.d/next/Core and Builtins/2023-01-04-12-49-33.gh-issue-100719.uRPccL.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-07-14-56-43.gh-issue-101632.Fd1yxk.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-08-17-13-31.gh-issue-101696.seJhTt.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-10-01-15-57.gh-issue-101430.T3Gegb.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-10-07-21-47.gh-issue-101765.MO5LlC.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-10-15-54-57.gh-issue-87849.IUVvPz.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-11-23-14-06.gh-issue-84783._P5sMa.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-12-22-40-22.gh-issue-101857._bribG.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-13-18-21-14.gh-issue-101799.wpHbCn.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-13-22-21-58.gh-issue-74895.esMNtq.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-16-16-57-23.gh-issue-101952.Zo1dlq.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-16-23-19-01.gh-issue-101967.Kqr1dz.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-17-10-12-13.gh-issue-100982.mJGJQw.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-20-15-18-33.gh-issue-102056.uHKuwH.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-22-15-15-32.gh-issue-102027.Km4G-d.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-26-23-10-32.gh-issue-102250.7MUKoC.rst D Misc/NEWS.d/next/Core and Builtins/2023-02-28-21-17-03.gh-issue-102336.-wL3Tm.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst D Misc/NEWS.d/next/Core and Builtins/2023-03-07-16-56-28.gh-issue-102493.gTXrcD.rst D Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst D Misc/NEWS.d/next/Documentation/2023-02-19-10-33-01.gh-issue-85417.kYO8u3.rst D Misc/NEWS.d/next/Library/2018-06-20-09-12-21.bpo-23224.zxCQ13.rst D Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst D Misc/NEWS.d/next/Library/2022-10-22-09-26-43.gh-issue-96764.Dh9Y5L.rst D Misc/NEWS.d/next/Library/2023-01-02-22-41-44.gh-issue-99138.17hp9U.rst D Misc/NEWS.d/next/Library/2023-01-06-21-14-41.gh-issue-100809.I697UT.rst D Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst D Misc/NEWS.d/next/Library/2023-01-27-02-53-50.gh-issue-101360.bPB7SL.rst D Misc/NEWS.d/next/Library/2023-02-01-10-42-16.gh-issue-63301.XNxSFh.rst D Misc/NEWS.d/next/Library/2023-02-04-16-35-46.gh-issue-101561.Xo6pIZ.rst D Misc/NEWS.d/next/Library/2023-02-05-21-40-15.gh-issue-85984.Kfzbb2.rst D Misc/NEWS.d/next/Library/2023-02-07-20-46-08.gh-issue-101362.2ckZ6R.rst D Misc/NEWS.d/next/Library/2023-02-07-21-16-41.gh-issue-101362.KMQllM.rst D Misc/NEWS.d/next/Library/2023-02-07-22-20-32.gh-issue-101362.Jlk6mt.rst D Misc/NEWS.d/next/Library/2023-02-07-22-21-46.gh-issue-101446.-c0FdK.rst D Misc/NEWS.d/next/Library/2023-02-08-18-20-58.gh-issue-101693.4_LPXj.rst D Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst D Misc/NEWS.d/next/Library/2023-02-10-16-02-29.gh-issue-101517.r7S2u8.rst D Misc/NEWS.d/next/Library/2023-02-11-13-23-29.gh-issue-97786.QjvQ1B.rst D Misc/NEWS.d/next/Library/2023-02-13-12-55-48.gh-issue-87634.q-SBhJ.rst D Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst D Misc/NEWS.d/next/Library/2023-02-15-01-54-06.gh-issue-99108.rjTSic.rst D Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst D Misc/NEWS.d/next/Library/2023-02-17-19-00-58.gh-issue-97930.C_nQjb.rst D Misc/NEWS.d/next/Library/2023-02-17-20-24-15.gh-issue-101566.FjgWBt.rst D Misc/NEWS.d/next/Library/2023-02-21-07-15-41.gh-issue-101936.QVOxHH.rst D Misc/NEWS.d/next/Library/2023-02-21-10-05-33.gh-issue-101961.7e56jh.rst D Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst D Misc/NEWS.d/next/Library/2023-02-23-20-39-52.gh-issue-81652.Vxz0Mr.rst D Misc/NEWS.d/next/Library/2023-02-26-12-37-17.gh-issue-91038.S4rFH_.rst D Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst D Misc/NEWS.d/next/Library/2023-03-04-14-46-47.gh-issue-102302.-b_s6Z.rst D Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst D Misc/NEWS.d/next/Security/2023-02-08-12-57-35.gh-issue-99108.6tnmhA.rst D Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst D Misc/NEWS.d/next/Security/2023-02-17-10-42-48.gh-issue-99108.MKA8-f.rst D Misc/NEWS.d/next/Tests/2023-02-11-20-28-08.gh-issue-89792.S-Y5BZ.rst D Misc/NEWS.d/next/Tests/2023-02-11-22-36-10.gh-issue-85984.EVXjT9.rst D Misc/NEWS.d/next/Tests/2023-02-18-10-51-02.gh-issue-102019.0797SJ.rst D Misc/NEWS.d/next/Windows/2023-01-25-11-33-54.gh-issue-101196.wAX_2g.rst D Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst D Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst D Misc/NEWS.d/next/Windows/2023-02-10-14-26-05.gh-issue-101763.RPaj7r.rst D Misc/NEWS.d/next/Windows/2023-02-13-16-32-50.gh-issue-101849.7lm_53.rst D Misc/NEWS.d/next/Windows/2023-02-13-18-05-49.gh-issue-101881._TnHzN.rst D Misc/NEWS.d/next/Windows/2023-02-15-11-08-10.gh-issue-101881.fScr3m.rst D Misc/NEWS.d/next/Windows/2023-03-01-01-36-39.gh-issue-102344.Dgfux4.rst D Misc/NEWS.d/next/macOS/2023-02-09-22-07-17.gh-issue-101759.B0JP2H.rst M Include/patchlevel.h M Lib/pydoc_data/topics.py M README.rst diff --git a/Include/patchlevel.h b/Include/patchlevel.h index 7957220ed7cf..fd16421eace9 100644 --- a/Include/patchlevel.h +++ b/Include/patchlevel.h @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 12 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 5 +#define PY_RELEASE_SERIAL 6 /* Version as a string */ -#define PY_VERSION "3.12.0a5+" +#define PY_VERSION "3.12.0a6" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index e7f403d3ffbf..573065b4b714 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Tue Feb 7 13:18:04 2023 +# Autogenerated by Sphinx on Tue Mar 7 22:42:28 2023 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -2499,42 +2499,33 @@ 'alive\n' 'until the next garbage collection occurs.\n' '\n' - 'Before an "except" clause?s suite is executed, details about ' - 'the\n' - 'exception are stored in the "sys" module and can be accessed ' - 'via\n' - '"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting ' - 'of the\n' - 'exception class, the exception instance and a traceback object ' - '(see\n' - 'section The standard type hierarchy) identifying the point in ' - 'the\n' - 'program where the exception occurred. The details about the ' - 'exception\n' - 'accessed via "sys.exc_info()" are restored to their previous ' - 'values\n' - 'when leaving an exception handler:\n' + 'Before an "except" clause?s suite is executed, the exception is ' + 'stored\n' + 'in the "sys" module, where it can be accessed from within the ' + 'body of\n' + 'the "except" clause by calling "sys.exception()". When leaving ' + 'an\n' + 'exception handler, the exception stored in the "sys" module is ' + 'reset\n' + 'to its previous value:\n' '\n' - ' >>> print(sys.exc_info())\n' - ' (None, None, None)\n' + ' >>> print(sys.exception())\n' + ' None\n' ' >>> try:\n' ' ... raise TypeError\n' ' ... except:\n' - ' ... print(sys.exc_info())\n' + ' ... print(repr(sys.exception()))\n' ' ... try:\n' ' ... raise ValueError\n' ' ... except:\n' - ' ... print(sys.exc_info())\n' - ' ... print(sys.exc_info())\n' + ' ... print(repr(sys.exception()))\n' + ' ... print(repr(sys.exception()))\n' ' ...\n' - " (, TypeError(), )\n' - " (, ValueError(), )\n' - " (, TypeError(), )\n' - ' >>> print(sys.exc_info())\n' - ' (None, None, None)\n' + ' TypeError()\n' + ' ValueError()\n' + ' TypeError()\n' + ' >>> print(sys.exception())\n' + ' None\n' '\n' '\n' '"except*" clause\n' @@ -4533,7 +4524,7 @@ 'objects and\n' ' implements an "__eq__()" method, it should not ' 'implement\n' - ' "__hash__()", since the implementation of hashable ' + ' "__hash__()", since the implementation of *hashable* ' 'collections\n' ' requires that a key?s hash value is immutable (if the ' 'object?s hash\n' @@ -9453,7 +9444,7 @@ ' hashable collections. If a class defines mutable objects ' 'and\n' ' implements an "__eq__()" method, it should not implement\n' - ' "__hash__()", since the implementation of hashable ' + ' "__hash__()", since the implementation of *hashable* ' 'collections\n' ' requires that a key?s hash value is immutable (if the ' 'object?s hash\n' @@ -12644,37 +12635,31 @@ 'cycle with the stack frame, keeping all locals in that frame alive\n' 'until the next garbage collection occurs.\n' '\n' - 'Before an "except" clause?s suite is executed, details about the\n' - 'exception are stored in the "sys" module and can be accessed via\n' - '"sys.exc_info()". "sys.exc_info()" returns a 3-tuple consisting of ' - 'the\n' - 'exception class, the exception instance and a traceback object (see\n' - 'section The standard type hierarchy) identifying the point in the\n' - 'program where the exception occurred. The details about the ' - 'exception\n' - 'accessed via "sys.exc_info()" are restored to their previous values\n' - 'when leaving an exception handler:\n' + 'Before an "except" clause?s suite is executed, the exception is ' + 'stored\n' + 'in the "sys" module, where it can be accessed from within the body ' + 'of\n' + 'the "except" clause by calling "sys.exception()". When leaving an\n' + 'exception handler, the exception stored in the "sys" module is reset\n' + 'to its previous value:\n' '\n' - ' >>> print(sys.exc_info())\n' - ' (None, None, None)\n' + ' >>> print(sys.exception())\n' + ' None\n' ' >>> try:\n' ' ... raise TypeError\n' ' ... except:\n' - ' ... print(sys.exc_info())\n' + ' ... print(repr(sys.exception()))\n' ' ... try:\n' ' ... raise ValueError\n' ' ... except:\n' - ' ... print(sys.exc_info())\n' - ' ... print(sys.exc_info())\n' + ' ... print(repr(sys.exception()))\n' + ' ... print(repr(sys.exception()))\n' ' ...\n' - " (, TypeError(), )\n' - " (, ValueError(), )\n' - " (, TypeError(), )\n' - ' >>> print(sys.exc_info())\n' - ' (None, None, None)\n' + ' TypeError()\n' + ' ValueError()\n' + ' TypeError()\n' + ' >>> print(sys.exception())\n' + ' None\n' '\n' '\n' '"except*" clause\n' @@ -14408,7 +14393,7 @@ ' New in version 3.10.\n' '\n' 'Keys views are set-like since their entries are unique and ' - 'hashable.\n' + '*hashable*.\n' 'If all values are hashable, so that "(key, value)" pairs are ' 'unique\n' 'and hashable, then the items view is also set-like. (Values ' diff --git a/Misc/NEWS.d/3.12.0a6.rst b/Misc/NEWS.d/3.12.0a6.rst new file mode 100644 index 000000000000..2bcb4c8c854d --- /dev/null +++ b/Misc/NEWS.d/3.12.0a6.rst @@ -0,0 +1,821 @@ +.. date: 2023-02-17-10-42-48 +.. gh-issue: 99108 +.. nonce: MKA8-f +.. release date: 2023-03-07 +.. section: Security + +Replace builtin hashlib implementations of MD5 and SHA1 with verified ones +from the HACL* project. + +.. + +.. date: 2023-02-08-22-03-04 +.. gh-issue: 101727 +.. nonce: 9P5eZz +.. section: Security + +Updated the OpenSSL version used in Windows and macOS binary release builds +to 1.1.1t to address CVE-2023-0286, CVE-2022-4303, and CVE-2022-4303 per +`the OpenSSL 2023-02-07 security advisory +`_. + +.. + +.. date: 2023-02-08-12-57-35 +.. gh-issue: 99108 +.. nonce: 6tnmhA +.. section: Security + +Replace the builtin :mod:`hashlib` implementations of SHA2-384 and SHA2-512 +originally from LibTomCrypt with formally verified, side-channel resistant +code from the `HACL* `_ project. +The builtins remain a fallback only used when OpenSSL does not provide them. + +.. + +.. date: 2023-01-24-16-12-00 +.. gh-issue: 101283 +.. nonce: 9tqu39 +.. section: Security + +:class:`subprocess.Popen` now uses a safer approach to find ``cmd.exe`` when +launching with ``shell=True``. Patch by Eryk Sun, based on a patch by Oleg +Iarygin. + +.. + +.. date: 2023-03-07-16-56-28 +.. gh-issue: 102493 +.. nonce: gTXrcD +.. section: Core and Builtins + +Fix regression in semantics of normalisation in ``PyErr_SetObject``. + +.. + +.. date: 2023-03-06-13-05-33 +.. gh-issue: 102416 +.. nonce: dz6K5f +.. section: Core and Builtins + +Do not memoize incorrectly automatically generated loop rules in the parser. +Patch by Pablo Galindo. + +.. + +.. date: 2023-03-04-20-56-12 +.. gh-issue: 102356 +.. nonce: 07KvUd +.. section: Core and Builtins + +Fix a bug that caused a crash when deallocating deeply nested filter +objects. Patch by Marta G?mez Mac?as. + +.. + +.. date: 2023-02-28-21-17-03 +.. gh-issue: 102336 +.. nonce: -wL3Tm +.. section: Core and Builtins + +Cleanup Windows 7 specific special handling. Patch by Max Bachmann. + +.. + +.. date: 2023-02-26-23-10-32 +.. gh-issue: 102250 +.. nonce: 7MUKoC +.. section: Core and Builtins + +Fixed a segfault occurring when the interpreter calls a ``__bool__`` method +that raises. + +.. + +.. date: 2023-02-24-17-59-39 +.. gh-issue: 102126 +.. nonce: HTT8Vc +.. section: Core and Builtins + +Fix deadlock at shutdown when clearing thread states if any finalizer tries +to acquire the runtime head lock. Patch by Kumar Aditya. + +.. + +.. date: 2023-02-22-15-15-32 +.. gh-issue: 102027 +.. nonce: Km4G-d +.. section: Core and Builtins + +Use ``GetCurrentProcessId`` on Windows when ``getpid`` is unavailable. Patch +by Max Bachmann. + +.. + +.. date: 2023-02-20-15-18-33 +.. gh-issue: 102056 +.. nonce: uHKuwH +.. section: Core and Builtins + +Fix error handling bugs in interpreter's exception printing code, which +could cause a crash on infinite recursion. + +.. + +.. date: 2023-02-17-10-12-13 +.. gh-issue: 100982 +.. nonce: mJGJQw +.. section: Core and Builtins + +Restrict the scope of the :opcode:`FOR_ITER_RANGE` instruction to the scope +of the original :opcode:`FOR_ITER` instruction, to allow instrumentation. + +.. + +.. date: 2023-02-16-23-19-01 +.. gh-issue: 101967 +.. nonce: Kqr1dz +.. section: Core and Builtins + +Fix possible segfault in ``positional_only_passed_as_keyword`` function, +when new list created. + +.. + +.. date: 2023-02-16-16-57-23 +.. gh-issue: 101952 +.. nonce: Zo1dlq +.. section: Core and Builtins + +Fix possible segfault in ``BUILD_SET`` opcode, when new set created. + +.. + +.. date: 2023-02-13-22-21-58 +.. gh-issue: 74895 +.. nonce: esMNtq +.. section: Core and Builtins + +:mod:`socket.getaddrinfo` no longer raises :class:`OverflowError` for +:class:`int` **port** values outside of the C long range. Out of range +values are left up to the underlying string based C library API to report. A +:class:`socket.gaierror` ``SAI_SERVICE`` may occur instead, or no error at +all as not all platform C libraries generate an error. + +.. + +.. date: 2023-02-13-18-21-14 +.. gh-issue: 101799 +.. nonce: wpHbCn +.. section: Core and Builtins + +Add :opcode:`CALL_INTRINSIC_2` and use it instead of +:opcode:`PREP_RERAISE_STAR`. + +.. + +.. date: 2023-02-12-22-40-22 +.. gh-issue: 101857 +.. nonce: _bribG +.. section: Core and Builtins + +Fix xattr support detection on Linux systems by widening the check to linux, +not just glibc. This fixes support for musl. + +.. + +.. date: 2023-02-11-23-14-06 +.. gh-issue: 84783 +.. nonce: _P5sMa +.. section: Core and Builtins + +Make the slice object hashable. + +.. + +.. date: 2023-02-10-15-54-57 +.. gh-issue: 87849 +.. nonce: IUVvPz +.. section: Core and Builtins + +Change the ``SEND`` instruction to leave the receiver on the stack. This +allows the specialized form of ``SEND`` to skip the chain of C calls and +jump directly to the ``RESUME`` in the generator or coroutine. + +.. + +.. date: 2023-02-10-07-21-47 +.. gh-issue: 101765 +.. nonce: MO5LlC +.. section: Core and Builtins + +Fix SystemError / segmentation fault in iter ``__reduce__`` when internal +access of ``builtins.__dict__`` keys mutates the iter object. + +.. + +.. date: 2023-02-10-01-15-57 +.. gh-issue: 101430 +.. nonce: T3Gegb +.. section: Core and Builtins + +Update :mod:`tracemalloc` to handle presize of object properly. Patch by +Dong-hee Na. + +.. + +.. date: 2023-02-08-17-13-31 +.. gh-issue: 101696 +.. nonce: seJhTt +.. section: Core and Builtins + +Invalidate type version tag in ``_PyStaticType_Dealloc`` for static types, +avoiding bug where a false cache hit could crash the interpreter. Patch by +Kumar Aditya. + +.. + +.. date: 2023-02-07-14-56-43 +.. gh-issue: 101632 +.. nonce: Fd1yxk +.. section: Core and Builtins + +Adds a new :opcode:`RETURN_CONST` instruction. + +.. + +.. date: 2023-01-04-12-49-33 +.. gh-issue: 100719 +.. nonce: uRPccL +.. section: Core and Builtins + +Remove gi_code field from generator (and coroutine and async generator) +objects as it is redundant. The frame already includes a reference to the +code object. + +.. + +.. date: 2022-11-02-20-23-47 +.. gh-issue: 98627 +.. nonce: VJkdRM +.. section: Core and Builtins + +When an interpreter is configured to check (and only then), importing an +extension module will now fail when the extension does not support multiple +interpreters (i.e. doesn't implement PEP 489 multi-phase init). This does +not apply to the main interpreter, nor to subinterpreters created with +``Py_NewInterpreter()``. + +.. + +.. date: 2023-03-04-14-46-47 +.. gh-issue: 102302 +.. nonce: -b_s6Z +.. section: Library + +Micro-optimise hashing of :class:`inspect.Parameter`, reducing the time it +takes to hash an instance by around 40%. + +.. + +.. date: 2023-02-28-09-52-25 +.. gh-issue: 101979 +.. nonce: or3hXV +.. section: Library + +Fix a bug where parentheses in the ``metavar`` argument to +:meth:`argparse.ArgumentParser.add_argument` were dropped. Patch by Yeojin +Kim. + +.. + +.. date: 2023-02-26-12-37-17 +.. gh-issue: 91038 +.. nonce: S4rFH_ +.. section: Library + +:meth:`platform.platform` now has boolean default arguments. + +.. + +.. date: 2023-02-23-20-39-52 +.. gh-issue: 81652 +.. nonce: Vxz0Mr +.. section: Library + +Add :data:`mmap.MAP_ALIGNED_SUPER` FreeBSD and :data:`mmap.MAP_CONCEAL` +OpenBSD constants to :mod:`mmap`. Patch by Yeojin Kim. + +.. + +.. date: 2023-02-23-15-06-01 +.. gh-issue: 102179 +.. nonce: P6KQ4c +.. section: Library + +Fix :func:`os.dup2` error message for negative fds. + +.. + +.. date: 2023-02-21-10-05-33 +.. gh-issue: 101961 +.. nonce: 7e56jh +.. section: Library + +For the binary mode, :func:`fileinput.hookcompressed` doesn't set the +``encoding`` value even if the value is ``None``. Patch by Gihwan Kim. + +.. + +.. date: 2023-02-21-07-15-41 +.. gh-issue: 101936 +.. nonce: QVOxHH +.. section: Library + +The default value of ``fp`` becomes :class:`io.BytesIO` if +:exc:`~urllib.error.HTTPError` is initialized without a designated ``fp`` +parameter. Patch by Long Vo. + +.. + +.. date: 2023-02-17-20-24-15 +.. gh-issue: 101566 +.. nonce: FjgWBt +.. section: Library + +In zipfile, sync Path with `zipp 3.14 +`_, including +fix for extractall on the underlying zipfile after being wrapped in +``Path``. + +.. + +.. date: 2023-02-17-19-00-58 +.. gh-issue: 97930 +.. nonce: C_nQjb +.. section: Library + +Apply changes from `importlib_resources 5.12 +`_, +including fix for ``MultiplexedPath`` to support directories in multiple +namespaces (python/importlib_resources#265). + +.. + +.. date: 2023-02-17-18-44-27 +.. gh-issue: 101997 +.. nonce: A6_blD +.. section: Library + +Upgrade pip wheel bundled with ensurepip (pip 23.0.1) + +.. + +.. date: 2023-02-15-01-54-06 +.. gh-issue: 99108 +.. nonce: rjTSic +.. section: Library + +The built-in extension modules for :mod:`hashlib` SHA2 algorithms, used when +OpenSSL does not provide them, now live in a single internal ``_sha2`` +module instead of separate ``_sha256`` and ``_sha512`` modules. + +.. + +.. date: 2023-02-14-09-08-48 +.. gh-issue: 101892 +.. nonce: FMos8l +.. section: Library + +Callable iterators no longer raise :class:`SystemError` when the callable +object exhausts the iterator but forgets to either return a sentinel value +or raise :class:`StopIteration`. + +.. + +.. date: 2023-02-13-12-55-48 +.. gh-issue: 87634 +.. nonce: q-SBhJ +.. section: Library + +Remove locking behavior from :func:`functools.cached_property`. + +.. + +.. date: 2023-02-11-13-23-29 +.. gh-issue: 97786 +.. nonce: QjvQ1B +.. section: Library + +Fix potential undefined behaviour in corner cases of floating-point-to-time +conversions. + +.. + +.. date: 2023-02-10-16-02-29 +.. gh-issue: 101517 +.. nonce: r7S2u8 +.. section: Library + +Fixed bug where :mod:`bdb` looks up the source line with :mod:`linecache` +with a ``lineno=None``, which causes it to fail with an unhandled exception. + +.. + +.. date: 2023-02-10-11-59-13 +.. gh-issue: 101773 +.. nonce: J_kI7y +.. section: Library + +Optimize :class:`fractions.Fraction` for small components. The private +argument ``_normalize`` of the :class:`fractions.Fraction` constructor has +been removed. + +.. + +.. date: 2023-02-08-18-20-58 +.. gh-issue: 101693 +.. nonce: 4_LPXj +.. section: Library + +In :meth:`sqlite3.Cursor.execute`, :exc:`DeprecationWarning` is now emitted +when :ref:`named placeholders ` are used together with +parameters supplied as a :term:`sequence` instead of as a :class:`dict`. +Starting from Python 3.14, using named placeholders with parameters supplied +as a sequence will raise a :exc:`~sqlite3.ProgrammingError`. Patch by Erlend +E. Aasland. + +.. + +.. date: 2023-02-07-22-21-46 +.. gh-issue: 101446 +.. nonce: -c0FdK +.. section: Library + +Change repr of :class:`collections.OrderedDict` to use regular dictionary +formating instead of pairs of keys and values. + +.. + +.. date: 2023-02-07-22-20-32 +.. gh-issue: 101362 +.. nonce: Jlk6mt +.. section: Library + +Speed up :class:`pathlib.PurePath` construction by handling arguments more +uniformly. When a :class:`pathlib.Path` argument is supplied, we use its +string representation rather than joining its parts with +:func:`os.path.join`. + +.. + +.. date: 2023-02-07-21-16-41 +.. gh-issue: 101362 +.. nonce: KMQllM +.. section: Library + +Speed up :class:`pathlib.PurePath` construction by calling +:func:`os.path.join` only when two or more arguments are given. + +.. + +.. date: 2023-02-07-20-46-08 +.. gh-issue: 101362 +.. nonce: 2ckZ6R +.. section: Library + +Speed up :class:`pathlib.Path` construction by running the path flavour +compatibility check only when pathlib is imported. + +.. + +.. date: 2023-02-05-21-40-15 +.. gh-issue: 85984 +.. nonce: Kfzbb2 +.. section: Library + +Refactored the implementation of :func:`pty.fork` to use +:func:`os.login_tty`. + +A :exc:`DeprecationWarning` is now raised by ``pty.master_open()`` and +``pty.slave_open()``. They were undocumented and deprecated long long ago in +the docstring in favor of :func:`pty.openpty`. + +.. + +.. date: 2023-02-04-16-35-46 +.. gh-issue: 101561 +.. nonce: Xo6pIZ +.. section: Library + +Add a new decorator :func:`typing.override`. See :pep:`698` for details. +Patch by Steven Troxler. + +.. + +.. date: 2023-02-01-10-42-16 +.. gh-issue: 63301 +.. nonce: XNxSFh +.. section: Library + +Set exit code when :mod:`tabnanny` CLI exits on error. + +.. + +.. date: 2023-01-27-02-53-50 +.. gh-issue: 101360 +.. nonce: bPB7SL +.. section: Library + +Fix anchor matching in :meth:`pathlib.PureWindowsPath.match`. Path and +pattern anchors are now matched with :mod:`fnmatch`, just like other path +parts. This allows patterns such as ``"*:/Users/*"`` to be matched. + +.. + +.. date: 2023-01-25-00-14-52 +.. gh-issue: 101277 +.. nonce: FceHX7 +.. section: Library + +Remove global state from :mod:`itertools` module (:pep:`687`). Patches by +Erlend E. Aasland. + +.. + +.. date: 2023-01-06-21-14-41 +.. gh-issue: 100809 +.. nonce: I697UT +.. section: Library + +Fix handling of drive-relative paths (like 'C:' and 'C:foo') in +:meth:`pathlib.Path.absolute`. This method now uses the OS API to retrieve +the correct current working directory for the drive. + +.. + +.. date: 2023-01-02-22-41-44 +.. gh-issue: 99138 +.. nonce: 17hp9U +.. section: Library + +Apply :pep:`687` to :mod:`zoneinfo`. Patch by Erlend E. Aasland. + +.. + +.. date: 2022-10-22-09-26-43 +.. gh-issue: 96764 +.. nonce: Dh9Y5L +.. section: Library + +:func:`asyncio.wait_for` now uses :func:`asyncio.timeout` as its underlying +implementation. Patch by Kumar Aditya. + +.. + +.. date: 2022-09-05-12-17-34 +.. gh-issue: 88233 +.. nonce: gff9qJ +.. section: Library + +Correctly preserve "extra" fields in ``zipfile`` regardless of their +ordering relative to a zip64 "extra." + +.. + +.. bpo: 23224 +.. date: 2018-06-20-09-12-21 +.. nonce: zxCQ13 +.. section: Library + +Fix segfaults when creating :class:`lzma.LZMADecompressor` and +:class:`bz2.BZ2Decompressor` objects without calling ``__init__()``, and fix +leakage of locks and internal buffers when calling the ``__init__()`` +methods of :class:`lzma.LZMADecompressor`, :class:`lzma.LZMACompressor`, +:class:`bz2.BZ2Compressor`, and :class:`bz2.BZ2Decompressor` objects +multiple times. + +.. + +.. date: 2023-02-19-10-33-01 +.. gh-issue: 85417 +.. nonce: kYO8u3 +.. section: Documentation + +Update :mod:`cmath` documentation to clarify behaviour on branch cuts. + +.. + +.. date: 2023-02-07-21-43-24 +.. gh-issue: 97725 +.. nonce: cuY7Cd +.. section: Documentation + +Fix :meth:`asyncio.Task.print_stack` description for ``file=None``. Patch by +Oleg Iarygin. + +.. + +.. date: 2023-02-18-10-51-02 +.. gh-issue: 102019 +.. nonce: 0797SJ +.. section: Tests + +Fix deadlock on shutdown if ``test_current_{exception,frames}`` fails. Patch +by Jacob Bower. + +.. + +.. date: 2023-02-11-22-36-10 +.. gh-issue: 85984 +.. nonce: EVXjT9 +.. section: Tests + +Utilize new "winsize" functions from termios in pty tests. + +.. + +.. date: 2023-02-11-20-28-08 +.. gh-issue: 89792 +.. nonce: S-Y5BZ +.. section: Tests + +``test_tools`` now copies up to 10x less source data to a temporary +directory during the ``freeze`` test by ignoring git metadata and other +artifacts. It also limits its python build parallelism based on +os.cpu_count instead of hard coding it as 8 cores. + +.. + +.. date: 2023-01-12-00-49-16 +.. gh-issue: 99942 +.. nonce: DUR8b4 +.. section: Build + +On Android, in a static build, python-config in embed mode no longer +incorrectly reports a library to link to. + +.. + +.. date: 2022-12-20-01-06-17 +.. gh-issue: 99942 +.. nonce: lbmzYj +.. section: Build + +On Android, python.pc now correctly reports the library to link to, the same +as python-config.sh. + +.. + +.. date: 2022-12-18-08-33-28 +.. gh-issue: 100221 +.. nonce: K94Ct3 +.. section: Build + +Fix creating install directories in ``make sharedinstall`` if they exist +outside ``DESTDIR`` already. + +.. + +.. date: 2022-09-14-10-38-15 +.. gh-issue: 96821 +.. nonce: Zk2a9c +.. section: Build + +Explicitly mark C extension modules that need defined signed integer +overflow, and add a configure option :option:`--with-strict-overflow`. Patch +by Matthias G?rgens and Shantanu Jain. + +.. + +.. date: 2023-03-01-01-36-39 +.. gh-issue: 102344 +.. nonce: Dgfux4 +.. section: Windows + +Implement ``winreg.QueryValue`` using ``QueryValueEx`` and +``winreg.SetValue`` using ``SetValueEx``. Patch by Max Bachmann. + +.. + +.. date: 2023-02-15-11-08-10 +.. gh-issue: 101881 +.. nonce: fScr3m +.. section: Windows + +Handle read and write operations on non-blocking pipes properly on Windows. + +.. + +.. date: 2023-02-13-18-05-49 +.. gh-issue: 101881 +.. nonce: _TnHzN +.. section: Windows + +Add support for the os.get_blocking() and os.set_blocking() functions on +Windows. + +.. + +.. date: 2023-02-13-16-32-50 +.. gh-issue: 101849 +.. nonce: 7lm_53 +.. section: Windows + +Ensures installer will correctly upgrade existing ``py.exe`` launcher +installs. + +.. + +.. date: 2023-02-10-14-26-05 +.. gh-issue: 101763 +.. nonce: RPaj7r +.. section: Windows + +Updates copy of libffi bundled with Windows installs to 3.4.4. + +.. + +.. date: 2023-02-09-22-09-27 +.. gh-issue: 101759 +.. nonce: zFlqSH +.. section: Windows + +Update Windows installer to SQLite 3.40.1. + +.. + +.. date: 2023-02-07-18-22-54 +.. gh-issue: 101614 +.. nonce: NjVP0n +.. section: Windows + +Correctly handle extensions built against debug binaries that reference +``python3_d.dll``. + +.. + +.. date: 2023-01-25-11-33-54 +.. gh-issue: 101196 +.. nonce: wAX_2g +.. section: Windows + +The functions ``os.path.isdir``, ``os.path.isfile``, ``os.path.islink`` and +``os.path.exists`` are now 13% to 28% faster on Windows, by making fewer +Win32 API calls. + +.. + +.. date: 2023-02-09-22-07-17 +.. gh-issue: 101759 +.. nonce: B0JP2H +.. section: macOS + +Update macOS installer to SQLite 3.40.1. + +.. + +.. date: 2023-02-14-15-53-01 +.. gh-issue: 101907 +.. nonce: HgF1N2 +.. section: C API + +Removes use of non-standard C++ extension in public header files. + +.. + +.. date: 2023-02-09-10-38-20 +.. gh-issue: 99293 +.. nonce: mFqfpp +.. section: C API + +Document that the Py_TPFLAGS_VALID_VERSION_TAG is an internal feature, +should not be used, and will be removed. + +.. + +.. date: 2023-02-06-16-14-30 +.. gh-issue: 101578 +.. nonce: PW5fA9 +.. section: C API + +Add :c:func:`PyErr_GetRaisedException` and +:c:func:`PyErr_SetRaisedException` for saving and restoring the current +exception. These functions return and accept a single exception object, +rather than the triple arguments of the now-deprecated :c:func:`PyErr_Fetch` +and :c:func:`PyErr_Restore`. This is less error prone and a bit more +efficient. + +Add :c:func:`PyException_GetArgs` and :c:func:`PyException_SetArgs` as +convenience functions for retrieving and modifying the +:attr:`~BaseException.args` passed to the exception's constructor. + +.. + +.. date: 2022-04-21-17-25-22 +.. gh-issue: 91744 +.. nonce: FgvaMi +.. section: C API + +Introduced the *Unstable C API tier*, marking APi that is allowed to change +in minor releases without a deprecation period. See :pep:`689` for details. diff --git a/Misc/NEWS.d/next/Build/2022-09-14-10-38-15.gh-issue-96821.Zk2a9c.rst b/Misc/NEWS.d/next/Build/2022-09-14-10-38-15.gh-issue-96821.Zk2a9c.rst deleted file mode 100644 index 865cfde8b063..000000000000 --- a/Misc/NEWS.d/next/Build/2022-09-14-10-38-15.gh-issue-96821.Zk2a9c.rst +++ /dev/null @@ -1,3 +0,0 @@ -Explicitly mark C extension modules that need defined signed integer overflow, -and add a configure option :option:`--with-strict-overflow`. -Patch by Matthias G?rgens and Shantanu Jain. diff --git a/Misc/NEWS.d/next/Build/2022-12-18-08-33-28.gh-issue-100221.K94Ct3.rst b/Misc/NEWS.d/next/Build/2022-12-18-08-33-28.gh-issue-100221.K94Ct3.rst deleted file mode 100644 index 27c948330cfc..000000000000 --- a/Misc/NEWS.d/next/Build/2022-12-18-08-33-28.gh-issue-100221.K94Ct3.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix creating install directories in ``make sharedinstall`` if they exist -outside ``DESTDIR`` already. diff --git a/Misc/NEWS.d/next/Build/2022-12-20-01-06-17.gh-issue-99942.lbmzYj.rst b/Misc/NEWS.d/next/Build/2022-12-20-01-06-17.gh-issue-99942.lbmzYj.rst deleted file mode 100644 index 63a640a9cdf7..000000000000 --- a/Misc/NEWS.d/next/Build/2022-12-20-01-06-17.gh-issue-99942.lbmzYj.rst +++ /dev/null @@ -1,2 +0,0 @@ -On Android, python.pc now correctly reports the library to link to, the same -as python-config.sh. diff --git a/Misc/NEWS.d/next/Build/2023-01-12-00-49-16.gh-issue-99942.DUR8b4.rst b/Misc/NEWS.d/next/Build/2023-01-12-00-49-16.gh-issue-99942.DUR8b4.rst deleted file mode 100644 index 5b692c3cc458..000000000000 --- a/Misc/NEWS.d/next/Build/2023-01-12-00-49-16.gh-issue-99942.DUR8b4.rst +++ /dev/null @@ -1,2 +0,0 @@ -On Android, in a static build, python-config in embed mode no longer -incorrectly reports a library to link to. diff --git a/Misc/NEWS.d/next/C API/2022-04-21-17-25-22.gh-issue-91744.FgvaMi.rst b/Misc/NEWS.d/next/C API/2022-04-21-17-25-22.gh-issue-91744.FgvaMi.rst deleted file mode 100644 index 20db25ddd0c1..000000000000 --- a/Misc/NEWS.d/next/C API/2022-04-21-17-25-22.gh-issue-91744.FgvaMi.rst +++ /dev/null @@ -1,3 +0,0 @@ -Introduced the *Unstable C API tier*, marking APi that is allowed to change -in minor releases without a deprecation period. -See :pep:`689` for details. diff --git a/Misc/NEWS.d/next/C API/2023-02-06-16-14-30.gh-issue-101578.PW5fA9.rst b/Misc/NEWS.d/next/C API/2023-02-06-16-14-30.gh-issue-101578.PW5fA9.rst deleted file mode 100644 index 27294a9e5179..000000000000 --- a/Misc/NEWS.d/next/C API/2023-02-06-16-14-30.gh-issue-101578.PW5fA9.rst +++ /dev/null @@ -1,10 +0,0 @@ -Add :c:func:`PyErr_GetRaisedException` and :c:func:`PyErr_SetRaisedException` -for saving and restoring the current exception. -These functions return and accept a single exception object, -rather than the triple arguments of the now-deprecated -:c:func:`PyErr_Fetch` and :c:func:`PyErr_Restore`. -This is less error prone and a bit more efficient. - -Add :c:func:`PyException_GetArgs` and :c:func:`PyException_SetArgs` -as convenience functions for retrieving and modifying -the :attr:`~BaseException.args` passed to the exception's constructor. diff --git a/Misc/NEWS.d/next/C API/2023-02-09-10-38-20.gh-issue-99293.mFqfpp.rst b/Misc/NEWS.d/next/C API/2023-02-09-10-38-20.gh-issue-99293.mFqfpp.rst deleted file mode 100644 index 8c0f05543747..000000000000 --- a/Misc/NEWS.d/next/C API/2023-02-09-10-38-20.gh-issue-99293.mFqfpp.rst +++ /dev/null @@ -1,2 +0,0 @@ -Document that the Py_TPFLAGS_VALID_VERSION_TAG is an internal feature, -should not be used, and will be removed. diff --git a/Misc/NEWS.d/next/C API/2023-02-14-15-53-01.gh-issue-101907.HgF1N2.rst b/Misc/NEWS.d/next/C API/2023-02-14-15-53-01.gh-issue-101907.HgF1N2.rst deleted file mode 100644 index cfc0d72cdbca..000000000000 --- a/Misc/NEWS.d/next/C API/2023-02-14-15-53-01.gh-issue-101907.HgF1N2.rst +++ /dev/null @@ -1 +0,0 @@ -Removes use of non-standard C++ extension in public header files. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-02-20-23-47.gh-issue-98627.VJkdRM.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-02-20-23-47.gh-issue-98627.VJkdRM.rst deleted file mode 100644 index 3d2d6f6eb0c4..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2022-11-02-20-23-47.gh-issue-98627.VJkdRM.rst +++ /dev/null @@ -1,5 +0,0 @@ -When an interpreter is configured to check (and only then), importing an -extension module will now fail when the extension does not support multiple -interpreters (i.e. doesn't implement PEP 489 multi-phase init). This does -not apply to the main interpreter, nor to subinterpreters created with -``Py_NewInterpreter()``. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-04-12-49-33.gh-issue-100719.uRPccL.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-04-12-49-33.gh-issue-100719.uRPccL.rst deleted file mode 100644 index 2addef27b8ea..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-01-04-12-49-33.gh-issue-100719.uRPccL.rst +++ /dev/null @@ -1,3 +0,0 @@ -Remove gi_code field from generator (and coroutine and async generator) -objects as it is redundant. The frame already includes a reference to the -code object. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-07-14-56-43.gh-issue-101632.Fd1yxk.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-07-14-56-43.gh-issue-101632.Fd1yxk.rst deleted file mode 100644 index 136909ca6999..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-07-14-56-43.gh-issue-101632.Fd1yxk.rst +++ /dev/null @@ -1 +0,0 @@ -Adds a new :opcode:`RETURN_CONST` instruction. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-08-17-13-31.gh-issue-101696.seJhTt.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-08-17-13-31.gh-issue-101696.seJhTt.rst deleted file mode 100644 index ff2bbb4b5642..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-08-17-13-31.gh-issue-101696.seJhTt.rst +++ /dev/null @@ -1 +0,0 @@ -Invalidate type version tag in ``_PyStaticType_Dealloc`` for static types, avoiding bug where a false cache hit could crash the interpreter. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-10-01-15-57.gh-issue-101430.T3Gegb.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-10-01-15-57.gh-issue-101430.T3Gegb.rst deleted file mode 100644 index e617d8524214..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-10-01-15-57.gh-issue-101430.T3Gegb.rst +++ /dev/null @@ -1,2 +0,0 @@ -Update :mod:`tracemalloc` to handle presize of object properly. Patch by -Dong-hee Na. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-10-07-21-47.gh-issue-101765.MO5LlC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-10-07-21-47.gh-issue-101765.MO5LlC.rst deleted file mode 100644 index cc99779a944e..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-10-07-21-47.gh-issue-101765.MO5LlC.rst +++ /dev/null @@ -1 +0,0 @@ -Fix SystemError / segmentation fault in iter ``__reduce__`` when internal access of ``builtins.__dict__`` keys mutates the iter object. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-10-15-54-57.gh-issue-87849.IUVvPz.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-10-15-54-57.gh-issue-87849.IUVvPz.rst deleted file mode 100644 index da5f3ff79fd5..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-10-15-54-57.gh-issue-87849.IUVvPz.rst +++ /dev/null @@ -1,3 +0,0 @@ -Change the ``SEND`` instruction to leave the receiver on the stack. This -allows the specialized form of ``SEND`` to skip the chain of C calls and jump -directly to the ``RESUME`` in the generator or coroutine. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-11-23-14-06.gh-issue-84783._P5sMa.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-11-23-14-06.gh-issue-84783._P5sMa.rst deleted file mode 100644 index e1c851a0825a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-11-23-14-06.gh-issue-84783._P5sMa.rst +++ /dev/null @@ -1 +0,0 @@ -Make the slice object hashable. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-12-22-40-22.gh-issue-101857._bribG.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-12-22-40-22.gh-issue-101857._bribG.rst deleted file mode 100644 index 832cc300fa94..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-12-22-40-22.gh-issue-101857._bribG.rst +++ /dev/null @@ -1 +0,0 @@ -Fix xattr support detection on Linux systems by widening the check to linux, not just glibc. This fixes support for musl. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-13-18-21-14.gh-issue-101799.wpHbCn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-13-18-21-14.gh-issue-101799.wpHbCn.rst deleted file mode 100644 index 3233a573be7a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-13-18-21-14.gh-issue-101799.wpHbCn.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :opcode:`CALL_INTRINSIC_2` and use it instead of -:opcode:`PREP_RERAISE_STAR`. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-13-22-21-58.gh-issue-74895.esMNtq.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-13-22-21-58.gh-issue-74895.esMNtq.rst deleted file mode 100644 index adbbb601634a..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-13-22-21-58.gh-issue-74895.esMNtq.rst +++ /dev/null @@ -1,5 +0,0 @@ -:mod:`socket.getaddrinfo` no longer raises :class:`OverflowError` for -:class:`int` **port** values outside of the C long range. Out of range values -are left up to the underlying string based C library API to report. A -:class:`socket.gaierror` ``SAI_SERVICE`` may occur instead, or no error at all -as not all platform C libraries generate an error. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-16-16-57-23.gh-issue-101952.Zo1dlq.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-16-16-57-23.gh-issue-101952.Zo1dlq.rst deleted file mode 100644 index 3902c988c8bf..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-16-16-57-23.gh-issue-101952.Zo1dlq.rst +++ /dev/null @@ -1 +0,0 @@ -Fix possible segfault in ``BUILD_SET`` opcode, when new set created. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-16-23-19-01.gh-issue-101967.Kqr1dz.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-16-23-19-01.gh-issue-101967.Kqr1dz.rst deleted file mode 100644 index 6e681f910f53..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-16-23-19-01.gh-issue-101967.Kqr1dz.rst +++ /dev/null @@ -1 +0,0 @@ -Fix possible segfault in ``positional_only_passed_as_keyword`` function, when new list created. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-17-10-12-13.gh-issue-100982.mJGJQw.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-17-10-12-13.gh-issue-100982.mJGJQw.rst deleted file mode 100644 index 53bbc860c53f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-17-10-12-13.gh-issue-100982.mJGJQw.rst +++ /dev/null @@ -1,2 +0,0 @@ -Restrict the scope of the :opcode:`FOR_ITER_RANGE` instruction to the scope of the -original :opcode:`FOR_ITER` instruction, to allow instrumentation. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-20-15-18-33.gh-issue-102056.uHKuwH.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-20-15-18-33.gh-issue-102056.uHKuwH.rst deleted file mode 100644 index 78cd525b365f..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-20-15-18-33.gh-issue-102056.uHKuwH.rst +++ /dev/null @@ -1 +0,0 @@ -Fix error handling bugs in interpreter's exception printing code, which could cause a crash on infinite recursion. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-22-15-15-32.gh-issue-102027.Km4G-d.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-22-15-15-32.gh-issue-102027.Km4G-d.rst deleted file mode 100644 index 514a8ef26594..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-22-15-15-32.gh-issue-102027.Km4G-d.rst +++ /dev/null @@ -1,2 +0,0 @@ -Use ``GetCurrentProcessId`` on Windows when ``getpid`` is unavailable. Patch by -Max Bachmann. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst deleted file mode 100644 index 68c43688c3df..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst +++ /dev/null @@ -1 +0,0 @@ -Fix deadlock at shutdown when clearing thread states if any finalizer tries to acquire the runtime head lock. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-23-10-32.gh-issue-102250.7MUKoC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-23-10-32.gh-issue-102250.7MUKoC.rst deleted file mode 100644 index 17ab0cd43679..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-23-10-32.gh-issue-102250.7MUKoC.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed a segfault occurring when the interpreter calls a ``__bool__`` method that raises. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-28-21-17-03.gh-issue-102336.-wL3Tm.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-28-21-17-03.gh-issue-102336.-wL3Tm.rst deleted file mode 100644 index 0c3e4bd4b860..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-02-28-21-17-03.gh-issue-102336.-wL3Tm.rst +++ /dev/null @@ -1 +0,0 @@ -Cleanup Windows 7 specific special handling. Patch by Max Bachmann. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst deleted file mode 100644 index c03fd5266bc3..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-20-56-12.gh-issue-102356.07KvUd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug that caused a crash when deallocating deeply nested filter -objects. Patch by Marta G?mez Mac?as. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst deleted file mode 100644 index 9ffc67cfb7ed..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-13-05-33.gh-issue-102416.dz6K5f.rst +++ /dev/null @@ -1 +0,0 @@ -Do not memoize incorrectly automatically generated loop rules in the parser. Patch by Pablo Galindo. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-07-16-56-28.gh-issue-102493.gTXrcD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-07-16-56-28.gh-issue-102493.gTXrcD.rst deleted file mode 100644 index 4c4e88ca4e7c..000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2023-03-07-16-56-28.gh-issue-102493.gTXrcD.rst +++ /dev/null @@ -1 +0,0 @@ -Fix regression in semantics of normalisation in ``PyErr_SetObject``. diff --git a/Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst b/Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst deleted file mode 100644 index fd9ea049c239..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix :meth:`asyncio.Task.print_stack` description for ``file=None``. -Patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/next/Documentation/2023-02-19-10-33-01.gh-issue-85417.kYO8u3.rst b/Misc/NEWS.d/next/Documentation/2023-02-19-10-33-01.gh-issue-85417.kYO8u3.rst deleted file mode 100644 index a5532df14795..000000000000 --- a/Misc/NEWS.d/next/Documentation/2023-02-19-10-33-01.gh-issue-85417.kYO8u3.rst +++ /dev/null @@ -1 +0,0 @@ -Update :mod:`cmath` documentation to clarify behaviour on branch cuts. diff --git a/Misc/NEWS.d/next/Library/2018-06-20-09-12-21.bpo-23224.zxCQ13.rst b/Misc/NEWS.d/next/Library/2018-06-20-09-12-21.bpo-23224.zxCQ13.rst deleted file mode 100644 index 8909753c7f9e..000000000000 --- a/Misc/NEWS.d/next/Library/2018-06-20-09-12-21.bpo-23224.zxCQ13.rst +++ /dev/null @@ -1,6 +0,0 @@ -Fix segfaults when creating :class:`lzma.LZMADecompressor` and -:class:`bz2.BZ2Decompressor` objects without calling ``__init__()``, and fix -leakage of locks and internal buffers when calling the ``__init__()`` -methods of :class:`lzma.LZMADecompressor`, :class:`lzma.LZMACompressor`, -:class:`bz2.BZ2Compressor`, and :class:`bz2.BZ2Decompressor` objects -multiple times. diff --git a/Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst b/Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst deleted file mode 100644 index 806f7011edc3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Correctly preserve "extra" fields in ``zipfile`` regardless of their -ordering relative to a zip64 "extra." diff --git a/Misc/NEWS.d/next/Library/2022-10-22-09-26-43.gh-issue-96764.Dh9Y5L.rst b/Misc/NEWS.d/next/Library/2022-10-22-09-26-43.gh-issue-96764.Dh9Y5L.rst deleted file mode 100644 index a0174291cbc3..000000000000 --- a/Misc/NEWS.d/next/Library/2022-10-22-09-26-43.gh-issue-96764.Dh9Y5L.rst +++ /dev/null @@ -1 +0,0 @@ -:func:`asyncio.wait_for` now uses :func:`asyncio.timeout` as its underlying implementation. Patch by Kumar Aditya. diff --git a/Misc/NEWS.d/next/Library/2023-01-02-22-41-44.gh-issue-99138.17hp9U.rst b/Misc/NEWS.d/next/Library/2023-01-02-22-41-44.gh-issue-99138.17hp9U.rst deleted file mode 100644 index 3dd4646f40e1..000000000000 --- a/Misc/NEWS.d/next/Library/2023-01-02-22-41-44.gh-issue-99138.17hp9U.rst +++ /dev/null @@ -1 +0,0 @@ -Apply :pep:`687` to :mod:`zoneinfo`. Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2023-01-06-21-14-41.gh-issue-100809.I697UT.rst b/Misc/NEWS.d/next/Library/2023-01-06-21-14-41.gh-issue-100809.I697UT.rst deleted file mode 100644 index 54082de88ccf..000000000000 --- a/Misc/NEWS.d/next/Library/2023-01-06-21-14-41.gh-issue-100809.I697UT.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix handling of drive-relative paths (like 'C:' and 'C:foo') in -:meth:`pathlib.Path.absolute`. This method now uses the OS API -to retrieve the correct current working directory for the drive. diff --git a/Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst b/Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst deleted file mode 100644 index e09c0e09fb38..000000000000 --- a/Misc/NEWS.d/next/Library/2023-01-25-00-14-52.gh-issue-101277.FceHX7.rst +++ /dev/null @@ -1,2 +0,0 @@ -Remove global state from :mod:`itertools` module (:pep:`687`). Patches by -Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2023-01-27-02-53-50.gh-issue-101360.bPB7SL.rst b/Misc/NEWS.d/next/Library/2023-01-27-02-53-50.gh-issue-101360.bPB7SL.rst deleted file mode 100644 index 4cfb136c5db8..000000000000 --- a/Misc/NEWS.d/next/Library/2023-01-27-02-53-50.gh-issue-101360.bPB7SL.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fix anchor matching in :meth:`pathlib.PureWindowsPath.match`. Path and -pattern anchors are now matched with :mod:`fnmatch`, just like other path -parts. This allows patterns such as ``"*:/Users/*"`` to be matched. diff --git a/Misc/NEWS.d/next/Library/2023-02-01-10-42-16.gh-issue-63301.XNxSFh.rst b/Misc/NEWS.d/next/Library/2023-02-01-10-42-16.gh-issue-63301.XNxSFh.rst deleted file mode 100644 index e00e71fb8554..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-01-10-42-16.gh-issue-63301.XNxSFh.rst +++ /dev/null @@ -1 +0,0 @@ -Set exit code when :mod:`tabnanny` CLI exits on error. diff --git a/Misc/NEWS.d/next/Library/2023-02-04-16-35-46.gh-issue-101561.Xo6pIZ.rst b/Misc/NEWS.d/next/Library/2023-02-04-16-35-46.gh-issue-101561.Xo6pIZ.rst deleted file mode 100644 index 2f6a4153062e..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-04-16-35-46.gh-issue-101561.Xo6pIZ.rst +++ /dev/null @@ -1 +0,0 @@ -Add a new decorator :func:`typing.override`. See :pep:`698` for details. Patch by Steven Troxler. diff --git a/Misc/NEWS.d/next/Library/2023-02-05-21-40-15.gh-issue-85984.Kfzbb2.rst b/Misc/NEWS.d/next/Library/2023-02-05-21-40-15.gh-issue-85984.Kfzbb2.rst deleted file mode 100644 index c91829f2c739..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-05-21-40-15.gh-issue-85984.Kfzbb2.rst +++ /dev/null @@ -1,4 +0,0 @@ -Refactored the implementation of :func:`pty.fork` to use :func:`os.login_tty`. - -A :exc:`DeprecationWarning` is now raised by ``pty.master_open()`` and ``pty.slave_open()``. They were -undocumented and deprecated long long ago in the docstring in favor of :func:`pty.openpty`. diff --git a/Misc/NEWS.d/next/Library/2023-02-07-20-46-08.gh-issue-101362.2ckZ6R.rst b/Misc/NEWS.d/next/Library/2023-02-07-20-46-08.gh-issue-101362.2ckZ6R.rst deleted file mode 100644 index 8421466cdbb3..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-07-20-46-08.gh-issue-101362.2ckZ6R.rst +++ /dev/null @@ -1,2 +0,0 @@ -Speed up :class:`pathlib.Path` construction by running the path flavour -compatibility check only when pathlib is imported. diff --git a/Misc/NEWS.d/next/Library/2023-02-07-21-16-41.gh-issue-101362.KMQllM.rst b/Misc/NEWS.d/next/Library/2023-02-07-21-16-41.gh-issue-101362.KMQllM.rst deleted file mode 100644 index af4ee9ad9048..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-07-21-16-41.gh-issue-101362.KMQllM.rst +++ /dev/null @@ -1,2 +0,0 @@ -Speed up :class:`pathlib.PurePath` construction by calling -:func:`os.path.join` only when two or more arguments are given. diff --git a/Misc/NEWS.d/next/Library/2023-02-07-22-20-32.gh-issue-101362.Jlk6mt.rst b/Misc/NEWS.d/next/Library/2023-02-07-22-20-32.gh-issue-101362.Jlk6mt.rst deleted file mode 100644 index c05f92ae699d..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-07-22-20-32.gh-issue-101362.Jlk6mt.rst +++ /dev/null @@ -1,4 +0,0 @@ -Speed up :class:`pathlib.PurePath` construction by handling arguments more -uniformly. When a :class:`pathlib.Path` argument is supplied, -we use its string representation rather than joining its parts -with :func:`os.path.join`. diff --git a/Misc/NEWS.d/next/Library/2023-02-07-22-21-46.gh-issue-101446.-c0FdK.rst b/Misc/NEWS.d/next/Library/2023-02-07-22-21-46.gh-issue-101446.-c0FdK.rst deleted file mode 100644 index ddf897b71bb1..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-07-22-21-46.gh-issue-101446.-c0FdK.rst +++ /dev/null @@ -1,2 +0,0 @@ -Change repr of :class:`collections.OrderedDict` to use regular dictionary -formating instead of pairs of keys and values. diff --git a/Misc/NEWS.d/next/Library/2023-02-08-18-20-58.gh-issue-101693.4_LPXj.rst b/Misc/NEWS.d/next/Library/2023-02-08-18-20-58.gh-issue-101693.4_LPXj.rst deleted file mode 100644 index e436054b15b6..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-08-18-20-58.gh-issue-101693.4_LPXj.rst +++ /dev/null @@ -1,6 +0,0 @@ -In :meth:`sqlite3.Cursor.execute`, :exc:`DeprecationWarning` is now emitted -when :ref:`named placeholders ` are used together with -parameters supplied as a :term:`sequence` instead of as a :class:`dict`. -Starting from Python 3.14, using named placeholders with parameters supplied -as a sequence will raise a :exc:`~sqlite3.ProgrammingError`. -Patch by Erlend E. Aasland. diff --git a/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst b/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst deleted file mode 100644 index b577d93d28c2..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst +++ /dev/null @@ -1,2 +0,0 @@ -Optimize :class:`fractions.Fraction` for small components. The private argument -``_normalize`` of the :class:`fractions.Fraction` constructor has been removed. diff --git a/Misc/NEWS.d/next/Library/2023-02-10-16-02-29.gh-issue-101517.r7S2u8.rst b/Misc/NEWS.d/next/Library/2023-02-10-16-02-29.gh-issue-101517.r7S2u8.rst deleted file mode 100644 index a5f6bdfa5ac2..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-10-16-02-29.gh-issue-101517.r7S2u8.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed bug where :mod:`bdb` looks up the source line with :mod:`linecache` with a ``lineno=None``, which causes it to fail with an unhandled exception. diff --git a/Misc/NEWS.d/next/Library/2023-02-11-13-23-29.gh-issue-97786.QjvQ1B.rst b/Misc/NEWS.d/next/Library/2023-02-11-13-23-29.gh-issue-97786.QjvQ1B.rst deleted file mode 100644 index df194b67590d..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-11-13-23-29.gh-issue-97786.QjvQ1B.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix potential undefined behaviour in corner cases of floating-point-to-time -conversions. diff --git a/Misc/NEWS.d/next/Library/2023-02-13-12-55-48.gh-issue-87634.q-SBhJ.rst b/Misc/NEWS.d/next/Library/2023-02-13-12-55-48.gh-issue-87634.q-SBhJ.rst deleted file mode 100644 index a17927500bd9..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-13-12-55-48.gh-issue-87634.q-SBhJ.rst +++ /dev/null @@ -1 +0,0 @@ -Remove locking behavior from :func:`functools.cached_property`. diff --git a/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst b/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst deleted file mode 100644 index d586779b3a8a..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-14-09-08-48.gh-issue-101892.FMos8l.rst +++ /dev/null @@ -1,3 +0,0 @@ -Callable iterators no longer raise :class:`SystemError` when the -callable object exhausts the iterator but forgets to either return a -sentinel value or raise :class:`StopIteration`. diff --git a/Misc/NEWS.d/next/Library/2023-02-15-01-54-06.gh-issue-99108.rjTSic.rst b/Misc/NEWS.d/next/Library/2023-02-15-01-54-06.gh-issue-99108.rjTSic.rst deleted file mode 100644 index 1612c89c0ea6..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-15-01-54-06.gh-issue-99108.rjTSic.rst +++ /dev/null @@ -1,3 +0,0 @@ -The built-in extension modules for :mod:`hashlib` SHA2 algorithms, used when -OpenSSL does not provide them, now live in a single internal ``_sha2`` module -instead of separate ``_sha256`` and ``_sha512`` modules. diff --git a/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst b/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst deleted file mode 100644 index f9dfd46d1ed4..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst +++ /dev/null @@ -1 +0,0 @@ -Upgrade pip wheel bundled with ensurepip (pip 23.0.1) diff --git a/Misc/NEWS.d/next/Library/2023-02-17-19-00-58.gh-issue-97930.C_nQjb.rst b/Misc/NEWS.d/next/Library/2023-02-17-19-00-58.gh-issue-97930.C_nQjb.rst deleted file mode 100644 index 967e13f752bc..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-17-19-00-58.gh-issue-97930.C_nQjb.rst +++ /dev/null @@ -1,4 +0,0 @@ -Apply changes from `importlib_resources 5.12 -`_, -including fix for ``MultiplexedPath`` to support directories in multiple -namespaces (python/importlib_resources#265). diff --git a/Misc/NEWS.d/next/Library/2023-02-17-20-24-15.gh-issue-101566.FjgWBt.rst b/Misc/NEWS.d/next/Library/2023-02-17-20-24-15.gh-issue-101566.FjgWBt.rst deleted file mode 100644 index 5fc1a0288a82..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-17-20-24-15.gh-issue-101566.FjgWBt.rst +++ /dev/null @@ -1,4 +0,0 @@ -In zipfile, sync Path with `zipp 3.14 -`_, including -fix for extractall on the underlying zipfile after being wrapped in -``Path``. diff --git a/Misc/NEWS.d/next/Library/2023-02-21-07-15-41.gh-issue-101936.QVOxHH.rst b/Misc/NEWS.d/next/Library/2023-02-21-07-15-41.gh-issue-101936.QVOxHH.rst deleted file mode 100644 index 55841da44b11..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-21-07-15-41.gh-issue-101936.QVOxHH.rst +++ /dev/null @@ -1,2 +0,0 @@ -The default value of ``fp`` becomes :class:`io.BytesIO` if :exc:`~urllib.error.HTTPError` -is initialized without a designated ``fp`` parameter. Patch by Long Vo. diff --git a/Misc/NEWS.d/next/Library/2023-02-21-10-05-33.gh-issue-101961.7e56jh.rst b/Misc/NEWS.d/next/Library/2023-02-21-10-05-33.gh-issue-101961.7e56jh.rst deleted file mode 100644 index a3d4119e7cbd..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-21-10-05-33.gh-issue-101961.7e56jh.rst +++ /dev/null @@ -1,2 +0,0 @@ -For the binary mode, :func:`fileinput.hookcompressed` doesn't set the ``encoding`` value -even if the value is ``None``. Patch by Gihwan Kim. diff --git a/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst b/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst deleted file mode 100644 index f77493e267ac..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-23-15-06-01.gh-issue-102179.P6KQ4c.rst +++ /dev/null @@ -1 +0,0 @@ -Fix :func:`os.dup2` error message for negative fds. diff --git a/Misc/NEWS.d/next/Library/2023-02-23-20-39-52.gh-issue-81652.Vxz0Mr.rst b/Misc/NEWS.d/next/Library/2023-02-23-20-39-52.gh-issue-81652.Vxz0Mr.rst deleted file mode 100644 index 48acce1d863e..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-23-20-39-52.gh-issue-81652.Vxz0Mr.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add :data:`mmap.MAP_ALIGNED_SUPER` FreeBSD and :data:`mmap.MAP_CONCEAL` -OpenBSD constants to :mod:`mmap`. Patch by Yeojin Kim. diff --git a/Misc/NEWS.d/next/Library/2023-02-26-12-37-17.gh-issue-91038.S4rFH_.rst b/Misc/NEWS.d/next/Library/2023-02-26-12-37-17.gh-issue-91038.S4rFH_.rst deleted file mode 100644 index 2667ff120fd4..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-26-12-37-17.gh-issue-91038.S4rFH_.rst +++ /dev/null @@ -1 +0,0 @@ -:meth:`platform.platform` now has boolean default arguments. diff --git a/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst b/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst deleted file mode 100644 index 1efe72439b3a..000000000000 --- a/Misc/NEWS.d/next/Library/2023-02-28-09-52-25.gh-issue-101979.or3hXV.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix a bug where parentheses in the ``metavar`` argument to :meth:`argparse.ArgumentParser.add_argument` were -dropped. Patch by Yeojin Kim. diff --git a/Misc/NEWS.d/next/Library/2023-03-04-14-46-47.gh-issue-102302.-b_s6Z.rst b/Misc/NEWS.d/next/Library/2023-03-04-14-46-47.gh-issue-102302.-b_s6Z.rst deleted file mode 100644 index aaf4e62069ca..000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-04-14-46-47.gh-issue-102302.-b_s6Z.rst +++ /dev/null @@ -1 +0,0 @@ -Micro-optimise hashing of :class:`inspect.Parameter`, reducing the time it takes to hash an instance by around 40%. diff --git a/Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst b/Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst deleted file mode 100644 index 0efdfa102341..000000000000 --- a/Misc/NEWS.d/next/Security/2023-01-24-16-12-00.gh-issue-101283.9tqu39.rst +++ /dev/null @@ -1,3 +0,0 @@ -:class:`subprocess.Popen` now uses a safer approach to find -``cmd.exe`` when launching with ``shell=True``. Patch by Eryk Sun, -based on a patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/next/Security/2023-02-08-12-57-35.gh-issue-99108.6tnmhA.rst b/Misc/NEWS.d/next/Security/2023-02-08-12-57-35.gh-issue-99108.6tnmhA.rst deleted file mode 100644 index 6a7a309dad5d..000000000000 --- a/Misc/NEWS.d/next/Security/2023-02-08-12-57-35.gh-issue-99108.6tnmhA.rst +++ /dev/null @@ -1,4 +0,0 @@ -Replace the builtin :mod:`hashlib` implementations of SHA2-384 and SHA2-512 -originally from LibTomCrypt with formally verified, side-channel resistant -code from the `HACL* `_ project. -The builtins remain a fallback only used when OpenSSL does not provide them. diff --git a/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst b/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst deleted file mode 100644 index 43acc82063fd..000000000000 --- a/Misc/NEWS.d/next/Security/2023-02-08-22-03-04.gh-issue-101727.9P5eZz.rst +++ /dev/null @@ -1,4 +0,0 @@ -Updated the OpenSSL version used in Windows and macOS binary release builds -to 1.1.1t to address CVE-2023-0286, CVE-2022-4303, and CVE-2022-4303 per -`the OpenSSL 2023-02-07 security advisory -`_. diff --git a/Misc/NEWS.d/next/Security/2023-02-17-10-42-48.gh-issue-99108.MKA8-f.rst b/Misc/NEWS.d/next/Security/2023-02-17-10-42-48.gh-issue-99108.MKA8-f.rst deleted file mode 100644 index 723d8a43a09f..000000000000 --- a/Misc/NEWS.d/next/Security/2023-02-17-10-42-48.gh-issue-99108.MKA8-f.rst +++ /dev/null @@ -1,2 +0,0 @@ -Replace builtin hashlib implementations of MD5 and SHA1 with verified ones -from the HACL* project. diff --git a/Misc/NEWS.d/next/Tests/2023-02-11-20-28-08.gh-issue-89792.S-Y5BZ.rst b/Misc/NEWS.d/next/Tests/2023-02-11-20-28-08.gh-issue-89792.S-Y5BZ.rst deleted file mode 100644 index 9de278919ef2..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-02-11-20-28-08.gh-issue-89792.S-Y5BZ.rst +++ /dev/null @@ -1,4 +0,0 @@ -``test_tools`` now copies up to 10x less source data to a temporary directory -during the ``freeze`` test by ignoring git metadata and other artifacts. It -also limits its python build parallelism based on os.cpu_count instead of hard -coding it as 8 cores. diff --git a/Misc/NEWS.d/next/Tests/2023-02-11-22-36-10.gh-issue-85984.EVXjT9.rst b/Misc/NEWS.d/next/Tests/2023-02-11-22-36-10.gh-issue-85984.EVXjT9.rst deleted file mode 100644 index 402f99ea6c6e..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-02-11-22-36-10.gh-issue-85984.EVXjT9.rst +++ /dev/null @@ -1 +0,0 @@ -Utilize new "winsize" functions from termios in pty tests. diff --git a/Misc/NEWS.d/next/Tests/2023-02-18-10-51-02.gh-issue-102019.0797SJ.rst b/Misc/NEWS.d/next/Tests/2023-02-18-10-51-02.gh-issue-102019.0797SJ.rst deleted file mode 100644 index 63e36046d26d..000000000000 --- a/Misc/NEWS.d/next/Tests/2023-02-18-10-51-02.gh-issue-102019.0797SJ.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fix deadlock on shutdown if ``test_current_{exception,frames}`` fails. Patch -by Jacob Bower. diff --git a/Misc/NEWS.d/next/Windows/2023-01-25-11-33-54.gh-issue-101196.wAX_2g.rst b/Misc/NEWS.d/next/Windows/2023-01-25-11-33-54.gh-issue-101196.wAX_2g.rst deleted file mode 100644 index c61e9b90fb53..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-01-25-11-33-54.gh-issue-101196.wAX_2g.rst +++ /dev/null @@ -1,3 +0,0 @@ -The functions ``os.path.isdir``, ``os.path.isfile``, ``os.path.islink`` and -``os.path.exists`` are now 13% to 28% faster on Windows, by making fewer Win32 -API calls. diff --git a/Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst b/Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst deleted file mode 100644 index 8ed0995d7892..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-07-18-22-54.gh-issue-101614.NjVP0n.rst +++ /dev/null @@ -1 +0,0 @@ -Correctly handle extensions built against debug binaries that reference ``python3_d.dll``. diff --git a/Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst b/Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst deleted file mode 100644 index 62bcac34397d..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-09-22-09-27.gh-issue-101759.zFlqSH.rst +++ /dev/null @@ -1 +0,0 @@ -Update Windows installer to SQLite 3.40.1. diff --git a/Misc/NEWS.d/next/Windows/2023-02-10-14-26-05.gh-issue-101763.RPaj7r.rst b/Misc/NEWS.d/next/Windows/2023-02-10-14-26-05.gh-issue-101763.RPaj7r.rst deleted file mode 100644 index e7e5a73afeb5..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-10-14-26-05.gh-issue-101763.RPaj7r.rst +++ /dev/null @@ -1 +0,0 @@ -Updates copy of libffi bundled with Windows installs to 3.4.4. diff --git a/Misc/NEWS.d/next/Windows/2023-02-13-16-32-50.gh-issue-101849.7lm_53.rst b/Misc/NEWS.d/next/Windows/2023-02-13-16-32-50.gh-issue-101849.7lm_53.rst deleted file mode 100644 index 861d4de9f9a6..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-13-16-32-50.gh-issue-101849.7lm_53.rst +++ /dev/null @@ -1 +0,0 @@ -Ensures installer will correctly upgrade existing ``py.exe`` launcher installs. diff --git a/Misc/NEWS.d/next/Windows/2023-02-13-18-05-49.gh-issue-101881._TnHzN.rst b/Misc/NEWS.d/next/Windows/2023-02-13-18-05-49.gh-issue-101881._TnHzN.rst deleted file mode 100644 index ba58dd4f5cb4..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-13-18-05-49.gh-issue-101881._TnHzN.rst +++ /dev/null @@ -1 +0,0 @@ -Add support for the os.get_blocking() and os.set_blocking() functions on Windows. diff --git a/Misc/NEWS.d/next/Windows/2023-02-15-11-08-10.gh-issue-101881.fScr3m.rst b/Misc/NEWS.d/next/Windows/2023-02-15-11-08-10.gh-issue-101881.fScr3m.rst deleted file mode 100644 index 099b2c1c07a6..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-02-15-11-08-10.gh-issue-101881.fScr3m.rst +++ /dev/null @@ -1 +0,0 @@ -Handle read and write operations on non-blocking pipes properly on Windows. diff --git a/Misc/NEWS.d/next/Windows/2023-03-01-01-36-39.gh-issue-102344.Dgfux4.rst b/Misc/NEWS.d/next/Windows/2023-03-01-01-36-39.gh-issue-102344.Dgfux4.rst deleted file mode 100644 index 4804212be818..000000000000 --- a/Misc/NEWS.d/next/Windows/2023-03-01-01-36-39.gh-issue-102344.Dgfux4.rst +++ /dev/null @@ -1,2 +0,0 @@ -Implement ``winreg.QueryValue`` using ``QueryValueEx`` and -``winreg.SetValue`` using ``SetValueEx``. Patch by Max Bachmann. diff --git a/Misc/NEWS.d/next/macOS/2023-02-09-22-07-17.gh-issue-101759.B0JP2H.rst b/Misc/NEWS.d/next/macOS/2023-02-09-22-07-17.gh-issue-101759.B0JP2H.rst deleted file mode 100644 index fc53d08bffc4..000000000000 --- a/Misc/NEWS.d/next/macOS/2023-02-09-22-07-17.gh-issue-101759.B0JP2H.rst +++ /dev/null @@ -1 +0,0 @@ -Update macOS installer to SQLite 3.40.1. diff --git a/README.rst b/README.rst index b1756e20c141..6923b692f6c9 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,4 @@ -This is Python version 3.12.0 alpha 5 +This is Python version 3.12.0 alpha 6 ===================================== .. image:: https://github.com/python/cpython/workflows/Tests/badge.svg From webhook-mailer at python.org Wed Mar 8 02:25:44 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Wed, 08 Mar 2023 07:25:44 -0000 Subject: [Python-checkins] Fix style in argparse.rst (#101733) Message-ID: https://github.com/python/cpython/commit/061325e0d2bbec6ff89d03f527c91dc7bfa14003 commit: 061325e0d2bbec6ff89d03f527c91dc7bfa14003 branch: main author: Marcin Wieczorek committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-07T23:25:28-08:00 summary: Fix style in argparse.rst (#101733) files: M Doc/library/argparse.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 34b4c61649b9..ee68ac58d3de 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -34,9 +34,9 @@ around an instance of :class:`argparse.ArgumentParser`. It is a container for argument specifications and has options that apply to the parser as whole:: parser = argparse.ArgumentParser( - prog = 'ProgramName', - description = 'What the program does', - epilog = 'Text at the bottom of help') + prog='ProgramName', + description='What the program does', + epilog='Text at the bottom of help') The :meth:`ArgumentParser.add_argument` method attaches individual argument specifications to the parser. It supports positional arguments, options that From webhook-mailer at python.org Wed Mar 8 02:33:59 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 08 Mar 2023 07:33:59 -0000 Subject: [Python-checkins] Fix style in argparse.rst (GH-101733) Message-ID: https://github.com/python/cpython/commit/8bf8e3d9a001f1d955a9f0875ac5a70f6d5a5f5c commit: 8bf8e3d9a001f1d955a9f0875ac5a70f6d5a5f5c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-07T23:33:52-08:00 summary: Fix style in argparse.rst (GH-101733) (cherry picked from commit 061325e0d2bbec6ff89d03f527c91dc7bfa14003) Co-authored-by: Marcin Wieczorek files: M Doc/library/argparse.rst diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 7a36c5264aa0..8dfe86a4add3 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -34,9 +34,9 @@ around an instance of :class:`argparse.ArgumentParser`. It is a container for argument specifications and has options that apply the parser as whole:: parser = argparse.ArgumentParser( - prog = 'ProgramName', - description = 'What the program does', - epilog = 'Text at the bottom of help') + prog='ProgramName', + description='What the program does', + epilog='Text at the bottom of help') The :meth:`ArgumentParser.add_argument` method attaches individual argument specifications to the parser. It supports positional arguments, options that From webhook-mailer at python.org Wed Mar 8 02:59:59 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Wed, 08 Mar 2023 07:59:59 -0000 Subject: [Python-checkins] GH-102397: Fix segfault from race condition in signal handling (#102399) Message-ID: https://github.com/python/cpython/commit/1a84cc007e207f2dd61f86a7fc3d86632fdce72f commit: 1a84cc007e207f2dd61f86a7fc3d86632fdce72f branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-08T13:29:39+05:30 summary: GH-102397: Fix segfault from race condition in signal handling (#102399) Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst M Lib/test/test_signal.py M Modules/signalmodule.c diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 2562a57ea421..25afd6aabe07 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -1406,6 +1406,21 @@ def handler(a, b): signal.raise_signal(signal.SIGINT) self.assertTrue(is_ok) + def test__thread_interrupt_main(self): + # See https://github.com/python/cpython/issues/102397 + code = """if 1: + import _thread + class Foo(): + def __del__(self): + _thread.interrupt_main() + + x = Foo() + """ + + rc, out, err = assert_python_ok('-c', code) + self.assertIn(b'OSError: Signal 2 ignored due to race condition', err) + + class PidfdSignalTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst new file mode 100644 index 000000000000..db0b3f32c2ec --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst @@ -0,0 +1,2 @@ +Fix segfault from race condition in signal handling during garbage collection. +Patch by Kumar Aditya. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index cd26eca351c0..0e472e1ee4f9 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -148,6 +148,10 @@ get_signal_state(PyObject *module) static inline int compare_handler(PyObject *func, PyObject *dfl_ign_handler) { + // See https://github.com/python/cpython/pull/102399 + if (func == NULL || dfl_ign_handler == NULL) { + return 0; + } assert(PyLong_CheckExact(dfl_ign_handler)); if (!PyLong_CheckExact(func)) { return 0; From webhook-mailer at python.org Wed Mar 8 03:19:32 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 08 Mar 2023 08:19:32 -0000 Subject: [Python-checkins] gh-101100: Fix sphinx warnings in `zipapp` and `zipfile` modules (#102526) Message-ID: https://github.com/python/cpython/commit/1f557f94c2ee98c2a43bd090a7bf3f39a22ed874 commit: 1f557f94c2ee98c2a43bd090a7bf3f39a22ed874 branch: main author: Nikita Sobolev committer: AlexWaygood date: 2023-03-08T08:19:05Z summary: gh-101100: Fix sphinx warnings in `zipapp` and `zipfile` modules (#102526) files: M Doc/library/zipapp.rst M Doc/library/zipfile.rst diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index fb40a2b3e964..981020b13cd9 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -215,7 +215,7 @@ using the :func:`create_archive` function:: >>> import zipapp >>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3') -To update the file in place, do the replacement in memory using a :class:`BytesIO` +To update the file in place, do the replacement in memory using a :class:`~io.BytesIO` object, and then overwrite the source afterwards. Note that there is a risk when overwriting a file in place that an error will result in the loss of the original file. This code does not protect against such errors, but diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 0195abc3a992..e2a085d6e98e 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -288,7 +288,7 @@ ZipFile Objects (``ZipExtFile``) is read-only and provides the following methods: :meth:`~io.BufferedIOBase.read`, :meth:`~io.IOBase.readline`, :meth:`~io.IOBase.readlines`, :meth:`~io.IOBase.seek`, - :meth:`~io.IOBase.tell`, :meth:`__iter__`, :meth:`~iterator.__next__`. + :meth:`~io.IOBase.tell`, :meth:`~container.__iter__`, :meth:`~iterator.__next__`. These objects can operate independently of the ZipFile. With ``mode='w'``, a writable file handle is returned, which supports the From webhook-mailer at python.org Wed Mar 8 03:21:20 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Wed, 08 Mar 2023 08:21:20 -0000 Subject: [Python-checkins] [3.10] GH-102397: Fix segfault from race condition in signal handling (GH-102399) (#102527) Message-ID: https://github.com/python/cpython/commit/c4fb41816f6045dd608d4d97266f16feaf974b83 commit: c4fb41816f6045dd608d4d97266f16feaf974b83 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-08T13:51:13+05:30 summary: [3.10] GH-102397: Fix segfault from race condition in signal handling (GH-102399) (#102527) GH-102397: Fix segfault from race condition in signal handling (GH-102399) (cherry picked from commit 1a84cc007e207f2dd61f86a7fc3d86632fdce72f) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst M Lib/test/test_signal.py M Modules/signalmodule.c diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index c2b5861fc3e9..294cf3888d11 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -1349,6 +1349,21 @@ def handler(a, b): signal.raise_signal(signal.SIGINT) self.assertTrue(is_ok) + def test__thread_interrupt_main(self): + # See https://github.com/python/cpython/issues/102397 + code = """if 1: + import _thread + class Foo(): + def __del__(self): + _thread.interrupt_main() + + x = Foo() + """ + + rc, out, err = assert_python_ok('-c', code) + self.assertIn(b'OSError: Signal 2 ignored due to race condition', err) + + class PidfdSignalTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst new file mode 100644 index 000000000000..db0b3f32c2ec --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst @@ -0,0 +1,2 @@ +Fix segfault from race condition in signal handling during garbage collection. +Patch by Kumar Aditya. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 80fa4d50eef7..bcfd5537708d 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -177,6 +177,10 @@ get_signal_state(PyObject *module) static inline int compare_handler(PyObject *func, PyObject *dfl_ign_handler) { + // See https://github.com/python/cpython/pull/102399 + if (func == NULL || dfl_ign_handler == NULL) { + return 0; + } assert(PyLong_CheckExact(dfl_ign_handler)); if (!PyLong_CheckExact(func)) { return 0; From webhook-mailer at python.org Wed Mar 8 03:26:27 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 08 Mar 2023 08:26:27 -0000 Subject: [Python-checkins] GH-102397: Fix segfault from race condition in signal handling (GH-102399) Message-ID: https://github.com/python/cpython/commit/7905ae7b1a347a5dd15174f7e44bb67c4cdb5972 commit: 7905ae7b1a347a5dd15174f7e44bb67c4cdb5972 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-08T00:26:20-08:00 summary: GH-102397: Fix segfault from race condition in signal handling (GH-102399) (cherry picked from commit 1a84cc007e207f2dd61f86a7fc3d86632fdce72f) Co-authored-by: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst M Lib/test/test_signal.py M Modules/signalmodule.c diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 6aa529b06200..ddd635197a7a 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -1413,6 +1413,21 @@ def handler(a, b): signal.raise_signal(signal.SIGINT) self.assertTrue(is_ok) + def test__thread_interrupt_main(self): + # See https://github.com/python/cpython/issues/102397 + code = """if 1: + import _thread + class Foo(): + def __del__(self): + _thread.interrupt_main() + + x = Foo() + """ + + rc, out, err = assert_python_ok('-c', code) + self.assertIn(b'OSError: Signal 2 ignored due to race condition', err) + + class PidfdSignalTest(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst new file mode 100644 index 000000000000..db0b3f32c2ec --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-04-06-48-34.gh-issue-102397.ACJaOf.rst @@ -0,0 +1,2 @@ +Fix segfault from race condition in signal handling during garbage collection. +Patch by Kumar Aditya. diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 60a8067fc8c8..8305f6402033 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -181,6 +181,10 @@ get_signal_state(PyObject *module) static inline int compare_handler(PyObject *func, PyObject *dfl_ign_handler) { + // See https://github.com/python/cpython/pull/102399 + if (func == NULL || dfl_ign_handler == NULL) { + return 0; + } assert(PyLong_CheckExact(dfl_ign_handler)); if (!PyLong_CheckExact(func)) { return 0; From webhook-mailer at python.org Wed Mar 8 03:31:12 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 08 Mar 2023 08:31:12 -0000 Subject: [Python-checkins] gh-101100: Fix sphinx warnings in `zipapp` and `zipfile` modules (GH-102526) Message-ID: https://github.com/python/cpython/commit/ffb41eaaf4b04f7f52ee095253fcc1c5ba62ca28 commit: ffb41eaaf4b04f7f52ee095253fcc1c5ba62ca28 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-08T00:30:44-08:00 summary: gh-101100: Fix sphinx warnings in `zipapp` and `zipfile` modules (GH-102526) (cherry picked from commit 1f557f94c2ee98c2a43bd090a7bf3f39a22ed874) Co-authored-by: Nikita Sobolev files: M Doc/library/zipapp.rst M Doc/library/zipfile.rst diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index fb40a2b3e964..981020b13cd9 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -215,7 +215,7 @@ using the :func:`create_archive` function:: >>> import zipapp >>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3') -To update the file in place, do the replacement in memory using a :class:`BytesIO` +To update the file in place, do the replacement in memory using a :class:`~io.BytesIO` object, and then overwrite the source afterwards. Note that there is a risk when overwriting a file in place that an error will result in the loss of the original file. This code does not protect against such errors, but diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 9ad0a979e498..9e8e9c3cc205 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -288,7 +288,7 @@ ZipFile Objects (``ZipExtFile``) is read-only and provides the following methods: :meth:`~io.BufferedIOBase.read`, :meth:`~io.IOBase.readline`, :meth:`~io.IOBase.readlines`, :meth:`~io.IOBase.seek`, - :meth:`~io.IOBase.tell`, :meth:`__iter__`, :meth:`~iterator.__next__`. + :meth:`~io.IOBase.tell`, :meth:`~container.__iter__`, :meth:`~iterator.__next__`. These objects can operate independently of the ZipFile. With ``mode='w'``, a writable file handle is returned, which supports the From webhook-mailer at python.org Wed Mar 8 03:44:41 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 08 Mar 2023 08:44:41 -0000 Subject: [Python-checkins] gh-101100: Fix sphinx warnings in `zipapp` and `zipfile` modules (GH-102526) Message-ID: https://github.com/python/cpython/commit/7276ee0d122d072486b4a9fc03d17533f871da8f commit: 7276ee0d122d072486b4a9fc03d17533f871da8f branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-08T00:44:34-08:00 summary: gh-101100: Fix sphinx warnings in `zipapp` and `zipfile` modules (GH-102526) (cherry picked from commit 1f557f94c2ee98c2a43bd090a7bf3f39a22ed874) Co-authored-by: Nikita Sobolev files: M Doc/library/zipapp.rst M Doc/library/zipfile.rst diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst index fb40a2b3e964..981020b13cd9 100644 --- a/Doc/library/zipapp.rst +++ b/Doc/library/zipapp.rst @@ -215,7 +215,7 @@ using the :func:`create_archive` function:: >>> import zipapp >>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3') -To update the file in place, do the replacement in memory using a :class:`BytesIO` +To update the file in place, do the replacement in memory using a :class:`~io.BytesIO` object, and then overwrite the source afterwards. Note that there is a risk when overwriting a file in place that an error will result in the loss of the original file. This code does not protect against such errors, but diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst index 5072daa63354..78556851d351 100644 --- a/Doc/library/zipfile.rst +++ b/Doc/library/zipfile.rst @@ -266,7 +266,7 @@ ZipFile Objects (``ZipExtFile``) is read-only and provides the following methods: :meth:`~io.BufferedIOBase.read`, :meth:`~io.IOBase.readline`, :meth:`~io.IOBase.readlines`, :meth:`~io.IOBase.seek`, - :meth:`~io.IOBase.tell`, :meth:`__iter__`, :meth:`~iterator.__next__`. + :meth:`~io.IOBase.tell`, :meth:`~container.__iter__`, :meth:`~iterator.__next__`. These objects can operate independently of the ZipFile. With ``mode='w'``, a writable file handle is returned, which supports the From webhook-mailer at python.org Wed Mar 8 05:25:22 2023 From: webhook-mailer at python.org (JulienPalard) Date: Wed, 08 Mar 2023 10:25:22 -0000 Subject: [Python-checkins] Remove or update bitbucket links (GH-101963) Message-ID: https://github.com/python/cpython/commit/7d801f245e2021d19daff105ce722f22aa844391 commit: 7d801f245e2021d19daff105ce722f22aa844391 branch: main author: sblondon committer: JulienPalard date: 2023-03-08T11:24:39+01:00 summary: Remove or update bitbucket links (GH-101963) Since Mercurial removal from bitbucket.org, some links are broken. They are replaced by github.com or webarchive.org links if available. Otherwise, they are removed. Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/distributing/index.rst M Doc/installing/index.rst M Doc/library/venv.rst M Lib/test/test_pathlib.py M PC/launcher.c M PC/launcher2.c diff --git a/Doc/distributing/index.rst b/Doc/distributing/index.rst index 2ae2726d4e4b..21389adedf9c 100644 --- a/Doc/distributing/index.rst +++ b/Doc/distributing/index.rst @@ -39,8 +39,7 @@ Key terms developers and documentation authors responsible for the maintenance and evolution of the standard packaging tools and the associated metadata and file format standards. They maintain a variety of tools, documentation - and issue trackers on both `GitHub `__ and - `Bitbucket `__. + and issue trackers on `GitHub `__. * ``distutils`` is the original build and distribution system first added to the Python standard library in 1998. While direct use of ``distutils`` is being phased out, it still laid the foundation for the current packaging diff --git a/Doc/installing/index.rst b/Doc/installing/index.rst index e158bf1c4c0c..5aec5178d48f 100644 --- a/Doc/installing/index.rst +++ b/Doc/installing/index.rst @@ -52,8 +52,7 @@ Key terms developers and documentation authors responsible for the maintenance and evolution of the standard packaging tools and the associated metadata and file format standards. They maintain a variety of tools, documentation, - and issue trackers on both `GitHub `__ and - `Bitbucket `__. + and issue trackers on `GitHub `__. * ``distutils`` is the original build and distribution system first added to the Python standard library in 1998. While direct use of ``distutils`` is being phased out, it still laid the foundation for the current packaging diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 2a41096de006..8eb0b35eaa12 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -478,7 +478,7 @@ subclass which installs setuptools and pip into a created virtual environment:: :param context: The information for the virtual environment creation request being processed. """ - url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py' + url = "https://bootstrap.pypa.io/ez_setup.py" self.install_script(context, 'setuptools', url) # clear up the setuptools archive which gets downloaded pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz') diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index df9c1f6ba65d..f8e2f44d27fc 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1938,7 +1938,7 @@ def test_resolve_common(self): @os_helper.skip_unless_symlink def test_resolve_dot(self): - # See https://bitbucket.org/pitrou/pathlib/issue/9/pathresolve-fails-on-complex-symlinks + # See http://web.archive.org/web/20200623062557/https://bitbucket.org/pitrou/pathlib/issues/9/ p = self.cls(BASE) self.dirlink('.', join('0')) self.dirlink(os.path.join('0', '0'), join('1')) diff --git a/PC/launcher.c b/PC/launcher.c index da566a180168..0776e57249c4 100644 --- a/PC/launcher.c +++ b/PC/launcher.c @@ -770,8 +770,7 @@ run_child(wchar_t * cmdline) window, or fetching a message). As this launcher doesn't do this directly, that cursor remains even after the child process does these things. We avoid that by doing a simple post+get message. - See http://bugs.python.org/issue17290 and - https://bitbucket.org/vinay.sajip/pylauncher/issue/20/busy-cursor-for-a-long-time-when-running + See http://bugs.python.org/issue17290 */ MSG msg; diff --git a/PC/launcher2.c b/PC/launcher2.c index beeb2ae46b83..932665387f19 100644 --- a/PC/launcher2.c +++ b/PC/launcher2.c @@ -2473,8 +2473,7 @@ launchEnvironment(const SearchInfo *search, const EnvironmentInfo *launch, wchar window, or fetching a message). As this launcher doesn't do this directly, that cursor remains even after the child process does these things. We avoid that by doing a simple post+get message. - See http://bugs.python.org/issue17290 and - https://bitbucket.org/vinay.sajip/pylauncher/issue/20/busy-cursor-for-a-long-time-when-running + See http://bugs.python.org/issue17290 */ MSG msg; From webhook-mailer at python.org Wed Mar 8 06:45:45 2023 From: webhook-mailer at python.org (pablogsal) Date: Wed, 08 Mar 2023 11:45:45 -0000 Subject: [Python-checkins] gh-102515: Remove unused imports in the `Lib/` directory (#102516) Message-ID: https://github.com/python/cpython/commit/401d7a7f009ca2e282b1a0d1b880dc602afd39dc commit: 401d7a7f009ca2e282b1a0d1b880dc602afd39dc branch: main author: Alex Waygood committer: pablogsal date: 2023-03-08T11:45:38Z summary: gh-102515: Remove unused imports in the `Lib/` directory (#102516) files: M Lib/_pylong.py M Lib/concurrent/futures/process.py M Lib/dataclasses.py M Lib/importlib/_abc.py M Lib/sysconfig.py M Lib/test/_test_venv_multiprocessing.py M Lib/test/fork_wait.py M Lib/test/test__xxinterpchannels.py M Lib/test/test__xxsubinterpreters.py M Lib/test/test_asyncgen.py M Lib/test/test_asyncio/test_ssl.py M Lib/test/test_asyncio/test_subprocess.py M Lib/test/test_ctypes/test_callbacks.py M Lib/test/test_dataclasses.py M Lib/test/test_enum.py M Lib/test/test_grammar.py M Lib/test/test_hashlib.py M Lib/test/test_httplib.py M Lib/test/test_imaplib.py M Lib/test/test_isinstance.py M Lib/test/test_minidom.py M Lib/test/test_peg_generator/test_c_parser.py M Lib/test/test_shlex.py M Lib/test/test_sys_setprofile.py M Lib/test/test_sys_settrace.py M Lib/test/test_tkinter/test_widgets.py M Lib/test/test_tools/test_sundry.py M Lib/test/test_traceback.py M Lib/test/test_ttk/test_widgets.py M Lib/test/test_unicodedata.py M Lib/test/test_unittest/test_loader.py M Lib/test/test_wmi.py M Lib/test/test_zipfile64.py diff --git a/Lib/_pylong.py b/Lib/_pylong.py index d14c1d938363..936346e187ff 100644 --- a/Lib/_pylong.py +++ b/Lib/_pylong.py @@ -12,7 +12,6 @@ tricky or non-obvious code is not worth it. For people looking for maximum performance, they should use something like gmpy2.""" -import sys import re import decimal diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index bee162430a6f..3a8637b6fa1b 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -49,6 +49,8 @@ from concurrent.futures import _base import queue import multiprocessing as mp +# This import is required to load the multiprocessing.connection submodule +# so that it can be accessed later as `mp.connection` import multiprocessing.connection from multiprocessing.queues import Queue import threading diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 5c0257eba186..8bc8594d674b 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -4,7 +4,6 @@ import types import inspect import keyword -import builtins import functools import itertools import abc diff --git a/Lib/importlib/_abc.py b/Lib/importlib/_abc.py index 083205638965..693b46611263 100644 --- a/Lib/importlib/_abc.py +++ b/Lib/importlib/_abc.py @@ -1,7 +1,6 @@ """Subset of importlib.abc used to reduce importlib.util imports.""" from . import _bootstrap import abc -import warnings class Loader(metaclass=abc.ABCMeta): diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index c61100a6da85..122d441bd19f 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -3,7 +3,7 @@ import os import sys import threading -from os.path import pardir, realpath +from os.path import realpath __all__ = [ 'get_config_h_filename', diff --git a/Lib/test/_test_venv_multiprocessing.py b/Lib/test/_test_venv_multiprocessing.py index 044a0c6cd3f5..ad985dd8d56b 100644 --- a/Lib/test/_test_venv_multiprocessing.py +++ b/Lib/test/_test_venv_multiprocessing.py @@ -1,7 +1,6 @@ import multiprocessing import random import sys -import time def fill_queue(queue, code): queue.put(code) diff --git a/Lib/test/fork_wait.py b/Lib/test/fork_wait.py index c26c7aaaeb43..8c32895f5e09 100644 --- a/Lib/test/fork_wait.py +++ b/Lib/test/fork_wait.py @@ -9,7 +9,7 @@ active threads survive in the child after a fork(); this is an error. """ -import os, sys, time, unittest +import os, time, unittest import threading from test import support from test.support import threading_helper diff --git a/Lib/test/test__xxinterpchannels.py b/Lib/test/test__xxinterpchannels.py index 03bb5c80b8da..69bda89a1688 100644 --- a/Lib/test/test__xxinterpchannels.py +++ b/Lib/test/test__xxinterpchannels.py @@ -1,6 +1,5 @@ from collections import namedtuple import contextlib -import os import sys from textwrap import dedent import threading diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py index 687fcf3b7705..965967e3f273 100644 --- a/Lib/test/test__xxsubinterpreters.py +++ b/Lib/test/test__xxsubinterpreters.py @@ -1,4 +1,3 @@ -from collections import namedtuple import contextlib import itertools import os @@ -6,7 +5,6 @@ import sys from textwrap import dedent import threading -import time import unittest import _testcapi diff --git a/Lib/test/test_asyncgen.py b/Lib/test/test_asyncgen.py index 0421efdbf9da..09e4010b0e53 100644 --- a/Lib/test/test_asyncgen.py +++ b/Lib/test/test_asyncgen.py @@ -2,7 +2,6 @@ import types import unittest import contextlib -import warnings from test.support.import_helper import import_module from test.support import gc_collect, requires_working_socket diff --git a/Lib/test/test_asyncio/test_ssl.py b/Lib/test/test_asyncio/test_ssl.py index aaf3c37101f5..e9cc735613fb 100644 --- a/Lib/test/test_asyncio/test_ssl.py +++ b/Lib/test/test_asyncio/test_ssl.py @@ -1,5 +1,4 @@ import asyncio -import asyncio.sslproto import contextlib import gc import logging diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index f1ad10a9903f..eba6e2d1f28f 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -1,5 +1,4 @@ import os -import shutil import signal import sys import unittest diff --git a/Lib/test/test_ctypes/test_callbacks.py b/Lib/test/test_ctypes/test_callbacks.py index e8fa3e6f7aca..b185e388ab15 100644 --- a/Lib/test/test_ctypes/test_callbacks.py +++ b/Lib/test/test_ctypes/test_callbacks.py @@ -1,4 +1,3 @@ -import sys import functools import unittest from test import support diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 81a36aa241ac..589f229f4623 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -2261,7 +2261,6 @@ def test_base_has_init(self): class B: def __init__(self): self.z = 100 - pass # Make sure that declaring this class doesn't raise an error. # The issue is that we can't override __init__ in our class, diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 0a2e0c14d268..2b14590b2c21 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -20,7 +20,6 @@ from test import support from test.support import ALWAYS_EQ from test.support import threading_helper -from textwrap import dedent from datetime import timedelta python_version = sys.version_info[:2] @@ -1187,7 +1186,6 @@ class MyEnum(HexInt, enum.Enum): # class SillyInt(HexInt): __qualname__ = 'SillyInt' - pass class MyOtherEnum(SillyInt, enum.Enum): __qualname__ = 'MyOtherEnum' D = 4 diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 5b946020994e..ced9000f75f2 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -3,7 +3,6 @@ from test.support import check_syntax_error from test.support import import_helper -from test.support.warnings_helper import check_syntax_warning import inspect import unittest import sys @@ -15,7 +14,6 @@ # with import machinery import test.ann_module as ann_module import typing -from collections import ChainMap from test import ann_module2 import test diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py index 5ead88579435..08cb5eb0c2bb 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py @@ -22,7 +22,6 @@ from test.support import os_helper from test.support import requires_resource from test.support import threading_helper -from test.support import warnings_helper from http.client import HTTPException diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 620a5b19109a..9ff6afcbadec 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -8,7 +8,6 @@ import re import socket import threading -import warnings import unittest from unittest import mock @@ -17,7 +16,6 @@ from test import support from test.support import os_helper from test.support import socket_helper -from test.support import warnings_helper support.requires_working_socket(module=True) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 7626d9572e1e..60f5b671b1da 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -13,7 +13,6 @@ from test.support import verbose, run_with_tz, run_with_locale, cpython_only from test.support import hashlib_helper from test.support import threading_helper -from test.support import warnings_helper import unittest from unittest import mock from datetime import datetime, timezone, timedelta @@ -751,7 +750,6 @@ class NonUTF8Server(SimpleIMAPHandler): typ, data = client.login('user', 'pass') self.assertEqual(typ, 'OK') client.enable('UTF8=ACCEPT') - pass @threading_helper.reap_threads def test_enable_UTF8_True_append(self): diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py index 2fcf6ebbee7e..bf9332e40aea 100644 --- a/Lib/test/test_isinstance.py +++ b/Lib/test/test_isinstance.py @@ -3,7 +3,6 @@ # testing of error conditions uncovered when using extension types. import unittest -import sys import typing from test import support diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py index 2ca3908bd1ca..699265ccadc7 100644 --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -6,7 +6,6 @@ from test import support import unittest -import pyexpat import xml.dom.minidom from xml.dom.minidom import parse, Attr, Node, Document, parseString diff --git a/Lib/test/test_peg_generator/test_c_parser.py b/Lib/test/test_peg_generator/test_c_parser.py index 1b3fcbb92f82..d34ffef0dbc5 100644 --- a/Lib/test/test_peg_generator/test_c_parser.py +++ b/Lib/test/test_peg_generator/test_c_parser.py @@ -24,7 +24,6 @@ generate_parser_c_extension, generate_c_parser_source, ) - from pegen.ast_dump import ast_dump TEST_TEMPLATE = """ diff --git a/Lib/test/test_shlex.py b/Lib/test/test_shlex.py index 92598dbbd5f2..797c91ee7eff 100644 --- a/Lib/test/test_shlex.py +++ b/Lib/test/test_shlex.py @@ -3,7 +3,6 @@ import shlex import string import unittest -from unittest import mock # The original test data set was from shellwords, by Hartmut Goebel. diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py index acae433cd0a5..49e076c77d16 100644 --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -2,7 +2,6 @@ import pprint import sys import unittest -from test import support class TestGetProfile(unittest.TestCase): diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index a251b2272e95..4907c930e143 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -2,7 +2,6 @@ from test import support import unittest -from unittest.mock import MagicMock import sys import difflib import gc diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 6fde93cbecc7..64c947270654 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -9,8 +9,7 @@ AbstractDefaultRootTest) from test.test_tkinter.widget_tests import ( add_standard_options, - AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, - setUpModule) + AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests) requires('gui') diff --git a/Lib/test/test_tools/test_sundry.py b/Lib/test/test_tools/test_sundry.py index 81f06763980a..6a3dc12781b2 100644 --- a/Lib/test/test_tools/test_sundry.py +++ b/Lib/test/test_tools/test_sundry.py @@ -6,7 +6,6 @@ """ import os -import sys import unittest from test.support import import_helper diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 95b1bae4f608..92c5a0005858 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -6,7 +6,6 @@ import sys import types import inspect -import importlib import builtins import unittest import re diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index 6f47ccb8e8b3..79d65b496abd 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -8,8 +8,7 @@ from test.test_tkinter.support import (AbstractTkTest, tcl_version, get_tk_patchlevel, simulate_mouse_click, AbstractDefaultRootTest) from test.test_tkinter.widget_tests import (add_standard_options, - AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests, - setUpModule) + AbstractWidgetTest, StandardOptionsTests, IntegerSizeTests, PixelSizeTests) requires('gui') @@ -50,7 +49,6 @@ def test_configure_style(self): widget2 = self.create(class_='Foo') self.assertEqual(widget2['class'], 'Foo') # XXX - pass class WidgetTest(AbstractTkTest, unittest.TestCase): diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index 74503c89e559..3dc0790ca15b 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -12,8 +12,7 @@ import unicodedata import unittest from test.support import (open_urlresource, requires_resource, script_helper, - cpython_only, check_disallow_instantiation, - ResourceDenied) + cpython_only, check_disallow_instantiation) class UnicodeMethodsTest(unittest.TestCase): diff --git a/Lib/test/test_unittest/test_loader.py b/Lib/test/test_unittest/test_loader.py index bbdfb247ebaa..a203145a791b 100644 --- a/Lib/test/test_unittest/test_loader.py +++ b/Lib/test/test_unittest/test_loader.py @@ -1,7 +1,6 @@ import functools import sys import types -import warnings import unittest diff --git a/Lib/test/test_wmi.py b/Lib/test/test_wmi.py index 3f5795952905..3445702846d8 100644 --- a/Lib/test/test_wmi.py +++ b/Lib/test/test_wmi.py @@ -1,7 +1,6 @@ # Test the internal _wmi module on Windows # This is used by the platform module, and potentially others -import sys import unittest from test.support import import_helper, requires_resource diff --git a/Lib/test/test_zipfile64.py b/Lib/test/test_zipfile64.py index be654a8478b0..2e1affe02528 100644 --- a/Lib/test/test_zipfile64.py +++ b/Lib/test/test_zipfile64.py @@ -11,7 +11,7 @@ 'test requires loads of disk-space bytes and a long time to run' ) -import zipfile, os, unittest +import zipfile, unittest import time import sys From webhook-mailer at python.org Wed Mar 8 08:58:54 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 08 Mar 2023 13:58:54 -0000 Subject: [Python-checkins] gh-102507 Remove invisible pagebreak characters (#102531) Message-ID: https://github.com/python/cpython/commit/b097925858c6975c73e989226cf278cc382c0416 commit: b097925858c6975c73e989226cf278cc382c0416 branch: main author: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> committer: AlexWaygood date: 2023-03-08T13:58:14Z summary: gh-102507 Remove invisible pagebreak characters (#102531) Co-authored-by: AlexWaygood files: M Lib/email/__init__.py M Lib/email/base64mime.py M Lib/email/charset.py M Lib/email/encoders.py M Lib/email/feedparser.py M Lib/email/generator.py M Lib/email/header.py M Lib/email/iterators.py M Lib/email/mime/base.py M Lib/email/mime/message.py M Lib/email/mime/multipart.py M Lib/email/mime/nonmultipart.py M Lib/email/mime/text.py M Lib/email/parser.py M Modules/_io/bufferedio.c M Tools/i18n/pygettext.py diff --git a/Lib/email/__init__.py b/Lib/email/__init__.py index fae872439edc..9fa477830041 100644 --- a/Lib/email/__init__.py +++ b/Lib/email/__init__.py @@ -25,7 +25,6 @@ ] - # Some convenience routines. Don't import Parser and Message as side-effects # of importing email since those cascadingly import most of the rest of the # email package. diff --git a/Lib/email/base64mime.py b/Lib/email/base64mime.py index a7cc37365c6f..4cdf22666e30 100644 --- a/Lib/email/base64mime.py +++ b/Lib/email/base64mime.py @@ -45,7 +45,6 @@ MISC_LEN = 7 - # Helpers def header_length(bytearray): """Return the length of s when it is encoded with base64.""" @@ -57,7 +56,6 @@ def header_length(bytearray): return n - def header_encode(header_bytes, charset='iso-8859-1'): """Encode a single header line with Base64 encoding in a given charset. @@ -72,7 +70,6 @@ def header_encode(header_bytes, charset='iso-8859-1'): return '=?%s?b?%s?=' % (charset, encoded) - def body_encode(s, maxlinelen=76, eol=NL): r"""Encode a string with base64. @@ -98,7 +95,6 @@ def body_encode(s, maxlinelen=76, eol=NL): return EMPTYSTRING.join(encvec) - def decode(string): """Decode a raw base64 string, returning a bytes object. diff --git a/Lib/email/charset.py b/Lib/email/charset.py index 791b6584b247..9af269442fb8 100644 --- a/Lib/email/charset.py +++ b/Lib/email/charset.py @@ -18,7 +18,6 @@ from email.encoders import encode_7or8bit - # Flags for types of header encodings QP = 1 # Quoted-Printable BASE64 = 2 # Base64 @@ -32,7 +31,6 @@ EMPTYSTRING = '' - # Defaults CHARSETS = { # input header enc body enc output conv @@ -104,7 +102,6 @@ } - # Convenience functions for extending the above mappings def add_charset(charset, header_enc=None, body_enc=None, output_charset=None): """Add character set properties to the global registry. @@ -153,7 +150,6 @@ def add_codec(charset, codecname): CODEC_MAP[charset] = codecname - # Convenience function for encoding strings, taking into account # that they might be unknown-8bit (ie: have surrogate-escaped bytes) def _encode(string, codec): @@ -163,7 +159,6 @@ def _encode(string, codec): return string.encode(codec) - class Charset: """Map character sets to their email properties. diff --git a/Lib/email/encoders.py b/Lib/email/encoders.py index 0a66acb6240b..17bd1ab7b19f 100644 --- a/Lib/email/encoders.py +++ b/Lib/email/encoders.py @@ -16,7 +16,6 @@ from quopri import encodestring as _encodestring - def _qencode(s): enc = _encodestring(s, quotetabs=True) # Must encode spaces, which quopri.encodestring() doesn't do @@ -34,7 +33,6 @@ def encode_base64(msg): msg['Content-Transfer-Encoding'] = 'base64' - def encode_quopri(msg): """Encode the message's payload in quoted-printable. @@ -46,7 +44,6 @@ def encode_quopri(msg): msg['Content-Transfer-Encoding'] = 'quoted-printable' - def encode_7or8bit(msg): """Set the Content-Transfer-Encoding header to 7bit or 8bit.""" orig = msg.get_payload(decode=True) @@ -64,6 +61,5 @@ def encode_7or8bit(msg): msg['Content-Transfer-Encoding'] = '7bit' - def encode_noop(msg): """Do nothing.""" diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py index 97d3f5144d60..6bc4e0c4e598 100644 --- a/Lib/email/feedparser.py +++ b/Lib/email/feedparser.py @@ -41,7 +41,6 @@ NeedMoreData = object() - class BufferedSubFile(object): """A file-ish object that can have new data loaded into it. @@ -132,7 +131,6 @@ def __next__(self): return line - class FeedParser: """A feed-style parser of email.""" diff --git a/Lib/email/generator.py b/Lib/email/generator.py index 885e6ba98540..7ccbe10eb768 100644 --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -22,7 +22,6 @@ fcre = re.compile(r'^From ', re.MULTILINE) - class Generator: """Generates output from a Message object tree. @@ -392,7 +391,7 @@ def _make_boundary(cls, text=None): def _compile_re(cls, s, flags): return re.compile(s, flags) - + class BytesGenerator(Generator): """Generates a bytes version of a Message object tree. @@ -443,7 +442,6 @@ def _compile_re(cls, s, flags): return re.compile(s.encode('ascii'), flags) - _FMT = '[Non-text (%(type)s) part of message omitted, filename %(filename)s]' class DecodedGenerator(Generator): @@ -503,7 +501,6 @@ def _dispatch(self, msg): }, file=self) - # Helper used by Generator._make_boundary _width = len(repr(sys.maxsize-1)) _fmt = '%%0%dd' % _width diff --git a/Lib/email/header.py b/Lib/email/header.py index 4ab0032bc661..984851a7d9a6 100644 --- a/Lib/email/header.py +++ b/Lib/email/header.py @@ -52,12 +52,10 @@ _embedded_header = re.compile(r'\n[^ \t]+:') - # Helpers _max_append = email.quoprimime._max_append - def decode_header(header): """Decode a message header value without converting charset. @@ -152,7 +150,6 @@ def decode_header(header): return collapsed - def make_header(decoded_seq, maxlinelen=None, header_name=None, continuation_ws=' '): """Create a Header from a sequence of pairs as returned by decode_header() @@ -175,7 +172,6 @@ def make_header(decoded_seq, maxlinelen=None, header_name=None, return h - class Header: def __init__(self, s=None, charset=None, maxlinelen=None, header_name=None, @@ -409,7 +405,6 @@ def _normalize(self): self._chunks = chunks - class _ValueFormatter: def __init__(self, headerlen, maxlen, continuation_ws, splitchars): self._maxlen = maxlen diff --git a/Lib/email/iterators.py b/Lib/email/iterators.py index b5502ee97526..3410935e38f4 100644 --- a/Lib/email/iterators.py +++ b/Lib/email/iterators.py @@ -15,7 +15,6 @@ from io import StringIO - # This function will become a method of the Message class def walk(self): """Walk over the message tree, yielding each subpart. @@ -29,7 +28,6 @@ def walk(self): yield from subpart.walk() - # These two functions are imported into the Iterators.py interface module. def body_line_iterator(msg, decode=False): """Iterate over the parts, returning string payloads line-by-line. @@ -55,7 +53,6 @@ def typed_subpart_iterator(msg, maintype='text', subtype=None): yield subpart - def _structure(msg, fp=None, level=0, include_default=False): """A handy debugging aid""" if fp is None: diff --git a/Lib/email/mime/base.py b/Lib/email/mime/base.py index 1a3f9b51f6c0..f601f621cec3 100644 --- a/Lib/email/mime/base.py +++ b/Lib/email/mime/base.py @@ -11,7 +11,6 @@ from email import message - class MIMEBase(message.Message): """Base class for MIME specializations.""" diff --git a/Lib/email/mime/message.py b/Lib/email/mime/message.py index 07e4f2d11961..61836b5a7861 100644 --- a/Lib/email/mime/message.py +++ b/Lib/email/mime/message.py @@ -10,7 +10,6 @@ from email.mime.nonmultipart import MIMENonMultipart - class MIMEMessage(MIMENonMultipart): """Class representing message/* MIME documents.""" diff --git a/Lib/email/mime/multipart.py b/Lib/email/mime/multipart.py index 2d3f288810dd..94d81c771a47 100644 --- a/Lib/email/mime/multipart.py +++ b/Lib/email/mime/multipart.py @@ -9,7 +9,6 @@ from email.mime.base import MIMEBase - class MIMEMultipart(MIMEBase): """Base class for MIME multipart/* type messages.""" diff --git a/Lib/email/mime/nonmultipart.py b/Lib/email/mime/nonmultipart.py index e1f51968b59e..a41386eb148c 100644 --- a/Lib/email/mime/nonmultipart.py +++ b/Lib/email/mime/nonmultipart.py @@ -10,7 +10,6 @@ from email.mime.base import MIMEBase - class MIMENonMultipart(MIMEBase): """Base class for MIME non-multipart type messages.""" diff --git a/Lib/email/mime/text.py b/Lib/email/mime/text.py index 35b442383002..dfe53c426b2a 100644 --- a/Lib/email/mime/text.py +++ b/Lib/email/mime/text.py @@ -10,7 +10,6 @@ from email.mime.nonmultipart import MIMENonMultipart - class MIMEText(MIMENonMultipart): """Class for generating text/* type MIME documents.""" diff --git a/Lib/email/parser.py b/Lib/email/parser.py index e94d455baa52..06d99b17f2f9 100644 --- a/Lib/email/parser.py +++ b/Lib/email/parser.py @@ -64,7 +64,6 @@ def parsestr(self, text, headersonly=False): return self.parse(StringIO(text), headersonly=headersonly) - class HeaderParser(Parser): def parse(self, fp, headersonly=True): return Parser.parse(self, fp, True) @@ -72,7 +71,7 @@ def parse(self, fp, headersonly=True): def parsestr(self, text, headersonly=True): return Parser.parsestr(self, text, True) - + class BytesParser: def __init__(self, *args, **kw): diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 960026707fc5..2c71768be978 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1742,7 +1742,6 @@ _bufferedreader_peek_unlocked(buffered *self) self->pos = 0; return PyBytes_FromStringAndSize(self->buffer, r); } - /* @@ -2052,7 +2051,6 @@ _io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer) LEAVE_BUFFERED(self) return res; } - /* @@ -2266,7 +2264,6 @@ bufferedrwpair_closed_get(rwpair *self, void *context) } return PyObject_GetAttr((PyObject *) self->writer, &_Py_ID(closed)); } - /* diff --git a/Tools/i18n/pygettext.py b/Tools/i18n/pygettext.py index 7ada79105db1..3a0b27ba420e 100755 --- a/Tools/i18n/pygettext.py +++ b/Tools/i18n/pygettext.py @@ -174,7 +174,6 @@ EMPTYSTRING = '' - # The normal pot-file header. msgmerge and Emacs's po-mode work better if it's # there. pot_header = _('''\ @@ -196,7 +195,7 @@ ''') - + def usage(code, msg=''): print(__doc__ % globals(), file=sys.stderr) if msg: @@ -204,7 +203,6 @@ def usage(code, msg=''): sys.exit(code) - def make_escapes(pass_nonascii): global escapes, escape if pass_nonascii: @@ -258,7 +256,7 @@ def normalize(s, encoding): s = '""\n"' + lineterm.join(lines) + '"' return s - + def containsAny(str, set): """Check whether 'str' contains ANY of the chars in 'set'""" return 1 in [c in str for c in set] @@ -307,7 +305,7 @@ def getFilesForName(name): return [] - + class TokenEater: def __init__(self, options): self.__options = options @@ -515,7 +513,6 @@ def write(self, fp): print('msgstr ""\n', file=fp) - def main(): global default_keywords try: @@ -675,7 +672,7 @@ class Options: if closep: fp.close() - + if __name__ == '__main__': main() # some more test strings From webhook-mailer at python.org Wed Mar 8 12:03:36 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 08 Mar 2023 17:03:36 -0000 Subject: [Python-checkins] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (in Objects/) (#102218) Message-ID: https://github.com/python/cpython/commit/11a2c6ce516b24b2435cb627742a6c4df92d411c commit: 11a2c6ce516b24b2435cb627742a6c4df92d411c branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-08T17:03:18Z summary: gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (in Objects/) (#102218) files: M Objects/dictobject.c M Objects/exceptions.c M Objects/frameobject.c M Objects/genobject.c M Objects/object.c M Objects/odictobject.c M Objects/typeobject.c M Objects/weakrefobject.c diff --git a/Objects/dictobject.c b/Objects/dictobject.c index e3795e75e3da..75c92172a917 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -119,7 +119,7 @@ As a consequence of this, split keys have a maximum size of 16. #include "pycore_dict.h" // PyDictKeysObject #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() #include "pycore_object.h" // _PyObject_GC_TRACK() -#include "pycore_pyerrors.h" // _PyErr_Fetch() +#include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyThreadState_GET() #include "stringlib/eq.h" // unicode_eq() diff --git a/Objects/exceptions.c b/Objects/exceptions.c index a473cbdfeda7..c6fb6a3f19b2 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3781,16 +3781,13 @@ PyObject * _PyErr_TrySetFromCause(const char *format, ...) { PyObject* msg_prefix; - PyObject *exc, *val, *tb; - PyTypeObject *caught_type; PyObject *instance_args; Py_ssize_t num_args, caught_type_size, base_exc_size; - PyObject *new_exc, *new_val, *new_tb; va_list vargs; int same_basic_size; - PyErr_Fetch(&exc, &val, &tb); - caught_type = (PyTypeObject *)exc; + PyObject *exc = PyErr_GetRaisedException(); + PyTypeObject *caught_type = Py_TYPE(exc); /* Ensure type info indicates no extra state is stored at the C level * and that the type can be reinstantiated using PyErr_Format */ @@ -3810,31 +3807,30 @@ _PyErr_TrySetFromCause(const char *format, ...) * more state than just the exception type. Accordingly, we just * leave it alone. */ - PyErr_Restore(exc, val, tb); + PyErr_SetRaisedException(exc); return NULL; } /* Check the args are empty or contain a single string */ - PyErr_NormalizeException(&exc, &val, &tb); - instance_args = ((PyBaseExceptionObject *)val)->args; + instance_args = ((PyBaseExceptionObject *)exc)->args; num_args = PyTuple_GET_SIZE(instance_args); if (num_args > 1 || (num_args == 1 && !PyUnicode_CheckExact(PyTuple_GET_ITEM(instance_args, 0)))) { /* More than 1 arg, or the one arg we do have isn't a string */ - PyErr_Restore(exc, val, tb); + PyErr_SetRaisedException(exc); return NULL; } /* Ensure the instance dict is also empty */ - if (!_PyObject_IsInstanceDictEmpty(val)) { + if (!_PyObject_IsInstanceDictEmpty(exc)) { /* While we could potentially copy a non-empty instance dictionary * to the replacement exception, for now we take the more * conservative path of leaving exceptions with attributes set * alone. */ - PyErr_Restore(exc, val, tb); + PyErr_SetRaisedException(exc); return NULL; } @@ -3847,28 +3843,19 @@ _PyErr_TrySetFromCause(const char *format, ...) * types as well, but that's quite a bit trickier due to the extra * state potentially stored on OSError instances. */ - /* Ensure the traceback is set correctly on the existing exception */ - if (tb != NULL) { - PyException_SetTraceback(val, tb); - Py_DECREF(tb); - } - va_start(vargs, format); msg_prefix = PyUnicode_FromFormatV(format, vargs); va_end(vargs); if (msg_prefix == NULL) { Py_DECREF(exc); - Py_DECREF(val); return NULL; } - PyErr_Format(exc, "%U (%s: %S)", - msg_prefix, Py_TYPE(val)->tp_name, val); - Py_DECREF(exc); + PyErr_Format((PyObject*)Py_TYPE(exc), "%U (%s: %S)", + msg_prefix, Py_TYPE(exc)->tp_name, exc); Py_DECREF(msg_prefix); - PyErr_Fetch(&new_exc, &new_val, &new_tb); - PyErr_NormalizeException(&new_exc, &new_val, &new_tb); - PyException_SetCause(new_val, val); - PyErr_Restore(new_exc, new_val, new_tb); - return new_val; + PyObject *new_exc = PyErr_GetRaisedException(); + PyException_SetCause(new_exc, exc); + PyErr_SetRaisedException(new_exc); + return new_exc; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 34143c9a40b2..133c991bf701 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1308,7 +1308,6 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear) /* Merge locals into fast locals */ PyObject *locals; PyObject **fast; - PyObject *error_type, *error_value, *error_traceback; PyCodeObject *co; locals = frame->f_locals; if (locals == NULL) { @@ -1317,7 +1316,7 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear) fast = _PyFrame_GetLocalsArray(frame); co = frame->f_code; - PyErr_Fetch(&error_type, &error_value, &error_traceback); + PyObject *exc = PyErr_GetRaisedException(); for (int i = 0; i < co->co_nlocalsplus; i++) { _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i); @@ -1374,7 +1373,7 @@ _PyFrame_LocalsToFast(_PyInterpreterFrame *frame, int clear) } Py_XDECREF(value); } - PyErr_Restore(error_type, error_value, error_traceback); + PyErr_SetRaisedException(exc); } void diff --git a/Objects/genobject.c b/Objects/genobject.c index be08a59ece6b..61463774310f 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -69,8 +69,6 @@ void _PyGen_Finalize(PyObject *self) { PyGenObject *gen = (PyGenObject *)self; - PyObject *res = NULL; - PyObject *error_type, *error_value, *error_traceback; if (gen->gi_frame_state >= FRAME_COMPLETED) { /* Generator isn't paused, so no need to close */ @@ -82,23 +80,22 @@ _PyGen_Finalize(PyObject *self) PyObject *finalizer = agen->ag_origin_or_finalizer; if (finalizer && !agen->ag_closed) { /* Save the current exception, if any. */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - res = PyObject_CallOneArg(finalizer, self); + PyObject *exc = PyErr_GetRaisedException(); + PyObject *res = PyObject_CallOneArg(finalizer, self); if (res == NULL) { PyErr_WriteUnraisable(self); } else { Py_DECREF(res); } /* Restore the saved exception. */ - PyErr_Restore(error_type, error_value, error_traceback); + PyErr_SetRaisedException(exc); return; } } /* Save the current exception, if any. */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); + PyObject *exc = PyErr_GetRaisedException(); /* If `gen` is a coroutine, and if it was never awaited on, issue a RuntimeWarning. */ @@ -109,20 +106,19 @@ _PyGen_Finalize(PyObject *self) _PyErr_WarnUnawaitedCoroutine((PyObject *)gen); } else { - res = gen_close(gen, NULL); - } - - if (res == NULL) { - if (PyErr_Occurred()) { - PyErr_WriteUnraisable(self); + PyObject *res = gen_close(gen, NULL); + if (res == NULL) { + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(self); + } + } + else { + Py_DECREF(res); } - } - else { - Py_DECREF(res); } /* Restore the saved exception. */ - PyErr_Restore(error_type, error_value, error_traceback); + PyErr_SetRaisedException(exc); } static void @@ -648,39 +644,11 @@ _PyGen_SetStopIterationValue(PyObject *value) int _PyGen_FetchStopIterationValue(PyObject **pvalue) { - PyObject *et, *ev, *tb; PyObject *value = NULL; - if (PyErr_ExceptionMatches(PyExc_StopIteration)) { - PyErr_Fetch(&et, &ev, &tb); - if (ev) { - /* exception will usually be normalised already */ - if (PyObject_TypeCheck(ev, (PyTypeObject *) et)) { - value = Py_NewRef(((PyStopIterationObject *)ev)->value); - Py_DECREF(ev); - } else if (et == PyExc_StopIteration && !PyTuple_Check(ev)) { - /* Avoid normalisation and take ev as value. - * - * Normalization is required if the value is a tuple, in - * that case the value of StopIteration would be set to - * the first element of the tuple. - * - * (See _PyErr_CreateException code for details.) - */ - value = ev; - } else { - /* normalisation required */ - PyErr_NormalizeException(&et, &ev, &tb); - if (!PyObject_TypeCheck(ev, (PyTypeObject *)PyExc_StopIteration)) { - PyErr_Restore(et, ev, tb); - return -1; - } - value = Py_NewRef(((PyStopIterationObject *)ev)->value); - Py_DECREF(ev); - } - } - Py_XDECREF(et); - Py_XDECREF(tb); + PyObject *exc = PyErr_GetRaisedException(); + value = Py_NewRef(((PyStopIterationObject *)exc)->value); + Py_DECREF(exc); } else if (PyErr_Occurred()) { return -1; } diff --git a/Objects/object.c b/Objects/object.c index 446c7b1f5f03..5db2b6af21ef 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -370,13 +370,12 @@ _PyObject_Dump(PyObject* op) fflush(stderr); PyGILState_STATE gil = PyGILState_Ensure(); - PyObject *error_type, *error_value, *error_traceback; - PyErr_Fetch(&error_type, &error_value, &error_traceback); + PyObject *exc = PyErr_GetRaisedException(); (void)PyObject_Print(op, stderr, 0); fflush(stderr); - PyErr_Restore(error_type, error_value, error_traceback); + PyErr_SetRaisedException(exc); PyGILState_Release(gil); fprintf(stderr, "\n"); @@ -860,25 +859,22 @@ set_attribute_error_context(PyObject* v, PyObject* name) return 0; } // Intercept AttributeError exceptions and augment them to offer suggestions later. - PyObject *type, *value, *traceback; - PyErr_Fetch(&type, &value, &traceback); - PyErr_NormalizeException(&type, &value, &traceback); - // Check if the normalized exception is indeed an AttributeError - if (!PyErr_GivenExceptionMatches(value, PyExc_AttributeError)) { + PyObject *exc = PyErr_GetRaisedException(); + if (!PyErr_GivenExceptionMatches(exc, PyExc_AttributeError)) { goto restore; } - PyAttributeErrorObject* the_exc = (PyAttributeErrorObject*) value; + PyAttributeErrorObject* the_exc = (PyAttributeErrorObject*) exc; // Check if this exception was already augmented if (the_exc->name || the_exc->obj) { goto restore; } // Augment the exception with the name and object - if (PyObject_SetAttr(value, &_Py_ID(name), name) || - PyObject_SetAttr(value, &_Py_ID(obj), v)) { + if (PyObject_SetAttr(exc, &_Py_ID(name), name) || + PyObject_SetAttr(exc, &_Py_ID(obj), v)) { return 1; } restore: - PyErr_Restore(type, value, traceback); + PyErr_SetRaisedException(exc); return 0; } @@ -2190,9 +2186,8 @@ Py_ReprLeave(PyObject *obj) PyObject *dict; PyObject *list; Py_ssize_t i; - PyObject *error_type, *error_value, *error_traceback; - PyErr_Fetch(&error_type, &error_value, &error_traceback); + PyObject *exc = PyErr_GetRaisedException(); dict = PyThreadState_GetDict(); if (dict == NULL) @@ -2213,7 +2208,7 @@ Py_ReprLeave(PyObject *obj) finally: /* ignore exceptions because there is no way to report them. */ - PyErr_Restore(error_type, error_value, error_traceback); + PyErr_SetRaisedException(exc); } /* Trashcan support. */ diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 215a8af54fb2..39b0f6845105 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1556,10 +1556,9 @@ _PyODict_SetItem_KnownHash(PyObject *od, PyObject *key, PyObject *value, res = _odict_add_new_node((PyODictObject *)od, key, hash); if (res < 0) { /* Revert setting the value on the dict */ - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); + PyObject *exc = PyErr_GetRaisedException(); (void) _PyDict_DelItem_KnownHash(od, key, hash); - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_ChainExceptions1(exc); } } return res; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 981930f58417..f486b83fd69e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4397,10 +4397,9 @@ static void type_dealloc_common(PyTypeObject *type) { if (type->tp_bases != NULL) { - PyObject *tp, *val, *tb; - PyErr_Fetch(&tp, &val, &tb); + PyObject *exc = PyErr_GetRaisedException(); remove_all_subclasses(type, type->tp_bases); - PyErr_Restore(tp, val, tb); + PyErr_SetRaisedException(exc); } } @@ -8445,10 +8444,9 @@ slot_tp_finalize(PyObject *self) { int unbound; PyObject *del, *res; - PyObject *error_type, *error_value, *error_traceback; /* Save the current exception, if any. */ - PyErr_Fetch(&error_type, &error_value, &error_traceback); + PyObject *exc = PyErr_GetRaisedException(); /* Execute __del__ method, if any. */ del = lookup_maybe_method(self, &_Py_ID(__del__), &unbound); @@ -8462,7 +8460,7 @@ slot_tp_finalize(PyObject *self) } /* Restore the saved exception. */ - PyErr_Restore(error_type, error_value, error_traceback); + PyErr_SetRaisedException(exc); } static PyObject * diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index bd7720e27533..5a3e49a6fe45 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -959,9 +959,8 @@ PyObject_ClearWeakRefs(PyObject *object) if (*list != NULL) { PyWeakReference *current = *list; Py_ssize_t count = _PyWeakref_GetWeakrefCount(current); - PyObject *err_type, *err_value, *err_tb; + PyObject *exc = PyErr_GetRaisedException(); - PyErr_Fetch(&err_type, &err_value, &err_tb); if (count == 1) { PyObject *callback = current->wr_callback; @@ -980,7 +979,7 @@ PyObject_ClearWeakRefs(PyObject *object) tuple = PyTuple_New(count * 2); if (tuple == NULL) { - _PyErr_ChainExceptions(err_type, err_value, err_tb); + _PyErr_ChainExceptions1(exc); return; } @@ -1010,7 +1009,7 @@ PyObject_ClearWeakRefs(PyObject *object) Py_DECREF(tuple); } assert(!PyErr_Occurred()); - PyErr_Restore(err_type, err_value, err_tb); + PyErr_SetRaisedException(exc); } } From webhook-mailer at python.org Wed Mar 8 14:03:58 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 08 Mar 2023 19:03:58 -0000 Subject: [Python-checkins] gh-102304: Consolidate Direct Usage of _Py_RefTotal (gh-102514) Message-ID: https://github.com/python/cpython/commit/cbb0aa71d040022db61390380b8aebc7c04f3275 commit: cbb0aa71d040022db61390380b8aebc7c04f3275 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-08T12:03:50-07:00 summary: gh-102304: Consolidate Direct Usage of _Py_RefTotal (gh-102514) This simplifies further changes to _Py_RefTotal (e.g. make it atomic or move it to PyInterpreterState). https://github.com/python/cpython/issues/102304 files: M Include/cpython/object.h M Include/internal/pycore_object.h M Include/object.h M Modules/_testcapimodule.c M Objects/bytesobject.c M Objects/dictobject.c M Objects/object.c M Objects/structseq.c M Objects/tupleobject.c M Objects/unicodeobject.c diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 3f26f2487d70..7b687d311359 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -3,6 +3,7 @@ #endif PyAPI_FUNC(void) _Py_NewReference(PyObject *op); +PyAPI_FUNC(void) _Py_NewReferenceNoTotal(PyObject *op); #ifdef Py_TRACE_REFS /* Py_TRACE_REFS is such major surgery that we call external routines. */ diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 8796dfe2f6b8..e15685f174eb 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -37,11 +37,23 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc( #define _Py_FatalRefcountError(message) \ _Py_FatalRefcountErrorFunc(__func__, (message)) + +#ifdef Py_REF_DEBUG +/* The symbol is only exposed in the API for the sake of extensions + built against the pre-3.12 stable ABI. */ +PyAPI_DATA(Py_ssize_t) _Py_RefTotal; + +extern void _Py_AddRefTotal(Py_ssize_t); +extern void _Py_IncRefTotal(void); +extern void _Py_DecRefTotal(void); +# define _Py_DEC_REFTOTAL() _Py_RefTotal-- +#endif + // Increment reference count by n static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) { #ifdef Py_REF_DEBUG - _Py_RefTotal += n; + _Py_AddRefTotal(n); #endif op->ob_refcnt += n; } @@ -52,7 +64,7 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) { _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG - _Py_RefTotal--; + _Py_DEC_REFTOTAL(); #endif if (--op->ob_refcnt != 0) { assert(op->ob_refcnt > 0); @@ -70,7 +82,7 @@ _Py_DECREF_NO_DEALLOC(PyObject *op) { _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG - _Py_RefTotal--; + _Py_DEC_REFTOTAL(); #endif op->ob_refcnt--; #ifdef Py_DEBUG @@ -80,6 +92,11 @@ _Py_DECREF_NO_DEALLOC(PyObject *op) #endif } +#ifdef Py_REF_DEBUG +# undef _Py_DEC_REFTOTAL +#endif + + PyAPI_FUNC(int) _PyType_CheckConsistency(PyTypeObject *type); PyAPI_FUNC(int) _PyDict_CheckConsistency(PyObject *mp, int check_content); diff --git a/Include/object.h b/Include/object.h index 3774f1267300..844b9c4a51c3 100644 --- a/Include/object.h +++ b/Include/object.h @@ -490,7 +490,21 @@ you can count such references to the type object.) */ #ifdef Py_REF_DEBUG -PyAPI_DATA(Py_ssize_t) _Py_RefTotal; +# if defined(Py_LIMITED_API) && Py_LIMITED_API+0 < 0x030A0000 +extern Py_ssize_t _Py_RefTotal; +# define _Py_INC_REFTOTAL() _Py_RefTotal++ +# define _Py_DEC_REFTOTAL() _Py_RefTotal-- +# elif defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +extern void _Py_IncRefTotal(void); +extern void _Py_DecRefTotal(void); +# define _Py_INC_REFTOTAL() _Py_IncRefTotal() +# define _Py_DEC_REFTOTAL() _Py_DecRefTotal() +# elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 > 0x030C0000 +extern void _Py_IncRefTotal_DO_NOT_USE_THIS(void); +extern void _Py_DecRefTotal_DO_NOT_USE_THIS(void); +# define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS() +# define _Py_DEC_REFTOTAL() _Py_DecRefTotal_DO_NOT_USE_THIS() +# endif PyAPI_FUNC(void) _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op); #endif /* Py_REF_DEBUG */ @@ -519,8 +533,8 @@ static inline void Py_INCREF(PyObject *op) // Non-limited C API and limited C API for Python 3.9 and older access // directly PyObject.ob_refcnt. #ifdef Py_REF_DEBUG - _Py_RefTotal++; -#endif + _Py_INC_REFTOTAL(); +#endif // Py_REF_DEBUG op->ob_refcnt++; #endif } @@ -539,7 +553,7 @@ static inline void Py_DECREF(PyObject *op) { static inline void Py_DECREF(const char *filename, int lineno, PyObject *op) { _Py_DECREF_STAT_INC(); - _Py_RefTotal--; + _Py_DEC_REFTOTAL(); if (--op->ob_refcnt != 0) { if (op->ob_refcnt < 0) { _Py_NegativeRefcount(filename, lineno, op); @@ -564,6 +578,9 @@ static inline void Py_DECREF(PyObject *op) #define Py_DECREF(op) Py_DECREF(_PyObject_CAST(op)) #endif +#undef _Py_INC_REFTOTAL +#undef _Py_DEC_REFTOTAL + /* Safely decref `op` and set `op` to NULL, especially useful in tp_clear * and tp_dealloc implementations. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 10e507d6b481..ea67017a1ba3 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1654,15 +1654,10 @@ slot_tp_del(PyObject *self) */ { Py_ssize_t refcnt = Py_REFCNT(self); - _Py_NewReference(self); + _Py_NewReferenceNoTotal(self); Py_SET_REFCNT(self, refcnt); } assert(!PyType_IS_GC(Py_TYPE(self)) || PyObject_GC_IsTracked(self)); - /* If Py_REF_DEBUG macro is defined, _Py_NewReference() increased - _Py_RefTotal, so we need to undo that. */ -#ifdef Py_REF_DEBUG - _Py_RefTotal--; -#endif } static PyObject * diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 657443f31fa7..687a654bdae1 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3060,21 +3060,20 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) Py_DECREF(v); return 0; } - /* XXX UNREF/NEWREF interface should be more symmetrical */ -#ifdef Py_REF_DEBUG - _Py_RefTotal--; -#endif #ifdef Py_TRACE_REFS _Py_ForgetReference(v); #endif *pv = (PyObject *) PyObject_Realloc(v, PyBytesObject_SIZE + newsize); if (*pv == NULL) { +#ifdef Py_REF_DEBUG + _Py_DecRefTotal(); +#endif PyObject_Free(v); PyErr_NoMemory(); return -1; } - _Py_NewReference(*pv); + _Py_NewReferenceNoTotal(*pv); sv = (PyBytesObject *) *pv; Py_SET_SIZE(sv, newsize); sv->ob_sval[newsize] = '\0'; diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 75c92172a917..a60f275742a5 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -303,7 +303,7 @@ static inline void dictkeys_incref(PyDictKeysObject *dk) { #ifdef Py_REF_DEBUG - _Py_RefTotal++; + _Py_IncRefTotal(); #endif dk->dk_refcnt++; } @@ -313,7 +313,7 @@ dictkeys_decref(PyDictKeysObject *dk) { assert(dk->dk_refcnt > 0); #ifdef Py_REF_DEBUG - _Py_RefTotal--; + _Py_DecRefTotal(); #endif if (--dk->dk_refcnt == 0) { free_keys_object(dk); @@ -633,7 +633,7 @@ new_keys_object(uint8_t log2_size, bool unicode) } } #ifdef Py_REF_DEBUG - _Py_RefTotal++; + _Py_IncRefTotal(); #endif dk->dk_refcnt = 1; dk->dk_log2_size = log2_size; @@ -821,7 +821,7 @@ clone_combined_dict_keys(PyDictObject *orig) we have it now; calling dictkeys_incref would be an error as keys->dk_refcnt is already set to 1 (after memcpy). */ #ifdef Py_REF_DEBUG - _Py_RefTotal++; + _Py_IncRefTotal(); #endif return keys; } @@ -1520,7 +1520,7 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize, int unicode) // We can not use free_keys_object here because key's reference // are moved already. #ifdef Py_REF_DEBUG - _Py_RefTotal--; + _Py_DecRefTotal(); #endif if (oldkeys == Py_EMPTY_KEYS) { oldkeys->dk_refcnt--; diff --git a/Objects/object.c b/Objects/object.c index 5db2b6af21ef..38da4d497a96 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -56,6 +56,24 @@ _PyObject_CheckConsistency(PyObject *op, int check_content) #ifdef Py_REF_DEBUG Py_ssize_t _Py_RefTotal; +static inline void +reftotal_increment(void) +{ + _Py_RefTotal++; +} + +static inline void +reftotal_decrement(void) +{ + _Py_RefTotal--; +} + +void +_Py_AddRefTotal(Py_ssize_t n) +{ + _Py_RefTotal += n; +} + Py_ssize_t _Py_GetRefTotal(void) { @@ -121,6 +139,32 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op) filename, lineno, __func__); } +/* This is exposed strictly for use in Py_INCREF(). */ +PyAPI_FUNC(void) +_Py_IncRefTotal_DO_NOT_USE_THIS(void) +{ + reftotal_increment(); +} + +/* This is exposed strictly for use in Py_DECREF(). */ +PyAPI_FUNC(void) +_Py_DecRefTotal_DO_NOT_USE_THIS(void) +{ + reftotal_decrement(); +} + +void +_Py_IncRefTotal(void) +{ + reftotal_increment(); +} + +void +_Py_DecRefTotal(void) +{ + reftotal_decrement(); +} + #endif /* Py_REF_DEBUG */ void @@ -138,12 +182,18 @@ Py_DecRef(PyObject *o) void _Py_IncRef(PyObject *o) { +#ifdef Py_REF_DEBUG + reftotal_increment(); +#endif Py_INCREF(o); } void _Py_DecRef(PyObject *o) { +#ifdef Py_REF_DEBUG + reftotal_decrement(); +#endif Py_DECREF(o); } @@ -238,17 +288,12 @@ PyObject_CallFinalizerFromDealloc(PyObject *self) /* tp_finalize resurrected it! Make it look like the original Py_DECREF * never happened. */ Py_ssize_t refcnt = Py_REFCNT(self); - _Py_NewReference(self); + _Py_NewReferenceNoTotal(self); Py_SET_REFCNT(self, refcnt); _PyObject_ASSERT(self, (!_PyType_IS_GC(Py_TYPE(self)) || _PyObject_GC_IS_TRACKED(self))); - /* If Py_REF_DEBUG macro is defined, _Py_NewReference() increased - _Py_RefTotal, so we need to undo that. */ -#ifdef Py_REF_DEBUG - _Py_RefTotal--; -#endif return -1; } @@ -2010,21 +2055,33 @@ _PyTypes_FiniTypes(PyInterpreterState *interp) } -void -_Py_NewReference(PyObject *op) +static inline void +new_reference(PyObject *op) { if (_PyRuntime.tracemalloc.config.tracing) { _PyTraceMalloc_NewReference(op); } -#ifdef Py_REF_DEBUG - _Py_RefTotal++; -#endif Py_SET_REFCNT(op, 1); #ifdef Py_TRACE_REFS _Py_AddToAllObjects(op, 1); #endif } +void +_Py_NewReference(PyObject *op) +{ +#ifdef Py_REF_DEBUG + reftotal_increment(); +#endif + new_reference(op); +} + +void +_Py_NewReferenceNoTotal(PyObject *op) +{ + new_reference(op); +} + #ifdef Py_TRACE_REFS void diff --git a/Objects/structseq.c b/Objects/structseq.c index 100ccfef0a23..c20962ecd825 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -592,7 +592,7 @@ _PyStructSequence_FiniType(PyTypeObject *type) // Don't use Py_DECREF(): static type must not be deallocated Py_SET_REFCNT(type, 0); #ifdef Py_REF_DEBUG - _Py_RefTotal--; + _Py_DecRefTotal(); #endif // Make sure that _PyStructSequence_InitType() will initialize diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 6ee93ab5adc2..59c0251639d3 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -930,10 +930,6 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) return *pv == NULL ? -1 : 0; } - /* XXX UNREF/NEWREF interface should be more symmetrical */ -#ifdef Py_REF_DEBUG - _Py_RefTotal--; -#endif if (_PyObject_GC_IS_TRACKED(v)) { _PyObject_GC_UNTRACK(v); } @@ -947,10 +943,13 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) sv = PyObject_GC_Resize(PyTupleObject, v, newsize); if (sv == NULL) { *pv = NULL; +#ifdef Py_REF_DEBUG + _Py_DecRefTotal(); +#endif PyObject_GC_Del(v); return -1; } - _Py_NewReference((PyObject *) sv); + _Py_NewReferenceNoTotal((PyObject *) sv); /* Zero out items added by growing */ if (newsize > oldsize) memset(&sv->ob_item[oldsize], 0, diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 1ba30421c66d..2d50f9c340f2 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -947,21 +947,18 @@ resize_compact(PyObject *unicode, Py_ssize_t length) _PyUnicode_UTF8(unicode) = NULL; _PyUnicode_UTF8_LENGTH(unicode) = 0; } -#ifdef Py_REF_DEBUG - _Py_RefTotal--; -#endif #ifdef Py_TRACE_REFS _Py_ForgetReference(unicode); #endif new_unicode = (PyObject *)PyObject_Realloc(unicode, new_size); if (new_unicode == NULL) { - _Py_NewReference(unicode); + _Py_NewReferenceNoTotal(unicode); PyErr_NoMemory(); return NULL; } unicode = new_unicode; - _Py_NewReference(unicode); + _Py_NewReferenceNoTotal(unicode); _PyUnicode_LENGTH(unicode) = length; #ifdef Py_DEBUG From webhook-mailer at python.org Wed Mar 8 17:56:43 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 08 Mar 2023 22:56:43 -0000 Subject: [Python-checkins] gh-100227: Move func_state.next_version to PyInterpreterState (gh-102334) Message-ID: https://github.com/python/cpython/commit/66ff374d4f353ae427c148d2a1d141d223303a82 commit: 66ff374d4f353ae427c148d2a1d141d223303a82 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-08T15:56:36-07:00 summary: gh-100227: Move func_state.next_version to PyInterpreterState (gh-102334) https://github.com/python/cpython/issues/100227 files: M Include/internal/pycore_function.h M Include/internal/pycore_interp.h M Include/internal/pycore_runtime.h M Include/internal/pycore_runtime_init.h M Objects/funcobject.c diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index 5cedb33d7e3a..11988149843f 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -10,7 +10,7 @@ extern "C" { #define FUNC_MAX_WATCHERS 8 -struct _py_func_runtime_state { +struct _py_func_state { uint32_t next_version; }; diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 7ef9c40153e4..9efed0a1cf90 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -141,6 +141,7 @@ struct _is { struct _Py_float_state float_state; struct _Py_long_state long_state; struct _dtoa_state dtoa; + struct _py_func_state func_state; /* Using a cache is very effective since typically only a single slice is created and then deleted again. */ PySliceObject *slice_cache; diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 2350eaab5976..e0e3d4ace0cf 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -13,7 +13,6 @@ extern "C" { #include "pycore_dict_state.h" // struct _Py_dict_runtime_state #include "pycore_floatobject.h" // struct _Py_float_runtime_state #include "pycore_faulthandler.h" // struct _faulthandler_runtime_state -#include "pycore_function.h" // struct _func_runtime_state #include "pycore_global_objects.h" // struct _Py_global_objects #include "pycore_import.h" // struct _import_runtime_state #include "pycore_interp.h" // PyInterpreterState @@ -155,7 +154,6 @@ typedef struct pyruntimestate { struct _Py_float_runtime_state float_state; struct _Py_unicode_runtime_state unicode_state; struct _Py_dict_runtime_state dict_state; - struct _py_func_runtime_state func_state; struct { /* Used to set PyTypeObject.tp_version_tag */ diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index a2cc7c87c2f3..aeabcfd2b905 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -68,9 +68,6 @@ extern PyTypeObject _PyExc_MemoryError; .dict_state = { \ .next_keys_version = 2, \ }, \ - .func_state = { \ - .next_version = 1, \ - }, \ .types = { \ .next_version_tag = 1, \ }, \ @@ -116,6 +113,9 @@ extern PyTypeObject _PyExc_MemoryError; }, \ }, \ .dtoa = _dtoa_state_INIT(&(INTERP)), \ + .func_state = { \ + .next_version = 1, \ + }, \ .static_objects = { \ .singletons = { \ ._not_used = 1, \ diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 99048ea41c6c..ce5d7bda32c0 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -227,10 +227,11 @@ uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func) if (func->vectorcall != _PyFunction_Vectorcall) { return 0; } - if (_PyRuntime.func_state.next_version == 0) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (interp->func_state.next_version == 0) { return 0; } - uint32_t v = _PyRuntime.func_state.next_version++; + uint32_t v = interp->func_state.next_version++; func->func_version = v; return v; } From webhook-mailer at python.org Wed Mar 8 20:04:52 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 09 Mar 2023 01:04:52 -0000 Subject: [Python-checkins] gh-100227: Move next_keys_version to PyInterpreterState (gh-102335) Message-ID: https://github.com/python/cpython/commit/5e5acd291f4387876afc641163e9f8ae5c65086c commit: 5e5acd291f4387876afc641163e9f8ae5c65086c branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-08T18:04:16-07:00 summary: gh-100227: Move next_keys_version to PyInterpreterState (gh-102335) https://github.com/python/cpython/issues/100227 files: M Include/internal/pycore_dict.h M Include/internal/pycore_dict_state.h M Include/internal/pycore_runtime_init.h M Objects/dictobject.c M Python/specialize.c diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 1af5e59a677a..12c3c708e29b 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -37,7 +37,8 @@ extern PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); /* Gets a version number unique to the current state of the keys of dict, if possible. * Returns the version number, or zero if it was not possible to get a version number. */ -extern uint32_t _PyDictKeys_GetVersionForCurrentState(PyDictKeysObject *dictkeys); +extern uint32_t _PyDictKeys_GetVersionForCurrentState( + PyInterpreterState *interp, PyDictKeysObject *dictkeys); extern size_t _PyDict_KeysSize(PyDictKeysObject *keys); diff --git a/Include/internal/pycore_dict_state.h b/Include/internal/pycore_dict_state.h index 77375ea8beb8..c5142ee6763a 100644 --- a/Include/internal/pycore_dict_state.h +++ b/Include/internal/pycore_dict_state.h @@ -14,7 +14,6 @@ struct _Py_dict_runtime_state { * It is incremented each time that a dictionary is created and each * time that a dictionary is modified. */ uint64_t global_version; - uint32_t next_keys_version; }; @@ -30,6 +29,8 @@ struct _Py_dict_runtime_state { #define DICT_MAX_WATCHERS 8 struct _Py_dict_state { + uint32_t next_keys_version; + #if PyDict_MAXFREELIST > 0 /* Dictionary reuse scheme to save calls to malloc and free */ PyDictObject *free_list[PyDict_MAXFREELIST]; @@ -37,6 +38,7 @@ struct _Py_dict_state { int numfree; int keys_numfree; #endif + PyDict_WatchCallback watchers[DICT_MAX_WATCHERS]; }; diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index aeabcfd2b905..efc82b43a61d 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -65,9 +65,6 @@ extern PyTypeObject _PyExc_MemoryError; .float_format = _py_float_format_unknown, \ .double_format = _py_float_format_unknown, \ }, \ - .dict_state = { \ - .next_keys_version = 2, \ - }, \ .types = { \ .next_version_tag = 1, \ }, \ @@ -113,6 +110,9 @@ extern PyTypeObject _PyExc_MemoryError; }, \ }, \ .dtoa = _dtoa_state_INIT(&(INTERP)), \ + .dict_state = { \ + .next_keys_version = 2, \ + }, \ .func_state = { \ .next_version = 1, \ }, \ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index a60f275742a5..b58e93f4320d 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5655,15 +5655,16 @@ _PyDictKeys_DecRef(PyDictKeysObject *keys) dictkeys_decref(keys); } -uint32_t _PyDictKeys_GetVersionForCurrentState(PyDictKeysObject *dictkeys) +uint32_t _PyDictKeys_GetVersionForCurrentState(PyInterpreterState *interp, + PyDictKeysObject *dictkeys) { if (dictkeys->dk_version != 0) { return dictkeys->dk_version; } - if (_PyRuntime.dict_state.next_keys_version == 0) { + if (interp->dict_state.next_keys_version == 0) { return 0; } - uint32_t v = _PyRuntime.dict_state.next_keys_version++; + uint32_t v = interp->dict_state.next_keys_version++; dictkeys->dk_version = v; return v; } diff --git a/Python/specialize.c b/Python/specialize.c index 3405d2b0ab06..0a7af8991eec 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -512,7 +512,8 @@ specialize_module_load_attr( SPEC_FAIL_OUT_OF_RANGE); return -1; } - uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(dict->ma_keys); + uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState( + _PyInterpreterState_GET(), dict->ma_keys); if (keys_version == 0) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); return -1; @@ -1063,7 +1064,8 @@ PyObject *descr, DescriptorClassification kind) SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_SHADOWED); return 0; } - uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(keys); + uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState( + _PyInterpreterState_GET(), keys); if (keys_version == 0) { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS); return 0; @@ -1134,12 +1136,14 @@ _Py_Specialize_LoadGlobal( SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_EXPECTED_ERROR); goto fail; } + PyInterpreterState *interp = _PyInterpreterState_GET(); if (index != DKIX_EMPTY) { if (index != (uint16_t)index) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } - uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState(globals_keys); + uint32_t keys_version = _PyDictKeys_GetVersionForCurrentState( + interp, globals_keys); if (keys_version == 0) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; @@ -1167,12 +1171,14 @@ _Py_Specialize_LoadGlobal( SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); goto fail; } - uint32_t globals_version = _PyDictKeys_GetVersionForCurrentState(globals_keys); + uint32_t globals_version = _PyDictKeys_GetVersionForCurrentState( + interp, globals_keys); if (globals_version == 0) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } - uint32_t builtins_version = _PyDictKeys_GetVersionForCurrentState(builtin_keys); + uint32_t builtins_version = _PyDictKeys_GetVersionForCurrentState( + interp, builtin_keys); if (builtins_version == 0) { SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; From webhook-mailer at python.org Wed Mar 8 21:40:13 2023 From: webhook-mailer at python.org (Yhg1s) Date: Thu, 09 Mar 2023 02:40:13 -0000 Subject: [Python-checkins] GH-84783: Document GH-101264 (Make the slice object hashable) in What's New. (#102548) Message-ID: https://github.com/python/cpython/commit/58d761e5b5f253892a697941c71bac0159a1d74e commit: 58d761e5b5f253892a697941c71bac0159a1d74e branch: main author: T. Wouters committer: Yhg1s date: 2023-03-08T18:39:33-08:00 summary: GH-84783: Document GH-101264 (Make the slice object hashable) in What's New. (#102548) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index c0c021c67914..d982cb62ec2f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -189,6 +189,8 @@ Other Language Changes part of comprehensions (like ``a``) is still disallowed, as per :pep:`572`. (Contributed by Nikita Sobolev in :gh:`100581`.) +* :class:`slice` objects are now hashable, allowing them to be used as dict keys and + set items. (Contributed by Furkan Onder in :gh:`101264`.) New Modules =========== From webhook-mailer at python.org Thu Mar 9 10:25:57 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 09 Mar 2023 15:25:57 -0000 Subject: [Python-checkins] gh-100227: Move dict_state.global_version to PyInterpreterState (gh-102338) Message-ID: https://github.com/python/cpython/commit/b45d14b88611fefc6f054226d3e1117082d322c8 commit: b45d14b88611fefc6f054226d3e1117082d322c8 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-09T08:16:30-07:00 summary: gh-100227: Move dict_state.global_version to PyInterpreterState (gh-102338) https://github.com/python/cpython/issues/100227 files: M Include/internal/pycore_dict.h M Include/internal/pycore_dict_state.h M Include/internal/pycore_runtime.h M Objects/dictobject.c M Python/bytecodes.c M Python/generated_cases.c.h diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 12c3c708e29b..6253e0841ad3 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -149,8 +149,8 @@ static inline PyDictUnicodeEntry* DK_UNICODE_ENTRIES(PyDictKeysObject *dk) { #define DICT_VERSION_INCREMENT (1 << DICT_MAX_WATCHERS) #define DICT_VERSION_MASK (DICT_VERSION_INCREMENT - 1) -#define DICT_NEXT_VERSION() \ - (_PyRuntime.dict_state.global_version += DICT_VERSION_INCREMENT) +#define DICT_NEXT_VERSION(INTERP) \ + ((INTERP)->dict_state.global_version += DICT_VERSION_INCREMENT) void _PyDict_SendEvent(int watcher_bits, @@ -160,7 +160,8 @@ _PyDict_SendEvent(int watcher_bits, PyObject *value); static inline uint64_t -_PyDict_NotifyEvent(PyDict_WatchEvent event, +_PyDict_NotifyEvent(PyInterpreterState *interp, + PyDict_WatchEvent event, PyDictObject *mp, PyObject *key, PyObject *value) @@ -169,9 +170,9 @@ _PyDict_NotifyEvent(PyDict_WatchEvent event, int watcher_bits = mp->ma_version_tag & DICT_VERSION_MASK; if (watcher_bits) { _PyDict_SendEvent(watcher_bits, event, mp, key, value); - return DICT_NEXT_VERSION() | watcher_bits; + return DICT_NEXT_VERSION(interp) | watcher_bits; } - return DICT_NEXT_VERSION(); + return DICT_NEXT_VERSION(interp); } extern PyObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values); diff --git a/Include/internal/pycore_dict_state.h b/Include/internal/pycore_dict_state.h index c5142ee6763a..d608088ed2d7 100644 --- a/Include/internal/pycore_dict_state.h +++ b/Include/internal/pycore_dict_state.h @@ -9,14 +9,6 @@ extern "C" { #endif -struct _Py_dict_runtime_state { - /*Global counter used to set ma_version_tag field of dictionary. - * It is incremented each time that a dictionary is created and each - * time that a dictionary is modified. */ - uint64_t global_version; -}; - - #ifndef WITH_FREELISTS // without freelists # define PyDict_MAXFREELIST 0 @@ -29,6 +21,10 @@ struct _Py_dict_runtime_state { #define DICT_MAX_WATCHERS 8 struct _Py_dict_state { + /*Global counter used to set ma_version_tag field of dictionary. + * It is incremented each time that a dictionary is created and each + * time that a dictionary is modified. */ + uint64_t global_version; uint32_t next_keys_version; #if PyDict_MAXFREELIST > 0 diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index e0e3d4ace0cf..520109ca4404 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -10,7 +10,6 @@ extern "C" { #include "pycore_atomic.h" /* _Py_atomic_address */ #include "pycore_ceval_state.h" // struct _ceval_runtime_state -#include "pycore_dict_state.h" // struct _Py_dict_runtime_state #include "pycore_floatobject.h" // struct _Py_float_runtime_state #include "pycore_faulthandler.h" // struct _faulthandler_runtime_state #include "pycore_global_objects.h" // struct _Py_global_objects @@ -153,7 +152,6 @@ typedef struct pyruntimestate { struct _Py_float_runtime_state float_state; struct _Py_unicode_runtime_state unicode_state; - struct _Py_dict_runtime_state dict_state; struct { /* Used to set PyTypeObject.tp_version_tag */ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index b58e93f4320d..227e438a8dff 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -232,7 +232,8 @@ equally good collision statistics, needed less code & used less memory. */ -static int dictresize(PyDictObject *mp, uint8_t log_newsize, int unicode); +static int dictresize(PyInterpreterState *interp, PyDictObject *mp, + uint8_t log_newsize, int unicode); static PyObject* dict_iter(PyDictObject *dict); @@ -241,9 +242,8 @@ static PyObject* dict_iter(PyDictObject *dict); #if PyDict_MAXFREELIST > 0 static struct _Py_dict_state * -get_dict_state(void) +get_dict_state(PyInterpreterState *interp) { - PyInterpreterState *interp = _PyInterpreterState_GET(); return &interp->dict_state; } #endif @@ -289,7 +289,8 @@ void _PyDict_DebugMallocStats(FILE *out) { #if PyDict_MAXFREELIST > 0 - struct _Py_dict_state *state = get_dict_state(); + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _Py_dict_state *state = get_dict_state(interp); _PyDebugAllocatorStats(out, "free PyDictObject", state->numfree, sizeof(PyDictObject)); #endif @@ -297,7 +298,7 @@ _PyDict_DebugMallocStats(FILE *out) #define DK_MASK(dk) (DK_SIZE(dk)-1) -static void free_keys_object(PyDictKeysObject *keys); +static void free_keys_object(PyInterpreterState *interp, PyDictKeysObject *keys); static inline void dictkeys_incref(PyDictKeysObject *dk) @@ -309,14 +310,14 @@ dictkeys_incref(PyDictKeysObject *dk) } static inline void -dictkeys_decref(PyDictKeysObject *dk) +dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk) { assert(dk->dk_refcnt > 0); #ifdef Py_REF_DEBUG _Py_DecRefTotal(); #endif if (--dk->dk_refcnt == 0) { - free_keys_object(dk); + free_keys_object(interp, dk); } } @@ -586,7 +587,7 @@ _PyDict_CheckConsistency(PyObject *op, int check_content) static PyDictKeysObject* -new_keys_object(uint8_t log2_size, bool unicode) +new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) { PyDictKeysObject *dk; Py_ssize_t usable; @@ -612,7 +613,7 @@ new_keys_object(uint8_t log2_size, bool unicode) } #if PyDict_MAXFREELIST > 0 - struct _Py_dict_state *state = get_dict_state(); + struct _Py_dict_state *state = get_dict_state(interp); #ifdef Py_DEBUG // new_keys_object() must not be called after _PyDict_Fini() assert(state->keys_numfree != -1); @@ -648,7 +649,7 @@ new_keys_object(uint8_t log2_size, bool unicode) } static void -free_keys_object(PyDictKeysObject *keys) +free_keys_object(PyInterpreterState *interp, PyDictKeysObject *keys) { assert(keys != Py_EMPTY_KEYS); if (DK_IS_UNICODE(keys)) { @@ -668,7 +669,7 @@ free_keys_object(PyDictKeysObject *keys) } } #if PyDict_MAXFREELIST > 0 - struct _Py_dict_state *state = get_dict_state(); + struct _Py_dict_state *state = get_dict_state(interp); #ifdef Py_DEBUG // free_keys_object() must not be called after _PyDict_Fini() assert(state->keys_numfree != -1); @@ -709,12 +710,14 @@ free_values(PyDictValues *values) /* Consumes a reference to the keys object */ static PyObject * -new_dict(PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free_values_on_failure) +new_dict(PyInterpreterState *interp, + PyDictKeysObject *keys, PyDictValues *values, + Py_ssize_t used, int free_values_on_failure) { PyDictObject *mp; assert(keys != NULL); #if PyDict_MAXFREELIST > 0 - struct _Py_dict_state *state = get_dict_state(); + struct _Py_dict_state *state = get_dict_state(interp); #ifdef Py_DEBUG // new_dict() must not be called after _PyDict_Fini() assert(state->numfree != -1); @@ -731,7 +734,7 @@ new_dict(PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free { mp = PyObject_GC_New(PyDictObject, &PyDict_Type); if (mp == NULL) { - dictkeys_decref(keys); + dictkeys_decref(interp, keys); if (free_values_on_failure) { free_values(values); } @@ -741,7 +744,7 @@ new_dict(PyDictKeysObject *keys, PyDictValues *values, Py_ssize_t used, int free mp->ma_keys = keys; mp->ma_values = values; mp->ma_used = used; - mp->ma_version_tag = DICT_NEXT_VERSION(); + mp->ma_version_tag = DICT_NEXT_VERSION(interp); ASSERT_CONSISTENT(mp); return (PyObject *)mp; } @@ -754,19 +757,19 @@ shared_keys_usable_size(PyDictKeysObject *keys) /* Consumes a reference to the keys object */ static PyObject * -new_dict_with_shared_keys(PyDictKeysObject *keys) +new_dict_with_shared_keys(PyInterpreterState *interp, PyDictKeysObject *keys) { size_t size = shared_keys_usable_size(keys); PyDictValues *values = new_values(size); if (values == NULL) { - dictkeys_decref(keys); + dictkeys_decref(interp, keys); return PyErr_NoMemory(); } ((char *)values)[-2] = 0; for (size_t i = 0; i < size; i++) { values->values[i] = NULL; } - return new_dict(keys, values, 0, 1); + return new_dict(interp, keys, values, 0, 1); } @@ -829,8 +832,9 @@ clone_combined_dict_keys(PyDictObject *orig) PyObject * PyDict_New(void) { + PyInterpreterState *interp = _PyInterpreterState_GET(); dictkeys_incref(Py_EMPTY_KEYS); - return new_dict(Py_EMPTY_KEYS, NULL, 0, 0); + return new_dict(interp, Py_EMPTY_KEYS, NULL, 0, 0); } /* Search index of hash table from offset of entry table */ @@ -1170,9 +1174,9 @@ find_empty_slot(PyDictKeysObject *keys, Py_hash_t hash) } static int -insertion_resize(PyDictObject *mp, int unicode) +insertion_resize(PyInterpreterState *interp, PyDictObject *mp, int unicode) { - return dictresize(mp, calculate_log2_keysize(GROWTH_RATE(mp)), unicode); + return dictresize(interp, mp, calculate_log2_keysize(GROWTH_RATE(mp)), unicode); } static Py_ssize_t @@ -1214,12 +1218,13 @@ Returns -1 if an error occurred, or 0 on success. Consumes key and value references. */ static int -insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) +insertdict(PyInterpreterState *interp, PyDictObject *mp, + PyObject *key, Py_hash_t hash, PyObject *value) { PyObject *old_value; if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) { - if (insertion_resize(mp, 0) < 0) + if (insertion_resize(interp, mp, 0) < 0) goto Fail; assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL); } @@ -1231,13 +1236,14 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) MAINTAIN_TRACKING(mp, key, value); if (ix == DKIX_EMPTY) { - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, value); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_ADDED, mp, key, value); /* Insert into new slot. */ mp->ma_keys->dk_version = 0; assert(old_value == NULL); if (mp->ma_keys->dk_usable <= 0) { /* Need to resize. */ - if (insertion_resize(mp, 1) < 0) + if (insertion_resize(interp, mp, 1) < 0) goto Fail; } @@ -1275,7 +1281,8 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) } if (old_value != value) { - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, mp, key, value); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_MODIFIED, mp, key, value); if (_PyDict_HasSplitTable(mp)) { mp->ma_values->values[ix] = value; if (old_value == NULL) { @@ -1308,21 +1315,23 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) // Same to insertdict but specialized for ma_keys = Py_EMPTY_KEYS. // Consumes key and value references. static int -insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash, - PyObject *value) +insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp, + PyObject *key, Py_hash_t hash, PyObject *value) { assert(mp->ma_keys == Py_EMPTY_KEYS); - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, value); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_ADDED, mp, key, value); int unicode = PyUnicode_CheckExact(key); - PyDictKeysObject *newkeys = new_keys_object(PyDict_LOG_MINSIZE, unicode); + PyDictKeysObject *newkeys = new_keys_object( + interp, PyDict_LOG_MINSIZE, unicode); if (newkeys == NULL) { Py_DECREF(key); Py_DECREF(value); return -1; } - dictkeys_decref(Py_EMPTY_KEYS); + dictkeys_decref(interp, Py_EMPTY_KEYS); mp->ma_keys = newkeys; mp->ma_values = NULL; @@ -1397,7 +1406,8 @@ This function supports: - Generic -> Generic */ static int -dictresize(PyDictObject *mp, uint8_t log2_newsize, int unicode) +dictresize(PyInterpreterState *interp, PyDictObject *mp, + uint8_t log2_newsize, int unicode) { PyDictKeysObject *oldkeys; PyDictValues *oldvalues; @@ -1421,7 +1431,7 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize, int unicode) */ /* Allocate a new table. */ - mp->ma_keys = new_keys_object(log2_newsize, unicode); + mp->ma_keys = new_keys_object(interp, log2_newsize, unicode); if (mp->ma_keys == NULL) { mp->ma_keys = oldkeys; return -1; @@ -1462,7 +1472,7 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize, int unicode) } build_indices_unicode(mp->ma_keys, newentries, numentries); } - dictkeys_decref(oldkeys); + dictkeys_decref(interp, oldkeys); mp->ma_values = NULL; free_values(oldvalues); } @@ -1530,7 +1540,7 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize, int unicode) assert(oldkeys->dk_kind != DICT_KEYS_SPLIT); assert(oldkeys->dk_refcnt == 1); #if PyDict_MAXFREELIST > 0 - struct _Py_dict_state *state = get_dict_state(); + struct _Py_dict_state *state = get_dict_state(interp); #ifdef Py_DEBUG // dictresize() must not be called after _PyDict_Fini() assert(state->keys_numfree != -1); @@ -1557,7 +1567,7 @@ dictresize(PyDictObject *mp, uint8_t log2_newsize, int unicode) } static PyObject * -dict_new_presized(Py_ssize_t minused, bool unicode) +dict_new_presized(PyInterpreterState *interp, Py_ssize_t minused, bool unicode) { const uint8_t log2_max_presize = 17; const Py_ssize_t max_presize = ((Py_ssize_t)1) << log2_max_presize; @@ -1578,16 +1588,17 @@ dict_new_presized(Py_ssize_t minused, bool unicode) log2_newsize = estimate_log2_keysize(minused); } - new_keys = new_keys_object(log2_newsize, unicode); + new_keys = new_keys_object(interp, log2_newsize, unicode); if (new_keys == NULL) return NULL; - return new_dict(new_keys, NULL, 0, 0); + return new_dict(interp, new_keys, NULL, 0, 0); } PyObject * _PyDict_NewPresized(Py_ssize_t minused) { - return dict_new_presized(minused, false); + PyInterpreterState *interp = _PyInterpreterState_GET(); + return dict_new_presized(interp, minused, false); } PyObject * @@ -1597,6 +1608,7 @@ _PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset, { bool unicode = true; PyObject *const *ks = keys; + PyInterpreterState *interp = _PyInterpreterState_GET(); for (Py_ssize_t i = 0; i < length; i++) { if (!PyUnicode_CheckExact(*ks)) { @@ -1606,7 +1618,7 @@ _PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset, ks += keys_offset; } - PyObject *dict = dict_new_presized(length, unicode); + PyObject *dict = dict_new_presized(interp, length, unicode); if (dict == NULL) { return NULL; } @@ -1834,11 +1846,12 @@ _PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value) return -1; } } + PyInterpreterState *interp = _PyInterpreterState_GET(); if (mp->ma_keys == Py_EMPTY_KEYS) { - return insert_to_emptydict(mp, key, hash, value); + return insert_to_emptydict(interp, mp, key, hash, value); } /* insertdict() handles any resizing that might be necessary */ - return insertdict(mp, key, hash, value); + return insertdict(interp, mp, key, hash, value); } /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the @@ -1875,11 +1888,12 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value, assert(hash != -1); mp = (PyDictObject *)op; + PyInterpreterState *interp = _PyInterpreterState_GET(); if (mp->ma_keys == Py_EMPTY_KEYS) { - return insert_to_emptydict(mp, Py_NewRef(key), hash, Py_NewRef(value)); + return insert_to_emptydict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value)); } /* insertdict() handles any resizing that might be necessary */ - return insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value)); + return insertdict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value)); } static void @@ -1977,7 +1991,9 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) return -1; } - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, mp, key, NULL); + PyInterpreterState *interp = _PyInterpreterState_GET(); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_DELETED, mp, key, NULL); return delitem_common(mp, hash, ix, old_value, new_version); } @@ -2020,7 +2036,9 @@ _PyDict_DelItemIf(PyObject *op, PyObject *key, assert(hashpos >= 0); if (res > 0) { - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, mp, key, NULL); + PyInterpreterState *interp = _PyInterpreterState_GET(); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_DELETED, mp, key, NULL); return delitem_common(mp, hashpos, ix, old_value, new_version); } else { return 0; @@ -2045,7 +2063,9 @@ PyDict_Clear(PyObject *op) return; } /* Empty the dict... */ - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_CLEARED, mp, NULL, NULL); + PyInterpreterState *interp = _PyInterpreterState_GET(); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_CLEARED, mp, NULL, NULL); dictkeys_incref(Py_EMPTY_KEYS); mp->ma_keys = Py_EMPTY_KEYS; mp->ma_values = NULL; @@ -2057,11 +2077,11 @@ PyDict_Clear(PyObject *op) for (i = 0; i < n; i++) Py_CLEAR(oldvalues->values[i]); free_values(oldvalues); - dictkeys_decref(oldkeys); + dictkeys_decref(interp, oldkeys); } else { assert(oldkeys->dk_refcnt == 1); - dictkeys_decref(oldkeys); + dictkeys_decref(interp, oldkeys); } ASSERT_CONSISTENT(mp); } @@ -2165,6 +2185,7 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d Py_ssize_t ix; PyObject *old_value; PyDictObject *mp; + PyInterpreterState *interp = _PyInterpreterState_GET(); assert(PyDict_Check(dict)); mp = (PyDictObject *)dict; @@ -2187,7 +2208,8 @@ _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *d return NULL; } assert(old_value != NULL); - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, mp, key, NULL); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_DELETED, mp, key, NULL); delitem_common(mp, hash, ix, Py_NewRef(old_value), new_version); ASSERT_CONSISTENT(mp); @@ -2222,6 +2244,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) PyObject *key; PyObject *d; int status; + PyInterpreterState *interp = _PyInterpreterState_GET(); d = _PyObject_CallNoArgs(cls); if (d == NULL) @@ -2236,13 +2259,16 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) Py_hash_t hash; int unicode = DK_IS_UNICODE(((PyDictObject*)iterable)->ma_keys); - if (dictresize(mp, estimate_log2_keysize(PyDict_GET_SIZE(iterable)), unicode)) { + if (dictresize(interp, mp, + estimate_log2_keysize(PyDict_GET_SIZE(iterable)), + unicode)) { Py_DECREF(d); return NULL; } while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) { - if (insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value))) { + if (insertdict(interp, mp, + Py_NewRef(key), hash, Py_NewRef(value))) { Py_DECREF(d); return NULL; } @@ -2255,13 +2281,14 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) PyObject *key; Py_hash_t hash; - if (dictresize(mp, estimate_log2_keysize(PySet_GET_SIZE(iterable)), 0)) { + if (dictresize(interp, mp, + estimate_log2_keysize(PySet_GET_SIZE(iterable)), 0)) { Py_DECREF(d); return NULL; } while (_PySet_NextEntry(iterable, &pos, &key, &hash)) { - if (insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value))) { + if (insertdict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value))) { Py_DECREF(d); return NULL; } @@ -2308,9 +2335,10 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) static void dict_dealloc(PyDictObject *mp) { + PyInterpreterState *interp = _PyInterpreterState_GET(); assert(Py_REFCNT(mp) == 0); Py_SET_REFCNT(mp, 1); - _PyDict_NotifyEvent(PyDict_EVENT_DEALLOCATED, mp, NULL, NULL); + _PyDict_NotifyEvent(interp, PyDict_EVENT_DEALLOCATED, mp, NULL, NULL); if (Py_REFCNT(mp) > 1) { Py_SET_REFCNT(mp, Py_REFCNT(mp) - 1); return; @@ -2328,14 +2356,14 @@ dict_dealloc(PyDictObject *mp) Py_XDECREF(values->values[i]); } free_values(values); - dictkeys_decref(keys); + dictkeys_decref(interp, keys); } else if (keys != NULL) { assert(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS); - dictkeys_decref(keys); + dictkeys_decref(interp, keys); } #if PyDict_MAXFREELIST > 0 - struct _Py_dict_state *state = get_dict_state(); + struct _Py_dict_state *state = get_dict_state(interp); #ifdef Py_DEBUG // new_dict() must not be called after _PyDict_Fini() assert(state->numfree != -1); @@ -2765,7 +2793,7 @@ PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override) } static int -dict_merge(PyObject *a, PyObject *b, int override) +dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override) { PyDictObject *mp, *other; @@ -2799,13 +2827,14 @@ dict_merge(PyObject *a, PyObject *b, int override) other->ma_used == okeys->dk_nentries && (DK_LOG_SIZE(okeys) == PyDict_LOG_MINSIZE || USABLE_FRACTION(DK_SIZE(okeys)/2) < other->ma_used)) { - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_CLONED, mp, b, NULL); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_CLONED, mp, b, NULL); PyDictKeysObject *keys = clone_combined_dict_keys(other); if (keys == NULL) { return -1; } - dictkeys_decref(mp->ma_keys); + dictkeys_decref(interp, mp->ma_keys); mp->ma_keys = keys; if (mp->ma_values != NULL) { free_values(mp->ma_values); @@ -2830,7 +2859,9 @@ dict_merge(PyObject *a, PyObject *b, int override) */ if (USABLE_FRACTION(DK_SIZE(mp->ma_keys)) < other->ma_used) { int unicode = DK_IS_UNICODE(other->ma_keys); - if (dictresize(mp, estimate_log2_keysize(mp->ma_used + other->ma_used), unicode)) { + if (dictresize(interp, mp, + estimate_log2_keysize(mp->ma_used + other->ma_used), + unicode)) { return -1; } } @@ -2845,12 +2876,14 @@ dict_merge(PyObject *a, PyObject *b, int override) Py_INCREF(key); Py_INCREF(value); if (override == 1) { - err = insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value)); + err = insertdict(interp, mp, + Py_NewRef(key), hash, Py_NewRef(value)); } else { err = _PyDict_Contains_KnownHash(a, key, hash); if (err == 0) { - err = insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value)); + err = insertdict(interp, mp, + Py_NewRef(key), hash, Py_NewRef(value)); } else if (err > 0) { if (override != 0) { @@ -2936,20 +2969,23 @@ dict_merge(PyObject *a, PyObject *b, int override) int PyDict_Update(PyObject *a, PyObject *b) { - return dict_merge(a, b, 1); + PyInterpreterState *interp = _PyInterpreterState_GET(); + return dict_merge(interp, a, b, 1); } int PyDict_Merge(PyObject *a, PyObject *b, int override) { + PyInterpreterState *interp = _PyInterpreterState_GET(); /* XXX Deprecate override not in (0, 1). */ - return dict_merge(a, b, override != 0); + return dict_merge(interp, a, b, override != 0); } int _PyDict_MergeEx(PyObject *a, PyObject *b, int override) { - return dict_merge(a, b, override); + PyInterpreterState *interp = _PyInterpreterState_GET(); + return dict_merge(interp, a, b, override); } static PyObject * @@ -2963,6 +2999,7 @@ PyDict_Copy(PyObject *o) { PyObject *copy; PyDictObject *mp; + PyInterpreterState *interp = _PyInterpreterState_GET(); if (o == NULL || !PyDict_Check(o)) { PyErr_BadInternalCall(); @@ -2991,7 +3028,7 @@ PyDict_Copy(PyObject *o) split_copy->ma_values = newvalues; split_copy->ma_keys = mp->ma_keys; split_copy->ma_used = mp->ma_used; - split_copy->ma_version_tag = DICT_NEXT_VERSION(); + split_copy->ma_version_tag = DICT_NEXT_VERSION(interp); dictkeys_incref(mp->ma_keys); for (size_t i = 0; i < size; i++) { PyObject *value = mp->ma_values->values[i]; @@ -3024,7 +3061,7 @@ PyDict_Copy(PyObject *o) if (keys == NULL) { return NULL; } - PyDictObject *new = (PyDictObject *)new_dict(keys, NULL, 0, 0); + PyDictObject *new = (PyDictObject *)new_dict(interp, keys, NULL, 0, 0); if (new == NULL) { /* In case of an error, `new_dict()` takes care of cleaning up `keys`. */ @@ -3044,7 +3081,7 @@ PyDict_Copy(PyObject *o) copy = PyDict_New(); if (copy == NULL) return NULL; - if (dict_merge(copy, o, 1) == 0) + if (dict_merge(interp, copy, o, 1) == 0) return copy; Py_DECREF(copy); return NULL; @@ -3244,6 +3281,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) PyDictObject *mp = (PyDictObject *)d; PyObject *value; Py_hash_t hash; + PyInterpreterState *interp = _PyInterpreterState_GET(); if (!PyDict_Check(d)) { PyErr_BadInternalCall(); @@ -3257,7 +3295,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) } if (mp->ma_keys == Py_EMPTY_KEYS) { - if (insert_to_emptydict(mp, Py_NewRef(key), hash, + if (insert_to_emptydict(interp, mp, Py_NewRef(key), hash, Py_NewRef(defaultobj)) < 0) { return NULL; } @@ -3265,7 +3303,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) } if (!PyUnicode_CheckExact(key) && DK_IS_UNICODE(mp->ma_keys)) { - if (insertion_resize(mp, 0) < 0) { + if (insertion_resize(interp, mp, 0) < 0) { return NULL; } } @@ -3275,11 +3313,12 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) return NULL; if (ix == DKIX_EMPTY) { - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, defaultobj); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_ADDED, mp, key, defaultobj); mp->ma_keys->dk_version = 0; value = defaultobj; if (mp->ma_keys->dk_usable <= 0) { - if (insertion_resize(mp, 1) < 0) { + if (insertion_resize(interp, mp, 1) < 0) { return NULL; } } @@ -3314,7 +3353,8 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) assert(mp->ma_keys->dk_usable >= 0); } else if (value == NULL) { - uint64_t new_version = _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, defaultobj); + uint64_t new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_ADDED, mp, key, defaultobj); value = defaultobj; assert(_PyDict_HasSplitTable(mp)); assert(mp->ma_values->values[ix] == NULL); @@ -3395,6 +3435,7 @@ dict_popitem_impl(PyDictObject *self) Py_ssize_t i, j; PyObject *res; uint64_t new_version; + PyInterpreterState *interp = _PyInterpreterState_GET(); /* Allocate the result tuple before checking the size. Believe it * or not, this allocation could trigger a garbage collection which @@ -3415,7 +3456,7 @@ dict_popitem_impl(PyDictObject *self) } /* Convert split table to combined table */ if (self->ma_keys->dk_kind == DICT_KEYS_SPLIT) { - if (dictresize(self, DK_LOG_SIZE(self->ma_keys), 1)) { + if (dictresize(interp, self, DK_LOG_SIZE(self->ma_keys), 1)) { Py_DECREF(res); return NULL; } @@ -3434,7 +3475,8 @@ dict_popitem_impl(PyDictObject *self) assert(i >= 0); key = ep0[i].me_key; - new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, self, key, NULL); + new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_DELETED, self, key, NULL); hash = unicode_get_hash(key); value = ep0[i].me_value; ep0[i].me_key = NULL; @@ -3449,7 +3491,8 @@ dict_popitem_impl(PyDictObject *self) assert(i >= 0); key = ep0[i].me_key; - new_version = _PyDict_NotifyEvent(PyDict_EVENT_DELETED, self, key, NULL); + new_version = _PyDict_NotifyEvent( + interp, PyDict_EVENT_DELETED, self, key, NULL); hash = ep0[i].me_hash; value = ep0[i].me_value; ep0[i].me_key = NULL; @@ -3708,7 +3751,8 @@ dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyDictObject *d = (PyDictObject *)self; d->ma_used = 0; - d->ma_version_tag = DICT_NEXT_VERSION(); + d->ma_version_tag = DICT_NEXT_VERSION( + _PyInterpreterState_GET()); dictkeys_incref(Py_EMPTY_KEYS); d->ma_keys = Py_EMPTY_KEYS; d->ma_values = NULL; @@ -5262,7 +5306,9 @@ dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored)) PyDictKeysObject * _PyDict_NewKeysForClass(void) { - PyDictKeysObject *keys = new_keys_object(NEXT_LOG2_SHARED_KEYS_MAX_SIZE, 1); + PyInterpreterState *interp = _PyInterpreterState_GET(); + PyDictKeysObject *keys = new_keys_object( + interp, NEXT_LOG2_SHARED_KEYS_MAX_SIZE, 1); if (keys == NULL) { PyErr_Clear(); } @@ -5306,6 +5352,7 @@ init_inline_values(PyObject *obj, PyTypeObject *tp) int _PyObject_InitializeDict(PyObject *obj) { + PyInterpreterState *interp = _PyInterpreterState_GET(); PyTypeObject *tp = Py_TYPE(obj); if (tp->tp_dictoffset == 0) { return 0; @@ -5317,7 +5364,7 @@ _PyObject_InitializeDict(PyObject *obj) PyObject *dict; if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) { dictkeys_incref(CACHED_KEYS(tp)); - dict = new_dict_with_shared_keys(CACHED_KEYS(tp)); + dict = new_dict_with_shared_keys(interp, CACHED_KEYS(tp)); } else { dict = PyDict_New(); @@ -5331,7 +5378,8 @@ _PyObject_InitializeDict(PyObject *obj) } static PyObject * -make_dict_from_instance_attributes(PyDictKeysObject *keys, PyDictValues *values) +make_dict_from_instance_attributes(PyInterpreterState *interp, + PyDictKeysObject *keys, PyDictValues *values) { dictkeys_incref(keys); Py_ssize_t used = 0; @@ -5344,7 +5392,7 @@ make_dict_from_instance_attributes(PyDictKeysObject *keys, PyDictValues *values) track += _PyObject_GC_MAY_BE_TRACKED(val); } } - PyObject *res = new_dict(keys, values, used, 0); + PyObject *res = new_dict(interp, keys, values, used, 0); if (track && res) { _PyObject_GC_TRACK(res); } @@ -5354,15 +5402,17 @@ make_dict_from_instance_attributes(PyDictKeysObject *keys, PyDictValues *values) PyObject * _PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values) { + PyInterpreterState *interp = _PyInterpreterState_GET(); PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj)); OBJECT_STAT_INC(dict_materialized_on_request); - return make_dict_from_instance_attributes(keys, values); + return make_dict_from_instance_attributes(interp, keys, values); } int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values, PyObject *name, PyObject *value) { + PyInterpreterState *interp = _PyInterpreterState_GET(); PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj)); assert(keys != NULL); assert(values != NULL); @@ -5385,7 +5435,8 @@ _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values, OBJECT_STAT_INC(dict_materialized_str_subclass); } #endif - PyObject *dict = make_dict_from_instance_attributes(keys, values); + PyObject *dict = make_dict_from_instance_attributes( + interp, keys, values); if (dict == NULL) { return -1; } @@ -5564,13 +5615,15 @@ PyObject * PyObject_GenericGetDict(PyObject *obj, void *context) { PyObject *dict; + PyInterpreterState *interp = _PyInterpreterState_GET(); PyTypeObject *tp = Py_TYPE(obj); if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) { PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj); if (_PyDictOrValues_IsValues(*dorv_ptr)) { PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr); OBJECT_STAT_INC(dict_materialized_on_request); - dict = make_dict_from_instance_attributes(CACHED_KEYS(tp), values); + dict = make_dict_from_instance_attributes( + interp, CACHED_KEYS(tp), values); if (dict != NULL) { dorv_ptr->dict = dict; } @@ -5579,7 +5632,7 @@ PyObject_GenericGetDict(PyObject *obj, void *context) dict = _PyDictOrValues_GetDict(*dorv_ptr); if (dict == NULL) { dictkeys_incref(CACHED_KEYS(tp)); - dict = new_dict_with_shared_keys(CACHED_KEYS(tp)); + dict = new_dict_with_shared_keys(interp, CACHED_KEYS(tp)); dorv_ptr->dict = dict; } } @@ -5596,7 +5649,8 @@ PyObject_GenericGetDict(PyObject *obj, void *context) PyTypeObject *tp = Py_TYPE(obj); if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) { dictkeys_incref(CACHED_KEYS(tp)); - *dictptr = dict = new_dict_with_shared_keys(CACHED_KEYS(tp)); + *dictptr = dict = new_dict_with_shared_keys( + interp, CACHED_KEYS(tp)); } else { *dictptr = dict = PyDict_New(); @@ -5613,6 +5667,7 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, PyObject *dict; int res; PyDictKeysObject *cached; + PyInterpreterState *interp = _PyInterpreterState_GET(); assert(dictptr != NULL); if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && (cached = CACHED_KEYS(tp))) { @@ -5620,7 +5675,7 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, dict = *dictptr; if (dict == NULL) { dictkeys_incref(cached); - dict = new_dict_with_shared_keys(cached); + dict = new_dict_with_shared_keys(interp, cached); if (dict == NULL) return -1; *dictptr = dict; @@ -5652,7 +5707,8 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, void _PyDictKeys_DecRef(PyDictKeysObject *keys) { - dictkeys_decref(keys); + PyInterpreterState *interp = _PyInterpreterState_GET(); + dictkeys_decref(interp, keys); } uint32_t _PyDictKeys_GetVersionForCurrentState(PyInterpreterState *interp, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 63dbecad3b45..45d507266743 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1679,7 +1679,7 @@ dummy_func( DEOPT_IF(ep->me_key != name, STORE_ATTR); old_value = ep->me_value; DEOPT_IF(old_value == NULL, STORE_ATTR); - new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); + new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } else { @@ -1687,7 +1687,7 @@ dummy_func( DEOPT_IF(ep->me_key != name, STORE_ATTR); old_value = ep->me_value; DEOPT_IF(old_value == NULL, STORE_ATTR); - new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); + new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } Py_DECREF(old_value); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 82e18505b0d4..51357cda4c89 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2114,7 +2114,7 @@ DEOPT_IF(ep->me_key != name, STORE_ATTR); old_value = ep->me_value; DEOPT_IF(old_value == NULL, STORE_ATTR); - new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); + new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } else { @@ -2122,7 +2122,7 @@ DEOPT_IF(ep->me_key != name, STORE_ATTR); old_value = ep->me_value; DEOPT_IF(old_value == NULL, STORE_ATTR); - new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); + new_version = _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, value); ep->me_value = value; } Py_DECREF(old_value); From webhook-mailer at python.org Thu Mar 9 11:46:44 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 09 Mar 2023 16:46:44 -0000 Subject: [Python-checkins] gh-100227: Isolate the Import State to Each Interpreter (gh-101941) Message-ID: https://github.com/python/cpython/commit/cf6e7c5e551b3513817d6a77ba88253dc8473298 commit: cf6e7c5e551b3513817d6a77ba88253dc8473298 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-09T09:46:21-07:00 summary: gh-100227: Isolate the Import State to Each Interpreter (gh-101941) Specific changes: * move the import lock to PyInterpreterState * move the "find_and_load" diagnostic state to PyInterpreterState Note that the import lock exists to keep multiple imports of the same module in the same interpreter (but in different threads) from stomping on each other. Independently, we use a distinct global lock to protect globally shared import state, especially related to loaded extension modules. For now we can rely on the GIL as that lock but with a per-interpreter GIL we'll need a new global lock. The remaining state in _PyRuntimeState.imports will (probably) continue being global. https://github.com/python/cpython/issues/100227 files: M Include/cpython/import.h M Include/internal/pycore_import.h M Include/internal/pycore_runtime_init.h M Modules/posixmodule.c M Python/import.c diff --git a/Include/cpython/import.h b/Include/cpython/import.h index a58801b47f1b..2bca4ade4c4f 100644 --- a/Include/cpython/import.h +++ b/Include/cpython/import.h @@ -10,8 +10,8 @@ PyAPI_FUNC(PyObject *) _PyImport_GetModuleId(_Py_Identifier *name); PyAPI_FUNC(int) _PyImport_SetModule(PyObject *name, PyObject *module); PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module); -PyAPI_FUNC(void) _PyImport_AcquireLock(void); -PyAPI_FUNC(int) _PyImport_ReleaseLock(void); +PyAPI_FUNC(void) _PyImport_AcquireLock(PyInterpreterState *interp); +PyAPI_FUNC(int) _PyImport_ReleaseLock(PyInterpreterState *interp); PyAPI_FUNC(int) _PyImport_FixupBuiltin( PyObject *mod, diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index b7ffe01c0c0e..69ed6273b7e6 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -21,17 +21,6 @@ struct _import_runtime_state { This is initialized lazily in _PyImport_FixupExtensionObject(). Modules are added there and looked up in _imp.find_extension(). */ PyObject *extensions; - /* The global import lock. */ - struct { - PyThread_type_lock mutex; - unsigned long thread; - int level; - } lock; - struct { - int import_level; - _PyTime_t accumulated; - int header; - } find_and_load; /* Package context -- the full module name for package imports */ const char * pkgcontext; }; @@ -69,6 +58,18 @@ struct _import_state { int dlopenflags; #endif PyObject *import_func; + /* The global import lock. */ + struct { + PyThread_type_lock mutex; + unsigned long thread; + int level; + } lock; + /* diagnostic info in PyImport_ImportModuleLevelObject() */ + struct { + int import_level; + _PyTime_t accumulated; + int header; + } find_and_load; }; #ifdef HAVE_DLOPEN @@ -86,8 +87,15 @@ struct _import_state { #define IMPORTS_INIT \ { \ - .override_frozen_modules = 0, \ DLOPENFLAGS_INIT \ + .lock = { \ + .mutex = NULL, \ + .thread = PYTHREAD_INVALID_THREAD_ID, \ + .level = 0, \ + }, \ + .find_and_load = { \ + .header = 1, \ + }, \ } extern void _PyImport_ClearCore(PyInterpreterState *interp); @@ -138,7 +146,7 @@ extern void _PyImport_FiniExternal(PyInterpreterState *interp); #ifdef HAVE_FORK -extern PyStatus _PyImport_ReInitLock(void); +extern PyStatus _PyImport_ReInitLock(PyInterpreterState *interp); #endif diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index efc82b43a61d..bdecac944dfd 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -40,16 +40,6 @@ extern PyTypeObject _PyExc_MemoryError; in accordance with the specification. */ \ .autoTSSkey = Py_tss_NEEDS_INIT, \ .parser = _parser_runtime_state_INIT, \ - .imports = { \ - .lock = { \ - .mutex = NULL, \ - .thread = PYTHREAD_INVALID_THREAD_ID, \ - .level = 0, \ - }, \ - .find_and_load = { \ - .header = 1, \ - }, \ - }, \ .ceval = { \ .perf = _PyEval_RUNTIME_PERF_INIT, \ }, \ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 7beb2cee64a0..a3d86cbe7a57 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -567,18 +567,21 @@ run_at_forkers(PyObject *lst, int reverse) void PyOS_BeforeFork(void) { - run_at_forkers(_PyInterpreterState_GET()->before_forkers, 1); + PyInterpreterState *interp = _PyInterpreterState_GET(); + run_at_forkers(interp->before_forkers, 1); - _PyImport_AcquireLock(); + _PyImport_AcquireLock(interp); } void PyOS_AfterFork_Parent(void) { - if (_PyImport_ReleaseLock() <= 0) + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (_PyImport_ReleaseLock(interp) <= 0) { Py_FatalError("failed releasing import lock after fork"); + } - run_at_forkers(_PyInterpreterState_GET()->after_forkers_parent, 0); + run_at_forkers(interp->after_forkers_parent, 0); } void @@ -604,7 +607,7 @@ PyOS_AfterFork_Child(void) goto fatal_error; } - status = _PyImport_ReInitLock(); + status = _PyImport_ReInitLock(tstate->interp); if (_PyStatus_EXCEPTION(status)) { goto fatal_error; } diff --git a/Python/import.c b/Python/import.c index 57d4eea14881..1bf4199e125a 100644 --- a/Python/import.c +++ b/Python/import.c @@ -56,11 +56,6 @@ static struct _inittab *inittab_copy = NULL; #define LAST_MODULE_INDEX _PyRuntime.imports.last_module_index #define EXTENSIONS _PyRuntime.imports.extensions -#define import_lock _PyRuntime.imports.lock.mutex -#define import_lock_thread _PyRuntime.imports.lock.thread -#define import_lock_level _PyRuntime.imports.lock.level - -#define FIND_AND_LOAD _PyRuntime.imports.find_and_load #define PKGCONTEXT (_PyRuntime.imports.pkgcontext) @@ -85,6 +80,16 @@ static struct _inittab *inittab_copy = NULL; #define IMPORT_FUNC(interp) \ (interp)->imports.import_func +#define IMPORT_LOCK(interp) \ + (interp)->imports.lock.mutex +#define IMPORT_LOCK_THREAD(interp) \ + (interp)->imports.lock.thread +#define IMPORT_LOCK_LEVEL(interp) \ + (interp)->imports.lock.level + +#define FIND_AND_LOAD(interp) \ + (interp)->imports.find_and_load + /*******************/ /* the import lock */ @@ -95,45 +100,45 @@ static struct _inittab *inittab_copy = NULL; These calls are serialized by the global interpreter lock. */ void -_PyImport_AcquireLock(void) +_PyImport_AcquireLock(PyInterpreterState *interp) { unsigned long me = PyThread_get_thread_ident(); if (me == PYTHREAD_INVALID_THREAD_ID) return; /* Too bad */ - if (import_lock == NULL) { - import_lock = PyThread_allocate_lock(); - if (import_lock == NULL) + if (IMPORT_LOCK(interp) == NULL) { + IMPORT_LOCK(interp) = PyThread_allocate_lock(); + if (IMPORT_LOCK(interp) == NULL) return; /* Nothing much we can do. */ } - if (import_lock_thread == me) { - import_lock_level++; + if (IMPORT_LOCK_THREAD(interp) == me) { + IMPORT_LOCK_LEVEL(interp)++; return; } - if (import_lock_thread != PYTHREAD_INVALID_THREAD_ID || - !PyThread_acquire_lock(import_lock, 0)) + if (IMPORT_LOCK_THREAD(interp) != PYTHREAD_INVALID_THREAD_ID || + !PyThread_acquire_lock(IMPORT_LOCK(interp), 0)) { PyThreadState *tstate = PyEval_SaveThread(); - PyThread_acquire_lock(import_lock, WAIT_LOCK); + PyThread_acquire_lock(IMPORT_LOCK(interp), WAIT_LOCK); PyEval_RestoreThread(tstate); } - assert(import_lock_level == 0); - import_lock_thread = me; - import_lock_level = 1; + assert(IMPORT_LOCK_LEVEL(interp) == 0); + IMPORT_LOCK_THREAD(interp) = me; + IMPORT_LOCK_LEVEL(interp) = 1; } int -_PyImport_ReleaseLock(void) +_PyImport_ReleaseLock(PyInterpreterState *interp) { unsigned long me = PyThread_get_thread_ident(); - if (me == PYTHREAD_INVALID_THREAD_ID || import_lock == NULL) + if (me == PYTHREAD_INVALID_THREAD_ID || IMPORT_LOCK(interp) == NULL) return 0; /* Too bad */ - if (import_lock_thread != me) + if (IMPORT_LOCK_THREAD(interp) != me) return -1; - import_lock_level--; - assert(import_lock_level >= 0); - if (import_lock_level == 0) { - import_lock_thread = PYTHREAD_INVALID_THREAD_ID; - PyThread_release_lock(import_lock); + IMPORT_LOCK_LEVEL(interp)--; + assert(IMPORT_LOCK_LEVEL(interp) >= 0); + if (IMPORT_LOCK_LEVEL(interp) == 0) { + IMPORT_LOCK_THREAD(interp) = PYTHREAD_INVALID_THREAD_ID; + PyThread_release_lock(IMPORT_LOCK(interp)); } return 1; } @@ -144,23 +149,23 @@ _PyImport_ReleaseLock(void) We now acquire the import lock around fork() calls but on some platforms (Solaris 9 and earlier? see isue7242) that still left us with problems. */ PyStatus -_PyImport_ReInitLock(void) +_PyImport_ReInitLock(PyInterpreterState *interp) { - if (import_lock != NULL) { - if (_PyThread_at_fork_reinit(&import_lock) < 0) { + if (IMPORT_LOCK(interp) != NULL) { + if (_PyThread_at_fork_reinit(&IMPORT_LOCK(interp)) < 0) { return _PyStatus_ERR("failed to create a new lock"); } } - if (import_lock_level > 1) { + if (IMPORT_LOCK_LEVEL(interp) > 1) { /* Forked as a side effect of import */ unsigned long me = PyThread_get_thread_ident(); - PyThread_acquire_lock(import_lock, WAIT_LOCK); - import_lock_thread = me; - import_lock_level--; + PyThread_acquire_lock(IMPORT_LOCK(interp), WAIT_LOCK); + IMPORT_LOCK_THREAD(interp) = me; + IMPORT_LOCK_LEVEL(interp)--; } else { - import_lock_thread = PYTHREAD_INVALID_THREAD_ID; - import_lock_level = 0; + IMPORT_LOCK_THREAD(interp) = PYTHREAD_INVALID_THREAD_ID; + IMPORT_LOCK_LEVEL(interp) = 0; } return _PyStatus_OK(); } @@ -2506,8 +2511,8 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name) PyObject *mod = NULL; PyInterpreterState *interp = tstate->interp; int import_time = _PyInterpreterState_GetConfig(interp)->import_time; -#define import_level FIND_AND_LOAD.import_level -#define accumulated FIND_AND_LOAD.accumulated +#define import_level FIND_AND_LOAD(interp).import_level +#define accumulated FIND_AND_LOAD(interp).accumulated _PyTime_t t1 = 0, accumulated_copy = accumulated; @@ -2528,7 +2533,7 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name) * _PyDict_GetItemIdWithError(). */ if (import_time) { -#define header FIND_AND_LOAD.header +#define header FIND_AND_LOAD(interp).header if (header) { fputs("import time: self [us] | cumulative | imported package\n", stderr); @@ -2867,10 +2872,6 @@ _PyImport_Fini(void) { /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ _extensions_cache_clear_all(); - if (import_lock != NULL) { - PyThread_free_lock(import_lock); - import_lock = NULL; - } /* Use the same memory allocator as _PyImport_Init(). */ PyMemAllocatorEx old_alloc; @@ -2959,6 +2960,11 @@ _PyImport_FiniCore(PyInterpreterState *interp) PyErr_WriteUnraisable(NULL); } + if (IMPORT_LOCK(interp) != NULL) { + PyThread_free_lock(IMPORT_LOCK(interp)); + IMPORT_LOCK(interp) = NULL; + } + _PyImport_ClearCore(interp); } @@ -3090,7 +3096,9 @@ static PyObject * _imp_lock_held_impl(PyObject *module) /*[clinic end generated code: output=8b89384b5e1963fc input=9b088f9b217d9bdf]*/ { - return PyBool_FromLong(import_lock_thread != PYTHREAD_INVALID_THREAD_ID); + PyInterpreterState *interp = _PyInterpreterState_GET(); + return PyBool_FromLong( + IMPORT_LOCK_THREAD(interp) != PYTHREAD_INVALID_THREAD_ID); } /*[clinic input] @@ -3106,7 +3114,8 @@ static PyObject * _imp_acquire_lock_impl(PyObject *module) /*[clinic end generated code: output=1aff58cb0ee1b026 input=4a2d4381866d5fdc]*/ { - _PyImport_AcquireLock(); + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyImport_AcquireLock(interp); Py_RETURN_NONE; } @@ -3122,7 +3131,8 @@ static PyObject * _imp_release_lock_impl(PyObject *module) /*[clinic end generated code: output=7faab6d0be178b0a input=934fb11516dd778b]*/ { - if (_PyImport_ReleaseLock() < 0) { + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (_PyImport_ReleaseLock(interp) < 0) { PyErr_SetString(PyExc_RuntimeError, "not holding the import lock"); return NULL; From webhook-mailer at python.org Thu Mar 9 11:50:41 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 09 Mar 2023 16:50:41 -0000 Subject: [Python-checkins] gh-81057: Vendor a Subset of distutils for the c-analyzer Tool (gh-102505) Message-ID: https://github.com/python/cpython/commit/ca066bdbed85094a9c4d9930823ce3587807db48 commit: ca066bdbed85094a9c4d9930823ce3587807db48 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-09T09:50:33-07:00 summary: gh-81057: Vendor a Subset of distutils for the c-analyzer Tool (gh-102505) distutils was removed in November. However, the c-analyzer relies on it. To solve that here, we vendor the parts the tool needs so it can be run against 3.12+. (Also see gh-92584.) Note that we may end up removing this code later in favor of a solution in common with the peg_generator tool (which also relies on distutils). At the least, the copy here makes sure the c-analyzer tool works on 3.12+ in the meantime. files: A Tools/c-analyzer/distutils/README A Tools/c-analyzer/distutils/__init__.py A Tools/c-analyzer/distutils/_msvccompiler.py A Tools/c-analyzer/distutils/bcppcompiler.py A Tools/c-analyzer/distutils/ccompiler.py A Tools/c-analyzer/distutils/cygwinccompiler.py A Tools/c-analyzer/distutils/debug.py A Tools/c-analyzer/distutils/dep_util.py A Tools/c-analyzer/distutils/errors.py A Tools/c-analyzer/distutils/log.py A Tools/c-analyzer/distutils/msvc9compiler.py A Tools/c-analyzer/distutils/msvccompiler.py A Tools/c-analyzer/distutils/spawn.py A Tools/c-analyzer/distutils/unixccompiler.py A Tools/c-analyzer/distutils/util.py diff --git a/Tools/c-analyzer/distutils/README b/Tools/c-analyzer/distutils/README new file mode 100644 index 000000000000..b260b8e06fac --- /dev/null +++ b/Tools/c-analyzer/distutils/README @@ -0,0 +1,2 @@ +This is a partial copy of distutils as it was removed in 0faa0ba240e. +It only includes the parts needed by the C parser. diff --git a/Tools/c-analyzer/distutils/__init__.py b/Tools/c-analyzer/distutils/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Tools/c-analyzer/distutils/_msvccompiler.py b/Tools/c-analyzer/distutils/_msvccompiler.py new file mode 100644 index 000000000000..1e67870d1332 --- /dev/null +++ b/Tools/c-analyzer/distutils/_msvccompiler.py @@ -0,0 +1,203 @@ +"""distutils._msvccompiler + +Contains MSVCCompiler, an implementation of the abstract CCompiler class +for Microsoft Visual Studio 2015. + +The module is compatible with VS 2015 and later. You can find legacy support +for older versions in distutils.msvc9compiler and distutils.msvccompiler. +""" + +# Written by Perry Stoll +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) +# ported to VS 2005 and VS 2008 by Christian Heimes +# ported to VS 2015 by Steve Dower + +import os +import subprocess +import winreg + +from distutils.errors import DistutilsPlatformError +from distutils.ccompiler import CCompiler +from distutils import log + +from itertools import count + +def _find_vc2015(): + try: + key = winreg.OpenKeyEx( + winreg.HKEY_LOCAL_MACHINE, + r"Software\Microsoft\VisualStudio\SxS\VC7", + access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY + ) + except OSError: + log.debug("Visual C++ is not registered") + return None, None + + best_version = 0 + best_dir = None + with key: + for i in count(): + try: + v, vc_dir, vt = winreg.EnumValue(key, i) + except OSError: + break + if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir): + try: + version = int(float(v)) + except (ValueError, TypeError): + continue + if version >= 14 and version > best_version: + best_version, best_dir = version, vc_dir + return best_version, best_dir + +def _find_vc2017(): + """Returns "15, path" based on the result of invoking vswhere.exe + If no install is found, returns "None, None" + + The version is returned to avoid unnecessarily changing the function + result. It may be ignored when the path is not None. + + If vswhere.exe is not available, by definition, VS 2017 is not + installed. + """ + root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles") + if not root: + return None, None + + try: + path = subprocess.check_output([ + os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"), + "-latest", + "-prerelease", + "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", "installationPath", + "-products", "*", + ], encoding="mbcs", errors="strict").strip() + except (subprocess.CalledProcessError, OSError, UnicodeDecodeError): + return None, None + + path = os.path.join(path, "VC", "Auxiliary", "Build") + if os.path.isdir(path): + return 15, path + + return None, None + +PLAT_SPEC_TO_RUNTIME = { + 'x86' : 'x86', + 'x86_amd64' : 'x64', + 'x86_arm' : 'arm', + 'x86_arm64' : 'arm64' +} + +def _find_vcvarsall(plat_spec): + # bpo-38597: Removed vcruntime return value + _, best_dir = _find_vc2017() + + if not best_dir: + best_version, best_dir = _find_vc2015() + + if not best_dir: + log.debug("No suitable Visual C++ version found") + return None, None + + vcvarsall = os.path.join(best_dir, "vcvarsall.bat") + if not os.path.isfile(vcvarsall): + log.debug("%s cannot be found", vcvarsall) + return None, None + + return vcvarsall, None + +def _get_vc_env(plat_spec): + if os.getenv("DISTUTILS_USE_SDK"): + return { + key.lower(): value + for key, value in os.environ.items() + } + + vcvarsall, _ = _find_vcvarsall(plat_spec) + if not vcvarsall: + raise DistutilsPlatformError("Unable to find vcvarsall.bat") + + try: + out = subprocess.check_output( + 'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec), + stderr=subprocess.STDOUT, + ).decode('utf-16le', errors='replace') + except subprocess.CalledProcessError as exc: + log.error(exc.output) + raise DistutilsPlatformError("Error executing {}" + .format(exc.cmd)) + + env = { + key.lower(): value + for key, _, value in + (line.partition('=') for line in out.splitlines()) + if key and value + } + + return env + +def _find_exe(exe, paths=None): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + if not paths: + paths = os.getenv('path').split(os.pathsep) + for p in paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + return exe + +# A map keyed by get_platform() return values to values accepted by +# 'vcvarsall.bat'. Always cross-compile from x86 to work with the +# lighter-weight MSVC installs that do not include native 64-bit tools. +PLAT_TO_VCVARS = { + 'win32' : 'x86', + 'win-amd64' : 'x86_amd64', + 'win-arm32' : 'x86_arm', + 'win-arm64' : 'x86_arm64' +} + +class MSVCCompiler(CCompiler) : + """Concrete class that implements an interface to Microsoft Visual C++, + as defined by the CCompiler abstract class.""" + + compiler_type = 'msvc' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + _rc_extensions = ['.rc'] + _mc_extensions = ['.mc'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = (_c_extensions + _cpp_extensions + + _rc_extensions + _mc_extensions) + res_extension = '.res' + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + + def __init__(self, verbose=0, dry_run=0, force=0): + CCompiler.__init__ (self, verbose, dry_run, force) + # target platform (.plat_name is consistent with 'bdist') + self.plat_name = None + self.initialized = False diff --git a/Tools/c-analyzer/distutils/bcppcompiler.py b/Tools/c-analyzer/distutils/bcppcompiler.py new file mode 100644 index 000000000000..4575b665c10c --- /dev/null +++ b/Tools/c-analyzer/distutils/bcppcompiler.py @@ -0,0 +1,109 @@ +"""distutils.bcppcompiler + +Contains BorlandCCompiler, an implementation of the abstract CCompiler class +for the Borland C++ compiler. +""" + +# This implementation by Lyle Johnson, based on the original msvccompiler.py +# module and using the directions originally published by Gordon Williams. + +# XXX looks like there's a LOT of overlap between these two classes: +# someone should sit down and factor out the common code as +# WindowsCCompiler! --GPW + + +import os +from distutils.errors import DistutilsExecError, CompileError +from distutils.ccompiler import \ + CCompiler, gen_preprocess_options +from distutils.dep_util import newer + +class BCPPCompiler(CCompiler) : + """Concrete class that implements an interface to the Borland C/C++ + compiler, as defined by the CCompiler abstract class. + """ + + compiler_type = 'bcpp' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = _c_extensions + _cpp_extensions + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + + def __init__ (self, + verbose=0, + dry_run=0, + force=0): + + CCompiler.__init__ (self, verbose, dry_run, force) + + # These executables are assumed to all be in the path. + # Borland doesn't seem to use any special registry settings to + # indicate their installation locations. + + self.cc = "bcc32.exe" + self.linker = "ilink32.exe" + self.lib = "tlib.exe" + + self.preprocess_options = None + self.compile_options = ['/tWM', '/O2', '/q', '/g0'] + self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0'] + + self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x'] + self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x'] + self.ldflags_static = [] + self.ldflags_exe = ['/Gn', '/q', '/x'] + self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r'] + + + # -- Worker methods ------------------------------------------------ + + def preprocess (self, + source, + output_file=None, + macros=None, + include_dirs=None, + extra_preargs=None, + extra_postargs=None): + + (_, macros, include_dirs) = \ + self._fix_compile_args(None, macros, include_dirs) + pp_opts = gen_preprocess_options(macros, include_dirs) + pp_args = ['cpp32.exe'] + pp_opts + if output_file is not None: + pp_args.append('-o' + output_file) + if extra_preargs: + pp_args[:0] = extra_preargs + if extra_postargs: + pp_args.extend(extra_postargs) + pp_args.append(source) + + # We need to preprocess: either we're being forced to, or the + # source file is newer than the target (or the target doesn't + # exist). + if self.force or output_file is None or newer(source, output_file): + if output_file: + self.mkpath(os.path.dirname(output_file)) + try: + self.spawn(pp_args) + except DistutilsExecError as msg: + print(msg) + raise CompileError(msg) + + # preprocess() diff --git a/Tools/c-analyzer/distutils/ccompiler.py b/Tools/c-analyzer/distutils/ccompiler.py new file mode 100644 index 000000000000..13e43103b94f --- /dev/null +++ b/Tools/c-analyzer/distutils/ccompiler.py @@ -0,0 +1,470 @@ +"""distutils.ccompiler + +Contains CCompiler, an abstract base class that defines the interface +for the Distutils compiler abstraction model.""" + +import sys, os, re +from distutils.errors import ( + DistutilsModuleError, DistutilsPlatformError, +) +from distutils.util import split_quoted + +class CCompiler: + """Abstract base class to define the interface that must be implemented + by real compiler classes. Also has some utility methods used by + several compiler classes. + + The basic idea behind a compiler abstraction class is that each + instance can be used for all the compile/link steps in building a + single project. Thus, attributes common to all of those compile and + link steps -- include directories, macros to define, libraries to link + against, etc. -- are attributes of the compiler instance. To allow for + variability in how individual files are treated, most of those + attributes may be varied on a per-compilation or per-link basis. + """ + + # 'compiler_type' is a class attribute that identifies this class. It + # keeps code that wants to know what kind of compiler it's dealing with + # from having to import all possible compiler classes just to do an + # 'isinstance'. In concrete CCompiler subclasses, 'compiler_type' + # should really, really be one of the keys of the 'compiler_class' + # dictionary (see below -- used by the 'new_compiler()' factory + # function) -- authors of new compiler interface classes are + # responsible for updating 'compiler_class'! + compiler_type = None + + # XXX things not handled by this compiler abstraction model: + # * client can't provide additional options for a compiler, + # e.g. warning, optimization, debugging flags. Perhaps this + # should be the domain of concrete compiler abstraction classes + # (UnixCCompiler, MSVCCompiler, etc.) -- or perhaps the base + # class should have methods for the common ones. + # * can't completely override the include or library searchg + # path, ie. no "cc -I -Idir1 -Idir2" or "cc -L -Ldir1 -Ldir2". + # I'm not sure how widely supported this is even by Unix + # compilers, much less on other platforms. And I'm even less + # sure how useful it is; maybe for cross-compiling, but + # support for that is a ways off. (And anyways, cross + # compilers probably have a dedicated binary with the + # right paths compiled in. I hope.) + # * can't do really freaky things with the library list/library + # dirs, e.g. "-Ldir1 -lfoo -Ldir2 -lfoo" to link against + # different versions of libfoo.a in different locations. I + # think this is useless without the ability to null out the + # library search path anyways. + + + # Subclasses that rely on the standard filename generation methods + # implemented below should override these; see the comment near + # those methods ('object_filenames()' et. al.) for details: + src_extensions = None # list of strings + obj_extension = None # string + static_lib_extension = None + shared_lib_extension = None # string + static_lib_format = None # format string + shared_lib_format = None # prob. same as static_lib_format + exe_extension = None # string + + # Default language settings. language_map is used to detect a source + # file or Extension target language, checking source filenames. + # language_order is used to detect the language precedence, when deciding + # what language to use when mixing source types. For example, if some + # extension has two files with ".c" extension, and one with ".cpp", it + # is still linked as c++. + language_map = {".c" : "c", + ".cc" : "c++", + ".cpp" : "c++", + ".cxx" : "c++", + ".m" : "objc", + } + language_order = ["c++", "objc", "c"] + + def __init__(self, verbose=0, dry_run=0, force=0): + self.dry_run = dry_run + self.force = force + self.verbose = verbose + + # 'output_dir': a common output directory for object, library, + # shared object, and shared library files + self.output_dir = None + + # 'macros': a list of macro definitions (or undefinitions). A + # macro definition is a 2-tuple (name, value), where the value is + # either a string or None (no explicit value). A macro + # undefinition is a 1-tuple (name,). + self.macros = [] + + # 'include_dirs': a list of directories to search for include files + self.include_dirs = [] + + # 'libraries': a list of libraries to include in any link + # (library names, not filenames: eg. "foo" not "libfoo.a") + self.libraries = [] + + # 'library_dirs': a list of directories to search for libraries + self.library_dirs = [] + + # 'runtime_library_dirs': a list of directories to search for + # shared libraries/objects at runtime + self.runtime_library_dirs = [] + + # 'objects': a list of object files (or similar, such as explicitly + # named library files) to include on any link + self.objects = [] + + for key in self.executables.keys(): + self.set_executable(key, self.executables[key]) + + def set_executables(self, **kwargs): + """Define the executables (and options for them) that will be run + to perform the various stages of compilation. The exact set of + executables that may be specified here depends on the compiler + class (via the 'executables' class attribute), but most will have: + compiler the C/C++ compiler + linker_so linker used to create shared objects and libraries + linker_exe linker used to create binary executables + archiver static library creator + + On platforms with a command-line (Unix, DOS/Windows), each of these + is a string that will be split into executable name and (optional) + list of arguments. (Splitting the string is done similarly to how + Unix shells operate: words are delimited by spaces, but quotes and + backslashes can override this. See + 'distutils.util.split_quoted()'.) + """ + + # Note that some CCompiler implementation classes will define class + # attributes 'cpp', 'cc', etc. with hard-coded executable names; + # this is appropriate when a compiler class is for exactly one + # compiler/OS combination (eg. MSVCCompiler). Other compiler + # classes (UnixCCompiler, in particular) are driven by information + # discovered at run-time, since there are many different ways to do + # basically the same things with Unix C compilers. + + for key in kwargs: + if key not in self.executables: + raise ValueError("unknown executable '%s' for class %s" % + (key, self.__class__.__name__)) + self.set_executable(key, kwargs[key]) + + def set_executable(self, key, value): + if isinstance(value, str): + setattr(self, key, split_quoted(value)) + else: + setattr(self, key, value) + + def _find_macro(self, name): + i = 0 + for defn in self.macros: + if defn[0] == name: + return i + i += 1 + return None + + def _check_macro_definitions(self, definitions): + """Ensures that every element of 'definitions' is a valid macro + definition, ie. either (name,value) 2-tuple or a (name,) tuple. Do + nothing if all definitions are OK, raise TypeError otherwise. + """ + for defn in definitions: + if not (isinstance(defn, tuple) and + (len(defn) in (1, 2) and + (isinstance (defn[1], str) or defn[1] is None)) and + isinstance (defn[0], str)): + raise TypeError(("invalid macro definition '%s': " % defn) + \ + "must be tuple (string,), (string, string), or " + \ + "(string, None)") + + + # -- Bookkeeping methods ------------------------------------------- + + def define_macro(self, name, value=None): + """Define a preprocessor macro for all compilations driven by this + compiler object. The optional parameter 'value' should be a + string; if it is not supplied, then the macro will be defined + without an explicit value and the exact outcome depends on the + compiler used (XXX true? does ANSI say anything about this?) + """ + # Delete from the list of macro definitions/undefinitions if + # already there (so that this one will take precedence). + i = self._find_macro (name) + if i is not None: + del self.macros[i] + + self.macros.append((name, value)) + + def undefine_macro(self, name): + """Undefine a preprocessor macro for all compilations driven by + this compiler object. If the same macro is defined by + 'define_macro()' and undefined by 'undefine_macro()' the last call + takes precedence (including multiple redefinitions or + undefinitions). If the macro is redefined/undefined on a + per-compilation basis (ie. in the call to 'compile()'), then that + takes precedence. + """ + # Delete from the list of macro definitions/undefinitions if + # already there (so that this one will take precedence). + i = self._find_macro (name) + if i is not None: + del self.macros[i] + + undefn = (name,) + self.macros.append(undefn) + + def add_include_dir(self, dir): + """Add 'dir' to the list of directories that will be searched for + header files. The compiler is instructed to search directories in + the order in which they are supplied by successive calls to + 'add_include_dir()'. + """ + self.include_dirs.append(dir) + + def set_include_dirs(self, dirs): + """Set the list of directories that will be searched to 'dirs' (a + list of strings). Overrides any preceding calls to + 'add_include_dir()'; subsequence calls to 'add_include_dir()' add + to the list passed to 'set_include_dirs()'. This does not affect + any list of standard include directories that the compiler may + search by default. + """ + self.include_dirs = dirs[:] + + + # -- Private utility methods -------------------------------------- + # (here for the convenience of subclasses) + + # Helper method to prep compiler in subclass compile() methods + + def _fix_compile_args(self, output_dir, macros, include_dirs): + """Typecheck and fix-up some of the arguments to the 'compile()' + method, and return fixed-up values. Specifically: if 'output_dir' + is None, replaces it with 'self.output_dir'; ensures that 'macros' + is a list, and augments it with 'self.macros'; ensures that + 'include_dirs' is a list, and augments it with 'self.include_dirs'. + Guarantees that the returned values are of the correct type, + i.e. for 'output_dir' either string or None, and for 'macros' and + 'include_dirs' either list or None. + """ + if output_dir is None: + output_dir = self.output_dir + elif not isinstance(output_dir, str): + raise TypeError("'output_dir' must be a string or None") + + if macros is None: + macros = self.macros + elif isinstance(macros, list): + macros = macros + (self.macros or []) + else: + raise TypeError("'macros' (if supplied) must be a list of tuples") + + if include_dirs is None: + include_dirs = self.include_dirs + elif isinstance(include_dirs, (list, tuple)): + include_dirs = list(include_dirs) + (self.include_dirs or []) + else: + raise TypeError( + "'include_dirs' (if supplied) must be a list of strings") + + return output_dir, macros, include_dirs + + + # -- Worker methods ------------------------------------------------ + # (must be implemented by subclasses) + + def preprocess(self, source, output_file=None, macros=None, + include_dirs=None, extra_preargs=None, extra_postargs=None): + """Preprocess a single C/C++ source file, named in 'source'. + Output will be written to file named 'output_file', or stdout if + 'output_file' not supplied. 'macros' is a list of macro + definitions as for 'compile()', which will augment the macros set + with 'define_macro()' and 'undefine_macro()'. 'include_dirs' is a + list of directory names that will be added to the default list. + + Raises PreprocessError on failure. + """ + pass + + + # -- Miscellaneous methods ----------------------------------------- + # These are all used by the 'gen_lib_options() function; there is + # no appropriate default implementation so subclasses should + # implement all of these. + +# def library_dir_option(self, dir): +# """Return the compiler option to add 'dir' to the list of +# directories searched for libraries. +# """ +# raise NotImplementedError +# +# def runtime_library_dir_option(self, dir): +# """Return the compiler option to add 'dir' to the list of +# directories searched for runtime libraries. +# """ +# raise NotImplementedError +# +# def library_option(self, lib): +# """Return the compiler option to add 'lib' to the list of libraries +# linked into the shared library or executable. +# """ +# raise NotImplementedError +# +# def find_library_file (self, dirs, lib, debug=0): +# """Search the specified list of directories for a static or shared +# library file 'lib' and return the full path to that file. If +# 'debug' true, look for a debugging version (if that makes sense on +# the current platform). Return None if 'lib' wasn't found in any of +# the specified directories. +# """ +# raise NotImplementedError + + + # -- Utility methods ----------------------------------------------- + + def spawn(self, cmd): + raise NotImplementedError + + +# Map a sys.platform/os.name ('posix', 'nt') to the default compiler +# type for that platform. Keys are interpreted as re match +# patterns. Order is important; platform mappings are preferred over +# OS names. +_default_compilers = ( + + # Platform string mappings + + # on a cygwin built python we can use gcc like an ordinary UNIXish + # compiler + ('cygwin.*', 'unix'), + + # OS name mappings + ('posix', 'unix'), + ('nt', 'msvc'), + + ) + +def get_default_compiler(osname=None, platform=None): + """Determine the default compiler to use for the given platform. + + osname should be one of the standard Python OS names (i.e. the + ones returned by os.name) and platform the common value + returned by sys.platform for the platform in question. + + The default values are os.name and sys.platform in case the + parameters are not given. + """ + if osname is None: + osname = os.name + if platform is None: + platform = sys.platform + for pattern, compiler in _default_compilers: + if re.match(pattern, platform) is not None or \ + re.match(pattern, osname) is not None: + return compiler + # Default to Unix compiler + return 'unix' + +# Map compiler types to (module_name, class_name) pairs -- ie. where to +# find the code that implements an interface to this compiler. (The module +# is assumed to be in the 'distutils' package.) +compiler_class = { 'unix': ('unixccompiler', 'UnixCCompiler', + "standard UNIX-style compiler"), + 'msvc': ('_msvccompiler', 'MSVCCompiler', + "Microsoft Visual C++"), + 'cygwin': ('cygwinccompiler', 'CygwinCCompiler', + "Cygwin port of GNU C Compiler for Win32"), + 'mingw32': ('cygwinccompiler', 'Mingw32CCompiler', + "Mingw32 port of GNU C Compiler for Win32"), + 'bcpp': ('bcppcompiler', 'BCPPCompiler', + "Borland C++ Compiler"), + } + + +def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0): + """Generate an instance of some CCompiler subclass for the supplied + platform/compiler combination. 'plat' defaults to 'os.name' + (eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler + for that platform. Currently only 'posix' and 'nt' are supported, and + the default compilers are "traditional Unix interface" (UnixCCompiler + class) and Visual C++ (MSVCCompiler class). Note that it's perfectly + possible to ask for a Unix compiler object under Windows, and a + Microsoft compiler object under Unix -- if you supply a value for + 'compiler', 'plat' is ignored. + """ + if plat is None: + plat = os.name + + try: + if compiler is None: + compiler = get_default_compiler(plat) + + (module_name, class_name, long_description) = compiler_class[compiler] + except KeyError: + msg = "don't know how to compile C/C++ code on platform '%s'" % plat + if compiler is not None: + msg = msg + " with '%s' compiler" % compiler + raise DistutilsPlatformError(msg) + + try: + module_name = "distutils." + module_name + __import__ (module_name) + module = sys.modules[module_name] + klass = vars(module)[class_name] + except ImportError: + raise + raise DistutilsModuleError( + "can't compile C/C++ code: unable to load module '%s'" % \ + module_name) + except KeyError: + raise DistutilsModuleError( + "can't compile C/C++ code: unable to find class '%s' " + "in module '%s'" % (class_name, module_name)) + + # XXX The None is necessary to preserve backwards compatibility + # with classes that expect verbose to be the first positional + # argument. + return klass(None, dry_run, force) + + +def gen_preprocess_options(macros, include_dirs): + """Generate C pre-processor options (-D, -U, -I) as used by at least + two types of compilers: the typical Unix compiler and Visual C++. + 'macros' is the usual thing, a list of 1- or 2-tuples, where (name,) + means undefine (-U) macro 'name', and (name,value) means define (-D) + macro 'name' to 'value'. 'include_dirs' is just a list of directory + names to be added to the header file search path (-I). Returns a list + of command-line options suitable for either Unix compilers or Visual + C++. + """ + # XXX it would be nice (mainly aesthetic, and so we don't generate + # stupid-looking command lines) to go over 'macros' and eliminate + # redundant definitions/undefinitions (ie. ensure that only the + # latest mention of a particular macro winds up on the command + # line). I don't think it's essential, though, since most (all?) + # Unix C compilers only pay attention to the latest -D or -U + # mention of a macro on their command line. Similar situation for + # 'include_dirs'. I'm punting on both for now. Anyways, weeding out + # redundancies like this should probably be the province of + # CCompiler, since the data structures used are inherited from it + # and therefore common to all CCompiler classes. + pp_opts = [] + for macro in macros: + if not (isinstance(macro, tuple) and 1 <= len(macro) <= 2): + raise TypeError( + "bad macro definition '%s': " + "each element of 'macros' list must be a 1- or 2-tuple" + % macro) + + if len(macro) == 1: # undefine this macro + pp_opts.append("-U%s" % macro[0]) + elif len(macro) == 2: + if macro[1] is None: # define with no explicit value + pp_opts.append("-D%s" % macro[0]) + else: + # XXX *don't* need to be clever about quoting the + # macro value here, because we're going to avoid the + # shell at all costs when we spawn the command! + pp_opts.append("-D%s=%s" % macro) + + for dir in include_dirs: + pp_opts.append("-I%s" % dir) + return pp_opts diff --git a/Tools/c-analyzer/distutils/cygwinccompiler.py b/Tools/c-analyzer/distutils/cygwinccompiler.py new file mode 100644 index 000000000000..a3505f31f1f0 --- /dev/null +++ b/Tools/c-analyzer/distutils/cygwinccompiler.py @@ -0,0 +1,286 @@ +"""distutils.cygwinccompiler + +Provides the CygwinCCompiler class, a subclass of UnixCCompiler that +handles the Cygwin port of the GNU C compiler to Windows. It also contains +the Mingw32CCompiler class which handles the mingw32 port of GCC (same as +cygwin in no-cygwin mode). +""" + +# problems: +# +# * if you use a msvc compiled python version (1.5.2) +# 1. you have to insert a __GNUC__ section in its config.h +# 2. you have to generate an import library for its dll +# - create a def-file for python??.dll +# - create an import library using +# dlltool --dllname python15.dll --def python15.def \ +# --output-lib libpython15.a +# +# see also http://starship.python.net/crew/kernr/mingw32/Notes.html +# +# * We put export_symbols in a def-file, and don't use +# --export-all-symbols because it doesn't worked reliable in some +# tested configurations. And because other windows compilers also +# need their symbols specified this no serious problem. +# +# tested configurations: +# +# * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works +# (after patching python's config.h and for C++ some other include files) +# see also http://starship.python.net/crew/kernr/mingw32/Notes.html +# * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works +# (ld doesn't support -shared, so we use dllwrap) +# * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now +# - its dllwrap doesn't work, there is a bug in binutils 2.10.90 +# see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html +# - using gcc -mdll instead dllwrap doesn't work without -static because +# it tries to link against dlls instead their import libraries. (If +# it finds the dll first.) +# By specifying -static we force ld to link against the import libraries, +# this is windows standard and there are normally not the necessary symbols +# in the dlls. +# *** only the version of June 2000 shows these problems +# * cygwin gcc 3.2/ld 2.13.90 works +# (ld supports -shared) +# * mingw gcc 3.2/ld 2.13 works +# (ld supports -shared) + +import os +import sys +from subprocess import Popen, PIPE, check_output +import re + +from distutils.unixccompiler import UnixCCompiler +from distutils.errors import CCompilerError +from distutils.version import LooseVersion +from distutils.spawn import find_executable + +def get_msvcr(): + """Include the appropriate MSVC runtime library if Python was built + with MSVC 7.0 or later. + """ + msc_pos = sys.version.find('MSC v.') + if msc_pos != -1: + msc_ver = sys.version[msc_pos+6:msc_pos+10] + if msc_ver == '1300': + # MSVC 7.0 + return ['msvcr70'] + elif msc_ver == '1310': + # MSVC 7.1 + return ['msvcr71'] + elif msc_ver == '1400': + # VS2005 / MSVC 8.0 + return ['msvcr80'] + elif msc_ver == '1500': + # VS2008 / MSVC 9.0 + return ['msvcr90'] + elif msc_ver == '1600': + # VS2010 / MSVC 10.0 + return ['msvcr100'] + else: + raise ValueError("Unknown MS Compiler version %s " % msc_ver) + + +class CygwinCCompiler(UnixCCompiler): + """ Handles the Cygwin port of the GNU C compiler to Windows. + """ + compiler_type = 'cygwin' + obj_extension = ".o" + static_lib_extension = ".a" + shared_lib_extension = ".dll" + static_lib_format = "lib%s%s" + shared_lib_format = "%s%s" + exe_extension = ".exe" + + def __init__(self, verbose=0, dry_run=0, force=0): + + UnixCCompiler.__init__(self, verbose, dry_run, force) + + status, details = check_config_h() + self.debug_print("Python's GCC status: %s (details: %s)" % + (status, details)) + if status is not CONFIG_H_OK: + self.warn( + "Python's pyconfig.h doesn't seem to support your compiler. " + "Reason: %s. " + "Compiling may fail because of undefined preprocessor macros." + % details) + + self.gcc_version, self.ld_version, self.dllwrap_version = \ + get_versions() + self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" % + (self.gcc_version, + self.ld_version, + self.dllwrap_version) ) + + # ld_version >= "2.10.90" and < "2.13" should also be able to use + # gcc -mdll instead of dllwrap + # Older dllwraps had own version numbers, newer ones use the + # same as the rest of binutils ( also ld ) + # dllwrap 2.10.90 is buggy + if self.ld_version >= "2.10.90": + self.linker_dll = "gcc" + else: + self.linker_dll = "dllwrap" + + # ld_version >= "2.13" support -shared so use it instead of + # -mdll -static + if self.ld_version >= "2.13": + shared_option = "-shared" + else: + shared_option = "-mdll -static" + + # Hard-code GCC because that's what this is all about. + # XXX optimization, warnings etc. should be customizable. + self.set_executables(compiler='gcc -mcygwin -O -Wall', + compiler_so='gcc -mcygwin -mdll -O -Wall', + compiler_cxx='g++ -mcygwin -O -Wall', + linker_exe='gcc -mcygwin', + linker_so=('%s -mcygwin %s' % + (self.linker_dll, shared_option))) + + # cygwin and mingw32 need different sets of libraries + if self.gcc_version == "2.91.57": + # cygwin shouldn't need msvcrt, but without the dlls will crash + # (gcc version 2.91.57) -- perhaps something about initialization + self.dll_libraries=["msvcrt"] + self.warn( + "Consider upgrading to a newer version of gcc") + else: + # Include the appropriate MSVC runtime library if Python was built + # with MSVC 7.0 or later. + self.dll_libraries = get_msvcr() + + +# the same as cygwin plus some additional parameters +class Mingw32CCompiler(CygwinCCompiler): + """ Handles the Mingw32 port of the GNU C compiler to Windows. + """ + compiler_type = 'mingw32' + + def __init__(self, verbose=0, dry_run=0, force=0): + + CygwinCCompiler.__init__ (self, verbose, dry_run, force) + + # ld_version >= "2.13" support -shared so use it instead of + # -mdll -static + if self.ld_version >= "2.13": + shared_option = "-shared" + else: + shared_option = "-mdll -static" + + # A real mingw32 doesn't need to specify a different entry point, + # but cygwin 2.91.57 in no-cygwin-mode needs it. + if self.gcc_version <= "2.91.57": + entry_point = '--entry _DllMain at 12' + else: + entry_point = '' + + if is_cygwingcc(): + raise CCompilerError( + 'Cygwin gcc cannot be used with --compiler=mingw32') + + self.set_executables(compiler='gcc -O -Wall', + compiler_so='gcc -mdll -O -Wall', + compiler_cxx='g++ -O -Wall', + linker_exe='gcc', + linker_so='%s %s %s' + % (self.linker_dll, shared_option, + entry_point)) + # Maybe we should also append -mthreads, but then the finished + # dlls need another dll (mingwm10.dll see Mingw32 docs) + # (-mthreads: Support thread-safe exception handling on `Mingw32') + + # no additional libraries needed + self.dll_libraries=[] + + # Include the appropriate MSVC runtime library if Python was built + # with MSVC 7.0 or later. + self.dll_libraries = get_msvcr() + +# Because these compilers aren't configured in Python's pyconfig.h file by +# default, we should at least warn the user if he is using an unmodified +# version. + +CONFIG_H_OK = "ok" +CONFIG_H_NOTOK = "not ok" +CONFIG_H_UNCERTAIN = "uncertain" + +def check_config_h(): + """Check if the current Python installation appears amenable to building + extensions with GCC. + + Returns a tuple (status, details), where 'status' is one of the following + constants: + + - CONFIG_H_OK: all is well, go ahead and compile + - CONFIG_H_NOTOK: doesn't look good + - CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h + + 'details' is a human-readable string explaining the situation. + + Note there are two ways to conclude "OK": either 'sys.version' contains + the string "GCC" (implying that this Python was built with GCC), or the + installed "pyconfig.h" contains the string "__GNUC__". + """ + + # XXX since this function also checks sys.version, it's not strictly a + # "pyconfig.h" check -- should probably be renamed... + + import sysconfig + + # if sys.version contains GCC then python was compiled with GCC, and the + # pyconfig.h file should be OK + if "GCC" in sys.version: + return CONFIG_H_OK, "sys.version mentions 'GCC'" + + # let's see if __GNUC__ is mentioned in python.h + fn = sysconfig.get_config_h_filename() + try: + config_h = open(fn) + try: + if "__GNUC__" in config_h.read(): + return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn + else: + return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn + finally: + config_h.close() + except OSError as exc: + return (CONFIG_H_UNCERTAIN, + "couldn't read '%s': %s" % (fn, exc.strerror)) + +RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)') + +def _find_exe_version(cmd): + """Find the version of an executable by running `cmd` in the shell. + + If the command is not found, or the output does not match + `RE_VERSION`, returns None. + """ + executable = cmd.split()[0] + if find_executable(executable) is None: + return None + out = Popen(cmd, shell=True, stdout=PIPE).stdout + try: + out_string = out.read() + finally: + out.close() + result = RE_VERSION.search(out_string) + if result is None: + return None + # LooseVersion works with strings + # so we need to decode our bytes + return LooseVersion(result.group(1).decode()) + +def get_versions(): + """ Try to find out the versions of gcc, ld and dllwrap. + + If not possible it returns None for it. + """ + commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version'] + return tuple([_find_exe_version(cmd) for cmd in commands]) + +def is_cygwingcc(): + '''Try to determine if the gcc that would be used is from cygwin.''' + out_string = check_output(['gcc', '-dumpmachine']) + return out_string.strip().endswith(b'cygwin') diff --git a/Tools/c-analyzer/distutils/debug.py b/Tools/c-analyzer/distutils/debug.py new file mode 100644 index 000000000000..daf1660f0d82 --- /dev/null +++ b/Tools/c-analyzer/distutils/debug.py @@ -0,0 +1,5 @@ +import os + +# If DISTUTILS_DEBUG is anything other than the empty string, we run in +# debug mode. +DEBUG = os.environ.get('DISTUTILS_DEBUG') diff --git a/Tools/c-analyzer/distutils/dep_util.py b/Tools/c-analyzer/distutils/dep_util.py new file mode 100644 index 000000000000..318c830f2eab --- /dev/null +++ b/Tools/c-analyzer/distutils/dep_util.py @@ -0,0 +1,29 @@ +"""distutils.dep_util + +Utility functions for simple, timestamp-based dependency of files +and groups of files; also, function based entirely on such +timestamp dependency analysis.""" + +import os +from distutils.errors import DistutilsFileError + + +def newer (source, target): + """Return true if 'source' exists and is more recently modified than + 'target', or if 'source' exists and 'target' doesn't. Return false if + both exist and 'target' is the same age or younger than 'source'. + Raise DistutilsFileError if 'source' does not exist. + """ + if not os.path.exists(source): + raise DistutilsFileError("file '%s' does not exist" % + os.path.abspath(source)) + if not os.path.exists(target): + return 1 + + from stat import ST_MTIME + mtime1 = os.stat(source)[ST_MTIME] + mtime2 = os.stat(target)[ST_MTIME] + + return mtime1 > mtime2 + +# newer () diff --git a/Tools/c-analyzer/distutils/errors.py b/Tools/c-analyzer/distutils/errors.py new file mode 100644 index 000000000000..10f8e316f675 --- /dev/null +++ b/Tools/c-analyzer/distutils/errors.py @@ -0,0 +1,48 @@ +"""distutils.errors + +Provides exceptions used by the Distutils modules. Note that Distutils +modules may raise standard exceptions; in particular, SystemExit is +usually raised for errors that are obviously the end-user's fault +(eg. bad command-line arguments). + +This module is safe to use in "from ... import *" mode; it only exports +symbols whose names start with "Distutils" and end with "Error".""" + +class DistutilsError (Exception): + """The root of all Distutils evil.""" + pass + +class DistutilsModuleError (DistutilsError): + """Unable to load an expected module, or to find an expected class + within some module (in particular, command modules and classes).""" + pass + +class DistutilsFileError (DistutilsError): + """Any problems in the filesystem: expected file not found, etc. + Typically this is for problems that we detect before OSError + could be raised.""" + pass + +class DistutilsPlatformError (DistutilsError): + """We don't know how to do something on the current platform (but + we do know how to do it on some platform) -- eg. trying to compile + C files on a platform not supported by a CCompiler subclass.""" + pass + +class DistutilsExecError (DistutilsError): + """Any problems executing an external program (such as the C + compiler, when compiling C files).""" + pass + +# Exception classes used by the CCompiler implementation classes +class CCompilerError (Exception): + """Some compile/link operation failed.""" + +class PreprocessError (CCompilerError): + """Failure to preprocess one or more C/C++ files.""" + +class CompileError (CCompilerError): + """Failure to compile one or more C/C++ source files.""" + +class UnknownFileError (CCompilerError): + """Attempt to process an unknown file type.""" diff --git a/Tools/c-analyzer/distutils/log.py b/Tools/c-analyzer/distutils/log.py new file mode 100644 index 000000000000..26ecf22ae19b --- /dev/null +++ b/Tools/c-analyzer/distutils/log.py @@ -0,0 +1,63 @@ +"""A simple log mechanism styled after PEP 282.""" + +# The class here is styled after PEP 282 so that it could later be +# replaced with a standard Python logging implementation. + +DEBUG = 1 +INFO = 2 +WARN = 3 +ERROR = 4 +FATAL = 5 + +import sys + +class Log: + + def __init__(self, threshold=WARN): + self.threshold = threshold + + def _log(self, level, msg, args): + if level not in (DEBUG, INFO, WARN, ERROR, FATAL): + raise ValueError('%s wrong log level' % str(level)) + + if level >= self.threshold: + if args: + msg = msg % args + if level in (WARN, ERROR, FATAL): + stream = sys.stderr + else: + stream = sys.stdout + try: + stream.write('%s\n' % msg) + except UnicodeEncodeError: + # emulate backslashreplace error handler + encoding = stream.encoding + msg = msg.encode(encoding, "backslashreplace").decode(encoding) + stream.write('%s\n' % msg) + stream.flush() + + def log(self, level, msg, *args): + self._log(level, msg, args) + + def debug(self, msg, *args): + self._log(DEBUG, msg, args) + + def info(self, msg, *args): + self._log(INFO, msg, args) + + def warn(self, msg, *args): + self._log(WARN, msg, args) + + def error(self, msg, *args): + self._log(ERROR, msg, args) + + def fatal(self, msg, *args): + self._log(FATAL, msg, args) + +_global_log = Log() +log = _global_log.log +debug = _global_log.debug +info = _global_log.info +warn = _global_log.warn +error = _global_log.error +fatal = _global_log.fatal diff --git a/Tools/c-analyzer/distutils/msvc9compiler.py b/Tools/c-analyzer/distutils/msvc9compiler.py new file mode 100644 index 000000000000..38fff9b2d531 --- /dev/null +++ b/Tools/c-analyzer/distutils/msvc9compiler.py @@ -0,0 +1,438 @@ +"""distutils.msvc9compiler + +Contains MSVCCompiler, an implementation of the abstract CCompiler class +for the Microsoft Visual Studio 2008. + +The module is compatible with VS 2005 and VS 2008. You can find legacy support +for older versions of VS in distutils.msvccompiler. +""" + +# Written by Perry Stoll +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) +# ported to VS2005 and VS 2008 by Christian Heimes + +import os +import subprocess +import sys +import re + +from distutils.errors import DistutilsPlatformError +from distutils.ccompiler import CCompiler +from distutils import log + +import winreg + +RegOpenKeyEx = winreg.OpenKeyEx +RegEnumKey = winreg.EnumKey +RegEnumValue = winreg.EnumValue +RegError = winreg.error + +HKEYS = (winreg.HKEY_USERS, + winreg.HKEY_CURRENT_USER, + winreg.HKEY_LOCAL_MACHINE, + winreg.HKEY_CLASSES_ROOT) + +NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32) +if NATIVE_WIN64: + # Visual C++ is a 32-bit application, so we need to look in + # the corresponding registry branch, if we're running a + # 64-bit Python on Win64 + VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f" + WINSDK_BASE = r"Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows" + NET_BASE = r"Software\Wow6432Node\Microsoft\.NETFramework" +else: + VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f" + WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows" + NET_BASE = r"Software\Microsoft\.NETFramework" + +# A map keyed by get_platform() return values to values accepted by +# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is +# the param to cross-compile on x86 targeting amd64.) +PLAT_TO_VCVARS = { + 'win32' : 'x86', + 'win-amd64' : 'amd64', +} + +class Reg: + """Helper class to read values from the registry + """ + + def get_value(cls, path, key): + for base in HKEYS: + d = cls.read_values(base, path) + if d and key in d: + return d[key] + raise KeyError(key) + get_value = classmethod(get_value) + + def read_keys(cls, base, key): + """Return list of registry keys.""" + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + L = [] + i = 0 + while True: + try: + k = RegEnumKey(handle, i) + except RegError: + break + L.append(k) + i += 1 + return L + read_keys = classmethod(read_keys) + + def read_values(cls, base, key): + """Return dict of registry keys and values. + + All names are converted to lowercase. + """ + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + d = {} + i = 0 + while True: + try: + name, value, type = RegEnumValue(handle, i) + except RegError: + break + name = name.lower() + d[cls.convert_mbcs(name)] = cls.convert_mbcs(value) + i += 1 + return d + read_values = classmethod(read_values) + + def convert_mbcs(s): + dec = getattr(s, "decode", None) + if dec is not None: + try: + s = dec("mbcs") + except UnicodeError: + pass + return s + convert_mbcs = staticmethod(convert_mbcs) + +class MacroExpander: + + def __init__(self, version): + self.macros = {} + self.vsbase = VS_BASE % version + self.load_macros(version) + + def set_macro(self, macro, path, key): + self.macros["$(%s)" % macro] = Reg.get_value(path, key) + + def load_macros(self, version): + self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir") + self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir") + self.set_macro("FrameworkDir", NET_BASE, "installroot") + try: + if version >= 8.0: + self.set_macro("FrameworkSDKDir", NET_BASE, + "sdkinstallrootv2.0") + else: + raise KeyError("sdkinstallrootv2.0") + except KeyError: + raise DistutilsPlatformError( + """Python was built with Visual Studio 2008; +extensions must be built with a compiler than can generate compatible binaries. +Visual Studio 2008 was not found on this system. If you have Cygwin installed, +you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") + + if version >= 9.0: + self.set_macro("FrameworkVersion", self.vsbase, "clr version") + self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder") + else: + p = r"Software\Microsoft\NET Framework Setup\Product" + for base in HKEYS: + try: + h = RegOpenKeyEx(base, p) + except RegError: + continue + key = RegEnumKey(h, 0) + d = Reg.get_value(base, r"%s\%s" % (p, key)) + self.macros["$(FrameworkVersion)"] = d["version"] + + def sub(self, s): + for k, v in self.macros.items(): + s = s.replace(k, v) + return s + +def get_build_version(): + """Return the version of MSVC that was used to build Python. + + For Python 2.3 and up, the version number is included in + sys.version. For earlier versions, assume the compiler is MSVC 6. + """ + prefix = "MSC v." + i = sys.version.find(prefix) + if i == -1: + return 6 + i = i + len(prefix) + s, rest = sys.version[i:].split(" ", 1) + majorVersion = int(s[:-2]) - 6 + if majorVersion >= 13: + # v13 was skipped and should be v14 + majorVersion += 1 + minorVersion = int(s[2:3]) / 10.0 + # I don't think paths are affected by minor version in version 6 + if majorVersion == 6: + minorVersion = 0 + if majorVersion >= 6: + return majorVersion + minorVersion + # else we don't know what version of the compiler this is + return None + +def normalize_and_reduce_paths(paths): + """Return a list of normalized paths with duplicates removed. + + The current order of paths is maintained. + """ + # Paths are normalized so things like: /a and /a/ aren't both preserved. + reduced_paths = [] + for p in paths: + np = os.path.normpath(p) + # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set. + if np not in reduced_paths: + reduced_paths.append(np) + return reduced_paths + +def removeDuplicates(variable): + """Remove duplicate values of an environment variable. + """ + oldList = variable.split(os.pathsep) + newList = [] + for i in oldList: + if i not in newList: + newList.append(i) + newVariable = os.pathsep.join(newList) + return newVariable + +def find_vcvarsall(version): + """Find the vcvarsall.bat file + + At first it tries to find the productdir of VS 2008 in the registry. If + that fails it falls back to the VS90COMNTOOLS env var. + """ + vsbase = VS_BASE % version + try: + productdir = Reg.get_value(r"%s\Setup\VC" % vsbase, + "productdir") + except KeyError: + log.debug("Unable to find productdir in registry") + productdir = None + + if not productdir or not os.path.isdir(productdir): + toolskey = "VS%0.f0COMNTOOLS" % version + toolsdir = os.environ.get(toolskey, None) + + if toolsdir and os.path.isdir(toolsdir): + productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC") + productdir = os.path.abspath(productdir) + if not os.path.isdir(productdir): + log.debug("%s is not a valid directory" % productdir) + return None + else: + log.debug("Env var %s is not set or invalid" % toolskey) + if not productdir: + log.debug("No productdir found") + return None + vcvarsall = os.path.join(productdir, "vcvarsall.bat") + if os.path.isfile(vcvarsall): + return vcvarsall + log.debug("Unable to find vcvarsall.bat") + return None + +def query_vcvarsall(version, arch="x86"): + """Launch vcvarsall.bat and read the settings from its environment + """ + vcvarsall = find_vcvarsall(version) + interesting = {"include", "lib", "libpath", "path"} + result = {} + + if vcvarsall is None: + raise DistutilsPlatformError("Unable to find vcvarsall.bat") + log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version) + popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + try: + stdout, stderr = popen.communicate() + if popen.wait() != 0: + raise DistutilsPlatformError(stderr.decode("mbcs")) + + stdout = stdout.decode("mbcs") + for line in stdout.split("\n"): + line = Reg.convert_mbcs(line) + if '=' not in line: + continue + line = line.strip() + key, value = line.split('=', 1) + key = key.lower() + if key in interesting: + if value.endswith(os.pathsep): + value = value[:-1] + result[key] = removeDuplicates(value) + + finally: + popen.stdout.close() + popen.stderr.close() + + if len(result) != len(interesting): + raise ValueError(str(list(result.keys()))) + + return result + +# More globals +VERSION = get_build_version() +if VERSION < 8.0: + raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION) +# MACROS = MacroExpander(VERSION) + +class MSVCCompiler(CCompiler) : + """Concrete class that implements an interface to Microsoft Visual C++, + as defined by the CCompiler abstract class.""" + + compiler_type = 'msvc' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + _rc_extensions = ['.rc'] + _mc_extensions = ['.mc'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = (_c_extensions + _cpp_extensions + + _rc_extensions + _mc_extensions) + res_extension = '.res' + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + def __init__(self, verbose=0, dry_run=0, force=0): + CCompiler.__init__ (self, verbose, dry_run, force) + self.__version = VERSION + self.__root = r"Software\Microsoft\VisualStudio" + # self.__macros = MACROS + self.__paths = [] + # target platform (.plat_name is consistent with 'bdist') + self.plat_name = None + self.__arch = None # deprecated name + self.initialized = False + + # -- Worker methods ------------------------------------------------ + + def manifest_setup_ldargs(self, output_filename, build_temp, ld_args): + # If we need a manifest at all, an embedded manifest is recommended. + # See MSDN article titled + # "How to: Embed a Manifest Inside a C/C++ Application" + # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx) + # Ask the linker to generate the manifest in the temp dir, so + # we can check it, and possibly embed it, later. + temp_manifest = os.path.join( + build_temp, + os.path.basename(output_filename) + ".manifest") + ld_args.append('/MANIFESTFILE:' + temp_manifest) + + def manifest_get_embed_info(self, target_desc, ld_args): + # If a manifest should be embedded, return a tuple of + # (manifest_filename, resource_id). Returns None if no manifest + # should be embedded. See http://bugs.python.org/issue7833 for why + # we want to avoid any manifest for extension modules if we can. + for arg in ld_args: + if arg.startswith("/MANIFESTFILE:"): + temp_manifest = arg.split(":", 1)[1] + break + else: + # no /MANIFESTFILE so nothing to do. + return None + if target_desc == CCompiler.EXECUTABLE: + # by default, executables always get the manifest with the + # CRT referenced. + mfid = 1 + else: + # Extension modules try and avoid any manifest if possible. + mfid = 2 + temp_manifest = self._remove_visual_c_ref(temp_manifest) + if temp_manifest is None: + return None + return temp_manifest, mfid + + def _remove_visual_c_ref(self, manifest_file): + try: + # Remove references to the Visual C runtime, so they will + # fall through to the Visual C dependency of Python.exe. + # This way, when installed for a restricted user (e.g. + # runtimes are not in WinSxS folder, but in Python's own + # folder), the runtimes do not need to be in every folder + # with .pyd's. + # Returns either the filename of the modified manifest or + # None if no manifest should be embedded. + manifest_f = open(manifest_file) + try: + manifest_buf = manifest_f.read() + finally: + manifest_f.close() + pattern = re.compile( + r"""|)""", + re.DOTALL) + manifest_buf = re.sub(pattern, "", manifest_buf) + pattern = r"\s*" + manifest_buf = re.sub(pattern, "", manifest_buf) + # Now see if any other assemblies are referenced - if not, we + # don't want a manifest embedded. + pattern = re.compile( + r"""|)""", re.DOTALL) + if re.search(pattern, manifest_buf) is None: + return None + + manifest_f = open(manifest_file, 'w') + try: + manifest_f.write(manifest_buf) + return manifest_file + finally: + manifest_f.close() + except OSError: + pass + + # -- Miscellaneous methods ----------------------------------------- + + # Helper methods for using the MSVC registry settings + + def find_exe(self, exe): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + for p in self.__paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + + # didn't find it; try existing path + for p in os.environ['Path'].split(';'): + fn = os.path.join(os.path.abspath(p),exe) + if os.path.isfile(fn): + return fn + + return exe diff --git a/Tools/c-analyzer/distutils/msvccompiler.py b/Tools/c-analyzer/distutils/msvccompiler.py new file mode 100644 index 000000000000..c0864b1f95d4 --- /dev/null +++ b/Tools/c-analyzer/distutils/msvccompiler.py @@ -0,0 +1,327 @@ +"""distutils.msvccompiler + +Contains MSVCCompiler, an implementation of the abstract CCompiler class +for the Microsoft Visual Studio. +""" + +# Written by Perry Stoll +# hacked by Robin Becker and Thomas Heller to do a better job of +# finding DevStudio (through the registry) + +import sys, os +from distutils.errors import DistutilsPlatformError +from distutils.ccompiler import CCompiler +from distutils import log + +_can_read_reg = False +try: + import winreg + + _can_read_reg = True + hkey_mod = winreg + + RegOpenKeyEx = winreg.OpenKeyEx + RegEnumKey = winreg.EnumKey + RegEnumValue = winreg.EnumValue + RegError = winreg.error + +except ImportError: + try: + import win32api + import win32con + _can_read_reg = True + hkey_mod = win32con + + RegOpenKeyEx = win32api.RegOpenKeyEx + RegEnumKey = win32api.RegEnumKey + RegEnumValue = win32api.RegEnumValue + RegError = win32api.error + except ImportError: + log.info("Warning: Can't read registry to find the " + "necessary compiler setting\n" + "Make sure that Python modules winreg, " + "win32api or win32con are installed.") + +if _can_read_reg: + HKEYS = (hkey_mod.HKEY_USERS, + hkey_mod.HKEY_CURRENT_USER, + hkey_mod.HKEY_LOCAL_MACHINE, + hkey_mod.HKEY_CLASSES_ROOT) + +def read_keys(base, key): + """Return list of registry keys.""" + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + L = [] + i = 0 + while True: + try: + k = RegEnumKey(handle, i) + except RegError: + break + L.append(k) + i += 1 + return L + +def read_values(base, key): + """Return dict of registry keys and values. + + All names are converted to lowercase. + """ + try: + handle = RegOpenKeyEx(base, key) + except RegError: + return None + d = {} + i = 0 + while True: + try: + name, value, type = RegEnumValue(handle, i) + except RegError: + break + name = name.lower() + d[convert_mbcs(name)] = convert_mbcs(value) + i += 1 + return d + +def convert_mbcs(s): + dec = getattr(s, "decode", None) + if dec is not None: + try: + s = dec("mbcs") + except UnicodeError: + pass + return s + +class MacroExpander: + def __init__(self, version): + self.macros = {} + self.load_macros(version) + + def set_macro(self, macro, path, key): + for base in HKEYS: + d = read_values(base, path) + if d: + self.macros["$(%s)" % macro] = d[key] + break + + def load_macros(self, version): + vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version + self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir") + self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir") + net = r"Software\Microsoft\.NETFramework" + self.set_macro("FrameworkDir", net, "installroot") + try: + if version > 7.0: + self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1") + else: + self.set_macro("FrameworkSDKDir", net, "sdkinstallroot") + except KeyError as exc: # + raise DistutilsPlatformError( + """Python was built with Visual Studio 2003; +extensions must be built with a compiler than can generate compatible binaries. +Visual Studio 2003 was not found on this system. If you have Cygwin installed, +you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") + + p = r"Software\Microsoft\NET Framework Setup\Product" + for base in HKEYS: + try: + h = RegOpenKeyEx(base, p) + except RegError: + continue + key = RegEnumKey(h, 0) + d = read_values(base, r"%s\%s" % (p, key)) + self.macros["$(FrameworkVersion)"] = d["version"] + + def sub(self, s): + for k, v in self.macros.items(): + s = s.replace(k, v) + return s + +def get_build_version(): + """Return the version of MSVC that was used to build Python. + + For Python 2.3 and up, the version number is included in + sys.version. For earlier versions, assume the compiler is MSVC 6. + """ + prefix = "MSC v." + i = sys.version.find(prefix) + if i == -1: + return 6 + i = i + len(prefix) + s, rest = sys.version[i:].split(" ", 1) + majorVersion = int(s[:-2]) - 6 + if majorVersion >= 13: + # v13 was skipped and should be v14 + majorVersion += 1 + minorVersion = int(s[2:3]) / 10.0 + # I don't think paths are affected by minor version in version 6 + if majorVersion == 6: + minorVersion = 0 + if majorVersion >= 6: + return majorVersion + minorVersion + # else we don't know what version of the compiler this is + return None + +def get_build_architecture(): + """Return the processor architecture. + + Possible results are "Intel" or "AMD64". + """ + + prefix = " bit (" + i = sys.version.find(prefix) + if i == -1: + return "Intel" + j = sys.version.find(")", i) + return sys.version[i+len(prefix):j] + +def normalize_and_reduce_paths(paths): + """Return a list of normalized paths with duplicates removed. + + The current order of paths is maintained. + """ + # Paths are normalized so things like: /a and /a/ aren't both preserved. + reduced_paths = [] + for p in paths: + np = os.path.normpath(p) + # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set. + if np not in reduced_paths: + reduced_paths.append(np) + return reduced_paths + + +class MSVCCompiler(CCompiler) : + """Concrete class that implements an interface to Microsoft Visual C++, + as defined by the CCompiler abstract class.""" + + compiler_type = 'msvc' + + # Just set this so CCompiler's constructor doesn't barf. We currently + # don't use the 'set_executables()' bureaucracy provided by CCompiler, + # as it really isn't necessary for this sort of single-compiler class. + # Would be nice to have a consistent interface with UnixCCompiler, + # though, so it's worth thinking about. + executables = {} + + # Private class data (need to distinguish C from C++ source for compiler) + _c_extensions = ['.c'] + _cpp_extensions = ['.cc', '.cpp', '.cxx'] + _rc_extensions = ['.rc'] + _mc_extensions = ['.mc'] + + # Needed for the filename generation methods provided by the + # base class, CCompiler. + src_extensions = (_c_extensions + _cpp_extensions + + _rc_extensions + _mc_extensions) + res_extension = '.res' + obj_extension = '.obj' + static_lib_extension = '.lib' + shared_lib_extension = '.dll' + static_lib_format = shared_lib_format = '%s%s' + exe_extension = '.exe' + + def __init__(self, verbose=0, dry_run=0, force=0): + CCompiler.__init__ (self, verbose, dry_run, force) + self.__version = get_build_version() + self.__arch = get_build_architecture() + if self.__arch == "Intel": + # x86 + if self.__version >= 7: + self.__root = r"Software\Microsoft\VisualStudio" + self.__macros = MacroExpander(self.__version) + else: + self.__root = r"Software\Microsoft\Devstudio" + self.__product = "Visual Studio version %s" % self.__version + else: + # Win64. Assume this was built with the platform SDK + self.__product = "Microsoft SDK compiler %s" % (self.__version + 6) + + self.initialized = False + + + # -- Miscellaneous methods ----------------------------------------- + + # Helper methods for using the MSVC registry settings + + def find_exe(self, exe): + """Return path to an MSVC executable program. + + Tries to find the program in several places: first, one of the + MSVC program search paths from the registry; next, the directories + in the PATH environment variable. If any of those work, return an + absolute path that is known to exist. If none of them work, just + return the original program name, 'exe'. + """ + for p in self.__paths: + fn = os.path.join(os.path.abspath(p), exe) + if os.path.isfile(fn): + return fn + + # didn't find it; try existing path + for p in os.environ['Path'].split(';'): + fn = os.path.join(os.path.abspath(p),exe) + if os.path.isfile(fn): + return fn + + return exe + + def get_msvc_paths(self, path, platform='x86'): + """Get a list of devstudio directories (include, lib or path). + + Return a list of strings. The list will be empty if unable to + access the registry or appropriate registry keys not found. + """ + if not _can_read_reg: + return [] + + path = path + " dirs" + if self.__version >= 7: + key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" + % (self.__root, self.__version)) + else: + key = (r"%s\6.0\Build System\Components\Platforms" + r"\Win32 (%s)\Directories" % (self.__root, platform)) + + for base in HKEYS: + d = read_values(base, key) + if d: + if self.__version >= 7: + return self.__macros.sub(d[path]).split(";") + else: + return d[path].split(";") + # MSVC 6 seems to create the registry entries we need only when + # the GUI is run. + if self.__version == 6: + for base in HKEYS: + if read_values(base, r"%s\6.0" % self.__root) is not None: + self.warn("It seems you have Visual Studio 6 installed, " + "but the expected registry settings are not present.\n" + "You must at least run the Visual Studio GUI once " + "so that these entries are created.") + break + return [] + + def set_path_env_var(self, name): + """Set environment variable 'name' to an MSVC path type value. + + This is equivalent to a SET command prior to execution of spawned + commands. + """ + + if name == "lib": + p = self.get_msvc_paths("library") + else: + p = self.get_msvc_paths(name) + if p: + os.environ[name] = ';'.join(p) + + +if get_build_version() >= 8.0: + log.debug("Importing new compiler from distutils.msvc9compiler") + OldMSVCCompiler = MSVCCompiler + from distutils.msvc9compiler import MSVCCompiler + # get_build_architecture not really relevant now we support cross-compile + from distutils.msvc9compiler import MacroExpander diff --git a/Tools/c-analyzer/distutils/spawn.py b/Tools/c-analyzer/distutils/spawn.py new file mode 100644 index 000000000000..eb9794964d7a --- /dev/null +++ b/Tools/c-analyzer/distutils/spawn.py @@ -0,0 +1,48 @@ +"""distutils.spawn + +Provides the 'spawn()' function, a front-end to various platform- +specific functions for launching another program in a sub-process. +Also provides the 'find_executable()' to search the path for a given +executable name. +""" + +import sys +import os +import os.path + + +def find_executable(executable, path=None): + """Tries to find 'executable' in the directories listed in 'path'. + + A string listing directories separated by 'os.pathsep'; defaults to + os.environ['PATH']. Returns the complete filename or None if not found. + """ + _, ext = os.path.splitext(executable) + if (sys.platform == 'win32') and (ext != '.exe'): + executable = executable + '.exe' + + if os.path.isfile(executable): + return executable + + if path is None: + path = os.environ.get('PATH', None) + if path is None: + try: + path = os.confstr("CS_PATH") + except (AttributeError, ValueError): + # os.confstr() or CS_PATH is not available + path = os.defpath + # bpo-35755: Don't use os.defpath if the PATH environment variable is + # set to an empty string + + # PATH='' doesn't match, whereas PATH=':' looks in the current directory + if not path: + return None + + paths = path.split(os.pathsep) + for p in paths: + f = os.path.join(p, executable) + if os.path.isfile(f): + # the file exists, we have a shot at spawn working + return f + return None diff --git a/Tools/c-analyzer/distutils/unixccompiler.py b/Tools/c-analyzer/distutils/unixccompiler.py new file mode 100644 index 000000000000..1a3a8e525507 --- /dev/null +++ b/Tools/c-analyzer/distutils/unixccompiler.py @@ -0,0 +1,102 @@ +"""distutils.unixccompiler + +Contains the UnixCCompiler class, a subclass of CCompiler that handles +the "typical" Unix-style command-line C compiler: + * macros defined with -Dname[=value] + * macros undefined with -Uname + * include search directories specified with -Idir + * libraries specified with -lllib + * library search directories specified with -Ldir + * compile handled by 'cc' (or similar) executable with -c option: + compiles .c to .o + * link static library handled by 'ar' command (possibly with 'ranlib') + * link shared library handled by 'cc -shared' +""" + +import os, sys, re + +from distutils.dep_util import newer +from distutils.ccompiler import CCompiler, gen_preprocess_options +from distutils.errors import DistutilsExecError, CompileError + +# XXX Things not currently handled: +# * optimization/debug/warning flags; we just use whatever's in Python's +# Makefile and live with it. Is this adequate? If not, we might +# have to have a bunch of subclasses GNUCCompiler, SGICCompiler, +# SunCCompiler, and I suspect down that road lies madness. +# * even if we don't know a warning flag from an optimization flag, +# we need some way for outsiders to feed preprocessor/compiler/linker +# flags in to us -- eg. a sysadmin might want to mandate certain flags +# via a site config file, or a user might want to set something for +# compiling this module distribution only via the setup.py command +# line, whatever. As long as these options come from something on the +# current system, they can be as system-dependent as they like, and we +# should just happily stuff them into the preprocessor/compiler/linker +# options and carry on. + + +class UnixCCompiler(CCompiler): + + compiler_type = 'unix' + + # These are used by CCompiler in two places: the constructor sets + # instance attributes 'preprocessor', 'compiler', etc. from them, and + # 'set_executable()' allows any of these to be set. The defaults here + # are pretty generic; they will probably have to be set by an outsider + # (eg. using information discovered by the sysconfig about building + # Python extensions). + executables = {'preprocessor' : None, + 'compiler' : ["cc"], + 'compiler_so' : ["cc"], + 'compiler_cxx' : ["cc"], + 'linker_so' : ["cc", "-shared"], + 'linker_exe' : ["cc"], + 'archiver' : ["ar", "-cr"], + 'ranlib' : None, + } + + if sys.platform[:6] == "darwin": + executables['ranlib'] = ["ranlib"] + + # Needed for the filename generation methods provided by the base + # class, CCompiler. NB. whoever instantiates/uses a particular + # UnixCCompiler instance should set 'shared_lib_ext' -- we set a + # reasonable common default here, but it's not necessarily used on all + # Unices! + + src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"] + obj_extension = ".o" + static_lib_extension = ".a" + shared_lib_extension = ".so" + dylib_lib_extension = ".dylib" + xcode_stub_lib_extension = ".tbd" + static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s" + xcode_stub_lib_format = dylib_lib_format + if sys.platform == "cygwin": + exe_extension = ".exe" + + def preprocess(self, source, output_file=None, macros=None, + include_dirs=None, extra_preargs=None, extra_postargs=None): + fixed_args = self._fix_compile_args(None, macros, include_dirs) + ignore, macros, include_dirs = fixed_args + pp_opts = gen_preprocess_options(macros, include_dirs) + pp_args = self.preprocessor + pp_opts + if output_file: + pp_args.extend(['-o', output_file]) + if extra_preargs: + pp_args[:0] = extra_preargs + if extra_postargs: + pp_args.extend(extra_postargs) + pp_args.append(source) + + # We need to preprocess: either we're being forced to, or we're + # generating output to stdout, or there's a target output file and + # the source file is newer than the target (or the target doesn't + # exist). + if self.force or output_file is None or newer(source, output_file): + if output_file: + self.mkpath(os.path.dirname(output_file)) + try: + self.spawn(pp_args) + except DistutilsExecError as msg: + raise CompileError(msg) diff --git a/Tools/c-analyzer/distutils/util.py b/Tools/c-analyzer/distutils/util.py new file mode 100644 index 000000000000..89ca094336fd --- /dev/null +++ b/Tools/c-analyzer/distutils/util.py @@ -0,0 +1,171 @@ +"""distutils.util + +Miscellaneous utility functions -- anything that doesn't fit into +one of the other *util.py modules. +""" + +import os +import re +import string +import sys +from distutils.errors import DistutilsPlatformError + +def get_host_platform(): + """Return a string that identifies the current platform. This is used mainly to + distinguish platform-specific build directories and platform-specific built + distributions. Typically includes the OS name and version and the + architecture (as supplied by 'os.uname()'), although the exact information + included depends on the OS; eg. on Linux, the kernel version isn't + particularly important. + + Examples of returned values: + linux-i586 + linux-alpha (?) + solaris-2.6-sun4u + + Windows will return one of: + win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) + win32 (all others - specifically, sys.platform is returned) + + For other non-POSIX platforms, currently just returns 'sys.platform'. + + """ + if os.name == 'nt': + if 'amd64' in sys.version.lower(): + return 'win-amd64' + if '(arm)' in sys.version.lower(): + return 'win-arm32' + if '(arm64)' in sys.version.lower(): + return 'win-arm64' + return sys.platform + + # Set for cross builds explicitly + if "_PYTHON_HOST_PLATFORM" in os.environ: + return os.environ["_PYTHON_HOST_PLATFORM"] + + if os.name != "posix" or not hasattr(os, 'uname'): + # XXX what about the architecture? NT is Intel or Alpha, + # Mac OS is M68k or PPC, etc. + return sys.platform + + # Try to distinguish various flavours of Unix + + (osname, host, release, version, machine) = os.uname() + + # Convert the OS name to lowercase, remove '/' characters, and translate + # spaces (for "Power Macintosh") + osname = osname.lower().replace('/', '') + machine = machine.replace(' ', '_') + machine = machine.replace('/', '-') + + if osname[:5] == "linux": + # At least on Linux/Intel, 'machine' is the processor -- + # i386, etc. + # XXX what about Alpha, SPARC, etc? + return "%s-%s" % (osname, machine) + elif osname[:5] == "sunos": + if release[0] >= "5": # SunOS 5 == Solaris 2 + osname = "solaris" + release = "%d.%s" % (int(release[0]) - 3, release[2:]) + # We can't use "platform.architecture()[0]" because a + # bootstrap problem. We use a dict to get an error + # if some suspicious happens. + bitness = {2147483647:"32bit", 9223372036854775807:"64bit"} + machine += ".%s" % bitness[sys.maxsize] + # fall through to standard osname-release-machine representation + elif osname[:3] == "aix": + from _aix_support import aix_platform + return aix_platform() + elif osname[:6] == "cygwin": + osname = "cygwin" + rel_re = re.compile (r'[\d.]+', re.ASCII) + m = rel_re.match(release) + if m: + release = m.group() + elif osname[:6] == "darwin": + import _osx_support, sysconfig + osname, release, machine = _osx_support.get_platform_osx( + sysconfig.get_config_vars(), + osname, release, machine) + + return "%s-%s-%s" % (osname, release, machine) + +def get_platform(): + if os.name == 'nt': + TARGET_TO_PLAT = { + 'x86' : 'win32', + 'x64' : 'win-amd64', + 'arm' : 'win-arm32', + } + return TARGET_TO_PLAT.get(os.environ.get('VSCMD_ARG_TGT_ARCH')) or get_host_platform() + else: + return get_host_platform() + + +# Needed by 'split_quoted()' +_wordchars_re = _squote_re = _dquote_re = None +def _init_regex(): + global _wordchars_re, _squote_re, _dquote_re + _wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace) + _squote_re = re.compile(r"'(?:[^'\\]|\\.)*'") + _dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"') + +def split_quoted (s): + """Split a string up according to Unix shell-like rules for quotes and + backslashes. In short: words are delimited by spaces, as long as those + spaces are not escaped by a backslash, or inside a quoted string. + Single and double quotes are equivalent, and the quote characters can + be backslash-escaped. The backslash is stripped from any two-character + escape sequence, leaving only the escaped character. The quote + characters are stripped from any quoted string. Returns a list of + words. + """ + + # This is a nice algorithm for splitting up a single string, since it + # doesn't require character-by-character examination. It was a little + # bit of a brain-bender to get it working right, though... + if _wordchars_re is None: _init_regex() + + s = s.strip() + words = [] + pos = 0 + + while s: + m = _wordchars_re.match(s, pos) + end = m.end() + if end == len(s): + words.append(s[:end]) + break + + if s[end] in string.whitespace: # unescaped, unquoted whitespace: now + words.append(s[:end]) # we definitely have a word delimiter + s = s[end:].lstrip() + pos = 0 + + elif s[end] == '\\': # preserve whatever is being escaped; + # will become part of the current word + s = s[:end] + s[end+1:] + pos = end+1 + + else: + if s[end] == "'": # slurp singly-quoted string + m = _squote_re.match(s, end) + elif s[end] == '"': # slurp doubly-quoted string + m = _dquote_re.match(s, end) + else: + raise RuntimeError("this can't happen (bad char '%c')" % s[end]) + + if m is None: + raise ValueError("bad string (mismatched %s quotes?)" % s[end]) + + (beg, end) = m.span() + s = s[:beg] + s[beg+1:end-1] + s[end:] + pos = m.end() - 2 + + if pos >= len(s): + words.append(s) + break + + return words + +# split_quoted () From webhook-mailer at python.org Thu Mar 9 16:09:20 2023 From: webhook-mailer at python.org (zooba) Date: Thu, 09 Mar 2023 21:09:20 -0000 Subject: [Python-checkins] gh-102255: Improve build support for Windows API partitions (GH-102256) Message-ID: https://github.com/python/cpython/commit/c6858d1e7f4cd3184d5ddea4025ad5dfc7596546 commit: c6858d1e7f4cd3184d5ddea4025ad5dfc7596546 branch: main author: Max Bachmann committer: zooba date: 2023-03-09T21:09:12Z summary: gh-102255: Improve build support for Windows API partitions (GH-102256) Add `MS_WINDOWS_DESKTOP`, `MS_WINDOWS_APPS`, `MS_WINDOWS_SYSTEM` and `MS_WINDOWS_GAMES` preprocessor definitions to allow switching off functionality missing from particular API partitions ("partitions" are used in Windows to identify overlapping subsets of APIs). CPython only officially supports `MS_WINDOWS_DESKTOP` and `MS_WINDOWS_SYSTEM` (APPS is included by normal desktop builds, but APPS without DESKTOP is not covered). Other configurations are a convenience for people building their own runtimes. `MS_WINDOWS_GAMES` is for the Xbox subset of the Windows API, which is also available on client OS, but is restricted compared to `MS_WINDOWS_DESKTOP`. These restrictions may change over time, as they relate to the build headers rather than the OS support, and so we assume that Xbox builds will use the latest available version of the GDK. files: A Misc/NEWS.d/next/Core and Builtins/2023-02-26-11-43-56.gh-issue-102255.cRnI5x.rst M Include/internal/pycore_fileutils.h M Lib/test/test_os.py M Modules/_io/_iomodule.c M Modules/_io/_iomodule.h M Modules/_io/clinic/winconsoleio.c.h M Modules/_io/fileio.c M Modules/_io/winconsoleio.c M Modules/_localemodule.c M Modules/_multiprocessing/multiprocessing.h M Modules/_pickle.c M Modules/_randommodule.c M Modules/_ssl.c M Modules/_winapi.c M Modules/clinic/posixmodule.c.h M Modules/errnomodule.c M Modules/faulthandler.c M Modules/getpath.c M Modules/mmapmodule.c M Modules/posixmodule.c M Modules/selectmodule.c M Modules/socketmodule.c M Modules/timemodule.c M Objects/obmalloc.c M PC/clinic/msvcrtmodule.c.h M PC/clinic/winreg.c.h M PC/config.c M PC/config_minimal.c M PC/msvcrtmodule.c M PC/pyconfig.h M PC/winreg.c M Parser/myreadline.c M Python/dynload_win.c M Python/fileutils.c M Python/pylifecycle.c M Python/sysmodule.c diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h index f8e2bf225908..445ac0a3d955 100644 --- a/Include/internal/pycore_fileutils.h +++ b/Include/internal/pycore_fileutils.h @@ -251,6 +251,14 @@ extern int _Py_add_relfile(wchar_t *dirname, extern size_t _Py_find_basename(const wchar_t *filename); PyAPI_FUNC(wchar_t *) _Py_normpath(wchar_t *path, Py_ssize_t size); +// The Windows Games API family does not provide these functions +// so provide our own implementations. Remove them in case they get added +// to the Games API family +#if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) +#include + +extern HRESULT PathCchSkipRoot(const wchar_t *pszPath, const wchar_t **ppszRootEnd); +#endif /* defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) */ // Macros to protect CRT calls against instant termination when passed an // invalid parameter (bpo-23524). IPH stands for Invalid Parameter Handler. diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 792794ca1094..ba6feb69ea17 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -3084,11 +3084,13 @@ def test_device_encoding(self): class PidTests(unittest.TestCase): @unittest.skipUnless(hasattr(os, 'getppid'), "test needs os.getppid") def test_getppid(self): - p = subprocess.Popen([sys.executable, '-c', + p = subprocess.Popen([sys._base_executable, '-c', 'import os; print(os.getppid())'], - stdout=subprocess.PIPE) - stdout, _ = p.communicate() + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, error = p.communicate() # We are the parent of our subprocess + self.assertEqual(error, b'') self.assertEqual(int(stdout), os.getpid()) def check_waitpid(self, code, exitcode, callback=None): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-11-43-56.gh-issue-102255.cRnI5x.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-11-43-56.gh-issue-102255.cRnI5x.rst new file mode 100644 index 000000000000..daabc3c15f6e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-11-43-56.gh-issue-102255.cRnI5x.rst @@ -0,0 +1 @@ +Improve build support for the Xbox. Patch by Max Bachmann. diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index d8d836b8382e..1506755427fc 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -317,7 +317,7 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, _PyIO_State *state = get_io_state(module); { PyObject *RawIO_class = (PyObject *)state->PyFileIO_Type; -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO const PyConfig *config = _Py_GetConfig(); if (!config->legacy_windows_stdio && _PyIO_get_console_type(path_or_fd) != '\0') { RawIO_class = (PyObject *)&PyWindowsConsoleIO_Type; @@ -660,7 +660,7 @@ static PyTypeObject* static_types[] = { // PyRawIOBase_Type(PyIOBase_Type) subclasses &_PyBytesIOBuffer_Type, -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO &PyWindowsConsoleIO_Type, #endif }; @@ -718,7 +718,7 @@ PyInit__io(void) } // Set type base classes -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; #endif diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 02daef9e8567..d7224e56f9a7 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -26,9 +26,9 @@ extern PyType_Spec fileio_spec; extern PyType_Spec stringio_spec; extern PyType_Spec textiowrapper_spec; -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO extern PyTypeObject PyWindowsConsoleIO_Type; -#endif /* MS_WINDOWS */ +#endif /* HAVE_WINDOWS_CONSOLE_IO */ /* These functions are used as METH_NOARGS methods, are normally called * with args=NULL, and return a new reference. @@ -178,7 +178,7 @@ find_io_state_by_def(PyTypeObject *type) extern _PyIO_State *_PyIO_get_module_state(void); -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO extern char _PyIO_get_console_type(PyObject *); #endif diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h index df834dbde40f..4c5cd0892c4a 100644 --- a/Modules/_io/clinic/winconsoleio.c.h +++ b/Modules/_io/clinic/winconsoleio.c.h @@ -8,7 +8,7 @@ preserve #endif -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO_close__doc__, "close($self, /)\n" @@ -31,9 +31,9 @@ _io__WindowsConsoleIO_close(winconsoleio *self, PyObject *Py_UNUSED(ignored)) return _io__WindowsConsoleIO_close_impl(self); } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO___init____doc__, "_WindowsConsoleIO(file, mode=\'r\', closefd=True, opener=None)\n" @@ -131,9 +131,9 @@ _io__WindowsConsoleIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) return return_value; } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO_fileno__doc__, "fileno($self, /)\n" @@ -153,9 +153,9 @@ _io__WindowsConsoleIO_fileno(winconsoleio *self, PyObject *Py_UNUSED(ignored)) return _io__WindowsConsoleIO_fileno_impl(self); } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO_readable__doc__, "readable($self, /)\n" @@ -175,9 +175,9 @@ _io__WindowsConsoleIO_readable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) return _io__WindowsConsoleIO_readable_impl(self); } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO_writable__doc__, "writable($self, /)\n" @@ -197,9 +197,9 @@ _io__WindowsConsoleIO_writable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) return _io__WindowsConsoleIO_writable_impl(self); } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO_readinto__doc__, "readinto($self, buffer, /)\n" @@ -239,9 +239,9 @@ _io__WindowsConsoleIO_readinto(winconsoleio *self, PyObject *arg) return return_value; } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO_readall__doc__, "readall($self, /)\n" @@ -263,9 +263,9 @@ _io__WindowsConsoleIO_readall(winconsoleio *self, PyObject *Py_UNUSED(ignored)) return _io__WindowsConsoleIO_readall_impl(self); } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO_read__doc__, "read($self, size=-1, /)\n" @@ -305,9 +305,9 @@ _io__WindowsConsoleIO_read(winconsoleio *self, PyObject *const *args, Py_ssize_t return return_value; } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO_write__doc__, "write($self, b, /)\n" @@ -348,9 +348,9 @@ _io__WindowsConsoleIO_write(winconsoleio *self, PyObject *arg) return return_value; } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ -#if defined(MS_WINDOWS) +#if defined(HAVE_WINDOWS_CONSOLE_IO) PyDoc_STRVAR(_io__WindowsConsoleIO_isatty__doc__, "isatty($self, /)\n" @@ -370,7 +370,7 @@ _io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) return _io__WindowsConsoleIO_isatty_impl(self); } -#endif /* defined(MS_WINDOWS) */ +#endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ #ifndef _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF #define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF @@ -407,4 +407,4 @@ _io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ -/*[clinic end generated code: output=4920e9068e0cf08a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=163e934aa9b0ef16 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 35a498ce5a83..1118d86e6c9a 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -37,7 +37,9 @@ #ifdef MS_WINDOWS /* can simulate truncate with Win32 API functions; see file_truncate */ #define HAVE_FTRUNCATE +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif #include #endif diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index de07b50f5ce4..f836e2302430 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -11,7 +11,7 @@ #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH #include "pycore_object.h" // _PyObject_GC_UNTRACK() -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO #include "structmember.h" // PyMemberDef #ifdef HAVE_SYS_TYPES_H @@ -22,7 +22,9 @@ #endif #include /* For offsetof */ +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif #include #include @@ -1177,4 +1179,4 @@ PyTypeObject PyWindowsConsoleIO_Type = { 0, /* tp_finalize */ }; -#endif /* MS_WINDOWS */ +#endif /* HAVE_WINDOWS_CONSOLE_IO */ diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index 23c38e14d997..96675cdfb661 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -35,7 +35,9 @@ This software comes with no warranty. Use at your own risk. #endif #if defined(MS_WINDOWS) +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif #include #endif @@ -457,12 +459,12 @@ _locale__getdefaultlocale_impl(PyObject *module) PyOS_snprintf(encoding, sizeof(encoding), "cp%u", GetACP()); - if (GetLocaleInfo(LOCALE_USER_DEFAULT, + if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, locale, sizeof(locale))) { Py_ssize_t i = strlen(locale); locale[i++] = '_'; - if (GetLocaleInfo(LOCALE_USER_DEFAULT, + if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, locale+i, (int)(sizeof(locale)-i))) return Py_BuildValue("ss", locale, encoding); @@ -474,7 +476,7 @@ _locale__getdefaultlocale_impl(PyObject *module) locale[0] = '0'; locale[1] = 'x'; - if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTLANGUAGE, + if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTLANGUAGE, locale+2, sizeof(locale)-2)) { return Py_BuildValue("ss", locale, encoding); } diff --git a/Modules/_multiprocessing/multiprocessing.h b/Modules/_multiprocessing/multiprocessing.h index b595e5a8dd18..dfc2a8e0799a 100644 --- a/Modules/_multiprocessing/multiprocessing.h +++ b/Modules/_multiprocessing/multiprocessing.h @@ -12,7 +12,9 @@ */ #ifdef MS_WINDOWS -# define WIN32_LEAN_AND_MEAN +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include # include # include /* getpid() */ diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 1b34977806b6..a26732af8ba2 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -42,6 +42,12 @@ enum { #define FLOAT FLOAT_ #define INT INT_ #define LONG LONG_ + +/* This can already be defined on Windows to set the character set + the Windows header files treat as default */ +#ifdef UNICODE +#undef UNICODE +#endif #endif /* Pickle opcodes. These must be kept updated with pickle.py. diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 68060c07033d..6e2205323930 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -77,6 +77,10 @@ # include // getpid() #endif +#ifdef MS_WINDOWS +# include +#endif + /* Period parameters -- These are all magic. Don't change. */ #define N 624 #define M 397 @@ -259,7 +263,7 @@ random_seed_time_pid(RandomObject *self) key[0] = (uint32_t)(now & 0xffffffffU); key[1] = (uint32_t)(now >> 32); -#ifdef MS_WINDOWS_NON_DESKTOP +#if defined(MS_WINDOWS) && !defined(MS_WINDOWS_DESKTOP) && !defined(MS_WINDOWS_SYSTEM) key[2] = (uint32_t)GetCurrentProcessId(); #elif defined(HAVE_GETPID) key[2] = (uint32_t)getpid(); diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 8f03a846aed0..28112317bc28 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -28,6 +28,10 @@ /* Include symbols from _socket module */ #include "socketmodule.h" +#ifdef MS_WINDOWS +# include +#endif + #include "_ssl.h" /* Redefined below for Windows debug builds after important #includes */ diff --git a/Modules/_winapi.c b/Modules/_winapi.c index eefc2571ee82..83cde7501176 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -39,8 +39,11 @@ #include "structmember.h" // PyMemberDef +#ifndef WINDOWS_LEAN_AND_MEAN #define WINDOWS_LEAN_AND_MEAN +#endif #include "windows.h" +#include #include #include "winreparse.h" @@ -63,6 +66,14 @@ #define T_HANDLE T_POINTER +// winbase.h limits the STARTF_* flags to the desktop API as of 10.0.19041. +#ifndef STARTF_USESHOWWINDOW +#define STARTF_USESHOWWINDOW 0x00000001 +#endif +#ifndef STARTF_USESTDHANDLES +#define STARTF_USESTDHANDLES 0x00000100 +#endif + typedef struct { PyTypeObject *overlapped_type; } WinApiState; @@ -1201,8 +1212,10 @@ _winapi_ExitProcess_impl(PyObject *module, UINT ExitCode) /*[clinic end generated code: output=a387deb651175301 input=4f05466a9406c558]*/ { #if defined(Py_DEBUG) +#ifdef MS_WINDOWS_DESKTOP SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT| SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX); +#endif _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); #endif diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index dcd25c28370c..6565f8df935c 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -10988,7 +10988,7 @@ os_getrandom(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject #endif /* defined(HAVE_GETRANDOM_SYSCALL) */ -#if defined(MS_WINDOWS) +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)) PyDoc_STRVAR(os__add_dll_directory__doc__, "_add_dll_directory($module, /, path)\n" @@ -11057,9 +11057,9 @@ os__add_dll_directory(PyObject *module, PyObject *const *args, Py_ssize_t nargs, return return_value; } -#endif /* defined(MS_WINDOWS) */ +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)) */ -#if defined(MS_WINDOWS) +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)) PyDoc_STRVAR(os__remove_dll_directory__doc__, "_remove_dll_directory($module, /, cookie)\n" @@ -11120,7 +11120,7 @@ os__remove_dll_directory(PyObject *module, PyObject *const *args, Py_ssize_t nar return return_value; } -#endif /* defined(MS_WINDOWS) */ +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)) */ #if (defined(WIFEXITED) || defined(MS_WINDOWS)) @@ -11796,4 +11796,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=1b0eb6a76b1a0e28 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9495478e51701b8a input=a9049054013a1b77]*/ diff --git a/Modules/errnomodule.c b/Modules/errnomodule.c index 4de4144520aa..df4e494ba8a9 100644 --- a/Modules/errnomodule.c +++ b/Modules/errnomodule.c @@ -5,7 +5,9 @@ /* Windows socket errors (WSA*) */ #ifdef MS_WINDOWS +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif #include /* The following constants were added to errno.h in VS2010 but have preferred WSA equivalents. */ diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index 5309a3728c5e..bfe35fed7a45 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -953,7 +953,7 @@ faulthandler_unregister_py(PyObject *self, PyObject *args) static void faulthandler_suppress_crash_report(void) { -#ifdef MS_WINDOWS +#ifdef MS_WINDOWS_DESKTOP UINT mode; /* Configure Windows to not display the Windows Error Reporting dialog */ diff --git a/Modules/getpath.c b/Modules/getpath.c index c807a3c8e9a2..2f20521592ce 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -745,10 +745,12 @@ static int library_to_dict(PyObject *dict, const char *key) { #ifdef MS_WINDOWS +#ifdef Py_ENABLE_SHARED extern HMODULE PyWin_DLLhModule; if (PyWin_DLLhModule) { return winmodule_to_dict(dict, key, PyWin_DLLhModule); } +#endif #elif defined(WITH_NEXT_FRAMEWORK) static char modPath[MAXPATHLEN + 1]; static int modPathInitialized = -1; diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 6054c2853d7a..fe76ca6eafaa 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -29,6 +29,10 @@ #include "structmember.h" // PyMemberDef #include // offsetof() +// to support MS_WINDOWS_SYSTEM OpenFileMappingA / CreateFileMappingA +// need to be replaced with OpenFileMappingW / CreateFileMappingW +#if !defined(MS_WINDOWS) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_GAMES) + #ifndef MS_WINDOWS #define UNIX # ifdef HAVE_FCNTL_H @@ -647,7 +651,7 @@ mmap_flush_method(mmap_object *self, PyObject *args) if (self->access == ACCESS_READ || self->access == ACCESS_COPY) Py_RETURN_NONE; -#ifdef MS_WINDOWS +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM) if (!FlushViewOfFile(self->data+offset, size)) { PyErr_SetFromWindowsErr(GetLastError()); return NULL; @@ -1724,3 +1728,5 @@ PyInit_mmap(void) { return PyModuleDef_Init(&mmapmodule); } + +#endif /* !MS_WINDOWS || MS_WINDOWS_DESKTOP || MS_WINDOWS_GAMES */ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a3d86cbe7a57..0d534f35f6a4 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -26,11 +26,15 @@ #ifdef MS_WINDOWS # include -# include +# if !defined(MS_WINDOWS_GAMES) || defined(MS_WINDOWS_DESKTOP) +# include +# endif # include # include // UNLEN # include "osdefs.h" // SEP -# define HAVE_SYMLINK +# if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) +# define HAVE_SYMLINK +# endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */ #endif #include "structmember.h" // PyMemberDef @@ -311,7 +315,7 @@ corresponding Unix manual entries for more information on calls."); # include #endif -#if defined(MS_WINDOWS) +#ifdef HAVE_WINDOWS_CONSOLE_IO # define TERMSIZE_USE_CONIO #elif defined(HAVE_SYS_IOCTL_H) # include @@ -321,7 +325,7 @@ corresponding Unix manual entries for more information on calls."); # if defined(TIOCGWINSZ) # define TERMSIZE_USE_IOCTL # endif -#endif /* MS_WINDOWS */ +#endif /* HAVE_WINDOWS_CONSOLE_IO */ /* Various compilers have only certain posix functions */ /* XXX Gosh I wish these were all moved into pyconfig.h */ @@ -329,21 +333,25 @@ corresponding Unix manual entries for more information on calls."); # define HAVE_OPENDIR 1 # define HAVE_SYSTEM 1 # include -#else -# ifdef _MSC_VER - /* Microsoft compiler */ +#elif defined( _MSC_VER) + /* Microsoft compiler */ +# if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM) # define HAVE_GETPPID 1 +# endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_APP | MS_WINDOWS_SYSTEM */ +# if defined(MS_WINDOWS_DESKTOP) # define HAVE_GETLOGIN 1 +# endif /* MS_WINDOWS_DESKTOP */ +# if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) # define HAVE_SPAWNV 1 # define HAVE_EXECV 1 # define HAVE_WSPAWNV 1 # define HAVE_WEXECV 1 -# define HAVE_PIPE 1 # define HAVE_SYSTEM 1 # define HAVE_CWAIT 1 -# define HAVE_FSYNC 1 -# define fsync _commit -# endif /* _MSC_VER */ +# endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */ +# define HAVE_PIPE 1 +# define HAVE_FSYNC 1 +# define fsync _commit #endif /* ! __WATCOMC__ || __QNX__ */ /*[clinic input] @@ -1536,7 +1544,7 @@ convertenviron(void) #ifdef MS_WINDOWS /* _wenviron must be initialized in this way if the program is started through main() instead of wmain(). */ - _wgetenv(L""); + (void)_wgetenv(L""); e = _wenviron; #elif defined(WITH_NEXT_FRAMEWORK) || (defined(__APPLE__) && defined(Py_ENABLE_SHARED)) /* environ is not accessible as an extern in a shared object on OSX; use @@ -1785,6 +1793,10 @@ attributes_from_dir(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *re if (n && (pszFile[n - 1] == L'\\' || pszFile[n - 1] == L'/')) { // cannot use PyMem_Malloc here because we do not hold the GIL filename = (LPCWSTR)malloc((n + 1) * sizeof(filename[0])); + if(!filename) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } wcsncpy_s((LPWSTR)filename, n + 1, pszFile, n); while (--n > 0 && (filename[n] == L'\\' || filename[n] == L'/')) { ((LPWSTR)filename)[n] = L'\0'; @@ -7933,10 +7945,10 @@ static PyObject * os_getpid_impl(PyObject *module) /*[clinic end generated code: output=9ea6fdac01ed2b3c input=5a9a00f0ab68aa00]*/ { -#ifdef MS_WINDOWS_NON_DESKTOP - return PyLong_FromUnsignedLong(GetCurrentProcessId()); -#else +#if !defined(MS_WINDOWS) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) return PyLong_FromPid(getpid()); +#else + return PyLong_FromUnsignedLong(GetCurrentProcessId()); #endif } #endif /* defined(HAVE_GETPID) */ @@ -8392,6 +8404,7 @@ os_kill_impl(PyObject *module, pid_t pid, Py_ssize_t signal) DWORD err; HANDLE handle; +#ifdef HAVE_WINDOWS_CONSOLE_IO /* Console processes which share a common console can be sent CTRL+C or CTRL+BREAK events, provided they handle said events. */ if (sig == CTRL_C_EVENT || sig == CTRL_BREAK_EVENT) { @@ -8399,9 +8412,11 @@ os_kill_impl(PyObject *module, pid_t pid, Py_ssize_t signal) err = GetLastError(); PyErr_SetFromWindowsErr(err); } - else + else { Py_RETURN_NONE; + } } +#endif /* HAVE_WINDOWS_CONSOLE_IO */ /* If the signal is outside of what GenerateConsoleCtrlEvent can use, attempt to open and terminate the process. */ @@ -13776,7 +13791,9 @@ os_cpu_count_impl(PyObject *module) { int ncpu = 0; #ifdef MS_WINDOWS +#ifdef MS_WINDOWS_DESKTOP ncpu = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); +#endif #elif defined(__hpux) ncpu = mpctl(MPC_GETNUMSPUS, NULL, NULL); #elif defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) @@ -13848,6 +13865,10 @@ os_set_inheritable_impl(PyObject *module, int fd, int inheritable) #ifdef MS_WINDOWS +#ifndef HANDLE_FLAG_INHERIT +#define HANDLE_FLAG_INHERIT 0x00000001 +#endif + /*[clinic input] os.get_handle_inheritable -> bool handle: intptr_t @@ -15023,7 +15044,8 @@ os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags) } #endif /* HAVE_GETRANDOM_SYSCALL */ -#ifdef MS_WINDOWS +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM) + /* bpo-36085: Helper functions for managing DLL search directories * on win32 */ @@ -15114,7 +15136,7 @@ os__remove_dll_directory_impl(PyObject *module, PyObject *cookie) Py_RETURN_NONE; } -#endif +#endif /* MS_WINDOWS_APP || MS_WINDOWS_SYSTEM */ /* Only check if WIFEXITED is available: expect that it comes diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index df4043de08da..5a1e40d0b4a4 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -57,8 +57,10 @@ extern void bzero(void *, int); #endif #ifdef MS_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include #else # define SOCKET int #endif diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 43a0cc0f963f..b7927750e334 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -270,7 +270,7 @@ shutdown(how) -- shut down traffic in one or both directions\n\ # include -#else +#else /* MS_WINDOWS */ /* MS_WINDOWS includes */ # ifdef HAVE_FCNTL_H @@ -281,7 +281,6 @@ shutdown(how) -- shut down traffic in one or both directions\n\ # include /* Macros based on the IPPROTO enum, see: https://bugs.python.org/issue29515 */ -#ifdef MS_WINDOWS #define IPPROTO_ICMP IPPROTO_ICMP #define IPPROTO_IGMP IPPROTO_IGMP #define IPPROTO_GGP IPPROTO_GGP @@ -312,7 +311,6 @@ shutdown(how) -- shut down traffic in one or both directions\n\ #define IPPROTO_PGM IPPROTO_PGM // WinSock2 only #define IPPROTO_L2TP IPPROTO_L2TP // WinSock2 only #define IPPROTO_SCTP IPPROTO_SCTP // WinSock2 only -#endif /* MS_WINDOWS */ /* Provides the IsWindows7SP1OrGreater() function */ #include @@ -348,13 +346,18 @@ remove_unusable_flags(PyObject *m) { PyObject *dict; OSVERSIONINFOEX info; - DWORDLONG dwlConditionMask; dict = PyModule_GetDict(m); if (dict == NULL) { return -1; } - +#ifndef MS_WINDOWS_DESKTOP + info.dwOSVersionInfoSize = sizeof(info); + if (!GetVersionExW((OSVERSIONINFOW*) &info)) { + PyErr_SetFromWindowsErr(0); + return -1; + } +#else /* set to Windows 10, except BuildNumber. */ memset(&info, 0, sizeof(info)); info.dwOSVersionInfoSize = sizeof(info); @@ -362,19 +365,30 @@ remove_unusable_flags(PyObject *m) info.dwMinorVersion = 0; /* set Condition Mask */ - dwlConditionMask = 0; + DWORDLONG dwlConditionMask = 0; VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); VER_SET_CONDITION(dwlConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL); +#endif for (int i=0; i 10 || + (info.dwMajorVersion == 10 && info.dwMinorVersion > 0) || + (info.dwMajorVersion == 10 && info.dwMinorVersion == 0 && + info.dwBuildNumber >= win_runtime_flags[i].build_number); +#endif + if (isSupported) { break; } else { @@ -497,14 +511,14 @@ remove_unusable_flags(PyObject *m) #endif #endif -#ifdef MS_WINDOWS +#ifdef MS_WINDOWS_DESKTOP #define sockaddr_rc SOCKADDR_BTH_REDEF #define USE_BLUETOOTH 1 #define AF_BLUETOOTH AF_BTH #define BTPROTO_RFCOMM BTHPROTO_RFCOMM #define _BT_RC_MEMB(sa, memb) ((sa)->memb) -#endif +#endif /* MS_WINDOWS_DESKTOP */ /* Convert "sock_addr_t *" to "struct sockaddr *". */ #define SAS2SA(x) (&((x)->sa)) @@ -2869,11 +2883,16 @@ sock_accept(PySocketSockObject *s, PyObject *Py_UNUSED(ignored)) newfd = ctx.result; #ifdef MS_WINDOWS +#if defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) +#ifndef HANDLE_FLAG_INHERIT +#define HANDLE_FLAG_INHERIT 0x00000001 +#endif if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) { PyErr_SetFromWindowsErr(0); SOCKETCLOSE(newfd); goto finally; } +#endif #else #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) @@ -5434,11 +5453,6 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto, proto = 0; } #ifdef MS_WINDOWS - /* Windows implementation */ -#ifndef WSA_FLAG_NO_HANDLE_INHERIT -#define WSA_FLAG_NO_HANDLE_INHERIT 0x80 -#endif - Py_BEGIN_ALLOW_THREADS fd = WSASocketW(family, type, proto, NULL, 0, @@ -6150,8 +6164,9 @@ socket_dup(PyObject *self, PyObject *fdobj) #endif fd = PyLong_AsSocket_t(fdobj); - if (fd == (SOCKET_T)(-1) && PyErr_Occurred()) + if (fd == (SOCKET_T)(-1) && PyErr_Occurred()) { return NULL; + } #ifdef MS_WINDOWS if (WSADuplicateSocketW(fd, GetCurrentProcessId(), &info)) @@ -6160,8 +6175,9 @@ socket_dup(PyObject *self, PyObject *fdobj) newfd = WSASocketW(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &info, 0, WSA_FLAG_OVERLAPPED); - if (newfd == INVALID_SOCKET) + if (newfd == INVALID_SOCKET) { return set_error(); + } if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) { closesocket(newfd); @@ -6171,13 +6187,15 @@ socket_dup(PyObject *self, PyObject *fdobj) #else /* On UNIX, dup can be used to duplicate the file descriptor of a socket */ newfd = _Py_dup(fd); - if (newfd == INVALID_SOCKET) + if (newfd == INVALID_SOCKET) { return NULL; + } #endif newfdobj = PyLong_FromSocket_t(newfd); - if (newfdobj == NULL) + if (newfdobj == NULL) { SOCKETCLOSE(newfd); + } return newfdobj; } diff --git a/Modules/timemodule.c b/Modules/timemodule.c index c2bacaae0c03..c50e689bb698 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -30,7 +30,9 @@ # include #else # ifdef MS_WINDOWS -# define WIN32_LEAN_AND_MEAN +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include # endif /* MS_WINDOWS */ #endif /* !__WATCOMC__ || __QNX__ */ @@ -1135,7 +1137,9 @@ time_tzset(PyObject *self, PyObject *unused) return NULL; } +#if !defined(MS_WINDOWS) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) tzset(); +#endif /* Reset timezone, altzone, daylight and tzname */ if (init_timezone(m) < 0) { @@ -1753,7 +1757,9 @@ init_timezone(PyObject *m) */ #ifdef HAVE_DECL_TZNAME PyObject *otz0, *otz1; +#if !defined(MS_WINDOWS) || defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) tzset(); +#endif PyModule_AddIntConstant(m, "timezone", _Py_timezone); #ifdef HAVE_ALTZONE PyModule_AddIntConstant(m, "altzone", altzone); diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 276c5a276c06..5e1bcda1d976 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -8,7 +8,6 @@ #include // malloc() #include - #undef uint #define uint pymem_uint diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h index d808ef0bbd0f..b708c6cdde75 100644 --- a/PC/clinic/msvcrtmodule.c.h +++ b/PC/clinic/msvcrtmodule.c.h @@ -261,6 +261,8 @@ msvcrt_getch(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } +#if defined(MS_WINDOWS_DESKTOP) + PyDoc_STRVAR(msvcrt_getwch__doc__, "getwch($module, /)\n" "--\n" @@ -285,6 +287,8 @@ msvcrt_getwch(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } +#endif /* defined(MS_WINDOWS_DESKTOP) */ + PyDoc_STRVAR(msvcrt_getche__doc__, "getche($module, /)\n" "--\n" @@ -309,6 +313,8 @@ msvcrt_getche(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } +#if defined(MS_WINDOWS_DESKTOP) + PyDoc_STRVAR(msvcrt_getwche__doc__, "getwche($module, /)\n" "--\n" @@ -333,6 +339,8 @@ msvcrt_getwche(PyObject *module, PyObject *Py_UNUSED(ignored)) return return_value; } +#endif /* defined(MS_WINDOWS_DESKTOP) */ + PyDoc_STRVAR(msvcrt_putch__doc__, "putch($module, char, /)\n" "--\n" @@ -367,6 +375,8 @@ msvcrt_putch(PyObject *module, PyObject *arg) return return_value; } +#if defined(MS_WINDOWS_DESKTOP) + PyDoc_STRVAR(msvcrt_putwch__doc__, "putwch($module, unicode_char, /)\n" "--\n" @@ -403,6 +413,8 @@ msvcrt_putwch(PyObject *module, PyObject *arg) return return_value; } +#endif /* defined(MS_WINDOWS_DESKTOP) */ + PyDoc_STRVAR(msvcrt_ungetch__doc__, "ungetch($module, char, /)\n" "--\n" @@ -441,6 +453,8 @@ msvcrt_ungetch(PyObject *module, PyObject *arg) return return_value; } +#if defined(MS_WINDOWS_DESKTOP) + PyDoc_STRVAR(msvcrt_ungetwch__doc__, "ungetwch($module, unicode_char, /)\n" "--\n" @@ -477,6 +491,8 @@ msvcrt_ungetwch(PyObject *module, PyObject *arg) return return_value; } +#endif /* defined(MS_WINDOWS_DESKTOP) */ + #if defined(_DEBUG) PyDoc_STRVAR(msvcrt_CrtSetReportFile__doc__, @@ -610,6 +626,8 @@ msvcrt_set_error_mode(PyObject *module, PyObject *arg) #endif /* defined(_DEBUG) */ +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)) + PyDoc_STRVAR(msvcrt_GetErrorMode__doc__, "GetErrorMode($module, /)\n" "--\n" @@ -628,6 +646,8 @@ msvcrt_GetErrorMode(PyObject *module, PyObject *Py_UNUSED(ignored)) return msvcrt_GetErrorMode_impl(module); } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM)) */ + PyDoc_STRVAR(msvcrt_SetErrorMode__doc__, "SetErrorMode($module, mode, /)\n" "--\n" @@ -656,6 +676,22 @@ msvcrt_SetErrorMode(PyObject *module, PyObject *arg) return return_value; } +#ifndef MSVCRT_GETWCH_METHODDEF + #define MSVCRT_GETWCH_METHODDEF +#endif /* !defined(MSVCRT_GETWCH_METHODDEF) */ + +#ifndef MSVCRT_GETWCHE_METHODDEF + #define MSVCRT_GETWCHE_METHODDEF +#endif /* !defined(MSVCRT_GETWCHE_METHODDEF) */ + +#ifndef MSVCRT_PUTWCH_METHODDEF + #define MSVCRT_PUTWCH_METHODDEF +#endif /* !defined(MSVCRT_PUTWCH_METHODDEF) */ + +#ifndef MSVCRT_UNGETWCH_METHODDEF + #define MSVCRT_UNGETWCH_METHODDEF +#endif /* !defined(MSVCRT_UNGETWCH_METHODDEF) */ + #ifndef MSVCRT_CRTSETREPORTFILE_METHODDEF #define MSVCRT_CRTSETREPORTFILE_METHODDEF #endif /* !defined(MSVCRT_CRTSETREPORTFILE_METHODDEF) */ @@ -667,4 +703,8 @@ msvcrt_SetErrorMode(PyObject *module, PyObject *arg) #ifndef MSVCRT_SET_ERROR_MODE_METHODDEF #define MSVCRT_SET_ERROR_MODE_METHODDEF #endif /* !defined(MSVCRT_SET_ERROR_MODE_METHODDEF) */ -/*[clinic end generated code: output=204bae9fee7f6124 input=a9049054013a1b77]*/ + +#ifndef MSVCRT_GETERRORMODE_METHODDEF + #define MSVCRT_GETERRORMODE_METHODDEF +#endif /* !defined(MSVCRT_GETERRORMODE_METHODDEF) */ +/*[clinic end generated code: output=2db6197608a6aab3 input=a9049054013a1b77]*/ diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h index 2834d9967a77..7a9474301da8 100644 --- a/PC/clinic/winreg.c.h +++ b/PC/clinic/winreg.c.h @@ -8,6 +8,8 @@ preserve #endif +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_HKEYType_Close__doc__, "Close($self, /)\n" "--\n" @@ -28,6 +30,10 @@ winreg_HKEYType_Close(PyHKEYObject *self, PyObject *Py_UNUSED(ignored)) return winreg_HKEYType_Close_impl(self); } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_HKEYType_Detach__doc__, "Detach($self, /)\n" "--\n" @@ -54,6 +60,10 @@ winreg_HKEYType_Detach(PyHKEYObject *self, PyObject *Py_UNUSED(ignored)) return winreg_HKEYType_Detach_impl(self); } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_HKEYType___enter____doc__, "__enter__($self, /)\n" "--\n" @@ -77,6 +87,10 @@ winreg_HKEYType___enter__(PyHKEYObject *self, PyObject *Py_UNUSED(ignored)) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_HKEYType___exit____doc__, "__exit__($self, /, exc_type, exc_value, traceback)\n" "--\n" @@ -136,6 +150,10 @@ winreg_HKEYType___exit__(PyHKEYObject *self, PyObject *const *args, Py_ssize_t n return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_CloseKey__doc__, "CloseKey($module, hkey, /)\n" "--\n" @@ -151,6 +169,10 @@ PyDoc_STRVAR(winreg_CloseKey__doc__, #define WINREG_CLOSEKEY_METHODDEF \ {"CloseKey", (PyCFunction)winreg_CloseKey, METH_O, winreg_CloseKey__doc__}, +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) + PyDoc_STRVAR(winreg_ConnectRegistry__doc__, "ConnectRegistry($module, computer_name, key, /)\n" "--\n" @@ -213,6 +235,10 @@ winreg_ConnectRegistry(PyObject *module, PyObject *const *args, Py_ssize_t nargs return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_CreateKey__doc__, "CreateKey($module, key, sub_key, /)\n" "--\n" @@ -278,6 +304,10 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_CreateKeyEx__doc__, "CreateKeyEx($module, /, key, sub_key, reserved=0,\n" " access=winreg.KEY_WRITE)\n" @@ -398,6 +428,10 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_DeleteKey__doc__, "DeleteKey($module, key, sub_key, /)\n" "--\n" @@ -452,6 +486,10 @@ winreg_DeleteKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_DeleteKeyEx__doc__, "DeleteKeyEx($module, /, key, sub_key, access=winreg.KEY_WOW64_64KEY,\n" " reserved=0)\n" @@ -565,6 +603,10 @@ winreg_DeleteKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_DeleteValue__doc__, "DeleteValue($module, key, value, /)\n" "--\n" @@ -617,6 +659,10 @@ winreg_DeleteValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_EnumKey__doc__, "EnumKey($module, key, index, /)\n" "--\n" @@ -661,6 +707,10 @@ winreg_EnumKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_EnumValue__doc__, "EnumValue($module, key, index, /)\n" "--\n" @@ -714,6 +764,10 @@ winreg_EnumValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_ExpandEnvironmentStrings__doc__, "ExpandEnvironmentStrings($module, string, /)\n" "--\n" @@ -750,6 +804,10 @@ winreg_ExpandEnvironmentStrings(PyObject *module, PyObject *arg) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) + PyDoc_STRVAR(winreg_FlushKey__doc__, "FlushKey($module, key, /)\n" "--\n" @@ -790,6 +848,10 @@ winreg_FlushKey(PyObject *module, PyObject *arg) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) + PyDoc_STRVAR(winreg_LoadKey__doc__, "LoadKey($module, key, sub_key, file_name, /)\n" "--\n" @@ -866,6 +928,10 @@ winreg_LoadKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_OpenKey__doc__, "OpenKey($module, /, key, sub_key, reserved=0, access=winreg.KEY_READ)\n" "--\n" @@ -979,6 +1045,10 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_OpenKeyEx__doc__, "OpenKeyEx($module, /, key, sub_key, reserved=0, access=winreg.KEY_READ)\n" "--\n" @@ -1092,6 +1162,10 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_QueryInfoKey__doc__, "QueryInfoKey($module, key, /)\n" "--\n" @@ -1128,6 +1202,10 @@ winreg_QueryInfoKey(PyObject *module, PyObject *arg) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_QueryValue__doc__, "QueryValue($module, key, sub_key, /)\n" "--\n" @@ -1189,6 +1267,10 @@ winreg_QueryValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_QueryValueEx__doc__, "QueryValueEx($module, key, name, /)\n" "--\n" @@ -1246,6 +1328,10 @@ winreg_QueryValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) + PyDoc_STRVAR(winreg_SaveKey__doc__, "SaveKey($module, key, file_name, /)\n" "--\n" @@ -1303,6 +1389,10 @@ winreg_SaveKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_SetValue__doc__, "SetValue($module, key, sub_key, type, value, /)\n" "--\n" @@ -1384,6 +1474,10 @@ winreg_SetValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) + PyDoc_STRVAR(winreg_SetValueEx__doc__, "SetValueEx($module, key, value_name, reserved, type, value, /)\n" "--\n" @@ -1478,6 +1572,10 @@ winreg_SetValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) + PyDoc_STRVAR(winreg_DisableReflectionKey__doc__, "DisableReflectionKey($module, key, /)\n" "--\n" @@ -1514,6 +1612,10 @@ winreg_DisableReflectionKey(PyObject *module, PyObject *arg) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) + PyDoc_STRVAR(winreg_EnableReflectionKey__doc__, "EnableReflectionKey($module, key, /)\n" "--\n" @@ -1548,6 +1650,10 @@ winreg_EnableReflectionKey(PyObject *module, PyObject *arg) return return_value; } +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */ + +#if (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) + PyDoc_STRVAR(winreg_QueryReflectionKey__doc__, "QueryReflectionKey($module, key, /)\n" "--\n" @@ -1579,4 +1685,114 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=7e817dc5edc914d3 input=a9049054013a1b77]*/ + +#endif /* (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)) && (defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM)) */ + +#ifndef WINREG_HKEYTYPE_CLOSE_METHODDEF + #define WINREG_HKEYTYPE_CLOSE_METHODDEF +#endif /* !defined(WINREG_HKEYTYPE_CLOSE_METHODDEF) */ + +#ifndef WINREG_HKEYTYPE_DETACH_METHODDEF + #define WINREG_HKEYTYPE_DETACH_METHODDEF +#endif /* !defined(WINREG_HKEYTYPE_DETACH_METHODDEF) */ + +#ifndef WINREG_HKEYTYPE___ENTER___METHODDEF + #define WINREG_HKEYTYPE___ENTER___METHODDEF +#endif /* !defined(WINREG_HKEYTYPE___ENTER___METHODDEF) */ + +#ifndef WINREG_HKEYTYPE___EXIT___METHODDEF + #define WINREG_HKEYTYPE___EXIT___METHODDEF +#endif /* !defined(WINREG_HKEYTYPE___EXIT___METHODDEF) */ + +#ifndef WINREG_CLOSEKEY_METHODDEF + #define WINREG_CLOSEKEY_METHODDEF +#endif /* !defined(WINREG_CLOSEKEY_METHODDEF) */ + +#ifndef WINREG_CONNECTREGISTRY_METHODDEF + #define WINREG_CONNECTREGISTRY_METHODDEF +#endif /* !defined(WINREG_CONNECTREGISTRY_METHODDEF) */ + +#ifndef WINREG_CREATEKEY_METHODDEF + #define WINREG_CREATEKEY_METHODDEF +#endif /* !defined(WINREG_CREATEKEY_METHODDEF) */ + +#ifndef WINREG_CREATEKEYEX_METHODDEF + #define WINREG_CREATEKEYEX_METHODDEF +#endif /* !defined(WINREG_CREATEKEYEX_METHODDEF) */ + +#ifndef WINREG_DELETEKEY_METHODDEF + #define WINREG_DELETEKEY_METHODDEF +#endif /* !defined(WINREG_DELETEKEY_METHODDEF) */ + +#ifndef WINREG_DELETEKEYEX_METHODDEF + #define WINREG_DELETEKEYEX_METHODDEF +#endif /* !defined(WINREG_DELETEKEYEX_METHODDEF) */ + +#ifndef WINREG_DELETEVALUE_METHODDEF + #define WINREG_DELETEVALUE_METHODDEF +#endif /* !defined(WINREG_DELETEVALUE_METHODDEF) */ + +#ifndef WINREG_ENUMKEY_METHODDEF + #define WINREG_ENUMKEY_METHODDEF +#endif /* !defined(WINREG_ENUMKEY_METHODDEF) */ + +#ifndef WINREG_ENUMVALUE_METHODDEF + #define WINREG_ENUMVALUE_METHODDEF +#endif /* !defined(WINREG_ENUMVALUE_METHODDEF) */ + +#ifndef WINREG_EXPANDENVIRONMENTSTRINGS_METHODDEF + #define WINREG_EXPANDENVIRONMENTSTRINGS_METHODDEF +#endif /* !defined(WINREG_EXPANDENVIRONMENTSTRINGS_METHODDEF) */ + +#ifndef WINREG_FLUSHKEY_METHODDEF + #define WINREG_FLUSHKEY_METHODDEF +#endif /* !defined(WINREG_FLUSHKEY_METHODDEF) */ + +#ifndef WINREG_LOADKEY_METHODDEF + #define WINREG_LOADKEY_METHODDEF +#endif /* !defined(WINREG_LOADKEY_METHODDEF) */ + +#ifndef WINREG_OPENKEY_METHODDEF + #define WINREG_OPENKEY_METHODDEF +#endif /* !defined(WINREG_OPENKEY_METHODDEF) */ + +#ifndef WINREG_OPENKEYEX_METHODDEF + #define WINREG_OPENKEYEX_METHODDEF +#endif /* !defined(WINREG_OPENKEYEX_METHODDEF) */ + +#ifndef WINREG_QUERYINFOKEY_METHODDEF + #define WINREG_QUERYINFOKEY_METHODDEF +#endif /* !defined(WINREG_QUERYINFOKEY_METHODDEF) */ + +#ifndef WINREG_QUERYVALUE_METHODDEF + #define WINREG_QUERYVALUE_METHODDEF +#endif /* !defined(WINREG_QUERYVALUE_METHODDEF) */ + +#ifndef WINREG_QUERYVALUEEX_METHODDEF + #define WINREG_QUERYVALUEEX_METHODDEF +#endif /* !defined(WINREG_QUERYVALUEEX_METHODDEF) */ + +#ifndef WINREG_SAVEKEY_METHODDEF + #define WINREG_SAVEKEY_METHODDEF +#endif /* !defined(WINREG_SAVEKEY_METHODDEF) */ + +#ifndef WINREG_SETVALUE_METHODDEF + #define WINREG_SETVALUE_METHODDEF +#endif /* !defined(WINREG_SETVALUE_METHODDEF) */ + +#ifndef WINREG_SETVALUEEX_METHODDEF + #define WINREG_SETVALUEEX_METHODDEF +#endif /* !defined(WINREG_SETVALUEEX_METHODDEF) */ + +#ifndef WINREG_DISABLEREFLECTIONKEY_METHODDEF + #define WINREG_DISABLEREFLECTIONKEY_METHODDEF +#endif /* !defined(WINREG_DISABLEREFLECTIONKEY_METHODDEF) */ + +#ifndef WINREG_ENABLEREFLECTIONKEY_METHODDEF + #define WINREG_ENABLEREFLECTIONKEY_METHODDEF +#endif /* !defined(WINREG_ENABLEREFLECTIONKEY_METHODDEF) */ + +#ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF + #define WINREG_QUERYREFLECTIONKEY_METHODDEF +#endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */ +/*[clinic end generated code: output=715db416dc1321ee input=a9049054013a1b77]*/ diff --git a/PC/config.c b/PC/config.c index b1481d79e650..9d0fe6f87df6 100644 --- a/PC/config.c +++ b/PC/config.c @@ -43,10 +43,14 @@ extern PyObject* PyInit__collections(void); extern PyObject* PyInit__heapq(void); extern PyObject* PyInit__bisect(void); extern PyObject* PyInit__symtable(void); +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_GAMES) extern PyObject* PyInit_mmap(void); +#endif extern PyObject* PyInit__csv(void); extern PyObject* PyInit__sre(void); +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) extern PyObject* PyInit_winreg(void); +#endif extern PyObject* PyInit__struct(void); extern PyObject* PyInit__datetime(void); extern PyObject* PyInit__functools(void); @@ -122,10 +126,14 @@ struct _inittab _PyImport_Inittab[] = { {"itertools", PyInit_itertools}, {"_collections", PyInit__collections}, {"_symtable", PyInit__symtable}, +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_GAMES) {"mmap", PyInit_mmap}, +#endif {"_csv", PyInit__csv}, {"_sre", PyInit__sre}, +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) {"winreg", PyInit_winreg}, +#endif {"_struct", PyInit__struct}, {"_datetime", PyInit__datetime}, {"_functools", PyInit__functools}, diff --git a/PC/config_minimal.c b/PC/config_minimal.c index 928a4efd32e1..9a66ea1d1cd3 100644 --- a/PC/config_minimal.c +++ b/PC/config_minimal.c @@ -5,8 +5,10 @@ #include "Python.h" +#ifdef Py_ENABLE_SHARED /* Define extern variables omitted from minimal builds */ void *PyWin_DLLhModule = NULL; +#endif extern PyObject* PyInit_faulthandler(void); @@ -14,7 +16,9 @@ extern PyObject* PyInit__tracemalloc(void); extern PyObject* PyInit_gc(void); extern PyObject* PyInit_nt(void); extern PyObject* PyInit__signal(void); +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) extern PyObject* PyInit_winreg(void); +#endif extern PyObject* PyInit__ast(void); extern PyObject* PyInit__io(void); @@ -35,7 +39,9 @@ struct _inittab _PyImport_Inittab[] = { {"_tokenize", PyInit__tokenize}, {"_tracemalloc", PyInit__tracemalloc}, +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) {"winreg", PyInit_winreg}, +#endif /* This module "lives in" with marshal.c */ {"marshal", PyMarshal_Init}, diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index 988d9c95aaa2..face4d03af9d 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -253,6 +253,8 @@ msvcrt_getch_impl(PyObject *module) return ch; } +#ifdef MS_WINDOWS_DESKTOP + /*[clinic input] msvcrt.getwch -> wchar_t @@ -271,6 +273,8 @@ msvcrt_getwch_impl(PyObject *module) return ch; } +#endif /* MS_WINDOWS_DESKTOP */ + /*[clinic input] msvcrt.getche -> byte_char @@ -289,6 +293,8 @@ msvcrt_getche_impl(PyObject *module) return ch; } +#ifdef MS_WINDOWS_DESKTOP + /*[clinic input] msvcrt.getwche -> wchar_t @@ -307,6 +313,8 @@ msvcrt_getwche_impl(PyObject *module) return ch; } +#endif /* MS_WINDOWS_DESKTOP */ + /*[clinic input] msvcrt.putch @@ -326,6 +334,8 @@ msvcrt_putch_impl(PyObject *module, char char_value) Py_RETURN_NONE; } +#ifdef MS_WINDOWS_DESKTOP + /*[clinic input] msvcrt.putwch @@ -346,6 +356,8 @@ msvcrt_putwch_impl(PyObject *module, int unicode_char) } +#endif /* MS_WINDOWS_DESKTOP */ + /*[clinic input] msvcrt.ungetch @@ -374,6 +386,8 @@ msvcrt_ungetch_impl(PyObject *module, char char_value) Py_RETURN_NONE; } +#ifdef MS_WINDOWS_DESKTOP + /*[clinic input] msvcrt.ungetwch @@ -398,6 +412,8 @@ msvcrt_ungetwch_impl(PyObject *module, int unicode_char) Py_RETURN_NONE; } +#endif /* MS_WINDOWS_DESKTOP */ + #ifdef _DEBUG /*[clinic input] msvcrt.CrtSetReportFile -> HANDLE @@ -475,6 +491,8 @@ msvcrt_set_error_mode_impl(PyObject *module, int mode) } #endif /* _DEBUG */ +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM) + /*[clinic input] msvcrt.GetErrorMode @@ -494,6 +512,8 @@ msvcrt_GetErrorMode_impl(PyObject *module) return PyLong_FromUnsignedLong(res); } +#endif /* MS_WINDOWS_APP || MS_WINDOWS_SYSTEM */ + /*[clinic input] msvcrt.SetErrorMode @@ -601,10 +621,12 @@ PyInit_msvcrt(void) insertint(d, "LK_NBRLCK", _LK_NBRLCK); insertint(d, "LK_RLCK", _LK_RLCK); insertint(d, "LK_UNLCK", _LK_UNLCK); +#ifdef MS_WINDOWS_DESKTOP insertint(d, "SEM_FAILCRITICALERRORS", SEM_FAILCRITICALERRORS); insertint(d, "SEM_NOALIGNMENTFAULTEXCEPT", SEM_NOALIGNMENTFAULTEXCEPT); insertint(d, "SEM_NOGPFAULTERRORBOX", SEM_NOGPFAULTERRORBOX); insertint(d, "SEM_NOOPENFILEERRORBOX", SEM_NOOPENFILEERRORBOX); +#endif #ifdef _DEBUG insertint(d, "CRT_WARN", _CRT_WARN); insertint(d, "CRT_ERROR", _CRT_ERROR); diff --git a/PC/pyconfig.h b/PC/pyconfig.h index a34d420ab7ec..8a3bf8968ce2 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -72,9 +72,27 @@ WIN32 is still required for the locale module. #define USE_SOCKET #endif -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) -#define MS_WINDOWS_NON_DESKTOP +#if defined(Py_BUILD_CORE) || defined(Py_BUILD_CORE_BUILTIN) || defined(Py_BUILD_CORE_MODULE) +#include + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define MS_WINDOWS_DESKTOP +#endif +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#define MS_WINDOWS_APP +#endif +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_SYSTEM) +#define MS_WINDOWS_SYSTEM #endif +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_GAMES) +#define MS_WINDOWS_GAMES +#endif + +/* Define to 1 if you support windows console io */ +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_APP) || defined(MS_WINDOWS_SYSTEM) +#define HAVE_WINDOWS_CONSOLE_IO 1 +#endif +#endif /* Py_BUILD_CORE || Py_BUILD_CORE_BUILTIN || Py_BUILD_CORE_MODULE */ /* Compiler specific defines */ @@ -300,7 +318,7 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ # endif /* Py_BUILD_CORE */ #endif /* MS_COREDLL */ -#if defined(MS_WIN64) +#ifdef MS_WIN64 /* maintain "win32" sys.platform for backward compatibility of Python code, the Win64 API should be close enough to the Win32 API to make this preferable */ diff --git a/PC/winreg.c b/PC/winreg.c index 86efed09855b..073598a12a68 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -18,6 +18,8 @@ #include "structmember.h" // PyMemberDef #include +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES) + static BOOL PyHKEY_AsHKEY(PyObject *ob, HKEY *pRes, BOOL bNoneOK); static BOOL clinic_HKEY_converter(PyObject *ob, void *p); static PyObject *PyHKEY_FromHKEY(HKEY h); @@ -829,6 +831,8 @@ winreg_CloseKey(PyObject *module, PyObject *hkey) Py_RETURN_NONE; } +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) + /*[clinic input] winreg.ConnectRegistry -> HKEY @@ -866,6 +870,8 @@ winreg_ConnectRegistry_impl(PyObject *module, return retKey; } +#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM */ + /*[clinic input] winreg.CreateKey -> HKEY @@ -1272,6 +1278,8 @@ winreg_ExpandEnvironmentStrings_impl(PyObject *module, return o; } +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) + /*[clinic input] winreg.FlushKey @@ -1305,6 +1313,9 @@ winreg_FlushKey_impl(PyObject *module, HKEY key) Py_RETURN_NONE; } +#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM */ + +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) /*[clinic input] winreg.LoadKey @@ -1354,6 +1365,8 @@ winreg_LoadKey_impl(PyObject *module, HKEY key, const Py_UNICODE *sub_key, Py_RETURN_NONE; } +#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM */ + /*[clinic input] winreg.OpenKey -> HKEY @@ -1463,6 +1476,7 @@ winreg_QueryInfoKey_impl(PyObject *module, HKEY key) return ret; } + /*[clinic input] winreg.QueryValue @@ -1634,6 +1648,8 @@ winreg_QueryValueEx_impl(PyObject *module, HKEY key, const Py_UNICODE *name) return result; } +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) + /*[clinic input] winreg.SaveKey @@ -1679,6 +1695,8 @@ winreg_SaveKey_impl(PyObject *module, HKEY key, const Py_UNICODE *file_name) Py_RETURN_NONE; } +#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM */ + /*[clinic input] winreg.SetValue @@ -1776,6 +1794,7 @@ winreg_SetValue_impl(PyObject *module, HKEY key, const Py_UNICODE *sub_key, return result; } + /*[clinic input] winreg.SetValueEx @@ -1861,6 +1880,8 @@ winreg_SetValueEx_impl(PyObject *module, HKEY key, return result; } +#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) + /*[clinic input] winreg.DisableReflectionKey @@ -2009,6 +2030,8 @@ winreg_QueryReflectionKey_impl(PyObject *module, HKEY key) return PyBool_FromLong(result); } +#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM */ + static struct PyMethodDef winreg_methods[] = { WINREG_CLOSEKEY_METHODDEF WINREG_CONNECTREGISTRY_METHODDEF @@ -2149,3 +2172,5 @@ PyMODINIT_FUNC PyInit_winreg(void) ADD_INT(REG_RESOURCE_REQUIREMENTS_LIST); return m; } + +#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM || MS_WINDOWS_GAMES */ diff --git a/Parser/myreadline.c b/Parser/myreadline.c index d55fcefbb6f2..3f0e29f051a4 100644 --- a/Parser/myreadline.c +++ b/Parser/myreadline.c @@ -13,7 +13,9 @@ #include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH #include "pycore_pystate.h" // _PyThreadState_GET() #ifdef MS_WINDOWS +# ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN +# endif # include "windows.h" #endif /* MS_WINDOWS */ @@ -108,7 +110,7 @@ my_fgets(PyThreadState* tstate, char *buf, int len, FILE *fp) /* NOTREACHED */ } -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO /* Readline implementation using ReadConsoleW */ extern char _get_console_type(HANDLE handle); @@ -233,7 +235,7 @@ _PyOS_WindowsConsoleReadline(PyThreadState *tstate, HANDLE hStdIn) return buf; } -#endif +#endif /* HAVE_WINDOWS_CONSOLE_IO */ /* Readline implementation using fgets() */ @@ -246,7 +248,7 @@ PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, const char *prompt) PyThreadState *tstate = _PyOS_ReadlineTState; assert(tstate != NULL); -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); if (!config->legacy_windows_stdio && sys_stdin == stdin) { HANDLE hStdIn, hStdErr; diff --git a/Python/dynload_win.c b/Python/dynload_win.c index 7bd04d573df4..acab05e2c6de 100644 --- a/Python/dynload_win.c +++ b/Python/dynload_win.c @@ -163,6 +163,7 @@ static char *GetPythonImport (HINSTANCE hModule) return NULL; } +#ifdef Py_ENABLE_SHARED /* Load python3.dll before loading any extension module that might refer to it. That way, we can be sure that always the python3.dll corresponding to this python DLL is loaded, not a python3.dll that might be on the path @@ -216,6 +217,7 @@ _Py_CheckPython3(void) return hPython3 != NULL; #undef MAXPATHLEN } +#endif /* Py_ENABLE_SHARED */ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, const char *shortname, @@ -224,7 +226,9 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, dl_funcptr p; char funcname[258], *import_python; +#ifdef Py_ENABLE_SHARED _Py_CheckPython3(); +#endif /* Py_ENABLE_SHARED */ wchar_t *wpathname = PyUnicode_AsWideCharString(pathname, NULL); if (wpathname == NULL) @@ -234,10 +238,12 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, { HINSTANCE hDLL = NULL; +#ifdef MS_WINDOWS_DESKTOP unsigned int old_mode; /* Don't display a message box when Python can't load a DLL */ old_mode = SetErrorMode(SEM_FAILCRITICALERRORS); +#endif /* bpo-36085: We use LoadLibraryEx with restricted search paths to avoid DLL preloading attacks and enable use of the @@ -250,8 +256,10 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, Py_END_ALLOW_THREADS PyMem_Free(wpathname); +#ifdef MS_WINDOWS_DESKTOP /* restore old error mode settings */ SetErrorMode(old_mode); +#endif if (hDLL==NULL){ PyObject *message; diff --git a/Python/fileutils.c b/Python/fileutils.c index 93bee9ee007c..4ac759c45a3a 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -8,7 +8,11 @@ #ifdef MS_WINDOWS # include # include -# include // PathCchCombineEx +# if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) +# define PATHCCH_ALLOW_LONG_PATHS 0x01 +# else +# include // PathCchCombineEx +# endif extern int winerror_to_errno(int); #endif @@ -77,7 +81,8 @@ _Py_device_encoding(int fd) if (!valid) Py_RETURN_NONE; -#if defined(MS_WINDOWS) +#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO UINT cp; if (fd == 0) cp = GetConsoleCP(); @@ -92,6 +97,9 @@ _Py_device_encoding(int fd) } return PyUnicode_FromFormat("cp%u", (unsigned int)cp); +#else + Py_RETURN_NONE; +#endif /* HAVE_WINDOWS_CONSOLE_IO */ #else if (_PyRuntime.preconfig.utf8_mode) { _Py_DECLARE_STR(utf_8, "utf-8"); @@ -1270,6 +1278,13 @@ _Py_stat(PyObject *path, struct stat *statbuf) #endif } +#ifdef MS_WINDOWS +// For some Windows API partitions, SetHandleInformation() is declared +// but none of the handle flags are defined. +#ifndef HANDLE_FLAG_INHERIT +#define HANDLE_FLAG_INHERIT 0x00000001 +#endif +#endif /* This function MUST be kept async-signal-safe on POSIX when raise=0. */ static int @@ -2096,6 +2111,72 @@ _Py_abspath(const wchar_t *path, wchar_t **abspath_p) #endif } +// The Windows Games API family implements the PathCch* APIs in the Xbox OS, +// but does not expose them yet. Load them dynamically until +// 1) they are officially exposed +// 2) we stop supporting older versions of the GDK which do not expose them +#if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) +HRESULT +PathCchSkipRoot(const wchar_t *path, const wchar_t **rootEnd) +{ + static int initialized = 0; + typedef HRESULT(__stdcall *PPathCchSkipRoot) (PCWSTR pszPath, + PCWSTR *ppszRootEnd); + static PPathCchSkipRoot _PathCchSkipRoot; + + if (initialized == 0) { + HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32); + if (pathapi) { + _PathCchSkipRoot = (PPathCchSkipRoot)GetProcAddress( + pathapi, "PathCchSkipRoot"); + } + else { + _PathCchSkipRoot = NULL; + } + initialized = 1; + } + + if (!_PathCchSkipRoot) { + return E_NOINTERFACE; + } + + return _PathCchSkipRoot(path, rootEnd); +} + +static HRESULT +PathCchCombineEx(wchar_t *buffer, size_t bufsize, const wchar_t *dirname, + const wchar_t *relfile, unsigned long flags) +{ + static int initialized = 0; + typedef HRESULT(__stdcall *PPathCchCombineEx) (PWSTR pszPathOut, + size_t cchPathOut, + PCWSTR pszPathIn, + PCWSTR pszMore, + unsigned long dwFlags); + static PPathCchCombineEx _PathCchCombineEx; + + if (initialized == 0) { + HMODULE pathapi = LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32); + if (pathapi) { + _PathCchCombineEx = (PPathCchCombineEx)GetProcAddress( + pathapi, "PathCchCombineEx"); + } + else { + _PathCchCombineEx = NULL; + } + initialized = 1; + } + + if (!_PathCchCombineEx) { + return E_NOINTERFACE; + } + + return _PathCchCombineEx(buffer, bufsize, dirname, relfile, flags); +} + +#endif /* defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) */ // The caller must ensure "buffer" is big enough. static int @@ -2491,12 +2572,12 @@ _Py_get_blocking(int fd) success = GetNamedPipeHandleStateW(handle, &mode, NULL, NULL, NULL, NULL, 0); Py_END_ALLOW_THREADS - + if (!success) { PyErr_SetFromWindowsErr(0); return -1; } - + return !(mode & PIPE_NOWAIT); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index e80dd30c89df..82e94090a602 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2289,7 +2289,7 @@ create_stdio(const PyConfig *config, PyObject* io, raw = Py_NewRef(buf); } -#ifdef MS_WINDOWS +#ifdef HAVE_WINDOWS_CONSOLE_IO /* Windows console IO is always UTF-8 encoded */ PyTypeObject *winconsoleio_type = (PyTypeObject *)_PyImport_GetModuleAttr( &_Py_ID(_io), &_Py_ID(_WindowsConsoleIO)); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 207abb964bca..764fb70bae6c 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1490,6 +1490,9 @@ static PyStructSequence_Desc windows_version_desc = { static PyObject * _sys_getwindowsversion_from_kernel32() { +#ifndef MS_WINDOWS_DESKTOP + return NULL; +#else HANDLE hKernel32; wchar_t kernel32_path[MAX_PATH]; LPVOID verblock; @@ -1523,6 +1526,7 @@ _sys_getwindowsversion_from_kernel32() realBuild = HIWORD(ffi->dwProductVersionLS); PyMem_RawFree(verblock); return Py_BuildValue("(kkk)", realMajor, realMinor, realBuild); +#endif /* !MS_WINDOWS_DESKTOP */ } /* Disable deprecation warnings about GetVersionEx as the result is From webhook-mailer at python.org Thu Mar 9 18:06:56 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 09 Mar 2023 23:06:56 -0000 Subject: [Python-checkins] gh-102378: don't bother stripping `/` from __text_signature__ (#102379) Message-ID: https://github.com/python/cpython/commit/71cf7c3dddd9c49ec70c1a95547f2fcd5daa7034 commit: 71cf7c3dddd9c49ec70c1a95547f2fcd5daa7034 branch: main author: David Hewitt <1939362+davidhewitt at users.noreply.github.com> committer: JelleZijlstra date: 2023-03-09T15:06:20-08:00 summary: gh-102378: don't bother stripping `/` from __text_signature__ (#102379) files: A Misc/NEWS.d/next/Library/2023-03-03-19-53-08.gh-issue-102378.kRdOZc.rst M Lib/inspect.py M Lib/test/test_inspect.py diff --git a/Lib/inspect.py b/Lib/inspect.py index 166667c62cdc..edc23b0ffa92 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2106,26 +2106,21 @@ def _signature_strip_non_python_syntax(signature): Private helper function. Takes a signature in Argument Clinic's extended signature format. - Returns a tuple of three things: - * that signature re-rendered in standard Python syntax, + Returns a tuple of two things: + * that signature re-rendered in standard Python syntax, and * the index of the "self" parameter (generally 0), or None if - the function does not have a "self" parameter, and - * the index of the last "positional only" parameter, - or None if the signature has no positional-only parameters. + the function does not have a "self" parameter. """ if not signature: - return signature, None, None + return signature, None self_parameter = None - last_positional_only = None lines = [l.encode('ascii') for l in signature.split('\n') if l] generator = iter(lines).__next__ token_stream = tokenize.tokenize(generator) - delayed_comma = False - skip_next_comma = False text = [] add = text.append @@ -2142,35 +2137,18 @@ def _signature_strip_non_python_syntax(signature): if type == OP: if string == ',': - if skip_next_comma: - skip_next_comma = False - else: - assert not delayed_comma - delayed_comma = True - current_parameter += 1 - continue - - if string == '/': - assert not skip_next_comma - assert last_positional_only is None - skip_next_comma = True - last_positional_only = current_parameter - 1 - continue + current_parameter += 1 if (type == ERRORTOKEN) and (string == '$'): assert self_parameter is None self_parameter = current_parameter continue - if delayed_comma: - delayed_comma = False - if not ((type == OP) and (string == ')')): - add(', ') add(string) if (string == ','): add(' ') clean_signature = ''.join(text) - return clean_signature, self_parameter, last_positional_only + return clean_signature, self_parameter def _signature_fromstr(cls, obj, s, skip_bound_arg=True): @@ -2179,8 +2157,7 @@ def _signature_fromstr(cls, obj, s, skip_bound_arg=True): """ Parameter = cls._parameter_cls - clean_signature, self_parameter, last_positional_only = \ - _signature_strip_non_python_syntax(s) + clean_signature, self_parameter = _signature_strip_non_python_syntax(s) program = "def foo" + clean_signature + ": pass" @@ -2269,17 +2246,17 @@ def p(name_node, default_node, default=empty): parameters.append(Parameter(name, kind, default=default, annotation=empty)) # non-keyword-only parameters - args = reversed(f.args.args) - defaults = reversed(f.args.defaults) - iter = itertools.zip_longest(args, defaults, fillvalue=None) - if last_positional_only is not None: - kind = Parameter.POSITIONAL_ONLY - else: - kind = Parameter.POSITIONAL_OR_KEYWORD - for i, (name, default) in enumerate(reversed(list(iter))): + total_non_kw_args = len(f.args.posonlyargs) + len(f.args.args) + required_non_kw_args = total_non_kw_args - len(f.args.defaults) + defaults = itertools.chain(itertools.repeat(None, required_non_kw_args), f.args.defaults) + + kind = Parameter.POSITIONAL_ONLY + for (name, default) in zip(f.args.posonlyargs, defaults): + p(name, default) + + kind = Parameter.POSITIONAL_OR_KEYWORD + for (name, default) in zip(f.args.args, defaults): p(name, default) - if i == last_positional_only: - kind = Parameter.POSITIONAL_OR_KEYWORD # *args if f.args.vararg: diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 92aba519d28a..02f8378d0413 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -4230,56 +4230,47 @@ def foo(a): pass class TestSignaturePrivateHelpers(unittest.TestCase): def _strip_non_python_syntax(self, input, - clean_signature, self_parameter, last_positional_only): + clean_signature, self_parameter): computed_clean_signature, \ - computed_self_parameter, \ - computed_last_positional_only = \ + computed_self_parameter = \ inspect._signature_strip_non_python_syntax(input) self.assertEqual(computed_clean_signature, clean_signature) self.assertEqual(computed_self_parameter, self_parameter) - self.assertEqual(computed_last_positional_only, last_positional_only) def test_signature_strip_non_python_syntax(self): self._strip_non_python_syntax( "($module, /, path, mode, *, dir_fd=None, " + "effective_ids=False,\n follow_symlinks=True)", - "(module, path, mode, *, dir_fd=None, " + + "(module, /, path, mode, *, dir_fd=None, " + "effective_ids=False, follow_symlinks=True)", - 0, 0) self._strip_non_python_syntax( "($module, word, salt, /)", - "(module, word, salt)", - 0, - 2) + "(module, word, salt, /)", + 0) self._strip_non_python_syntax( "(x, y=None, z=None, /)", - "(x, y=None, z=None)", - None, - 2) + "(x, y=None, z=None, /)", + None) self._strip_non_python_syntax( "(x, y=None, z=None)", "(x, y=None, z=None)", - None, None) self._strip_non_python_syntax( "(x,\n y=None,\n z = None )", "(x, y=None, z=None)", - None, None) self._strip_non_python_syntax( "", "", - None, None) self._strip_non_python_syntax( - None, None, None, None) diff --git a/Misc/NEWS.d/next/Library/2023-03-03-19-53-08.gh-issue-102378.kRdOZc.rst b/Misc/NEWS.d/next/Library/2023-03-03-19-53-08.gh-issue-102378.kRdOZc.rst new file mode 100644 index 000000000000..d30f65f30d10 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-03-19-53-08.gh-issue-102378.kRdOZc.rst @@ -0,0 +1 @@ +Private helper method ``inspect._signature_strip_non_python_syntax`` will no longer strip ``/`` from the input string. From webhook-mailer at python.org Fri Mar 10 04:03:18 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 10 Mar 2023 09:03:18 -0000 Subject: [Python-checkins] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives in `_ctypes` (#102477) Message-ID: https://github.com/python/cpython/commit/2999e02836f9112de6b17784eaca762fb87e71a9 commit: 2999e02836f9112de6b17784eaca762fb87e71a9 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-10T14:32:32+05:30 summary: gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives in `_ctypes` (#102477) files: M Modules/_ctypes/_ctypes.c M Modules/_ctypes/callproc.c diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 8690f2c1b078..6f92ca08dd53 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2200,7 +2200,6 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value) struct fielddesc *fd; PyObject *as_parameter; int res; - PyObject *exc, *val, *tb; /* If the value is already an instance of the requested type, we can use it as is */ @@ -2234,33 +2233,27 @@ PyCSimpleType_from_param(PyObject *type, PyObject *value) parg->obj = fd->setfunc(&parg->value, value, 0); if (parg->obj) return (PyObject *)parg; - PyErr_Fetch(&exc, &val, &tb); + PyObject *exc = PyErr_GetRaisedException(); Py_DECREF(parg); if (_PyObject_LookupAttr(value, &_Py_ID(_as_parameter_), &as_parameter) < 0) { Py_XDECREF(exc); - Py_XDECREF(val); - Py_XDECREF(tb); return NULL; } if (as_parameter) { if (_Py_EnterRecursiveCall("while processing _as_parameter_")) { Py_DECREF(as_parameter); Py_XDECREF(exc); - Py_XDECREF(val); - Py_XDECREF(tb); return NULL; } value = PyCSimpleType_from_param(type, as_parameter); _Py_LeaveRecursiveCall(); Py_DECREF(as_parameter); Py_XDECREF(exc); - Py_XDECREF(val); - Py_XDECREF(tb); return value; } if (exc) { - PyErr_Restore(exc, val, tb); + PyErr_SetRaisedException(exc); } else { PyErr_SetString(PyExc_TypeError, "wrong type"); diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index f6d98bbeebc2..4438727332bc 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -1013,41 +1013,43 @@ static PyObject *GetResult(PyObject *restype, void *result, PyObject *checker) void _ctypes_extend_error(PyObject *exc_class, const char *fmt, ...) { va_list vargs; - PyObject *tp, *v, *tb, *s, *cls_str, *msg_str; va_start(vargs, fmt); - s = PyUnicode_FromFormatV(fmt, vargs); + PyObject *s = PyUnicode_FromFormatV(fmt, vargs); va_end(vargs); - if (!s) + if (s == NULL) { return; + } - PyErr_Fetch(&tp, &v, &tb); - PyErr_NormalizeException(&tp, &v, &tb); - if (PyType_Check(tp)) - cls_str = PyType_GetName((PyTypeObject *)tp); - else - cls_str = PyObject_Str(tp); + assert(PyErr_Occurred()); + PyObject *exc = PyErr_GetRaisedException(); + assert(exc != NULL); + PyObject *cls_str = PyType_GetName(Py_TYPE(exc)); if (cls_str) { PyUnicode_AppendAndDel(&s, cls_str); PyUnicode_AppendAndDel(&s, PyUnicode_FromString(": ")); - if (s == NULL) + if (s == NULL) { goto error; - } else + } + } + else { PyErr_Clear(); - msg_str = PyObject_Str(v); - if (msg_str) + } + + PyObject *msg_str = PyObject_Str(exc); + if (msg_str) { PyUnicode_AppendAndDel(&s, msg_str); + } else { PyErr_Clear(); PyUnicode_AppendAndDel(&s, PyUnicode_FromString("???")); } - if (s == NULL) + if (s == NULL) { goto error; + } PyErr_SetObject(exc_class, s); error: - Py_XDECREF(tp); - Py_XDECREF(v); - Py_XDECREF(tb); + Py_XDECREF(exc); Py_XDECREF(s); } From webhook-mailer at python.org Fri Mar 10 07:21:45 2023 From: webhook-mailer at python.org (zooba) Date: Fri, 10 Mar 2023 12:21:45 -0000 Subject: [Python-checkins] gh-102519: Add os.listdrives, os.listvolumes and os.listmounts on Windows (GH-102544) Message-ID: https://github.com/python/cpython/commit/cb35882773a3ffc7fe0671e64848f4c926a2d52f commit: cb35882773a3ffc7fe0671e64848f4c926a2d52f branch: main author: Steve Dower committer: zooba date: 2023-03-10T12:21:37Z summary: gh-102519: Add os.listdrives, os.listvolumes and os.listmounts on Windows (GH-102544) files: A Misc/NEWS.d/next/Library/2023-03-08-23-08-38.gh-issue-102519.wlcsFI.rst M Doc/whatsnew/3.12.rst M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_unicodeobject_generated.h M Lib/test/test_os.py M Modules/clinic/posixmodule.c.h M Modules/posixmodule.c diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index d982cb62ec2f..48b7aab0595e 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -294,6 +294,10 @@ os method to check if the entry is a junction. (Contributed by Charles Machalow in :gh:`99547`.) +* Add :func:`os.listdrives`, :func:`os.listvolumes` and :func:`os.listmounts` + functions on Windows for enumerating drives, volumes and mount points. + (Contributed by Steve Dower in :gh:`102519`.) + os.path ------- diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index dc5cd58d8535..4b12ae523c32 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1216,6 +1216,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(value)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(values)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(version)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(volume)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(warnings)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(warnoptions)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(wbits)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 8b23aa154793..17fb9ffbbf9f 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -702,6 +702,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(value) STRUCT_FOR_ID(values) STRUCT_FOR_ID(version) + STRUCT_FOR_ID(volume) STRUCT_FOR_ID(warnings) STRUCT_FOR_ID(warnoptions) STRUCT_FOR_ID(wbits) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 471efadb13bb..b240be57369d 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1208,6 +1208,7 @@ extern "C" { INIT_ID(value), \ INIT_ID(values), \ INIT_ID(version), \ + INIT_ID(volume), \ INIT_ID(warnings), \ INIT_ID(warnoptions), \ INIT_ID(wbits), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index b47d240e492f..52af37a8e60a 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1310,6 +1310,8 @@ _PyUnicode_InitStaticStrings(void) { PyUnicode_InternInPlace(&string); string = &_Py_ID(version); PyUnicode_InternInPlace(&string); + string = &_Py_ID(volume); + PyUnicode_InternInPlace(&string); string = &_Py_ID(warnings); PyUnicode_InternInPlace(&string); string = &_Py_ID(warnoptions); diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index ba6feb69ea17..253e2a23238f 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2648,6 +2648,49 @@ def test_listdir_extended_path(self): [os.fsencode(path) for path in self.created_paths]) + at unittest.skipUnless(os.name == "nt", "NT specific tests") +class Win32ListdriveTests(unittest.TestCase): + """Test listdrive, listmounts and listvolume on Windows.""" + + def setUp(self): + # Get drives and volumes from fsutil + out = subprocess.check_output( + ["fsutil.exe", "volume", "list"], + cwd=os.path.join(os.getenv("SystemRoot", "\\Windows"), "System32"), + encoding="mbcs", + errors="ignore", + ) + lines = out.splitlines() + self.known_volumes = {l for l in lines if l.startswith('\\\\?\\')} + self.known_drives = {l for l in lines if l[1:] == ':\\'} + self.known_mounts = {l for l in lines if l[1:3] == ':\\'} + + def test_listdrives(self): + drives = os.listdrives() + self.assertIsInstance(drives, list) + self.assertSetEqual( + self.known_drives, + self.known_drives & set(drives), + ) + + def test_listvolumes(self): + volumes = os.listvolumes() + self.assertIsInstance(volumes, list) + self.assertSetEqual( + self.known_volumes, + self.known_volumes & set(volumes), + ) + + def test_listmounts(self): + for volume in os.listvolumes(): + mounts = os.listmounts(volume) + self.assertIsInstance(mounts, list) + self.assertSetEqual( + set(mounts), + self.known_mounts & set(mounts), + ) + + @unittest.skipUnless(hasattr(os, 'readlink'), 'needs os.readlink()') class ReadlinkTests(unittest.TestCase): filelink = 'readlinktest' diff --git a/Misc/NEWS.d/next/Library/2023-03-08-23-08-38.gh-issue-102519.wlcsFI.rst b/Misc/NEWS.d/next/Library/2023-03-08-23-08-38.gh-issue-102519.wlcsFI.rst new file mode 100644 index 000000000000..f47e4f70b130 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-08-23-08-38.gh-issue-102519.wlcsFI.rst @@ -0,0 +1,2 @@ +Add :func:`os.listdrives`, :func:`os.listvolumes` and :func:`os.listmounts` +functions on Windows for enumerating drives, volumes and mount points diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 6565f8df935c..8b0550d832fc 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -1601,6 +1601,120 @@ os_listdir(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject * #if defined(MS_WINDOWS) +PyDoc_STRVAR(os_listdrives__doc__, +"listdrives($module, /)\n" +"--\n" +"\n" +"Return a list containing the names of drives in the system.\n" +"\n" +"A drive name typically looks like \'C:\\\\\'."); + +#define OS_LISTDRIVES_METHODDEF \ + {"listdrives", (PyCFunction)os_listdrives, METH_NOARGS, os_listdrives__doc__}, + +static PyObject * +os_listdrives_impl(PyObject *module); + +static PyObject * +os_listdrives(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return os_listdrives_impl(module); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(os_listvolumes__doc__, +"listvolumes($module, /)\n" +"--\n" +"\n" +"Return a list containing the volumes in the system.\n" +"\n" +"Volumes are typically represented as a GUID path."); + +#define OS_LISTVOLUMES_METHODDEF \ + {"listvolumes", (PyCFunction)os_listvolumes, METH_NOARGS, os_listvolumes__doc__}, + +static PyObject * +os_listvolumes_impl(PyObject *module); + +static PyObject * +os_listvolumes(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return os_listvolumes_impl(module); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(os_listmounts__doc__, +"listmounts($module, /, volume)\n" +"--\n" +"\n" +"Return a list containing mount points for a particular volume.\n" +"\n" +"\'volume\' should be a GUID path as returned from os.listvolumes."); + +#define OS_LISTMOUNTS_METHODDEF \ + {"listmounts", _PyCFunction_CAST(os_listmounts), METH_FASTCALL|METH_KEYWORDS, os_listmounts__doc__}, + +static PyObject * +os_listmounts_impl(PyObject *module, path_t *volume); + +static PyObject * +os_listmounts(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(volume), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"volume", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "listmounts", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + path_t volume = PATH_T_INITIALIZE("listmounts", "volume", 0, 0); + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!path_converter(args[0], &volume)) { + goto exit; + } + return_value = os_listmounts_impl(module, &volume); + +exit: + /* Cleanup for volume */ + path_cleanup(&volume); + + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + PyDoc_STRVAR(os__getfullpathname__doc__, "_getfullpathname($module, path, /)\n" "--\n" @@ -11253,6 +11367,18 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #define OS_LINK_METHODDEF #endif /* !defined(OS_LINK_METHODDEF) */ +#ifndef OS_LISTDRIVES_METHODDEF + #define OS_LISTDRIVES_METHODDEF +#endif /* !defined(OS_LISTDRIVES_METHODDEF) */ + +#ifndef OS_LISTVOLUMES_METHODDEF + #define OS_LISTVOLUMES_METHODDEF +#endif /* !defined(OS_LISTVOLUMES_METHODDEF) */ + +#ifndef OS_LISTMOUNTS_METHODDEF + #define OS_LISTMOUNTS_METHODDEF +#endif /* !defined(OS_LISTMOUNTS_METHODDEF) */ + #ifndef OS__GETFULLPATHNAME_METHODDEF #define OS__GETFULLPATHNAME_METHODDEF #endif /* !defined(OS__GETFULLPATHNAME_METHODDEF) */ @@ -11796,4 +11922,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=9495478e51701b8a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=47750e0e29c8d707 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 0d534f35f6a4..7d91f7e4bac7 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4229,7 +4229,198 @@ os_listdir_impl(PyObject *module, path_t *path) #endif } + #ifdef MS_WINDOWS + +/*[clinic input] +os.listdrives + +Return a list containing the names of drives in the system. + +A drive name typically looks like 'C:\\'. + +[clinic start generated code]*/ + +static PyObject * +os_listdrives_impl(PyObject *module) +/*[clinic end generated code: output=aaece9dacdf682b5 input=1af9ccc9e583798e]*/ +{ + /* Number of possible drives is limited, so 256 should always be enough. + On the day when it is not, listmounts() will have to be used. */ + wchar_t buffer[256]; + DWORD buflen = Py_ARRAY_LENGTH(buffer); + PyObject *result = NULL; + if (PySys_Audit("os.listdrives", NULL) < 0) { + return NULL; + } + + Py_BEGIN_ALLOW_THREADS; + buflen = GetLogicalDriveStringsW(buflen, buffer); + Py_END_ALLOW_THREADS; + + if (!buflen) { + PyErr_SetFromWindowsErr(0); + return NULL; + } else if (buflen >= Py_ARRAY_LENGTH(buffer)) { + PyErr_SetFromWindowsErr(ERROR_MORE_DATA); + return NULL; + } + + /* buflen includes a null terminator, so remove it */ + PyObject *str = PyUnicode_FromWideChar(buffer, buflen - 1); + if (str) { + PyObject *nullchar = PyUnicode_FromStringAndSize("\0", 1); + if (nullchar) { + result = PyUnicode_Split(str, nullchar, -1); + Py_DECREF(nullchar); + } + Py_DECREF(str); + } + return result; +} + +/*[clinic input] +os.listvolumes + +Return a list containing the volumes in the system. + +Volumes are typically represented as a GUID path. + +[clinic start generated code]*/ + +static PyObject * +os_listvolumes_impl(PyObject *module) +/*[clinic end generated code: output=534e10ea2bf9d386 input=f6e4e70371f11e99]*/ +{ + PyObject *result = PyList_New(0); + HANDLE find = INVALID_HANDLE_VALUE; + wchar_t buffer[MAX_PATH + 1]; + if (!result) { + return NULL; + } + if (PySys_Audit("os.listvolumes", NULL) < 0) { + Py_DECREF(result); + return NULL; + } + + int err = 0; + Py_BEGIN_ALLOW_THREADS; + find = FindFirstVolumeW(buffer, Py_ARRAY_LENGTH(buffer)); + if (find == INVALID_HANDLE_VALUE) { + err = GetLastError(); + } + Py_END_ALLOW_THREADS; + + while (!err) { + PyObject *s = PyUnicode_FromWideChar(buffer, -1); + if (!s || PyList_Append(result, s) < 0) { + Py_XDECREF(s); + Py_CLEAR(result); + break; + } + Py_DECREF(s); + + Py_BEGIN_ALLOW_THREADS; + if (!FindNextVolumeW(find, buffer, Py_ARRAY_LENGTH(buffer))) { + err = GetLastError(); + } + Py_END_ALLOW_THREADS; + } + + if (find != INVALID_HANDLE_VALUE) { + Py_BEGIN_ALLOW_THREADS; + FindVolumeClose(find); + Py_END_ALLOW_THREADS; + } + if (err && err != ERROR_NO_MORE_FILES) { + PyErr_SetFromWindowsErr(err); + Py_XDECREF(result); + result = NULL; + } + return result; +} + + +/*[clinic input] +os.listmounts + + volume: path_t + +Return a list containing mount points for a particular volume. + +'volume' should be a GUID path as returned from os.listvolumes. + +[clinic start generated code]*/ + +static PyObject * +os_listmounts_impl(PyObject *module, path_t *volume) +/*[clinic end generated code: output=06da49679de4512e input=a8a27178e3f67845]*/ +{ + wchar_t default_buffer[MAX_PATH + 1]; + DWORD buflen = Py_ARRAY_LENGTH(default_buffer); + LPWSTR buffer = default_buffer; + DWORD attributes; + PyObject *str = NULL; + PyObject *nullchar = NULL; + PyObject *result = NULL; + + /* Ensure we have a valid volume path before continuing */ + Py_BEGIN_ALLOW_THREADS + attributes = GetFileAttributesW(volume->wide); + Py_END_ALLOW_THREADS + if (attributes == INVALID_FILE_ATTRIBUTES && + GetLastError() == ERROR_UNRECOGNIZED_VOLUME) + { + return PyErr_SetFromWindowsErr(ERROR_UNRECOGNIZED_VOLUME); + } + + if (PySys_Audit("os.listmounts", "O", volume->object) < 0) { + return NULL; + } + + while (1) { + BOOL success; + Py_BEGIN_ALLOW_THREADS + success = GetVolumePathNamesForVolumeNameW(volume->wide, buffer, + buflen, &buflen); + Py_END_ALLOW_THREADS + if (success) { + break; + } + if (GetLastError() != ERROR_MORE_DATA) { + PyErr_SetFromWindowsErr(0); + goto exit; + } + if (buffer != default_buffer) { + PyMem_Free((void *)buffer); + } + buffer = (wchar_t*)PyMem_Malloc(sizeof(wchar_t) * buflen); + if (!buffer) { + PyErr_NoMemory(); + goto exit; + } + } + if (buflen < 2) { + result = PyList_New(0); + goto exit; + } + // buflen includes two null terminators, one for the last string + // and one for the array of strings. + str = PyUnicode_FromWideChar(buffer, buflen - 2); + nullchar = PyUnicode_FromStringAndSize("\0", 1); + if (str && nullchar) { + result = PyUnicode_Split(str, nullchar, -1); + } +exit: + if (buffer != default_buffer) { + PyMem_Free(buffer); + } + Py_XDECREF(nullchar); + Py_XDECREF(str); + return result; +} + + int _PyOS_getfullpathname(const wchar_t *path, wchar_t **abspath_p) { @@ -15252,6 +15443,9 @@ static PyMethodDef posix_methods[] = { OS_GETCWDB_METHODDEF OS_LINK_METHODDEF OS_LISTDIR_METHODDEF + OS_LISTDRIVES_METHODDEF + OS_LISTMOUNTS_METHODDEF + OS_LISTVOLUMES_METHODDEF OS_LSTAT_METHODDEF OS_MKDIR_METHODDEF OS_NICE_METHODDEF From webhook-mailer at python.org Fri Mar 10 07:22:09 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Fri, 10 Mar 2023 12:22:09 -0000 Subject: [Python-checkins] gh-86509: Add link to Lib/_threading_local.py in threading docs (#101824) Message-ID: https://github.com/python/cpython/commit/53dceb53ade15587b9cfd30c0a0942232517dee9 commit: 53dceb53ade15587b9cfd30c0a0942232517dee9 branch: main author: Owain Davies <116417456+OTheDev at users.noreply.github.com> committer: erlend-aasland date: 2023-03-10T13:22:02+01:00 summary: gh-86509: Add link to Lib/_threading_local.py in threading docs (#101824) files: M Doc/library/threading.rst diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index b352125551fa..83ed48052704 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -272,7 +272,7 @@ The instance's values will be different for separate threads. A class that represents thread-local data. For more details and extensive examples, see the documentation string of the - :mod:`_threading_local` module. + :mod:`_threading_local` module: :source:`Lib/_threading_local.py`. .. _thread-objects: From webhook-mailer at python.org Fri Mar 10 07:30:33 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 10 Mar 2023 12:30:33 -0000 Subject: [Python-checkins] gh-86509: Add link to Lib/_threading_local.py in threading docs (GH-101824) Message-ID: https://github.com/python/cpython/commit/495cd2de77e9a67a409696531eeaa980ef3c77a8 commit: 495cd2de77e9a67a409696531eeaa980ef3c77a8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-10T04:30:24-08:00 summary: gh-86509: Add link to Lib/_threading_local.py in threading docs (GH-101824) (cherry picked from commit 53dceb53ade15587b9cfd30c0a0942232517dee9) Co-authored-by: Owain Davies <116417456+OTheDev at users.noreply.github.com> files: M Doc/library/threading.rst diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index ef140d75c431..65416221d975 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -254,7 +254,7 @@ The instance's values will be different for separate threads. A class that represents thread-local data. For more details and extensive examples, see the documentation string of the - :mod:`_threading_local` module. + :mod:`_threading_local` module: :source:`Lib/_threading_local.py`. .. _thread-objects: From webhook-mailer at python.org Fri Mar 10 10:30:01 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 10 Mar 2023 15:30:01 -0000 Subject: [Python-checkins] GH-102537: Handle check for PYTHONTZPATH failing in zoneinfo test (GH-102538) Message-ID: https://github.com/python/cpython/commit/64bde502cf89963bc7382b03ea9e1c0967d22e35 commit: 64bde502cf89963bc7382b03ea9e1c0967d22e35 branch: main author: Paul Ganssle <1377457+pganssle at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-10T07:29:37-08:00 summary: GH-102537: Handle check for PYTHONTZPATH failing in zoneinfo test (GH-102538) It is possible but unlikely for the `python_tzpath_context` function to fail between the start of the `try` block and the point where `os.environ.get` succeeds, in which case `old_env` will be undefined. In this case, we want to take no action. Practically speaking this will really only happen in an error condition anyway, so it doesn't really matter, but we should probably do it right anyway. files: A Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst M Lib/test/test_zoneinfo/test_zoneinfo.py diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index 82041a2b4883..ae921f7432c4 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -1543,13 +1543,20 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase): @contextlib.contextmanager def python_tzpath_context(value): path_var = "PYTHONTZPATH" + unset_env_sentinel = object() + old_env = unset_env_sentinel try: with OS_ENV_LOCK: old_env = os.environ.get(path_var, None) os.environ[path_var] = value yield finally: - if old_env is None: + if old_env is unset_env_sentinel: + # In this case, `old_env` was never retrieved from the + # environment for whatever reason, so there's no need to + # reset the environment TZPATH. + pass + elif old_env is None: del os.environ[path_var] else: os.environ[path_var] = old_env # pragma: nocover diff --git a/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst b/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst new file mode 100644 index 000000000000..94d160dd4127 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst @@ -0,0 +1,2 @@ +Adjust the error handling strategy in +``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. From webhook-mailer at python.org Fri Mar 10 10:41:50 2023 From: webhook-mailer at python.org (zooba) Date: Fri, 10 Mar 2023 15:41:50 -0000 Subject: [Python-checkins] gh-102519: Add doc updates for os.listdrives, listvolumes and listmounts (GH-102585) Message-ID: https://github.com/python/cpython/commit/12226bec2588f925f4698e1130ce78e118343934 commit: 12226bec2588f925f4698e1130ce78e118343934 branch: main author: Steve Dower committer: zooba date: 2023-03-10T15:41:32Z summary: gh-102519: Add doc updates for os.listdrives, listvolumes and listmounts (GH-102585) files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 23ce98785bed..5b9f49be1fad 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2188,6 +2188,69 @@ features: Accepts a :term:`path-like object`. +.. function:: listdrives() + + Return a list containing the names of drives on a Windows system. + + A drive name typically looks like ``'C:\\'``. Not every drive name + will be associated with a volume, and some may be inaccessible for + a variety of reasons, including permissions, network connectivity + or missing media. This function does not test for access. + + May raise :exc:`OSError` if an error occurs collecting the drive + names. + + .. audit-event:: os.listdrives "" os.listdrives + + .. availability:: Windows + + .. versionadded:: 3.12 + + +.. function:: listmounts(volume) + + Return a list containing the mount points for a volume on a Windows + system. + + *volume* must be represented as a GUID path, like those returned by + :func:`os.listvolumes`. Volumes may be mounted in multiple locations + or not at all. In the latter case, the list will be empty. Mount + points that are not associated with a volume will not be returned by + this function. + + The mount points return by this function will be absolute paths, and + may be longer than the drive name. + + Raises :exc:`OSError` if the volume is not recognized or if an error + occurs collecting the paths. + + .. audit-event:: os.listmounts volume os.listmounts + + .. availability:: Windows + + .. versionadded:: 3.12 + + +.. function:: listvolumes() + + Return a list containing the volumes in the system. + + Volumes are typically represented as a GUID path that looks like + ``\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\``. Files can + usually be accessed through a GUID path, permissions allowing. + However, users are generally not familiar with them, and so the + recommended use of this function is to retrieve mount points + using :func:`os.listmounts`. + + May raise :exc:`OSError` if an error occurs collecting the volumes. + + .. audit-event:: os.listvolumes "" os.listvolumes + + .. availability:: Windows + + .. versionadded:: 3.12 + + .. function:: lstat(path, *, dir_fd=None) Perform the equivalent of an :c:func:`lstat` system call on the given path. From webhook-mailer at python.org Fri Mar 10 10:54:54 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 10 Mar 2023 15:54:54 -0000 Subject: [Python-checkins] GH-102537: Handle check for PYTHONTZPATH failing in zoneinfo test (GH-102538) Message-ID: https://github.com/python/cpython/commit/123119ff8880986c7deae72484e2458f786f5ed3 commit: 123119ff8880986c7deae72484e2458f786f5ed3 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-10T07:54:45-08:00 summary: GH-102537: Handle check for PYTHONTZPATH failing in zoneinfo test (GH-102538) It is possible but unlikely for the `python_tzpath_context` function to fail between the start of the `try` block and the point where `os.environ.get` succeeds, in which case `old_env` will be undefined. In this case, we want to take no action. Practically speaking this will really only happen in an error condition anyway, so it doesn't really matter, but we should probably do it right anyway. (cherry picked from commit 64bde502cf89963bc7382b03ea9e1c0967d22e35) Co-authored-by: Paul Ganssle <1377457+pganssle at users.noreply.github.com> files: A Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst M Lib/test/test_zoneinfo/test_zoneinfo.py diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index a2172f3ac21d..fc19247b262e 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -1530,13 +1530,20 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase): @contextlib.contextmanager def python_tzpath_context(value): path_var = "PYTHONTZPATH" + unset_env_sentinel = object() + old_env = unset_env_sentinel try: with OS_ENV_LOCK: old_env = os.environ.get(path_var, None) os.environ[path_var] = value yield finally: - if old_env is None: + if old_env is unset_env_sentinel: + # In this case, `old_env` was never retrieved from the + # environment for whatever reason, so there's no need to + # reset the environment TZPATH. + pass + elif old_env is None: del os.environ[path_var] else: os.environ[path_var] = old_env # pragma: nocover diff --git a/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst b/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst new file mode 100644 index 000000000000..94d160dd4127 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst @@ -0,0 +1,2 @@ +Adjust the error handling strategy in +``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. From webhook-mailer at python.org Fri Mar 10 12:29:12 2023 From: webhook-mailer at python.org (zooba) Date: Fri, 10 Mar 2023 17:29:12 -0000 Subject: [Python-checkins] GH-80486: Fix handling of NTFS alternate data streams in pathlib (GH-102454) Message-ID: https://github.com/python/cpython/commit/90f1d777177e28b6c7b8d9ba751550e373d61b0a commit: 90f1d777177e28b6c7b8d9ba751550e373d61b0a branch: main author: Barney Gale committer: zooba date: 2023-03-10T17:29:04Z summary: GH-80486: Fix handling of NTFS alternate data streams in pathlib (GH-102454) Co-authored-by: Maor Kleinberger files: A Misc/NEWS.d/next/Library/2019-03-15-22-50-27.bpo-36305.Pbkv6u.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index d375529ff5f7..55c44f12e5a2 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -320,8 +320,9 @@ def _from_parsed_parts(cls, drv, root, parts): def _format_parsed_parts(cls, drv, root, parts): if drv or root: return drv + root + cls._flavour.sep.join(parts[1:]) - else: - return cls._flavour.sep.join(parts) + elif parts and cls._flavour.splitdrive(parts[0])[0]: + parts = ['.'] + parts + return cls._flavour.sep.join(parts) def __str__(self): """Return the string representation of the path, suitable for @@ -1188,7 +1189,8 @@ def expanduser(self): homedir = self._flavour.expanduser(self._parts[0]) if homedir[:1] == "~": raise RuntimeError("Could not determine home directory.") - return self._from_parts([homedir] + self._parts[1:]) + drv, root, parts = self._parse_parts((homedir,)) + return self._from_parsed_parts(drv, root, parts + self._parts[1:]) return self diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index f8e2f44d27fc..f05dead58867 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -122,6 +122,13 @@ def test_parse_parts(self): # the second path is relative. check(['c:/a/b', 'c:x/y'], ('c:', '\\', ['c:\\', 'a', 'b', 'x', 'y'])) check(['c:/a/b', 'c:/x/y'], ('c:', '\\', ['c:\\', 'x', 'y'])) + # Paths to files with NTFS alternate data streams + check(['./c:s'], ('', '', ['c:s'])) + check(['cc:s'], ('', '', ['cc:s'])) + check(['C:c:s'], ('C:', '', ['C:', 'c:s'])) + check(['C:/c:s'], ('C:', '\\', ['C:\\', 'c:s'])) + check(['D:a', './c:b'], ('D:', '', ['D:', 'a', 'c:b'])) + check(['D:/a', './c:b'], ('D:', '\\', ['D:\\', 'a', 'c:b'])) # @@ -165,6 +172,7 @@ def test_constructor_common(self): self.assertEqual(P(P('a'), 'b'), P('a/b')) self.assertEqual(P(P('a'), P('b')), P('a/b')) self.assertEqual(P(P('a'), P('b'), P('c')), P(FakePath("a/b/c"))) + self.assertEqual(P(P('./a:b')), P('./a:b')) def test_bytes(self): P = self.cls @@ -814,7 +822,8 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase): equivalences = _BasePurePathTest.equivalences.copy() equivalences.update({ - 'c:a': [ ('c:', 'a'), ('c:', 'a/'), ('/', 'c:', 'a') ], + './a:b': [ ('./a:b',) ], + 'c:a': [ ('c:', 'a'), ('c:', 'a/'), ('.', 'c:', 'a') ], 'c:/a': [ ('c:/', 'a'), ('c:', '/', 'a'), ('c:', '/a'), ('/z', 'c:/', 'a'), ('//x/y', 'c:/', 'a'), @@ -838,6 +847,7 @@ def test_str(self): self.assertEqual(str(p), '\\\\a\\b\\c\\d') def test_str_subclass(self): + self._check_str_subclass('.\\a:b') self._check_str_subclass('c:') self._check_str_subclass('c:a') self._check_str_subclass('c:a\\b.txt') @@ -1005,6 +1015,7 @@ def test_drive(self): self.assertEqual(P('//a/b').drive, '\\\\a\\b') self.assertEqual(P('//a/b/').drive, '\\\\a\\b') self.assertEqual(P('//a/b/c/d').drive, '\\\\a\\b') + self.assertEqual(P('./c:a').drive, '') def test_root(self): P = self.cls @@ -1341,6 +1352,14 @@ def test_join(self): self.assertEqual(pp, P('C:/a/b/x/y')) pp = p.joinpath('c:/x/y') self.assertEqual(pp, P('C:/x/y')) + # Joining with files with NTFS data streams => the filename should + # not be parsed as a drive letter + pp = p.joinpath(P('./d:s')) + self.assertEqual(pp, P('C:/a/b/d:s')) + pp = p.joinpath(P('./dd:s')) + self.assertEqual(pp, P('C:/a/b/dd:s')) + pp = p.joinpath(P('E:d:s')) + self.assertEqual(pp, P('E:d:s')) def test_div(self): # Basically the same as joinpath(). @@ -1361,6 +1380,11 @@ def test_div(self): # the second path is relative. self.assertEqual(p / 'c:x/y', P('C:/a/b/x/y')) self.assertEqual(p / 'c:/x/y', P('C:/x/y')) + # Joining with files with NTFS data streams => the filename should + # not be parsed as a drive letter + self.assertEqual(p / P('./d:s'), P('C:/a/b/d:s')) + self.assertEqual(p / P('./dd:s'), P('C:/a/b/dd:s')) + self.assertEqual(p / P('E:d:s'), P('E:d:s')) def test_is_reserved(self): P = self.cls @@ -1626,6 +1650,8 @@ def test_expanduser_common(self): self.assertEqual(p.expanduser(), p) p = P(P('').absolute().anchor) / '~' self.assertEqual(p.expanduser(), p) + p = P('~/a:b') + self.assertEqual(p.expanduser(), P(os.path.expanduser('~'), './a:b')) def test_exists(self): P = self.cls diff --git a/Misc/NEWS.d/next/Library/2019-03-15-22-50-27.bpo-36305.Pbkv6u.rst b/Misc/NEWS.d/next/Library/2019-03-15-22-50-27.bpo-36305.Pbkv6u.rst new file mode 100644 index 000000000000..d9360496ac24 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-03-15-22-50-27.bpo-36305.Pbkv6u.rst @@ -0,0 +1,2 @@ +Fix handling of Windows filenames that resemble drives, such as ``./a:b``, +in :mod:`pathlib`. From webhook-mailer at python.org Fri Mar 10 19:21:33 2023 From: webhook-mailer at python.org (ericvsmith) Date: Sat, 11 Mar 2023 00:21:33 -0000 Subject: [Python-checkins] gh-102578: Optimise setting and deleting mutable attributes on non-dataclass subclasses of frozen dataclasses (gh-102573) Message-ID: https://github.com/python/cpython/commit/ee6f8413a99d0ee4828e1c81911e203d3fff85d5 commit: ee6f8413a99d0ee4828e1c81911e203d3fff85d5 branch: main author: Xuehai Pan committer: ericvsmith date: 2023-03-10T19:21:22-05:00 summary: gh-102578: Optimise setting and deleting mutable attributes on non-dataclass subclasses of frozen dataclasses (gh-102573) files: A Misc/NEWS.d/next/Library/2023-03-10-13-21-16.gh-issue-102578.-gujoI.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 8bc8594d674b..78a126f051e2 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -616,21 +616,19 @@ def _repr_fn(fields, globals): def _frozen_get_del_attr(cls, fields, globals): locals = {'cls': cls, 'FrozenInstanceError': FrozenInstanceError} + condition = 'type(self) is cls' if fields: - fields_str = '(' + ','.join(repr(f.name) for f in fields) + ',)' - else: - # Special case for the zero-length tuple. - fields_str = '()' + condition += ' or name in {' + ', '.join(repr(f.name) for f in fields) + '}' return (_create_fn('__setattr__', ('self', 'name', 'value'), - (f'if type(self) is cls or name in {fields_str}:', + (f'if {condition}:', ' raise FrozenInstanceError(f"cannot assign to field {name!r}")', f'super(cls, self).__setattr__(name, value)'), locals=locals, globals=globals), _create_fn('__delattr__', ('self', 'name'), - (f'if type(self) is cls or name in {fields_str}:', + (f'if {condition}:', ' raise FrozenInstanceError(f"cannot delete field {name!r}")', f'super(cls, self).__delattr__(name)'), locals=locals, diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 589f229f4623..5486b2ef3f47 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -2767,6 +2767,19 @@ class C: c.i = 5 self.assertEqual(c.i, 10) + def test_frozen_empty(self): + @dataclass(frozen=True) + class C: + pass + + c = C() + self.assertFalse(hasattr(c, 'i')) + with self.assertRaises(FrozenInstanceError): + c.i = 5 + self.assertFalse(hasattr(c, 'i')) + with self.assertRaises(FrozenInstanceError): + del c.i + def test_inherit(self): @dataclass(frozen=True) class C: @@ -2890,6 +2903,37 @@ class S(D): self.assertEqual(s.y, 10) self.assertEqual(s.cached, True) + with self.assertRaises(FrozenInstanceError): + del s.x + self.assertEqual(s.x, 3) + with self.assertRaises(FrozenInstanceError): + del s.y + self.assertEqual(s.y, 10) + del s.cached + self.assertFalse(hasattr(s, 'cached')) + with self.assertRaises(AttributeError) as cm: + del s.cached + self.assertNotIsInstance(cm.exception, FrozenInstanceError) + + def test_non_frozen_normal_derived_from_empty_frozen(self): + @dataclass(frozen=True) + class D: + pass + + class S(D): + pass + + s = S() + self.assertFalse(hasattr(s, 'x')) + s.x = 5 + self.assertEqual(s.x, 5) + + del s.x + self.assertFalse(hasattr(s, 'x')) + with self.assertRaises(AttributeError) as cm: + del s.x + self.assertNotIsInstance(cm.exception, FrozenInstanceError) + def test_overwriting_frozen(self): # frozen uses __setattr__ and __delattr__. with self.assertRaisesRegex(TypeError, diff --git a/Misc/NEWS.d/next/Library/2023-03-10-13-21-16.gh-issue-102578.-gujoI.rst b/Misc/NEWS.d/next/Library/2023-03-10-13-21-16.gh-issue-102578.-gujoI.rst new file mode 100644 index 000000000000..7307148d9a81 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-10-13-21-16.gh-issue-102578.-gujoI.rst @@ -0,0 +1,4 @@ +Speed up setting or deleting mutable attributes on non-dataclass subclasses of +frozen dataclasses. Due to the implementation of ``__setattr__`` and +``__delattr__`` for frozen dataclasses, this previously had a time complexity +of ``O(n)``. It now has a time complexity of ``O(1)``. From webhook-mailer at python.org Fri Mar 10 19:26:52 2023 From: webhook-mailer at python.org (carljm) Date: Sat, 11 Mar 2023 00:26:52 -0000 Subject: [Python-checkins] gh-102103: add `module` argument to `dataclasses.make_dataclass` (#102104) Message-ID: https://github.com/python/cpython/commit/b48be8fa18518583abb21bf6e4f5d7e4b5c9d7b2 commit: b48be8fa18518583abb21bf6e4f5d7e4b5c9d7b2 branch: main author: Nikita Sobolev committer: carljm date: 2023-03-10T17:26:46-07:00 summary: gh-102103: add `module` argument to `dataclasses.make_dataclass` (#102104) files: A Misc/NEWS.d/next/Library/2023-02-21-11-56-16.gh-issue-102103.Dj0WEj.rst M Doc/library/dataclasses.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index 82faa7b77450..5f4dc25bfd78 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -389,7 +389,7 @@ Module contents :func:`astuple` raises :exc:`TypeError` if ``obj`` is not a dataclass instance. -.. function:: make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False) +.. function:: make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False, module=None) Creates a new dataclass with name ``cls_name``, fields as defined in ``fields``, base classes as given in ``bases``, and initialized @@ -401,6 +401,10 @@ Module contents ``match_args``, ``kw_only``, ``slots``, and ``weakref_slot`` have the same meaning as they do in :func:`dataclass`. + If ``module`` is defined, the ``__module__`` attribute + of the dataclass is set to that value. + By default, it is set to the module name of the caller. + This function is not strictly required, because any Python mechanism for creating a new class with ``__annotations__`` can then apply the :func:`dataclass` function to convert that class to diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 78a126f051e2..24f3779ebb8e 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1391,7 +1391,7 @@ def _astuple_inner(obj, tuple_factory): def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, - weakref_slot=False): + weakref_slot=False, module=None): """Return a new dynamically created dataclass. The dataclass name will be 'cls_name'. 'fields' is an iterable @@ -1455,6 +1455,19 @@ def exec_body_callback(ns): # of generic dataclasses. cls = types.new_class(cls_name, bases, {}, exec_body_callback) + # For pickling to work, the __module__ variable needs to be set to the frame + # where the dataclass is created. + if module is None: + try: + module = sys._getframemodulename(1) or '__main__' + except AttributeError: + try: + module = sys._getframe(1).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): + pass + if module is not None: + cls.__module__ = module + # Apply the normal decorator. return dataclass(cls, init=init, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen, diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 5486b2ef3f47..76bed0c33146 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3606,6 +3606,15 @@ def test_text_annotations(self): 'return': type(None)}) +ByMakeDataClass = make_dataclass('ByMakeDataClass', [('x', int)]) +ManualModuleMakeDataClass = make_dataclass('ManualModuleMakeDataClass', + [('x', int)], + module='test.test_dataclasses') +WrongNameMakeDataclass = make_dataclass('Wrong', [('x', int)]) +WrongModuleMakeDataclass = make_dataclass('WrongModuleMakeDataclass', + [('x', int)], + module='custom') + class TestMakeDataclass(unittest.TestCase): def test_simple(self): C = make_dataclass('C', @@ -3715,6 +3724,36 @@ def test_no_types(self): 'y': int, 'z': 'typing.Any'}) + def test_module_attr(self): + self.assertEqual(ByMakeDataClass.__module__, __name__) + self.assertEqual(ByMakeDataClass(1).__module__, __name__) + self.assertEqual(WrongModuleMakeDataclass.__module__, "custom") + Nested = make_dataclass('Nested', []) + self.assertEqual(Nested.__module__, __name__) + self.assertEqual(Nested().__module__, __name__) + + def test_pickle_support(self): + for klass in [ByMakeDataClass, ManualModuleMakeDataClass]: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + self.assertEqual( + pickle.loads(pickle.dumps(klass, proto)), + klass, + ) + self.assertEqual( + pickle.loads(pickle.dumps(klass(1), proto)), + klass(1), + ) + + def test_cannot_be_pickled(self): + for klass in [WrongNameMakeDataclass, WrongModuleMakeDataclass]: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + with self.assertRaises(pickle.PickleError): + pickle.dumps(klass, proto) + with self.assertRaises(pickle.PickleError): + pickle.dumps(klass(1), proto) + def test_invalid_type_specification(self): for bad_field in [(), (1, 2, 3, 4), diff --git a/Misc/NEWS.d/next/Library/2023-02-21-11-56-16.gh-issue-102103.Dj0WEj.rst b/Misc/NEWS.d/next/Library/2023-02-21-11-56-16.gh-issue-102103.Dj0WEj.rst new file mode 100644 index 000000000000..feba433f5bee --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-21-11-56-16.gh-issue-102103.Dj0WEj.rst @@ -0,0 +1,2 @@ +Add ``module`` argument to :func:`dataclasses.make_dataclass` and make +classes produced by it pickleable. From webhook-mailer at python.org Fri Mar 10 19:27:48 2023 From: webhook-mailer at python.org (carljm) Date: Sat, 11 Mar 2023 00:27:48 -0000 Subject: [Python-checkins] gh-88071: Update docstrings of dataclass' astuple and asdict (#101806) Message-ID: https://github.com/python/cpython/commit/767d3a8f6f2f94daa15ad3759d0ecdf4c009b7ab commit: 767d3a8f6f2f94daa15ad3759d0ecdf4c009b7ab branch: main author: Ilya V. Schurov committer: carljm date: 2023-03-10T17:27:41-07:00 summary: gh-88071: Update docstrings of dataclass' astuple and asdict (#101806) Update dataclasses.astuple and dataclasses.asdict docstrings to reflect that they deep copy objects in the field values. files: M Lib/dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 24f3779ebb8e..f4617b1dbdac 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1281,7 +1281,7 @@ class C: If given, 'dict_factory' will be used instead of built-in dict. The function applies recursively to field values that are dataclass instances. This will also look into built-in containers: - tuples, lists, and dicts. + tuples, lists, and dicts. Other objects are copied with 'copy.deepcopy()'. """ if not _is_dataclass_instance(obj): raise TypeError("asdict() should be called on dataclass instances") @@ -1353,7 +1353,7 @@ class C: If given, 'tuple_factory' will be used instead of built-in tuple. The function applies recursively to field values that are dataclass instances. This will also look into built-in containers: - tuples, lists, and dicts. + tuples, lists, and dicts. Other objects are copied with 'copy.deepcopy()'. """ if not _is_dataclass_instance(obj): From webhook-mailer at python.org Fri Mar 10 20:01:23 2023 From: webhook-mailer at python.org (brandtbucher) Date: Sat, 11 Mar 2023 01:01:23 -0000 Subject: [Python-checkins] GH-90997: Shrink the LOAD_GLOBAL caches (#102569) Message-ID: https://github.com/python/cpython/commit/08b67fb34f4519be1b0bb4673643a2c761c7ae92 commit: 08b67fb34f4519be1b0bb4673643a2c761c7ae92 branch: main author: Brandt Bucher committer: brandtbucher date: 2023-03-10T17:01:16-08:00 summary: GH-90997: Shrink the LOAD_GLOBAL caches (#102569) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-09-13-57-35.gh-issue-90997.J-Yhn2.rst M Doc/library/dis.rst M Include/internal/pycore_code.h M Include/internal/pycore_opcode.h M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Lib/test/test_dis.py M Python/bytecodes.c M Python/generated_cases.c.h M Python/opcode_metadata.h M Python/specialize.c diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index a5bc5e7fb6ea..f4f47b3bf484 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -57,9 +57,9 @@ the following command can be used to display the disassembly of 2 0 RESUME 0 3 2 LOAD_GLOBAL 1 (NULL + len) - 14 LOAD_FAST 0 (alist) - 16 CALL 1 - 26 RETURN_VALUE + 12 LOAD_FAST 0 (alist) + 14 CALL 1 + 24 RETURN_VALUE (The "2" is a line number). diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 10f1e320a12f..6bd212dd42c6 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -20,7 +20,7 @@ extern "C" { typedef struct { uint16_t counter; uint16_t index; - uint16_t module_keys_version[2]; + uint16_t module_keys_version; uint16_t builtin_keys_version; } _PyLoadGlobalCache; diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index f9ab95ca4bb9..da94fc81dcbe 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -48,7 +48,7 @@ const uint8_t _PyOpcode_Caches[256] = { [STORE_ATTR] = 4, [LOAD_ATTR] = 9, [COMPARE_OP] = 1, - [LOAD_GLOBAL] = 5, + [LOAD_GLOBAL] = 4, [BINARY_OP] = 1, [SEND] = 1, [COMPARE_AND_BRANCH] = 1, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 954401cfa85e..a01a0955182d 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -431,12 +431,17 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a5 3515 (Embed jump mask in COMPARE_OP oparg) # Python 3.12a5 3516 (Add COMPARE_AND_BRANCH instruction) # Python 3.12a5 3517 (Change YIELD_VALUE oparg to exception block depth) -# Python 3.12a5 3518 (Add RETURN_CONST instruction) -# Python 3.12a5 3519 (Modify SEND instruction) -# Python 3.12a5 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) +# Python 3.12a6 3518 (Add RETURN_CONST instruction) +# Python 3.12a6 3519 (Modify SEND instruction) +# Python 3.12a6 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) +# Python 3.12a7 3521 (Shrink the LOAD_GLOBAL caches) # Python 3.13 will start with 3550 +# Please don't copy-paste the same pre-release tag for new entries above!!! +# You should always use the *upcoming* tag. For example, if 3.12a6 came out +# a week ago, I should put "Python 3.12a7" next to my new magic number. + # MAGIC must change whenever the bytecode emitted by the compiler may no # longer be understood by older implementations of the eval loop (usually # due to the addition of new opcodes). @@ -446,7 +451,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3520).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3521).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 809d24e51676..23529d87a09e 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -390,7 +390,7 @@ def pseudo_op(name, op, real_ops): "LOAD_GLOBAL": { "counter": 1, "index": 1, - "module_keys_version": 2, + "module_keys_version": 1, "builtin_keys_version": 1, }, "BINARY_OP": { diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 9086824dd6f4..b77e3b06d0c1 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -138,10 +138,10 @@ def bug708901(): %3d CALL 2 GET_ITER - >> FOR_ITER 2 (to 38) + >> FOR_ITER 2 (to 36) STORE_FAST 0 (res) -%3d JUMP_BACKWARD 4 (to 30) +%3d JUMP_BACKWARD 4 (to 28) %3d >> END_FOR RETURN_CONST 0 (None) @@ -354,7 +354,7 @@ def bug42562(): %3d LOAD_GLOBAL 0 (Exception) CHECK_EXC_MATCH - POP_JUMP_IF_FALSE 23 (to 82) + POP_JUMP_IF_FALSE 23 (to 80) STORE_FAST 0 (e) %3d LOAD_FAST 0 (e) @@ -730,14 +730,14 @@ def loop_test(): LOAD_CONST 2 (3) BINARY_OP 5 (*) GET_ITER - >> FOR_ITER_LIST 15 (to 50) + >> FOR_ITER_LIST 14 (to 48) STORE_FAST 0 (i) %3d LOAD_GLOBAL_MODULE 1 (NULL + load_test) LOAD_FAST 0 (i) CALL_PY_WITH_DEFAULTS 1 POP_TOP - JUMP_BACKWARD 17 (to 16) + JUMP_BACKWARD 16 (to 16) %3d >> END_FOR RETURN_CONST 0 (None) @@ -1189,8 +1189,8 @@ def test_show_caches(self): caches = list(self.get_cached_values(quickened, adaptive)) for cache in caches: self.assertRegex(cache, pattern) - total_caches = 23 - empty_caches = 8 + total_caches = 22 + empty_caches = 7 self.assertEqual(caches.count(""), empty_caches) self.assertEqual(len(caches), total_caches) @@ -1483,17 +1483,17 @@ def _prepare_test_cases(): Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=20, starts_line=7, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=32, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=34, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval='', argrepr="''", offset=36, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=1, argrepr='1', offset=38, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='Hello world!', argrepr="'Hello world!'", offset=44, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=56, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=58, starts_line=8, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=30, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=32, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval='', argrepr="''", offset=34, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=1, argrepr='1', offset=36, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='Hello world!', argrepr="'Hello world!'", offset=42, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=56, starts_line=8, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=None), ] expected_opinfo_f = [ @@ -1511,145 +1511,145 @@ def _prepare_test_cases(): Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=22, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=24, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=26, starts_line=5, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=38, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=40, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=42, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=44, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=56, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=58, starts_line=6, is_jump_target=False, positions=None), - Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=36, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=38, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=40, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=42, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=56, starts_line=6, is_jump_target=False, positions=None), + Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=None), ] expected_opinfo_inner = [ Instruction(opname='COPY_FREE_VARS', opcode=149, arg=4, argval=4, argrepr='', offset=0, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=2, starts_line=3, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='NULL + print', offset=4, starts_line=4, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=16, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=18, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=20, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=22, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=24, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=26, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=40, starts_line=None, is_jump_target=False, positions=None) + Instruction(opname='LOAD_DEREF', opcode=137, arg=2, argval='a', argrepr='a', offset=14, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='b', argrepr='b', offset=16, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='c', argrepr='c', offset=18, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=20, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=22, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=24, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=38, starts_line=None, is_jump_target=False, positions=None), ] expected_opinfo_jumpy = [ Instruction(opname='RESUME', opcode=151, arg=0, argval=0, argrepr='', offset=0, starts_line=1, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='range', argrepr='NULL + range', offset=2, starts_line=3, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=14, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='FOR_ITER', opcode=93, arg=28, argval=88, argrepr='to 88', offset=28, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=32, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=34, starts_line=4, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=46, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=48, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=60, starts_line=5, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=62, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=64, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=72, argrepr='to 72', offset=68, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=22, argval=28, argrepr='to 28', offset=70, starts_line=6, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=72, starts_line=7, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=74, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=68, argval='>', argrepr='>', offset=76, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=84, argrepr='to 84', offset=80, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=28, argval=28, argrepr='to 28', offset=82, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=84, starts_line=8, is_jump_target=True, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=14, argval=116, argrepr='to 116', offset=86, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='END_FOR', opcode=4, arg=None, argval=None, argrepr='', offset=88, starts_line=3, is_jump_target=True, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=90, starts_line=10, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=102, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=104, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=114, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=116, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=33, argval=186, argrepr='to 186', offset=118, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=120, starts_line=12, is_jump_target=True, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=132, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=134, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=144, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=146, starts_line=13, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=148, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=150, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=154, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=156, starts_line=14, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=158, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=75, argval='>', argrepr='>', offset=160, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=168, argrepr='to 168', offset=164, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=26, argval=116, argrepr='to 116', offset=166, starts_line=15, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=168, starts_line=16, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=170, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=172, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=180, argrepr='to 180', offset=176, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=212, argrepr='to 212', offset=178, starts_line=17, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=180, starts_line=11, is_jump_target=True, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=186, argrepr='to 186', offset=182, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=120, argrepr='to 120', offset=184, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=186, starts_line=19, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=198, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=200, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=212, starts_line=20, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=214, starts_line=21, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=216, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=218, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=222, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=224, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=226, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=228, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=230, starts_line=26, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=242, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=244, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=254, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=256, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=258, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=260, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=262, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=272, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=274, starts_line=28, is_jump_target=True, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=286, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=288, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=298, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=300, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=302, starts_line=25, is_jump_target=False, positions=None), - Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=304, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=310, argrepr='to 310', offset=306, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=310, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=314, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=316, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=23, argval=274, argrepr='to 274', offset=318, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=320, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=322, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=326, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=328, starts_line=22, is_jump_target=False, positions=None), - Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=340, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=16, argval=376, argrepr='to 376', offset=342, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=344, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=346, starts_line=23, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=358, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=360, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=370, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=372, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=51, argval=274, argrepr='to 274', offset=374, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=376, starts_line=22, is_jump_target=True, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=378, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=382, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=384, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=386, starts_line=28, is_jump_target=False, positions=None), - Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=398, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=400, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=410, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=412, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=414, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=416, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=418, starts_line=None, is_jump_target=False, positions=None) + Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=12, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=14, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=24, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='FOR_ITER', opcode=93, arg=27, argval=84, argrepr='to 84', offset=26, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=30, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=32, starts_line=4, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=42, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=44, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=5, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=58, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=60, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=68, argrepr='to 68', offset=64, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=21, argval=26, argrepr='to 26', offset=66, starts_line=6, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=68, starts_line=7, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=70, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=68, argval='>', argrepr='>', offset=72, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=27, argval=26, argrepr='to 26', offset=78, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=80, starts_line=8, is_jump_target=True, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=13, argval=110, argrepr='to 110', offset=82, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='END_FOR', opcode=4, arg=None, argval=None, argrepr='', offset=84, starts_line=3, is_jump_target=True, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=86, starts_line=10, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=96, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=98, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=108, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST_CHECK', opcode=127, arg=0, argval='i', argrepr='i', offset=110, starts_line=11, is_jump_target=True, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=32, argval=178, argrepr='to 178', offset=112, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=114, starts_line=12, is_jump_target=True, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=124, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=138, starts_line=13, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=140, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=23, argval=23, argrepr='-=', offset=142, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=146, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=148, starts_line=14, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=150, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=75, argval='>', argrepr='>', offset=152, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=160, argrepr='to 160', offset=156, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=25, argval=110, argrepr='to 110', offset=158, starts_line=15, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=160, starts_line=16, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=162, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=164, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=172, argrepr='to 172', offset=168, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=15, argval=202, argrepr='to 202', offset=170, starts_line=17, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=172, starts_line=11, is_jump_target=True, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=178, argrepr='to 178', offset=174, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=32, argval=114, argrepr='to 114', offset=176, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=178, starts_line=19, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=188, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=200, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=202, starts_line=20, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=204, starts_line=21, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=206, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=208, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=214, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=218, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=220, starts_line=26, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=230, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=242, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=244, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=246, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=248, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=260, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=262, starts_line=28, is_jump_target=True, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=272, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=274, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=284, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RETURN_CONST', opcode=121, arg=0, argval=None, argrepr='None', offset=286, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=288, starts_line=25, is_jump_target=False, positions=None), + Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=290, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=296, argrepr='to 296', offset=292, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=294, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=296, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=298, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=300, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=302, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=22, argval=262, argrepr='to 262', offset=304, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=306, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=308, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=310, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=312, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=314, starts_line=22, is_jump_target=False, positions=None), + Instruction(opname='CHECK_EXC_MATCH', opcode=36, arg=None, argval=None, argrepr='', offset=324, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=15, argval=358, argrepr='to 358', offset=326, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=328, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=330, starts_line=23, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=340, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=342, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=352, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=354, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_BACKWARD', opcode=140, arg=48, argval=262, argrepr='to 262', offset=356, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=358, starts_line=22, is_jump_target=True, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=360, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=362, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=364, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=366, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=368, starts_line=28, is_jump_target=False, positions=None), + Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=378, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=380, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=390, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=392, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=394, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=396, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='RERAISE', opcode=119, arg=1, argval=1, argrepr='', offset=398, starts_line=None, is_jump_target=False, positions=None), ] # One last piece of inspect fodder to check the default line number handling diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-09-13-57-35.gh-issue-90997.J-Yhn2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-09-13-57-35.gh-issue-90997.J-Yhn2.rst new file mode 100644 index 000000000000..723a4b9fa777 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-09-13-57-35.gh-issue-90997.J-Yhn2.rst @@ -0,0 +1,2 @@ +Shrink the number of inline :opcode:`CACHE` entries used by +:opcode:`LOAD_GLOBAL`. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 45d507266743..dc2a20f22b60 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1078,7 +1078,7 @@ dummy_func( LOAD_GLOBAL_BUILTIN, }; - inst(LOAD_GLOBAL, (unused/1, unused/1, unused/2, unused/1 -- null if (oparg & 1), v)) { + inst(LOAD_GLOBAL, (unused/1, unused/1, unused/1, unused/1 -- null if (oparg & 1), v)) { #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1133,7 +1133,7 @@ dummy_func( null = NULL; } - inst(LOAD_GLOBAL_MODULE, (unused/1, index/1, version/2, unused/1 -- null if (oparg & 1), res)) { + inst(LOAD_GLOBAL_MODULE, (unused/1, index/1, version/1, unused/1 -- null if (oparg & 1), res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -1147,7 +1147,7 @@ dummy_func( null = NULL; } - inst(LOAD_GLOBAL_BUILTIN, (unused/1, index/1, mod_version/2, bltn_version/1 -- null if (oparg & 1), res)) { + inst(LOAD_GLOBAL_BUILTIN, (unused/1, index/1, mod_version/1, bltn_version/1 -- null if (oparg & 1), res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 51357cda4c89..3839aeecb912 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1349,7 +1349,7 @@ TARGET(LOAD_GLOBAL) { PREDICTED(LOAD_GLOBAL); - static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 5, "incorrect cache size"); + static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; #if ENABLE_SPECIALIZATION @@ -1408,7 +1408,7 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } - next_instr += 5; + next_instr += 4; DISPATCH(); } @@ -1416,7 +1416,7 @@ PyObject *null = NULL; PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); - uint32_t version = read_u32(&next_instr[2].cache); + uint16_t version = read_u16(&next_instr[2].cache); assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -1432,7 +1432,7 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } - next_instr += 5; + next_instr += 4; DISPATCH(); } @@ -1440,8 +1440,8 @@ PyObject *null = NULL; PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); - uint32_t mod_version = read_u32(&next_instr[2].cache); - uint16_t bltn_version = read_u16(&next_instr[4].cache); + uint16_t mod_version = read_u16(&next_instr[2].cache); + uint16_t bltn_version = read_u16(&next_instr[3].cache); assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); @@ -1460,7 +1460,7 @@ STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } - next_instr += 5; + next_instr += 4; DISPATCH(); } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 67cb0088c3b7..93f3c76c5b82 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -708,7 +708,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { #endif enum Direction { DIR_NONE, DIR_READ, DIR_WRITE }; -enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC0000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; +enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { enum Direction dir_op1; enum Direction dir_op2; @@ -790,9 +790,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [STORE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [DELETE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [LOAD_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0000 }, - [LOAD_GLOBAL_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0000 }, - [LOAD_GLOBAL_BUILTIN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0000 }, + [LOAD_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, + [LOAD_GLOBAL_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, + [LOAD_GLOBAL_BUILTIN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, [DELETE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [MAKE_CELL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [DELETE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, diff --git a/Python/specialize.c b/Python/specialize.c index 0a7af8991eec..719bd5bda329 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1148,8 +1148,12 @@ _Py_Specialize_LoadGlobal( SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } + if (keys_version != (uint16_t)keys_version) { + SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); + goto fail; + } cache->index = (uint16_t)index; - write_u32(cache->module_keys_version, keys_version); + cache->module_keys_version = (uint16_t)keys_version; instr->op.code = LOAD_GLOBAL_MODULE; goto success; } @@ -1177,6 +1181,10 @@ _Py_Specialize_LoadGlobal( SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } + if (globals_version != (uint16_t)globals_version) { + SPECIALIZATION_FAIL(LOAD_GLOBAL, SPEC_FAIL_OUT_OF_RANGE); + goto fail; + } uint32_t builtins_version = _PyDictKeys_GetVersionForCurrentState( interp, builtin_keys); if (builtins_version == 0) { @@ -1188,7 +1196,7 @@ _Py_Specialize_LoadGlobal( goto fail; } cache->index = (uint16_t)index; - write_u32(cache->module_keys_version, globals_version); + cache->module_keys_version = (uint16_t)globals_version; cache->builtin_keys_version = (uint16_t)builtins_version; instr->op.code = LOAD_GLOBAL_BUILTIN; goto success; From webhook-mailer at python.org Fri Mar 10 20:20:27 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 11 Mar 2023 01:20:27 -0000 Subject: [Python-checkins] gh-102433: Add tests for how classes with properties interact with `isinstance()` checks on `typing.runtime_checkable` protocols (#102449) Message-ID: https://github.com/python/cpython/commit/5ffdaf748d98da6065158534720f1996a45a0072 commit: 5ffdaf748d98da6065158534720f1996a45a0072 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-03-11T01:20:20Z summary: gh-102433: Add tests for how classes with properties interact with `isinstance()` checks on `typing.runtime_checkable` protocols (#102449) Co-authored-by: Carl Meyer files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 0483ca3aa42f..c17be6cd0bbc 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2530,6 +2530,94 @@ def meth(x): ... with self.assertRaises(TypeError): isinstance(C(), BadPG) + def test_protocols_isinstance_properties_and_descriptors(self): + class C: + @property + def attr(self): + return 42 + + class CustomDescriptor: + def __get__(self, obj, objtype=None): + return 42 + + class D: + attr = CustomDescriptor() + + # Check that properties set on superclasses + # are still found by the isinstance() logic + class E(C): ... + class F(D): ... + + class Empty: ... + + T = TypeVar('T') + + @runtime_checkable + class P(Protocol): + @property + def attr(self): ... + + @runtime_checkable + class P1(Protocol): + attr: int + + @runtime_checkable + class PG(Protocol[T]): + @property + def attr(self): ... + + @runtime_checkable + class PG1(Protocol[T]): + attr: T + + for protocol_class in P, P1, PG, PG1: + for klass in C, D, E, F: + with self.subTest( + klass=klass.__name__, + protocol_class=protocol_class.__name__ + ): + self.assertIsInstance(klass(), protocol_class) + + with self.subTest(klass="Empty", protocol_class=protocol_class.__name__): + self.assertNotIsInstance(Empty(), protocol_class) + + class BadP(Protocol): + @property + def attr(self): ... + + class BadP1(Protocol): + attr: int + + class BadPG(Protocol[T]): + @property + def attr(self): ... + + class BadPG1(Protocol[T]): + attr: T + + for obj in PG[T], PG[C], PG1[T], PG1[C], BadP, BadP1, BadPG, BadPG1: + for klass in C, D, E, F, Empty: + with self.subTest(klass=klass.__name__, obj=obj): + with self.assertRaises(TypeError): + isinstance(klass(), obj) + + def test_protocols_isinstance_not_fooled_by_custom_dir(self): + @runtime_checkable + class HasX(Protocol): + x: int + + class CustomDirWithX: + x = 10 + def __dir__(self): + return [] + + class CustomDirWithoutX: + def __dir__(self): + return ["x"] + + self.assertIsInstance(CustomDirWithX(), HasX) + self.assertNotIsInstance(CustomDirWithoutX(), HasX) + def test_protocols_isinstance_py36(self): class APoint: def __init__(self, x, y, label): From webhook-mailer at python.org Fri Mar 10 20:45:50 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 11 Mar 2023 01:45:50 -0000 Subject: [Python-checkins] gh-102433: Add tests for how classes with properties interact with `isinstance()` checks on `typing.runtime_checkable` protocols (GH-102449) Message-ID: https://github.com/python/cpython/commit/281078794f10a42d0aa99d660e25a434fde96ec4 commit: 281078794f10a42d0aa99d660e25a434fde96ec4 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-10T17:45:40-08:00 summary: gh-102433: Add tests for how classes with properties interact with `isinstance()` checks on `typing.runtime_checkable` protocols (GH-102449) (cherry picked from commit 5ffdaf748d98da6065158534720f1996a45a0072) Co-authored-by: Alex Waygood Co-authored-by: Carl Meyer files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 4e0a4f51fd07..a4d243400d17 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1142,6 +1142,94 @@ def meth(x): ... with self.assertRaises(TypeError): isinstance(C(), BadPG) + def test_protocols_isinstance_properties_and_descriptors(self): + class C: + @property + def attr(self): + return 42 + + class CustomDescriptor: + def __get__(self, obj, objtype=None): + return 42 + + class D: + attr = CustomDescriptor() + + # Check that properties set on superclasses + # are still found by the isinstance() logic + class E(C): ... + class F(D): ... + + class Empty: ... + + T = TypeVar('T') + + @runtime_checkable + class P(Protocol): + @property + def attr(self): ... + + @runtime_checkable + class P1(Protocol): + attr: int + + @runtime_checkable + class PG(Protocol[T]): + @property + def attr(self): ... + + @runtime_checkable + class PG1(Protocol[T]): + attr: T + + for protocol_class in P, P1, PG, PG1: + for klass in C, D, E, F: + with self.subTest( + klass=klass.__name__, + protocol_class=protocol_class.__name__ + ): + self.assertIsInstance(klass(), protocol_class) + + with self.subTest(klass="Empty", protocol_class=protocol_class.__name__): + self.assertNotIsInstance(Empty(), protocol_class) + + class BadP(Protocol): + @property + def attr(self): ... + + class BadP1(Protocol): + attr: int + + class BadPG(Protocol[T]): + @property + def attr(self): ... + + class BadPG1(Protocol[T]): + attr: T + + for obj in PG[T], PG[C], PG1[T], PG1[C], BadP, BadP1, BadPG, BadPG1: + for klass in C, D, E, F, Empty: + with self.subTest(klass=klass.__name__, obj=obj): + with self.assertRaises(TypeError): + isinstance(klass(), obj) + + def test_protocols_isinstance_not_fooled_by_custom_dir(self): + @runtime_checkable + class HasX(Protocol): + x: int + + class CustomDirWithX: + x = 10 + def __dir__(self): + return [] + + class CustomDirWithoutX: + def __dir__(self): + return ["x"] + + self.assertIsInstance(CustomDirWithX(), HasX) + self.assertNotIsInstance(CustomDirWithoutX(), HasX) + def test_protocols_isinstance_py36(self): class APoint: def __init__(self, x, y, label): From webhook-mailer at python.org Fri Mar 10 20:46:10 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 11 Mar 2023 01:46:10 -0000 Subject: [Python-checkins] gh-102433: Add tests for how classes with properties interact with `isinstance()` checks on `typing.runtime_checkable` protocols (GH-102449) Message-ID: https://github.com/python/cpython/commit/e467cb3a691d936b6e7b2ed7cc859a8c218e9f1a commit: e467cb3a691d936b6e7b2ed7cc859a8c218e9f1a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-10T17:46:04-08:00 summary: gh-102433: Add tests for how classes with properties interact with `isinstance()` checks on `typing.runtime_checkable` protocols (GH-102449) (cherry picked from commit 5ffdaf748d98da6065158534720f1996a45a0072) Co-authored-by: Alex Waygood Co-authored-by: Carl Meyer files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c222df41e90b..96cffdeda9c0 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2525,6 +2525,94 @@ def meth(x): ... with self.assertRaises(TypeError): isinstance(C(), BadPG) + def test_protocols_isinstance_properties_and_descriptors(self): + class C: + @property + def attr(self): + return 42 + + class CustomDescriptor: + def __get__(self, obj, objtype=None): + return 42 + + class D: + attr = CustomDescriptor() + + # Check that properties set on superclasses + # are still found by the isinstance() logic + class E(C): ... + class F(D): ... + + class Empty: ... + + T = TypeVar('T') + + @runtime_checkable + class P(Protocol): + @property + def attr(self): ... + + @runtime_checkable + class P1(Protocol): + attr: int + + @runtime_checkable + class PG(Protocol[T]): + @property + def attr(self): ... + + @runtime_checkable + class PG1(Protocol[T]): + attr: T + + for protocol_class in P, P1, PG, PG1: + for klass in C, D, E, F: + with self.subTest( + klass=klass.__name__, + protocol_class=protocol_class.__name__ + ): + self.assertIsInstance(klass(), protocol_class) + + with self.subTest(klass="Empty", protocol_class=protocol_class.__name__): + self.assertNotIsInstance(Empty(), protocol_class) + + class BadP(Protocol): + @property + def attr(self): ... + + class BadP1(Protocol): + attr: int + + class BadPG(Protocol[T]): + @property + def attr(self): ... + + class BadPG1(Protocol[T]): + attr: T + + for obj in PG[T], PG[C], PG1[T], PG1[C], BadP, BadP1, BadPG, BadPG1: + for klass in C, D, E, F, Empty: + with self.subTest(klass=klass.__name__, obj=obj): + with self.assertRaises(TypeError): + isinstance(klass(), obj) + + def test_protocols_isinstance_not_fooled_by_custom_dir(self): + @runtime_checkable + class HasX(Protocol): + x: int + + class CustomDirWithX: + x = 10 + def __dir__(self): + return [] + + class CustomDirWithoutX: + def __dir__(self): + return ["x"] + + self.assertIsInstance(CustomDirWithX(), HasX) + self.assertNotIsInstance(CustomDirWithoutX(), HasX) + def test_protocols_isinstance_py36(self): class APoint: def __init__(self, x, y, label): From webhook-mailer at python.org Sat Mar 11 06:11:56 2023 From: webhook-mailer at python.org (Fidget-Spinner) Date: Sat, 11 Mar 2023 11:11:56 -0000 Subject: [Python-checkins] gh-102213: Optimize the performance of `__getattr__` (GH-102248) Message-ID: https://github.com/python/cpython/commit/aa0a73d1bc53dcb6348a869df1e775138991e561 commit: aa0a73d1bc53dcb6348a869df1e775138991e561 branch: main author: wangxiang-hz <34048878+wangxiang-hz at users.noreply.github.com> committer: Fidget-Spinner date: 2023-03-11T19:11:37+08:00 summary: gh-102213: Optimize the performance of `__getattr__` (GH-102248) When __getattr__ is defined, python with try to find an attribute using _PyObject_GenericGetAttrWithDict find nothing is reasonable so we don't need an exception, it will hurt performance. files: A Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst M Include/internal/pycore_object.h M Objects/object.c M Objects/typeobject.c diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index e15685f174eb..318e6f3371c0 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -370,6 +370,7 @@ extern void _PyObject_FreeInstanceAttributes(PyObject *obj); extern int _PyObject_IsInstanceDictEmpty(PyObject *); extern int _PyType_HasSubclasses(PyTypeObject *); extern PyObject* _PyType_GetSubclasses(PyTypeObject *); +extern PyObject* _PyObject_GenericTryGetAttr(PyObject *, PyObject *); // Access macro to the members which are floating "behind" the object static inline PyMemberDef* _PyHeapType_GET_MEMBERS(PyHeapTypeObject *etype) { diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst new file mode 100644 index 000000000000..997bef226e71 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-26-13-12-55.gh-issue-102213.fTH8X7.rst @@ -0,0 +1 @@ +Fix performance loss when accessing an object's attributes with ``__getattr__`` defined. diff --git a/Objects/object.c b/Objects/object.c index 38da4d497a96..dff5e2afa16a 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1405,6 +1405,12 @@ PyObject_GenericGetAttr(PyObject *obj, PyObject *name) return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 0); } +PyObject * +_PyObject_GenericTryGetAttr(PyObject *obj, PyObject *name) +{ + return _PyObject_GenericGetAttrWithDict(obj, name, NULL, 1); +} + int _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name, PyObject *value, PyObject *dict) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f486b83fd69e..f0654c239f66 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8247,14 +8247,17 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name) (Py_IS_TYPE(getattribute, &PyWrapperDescr_Type) && ((PyWrapperDescrObject *)getattribute)->d_wrapped == (void *)PyObject_GenericGetAttr)) - res = PyObject_GenericGetAttr(self, name); + /* finding nothing is reasonable when __getattr__ is defined */ + res = _PyObject_GenericTryGetAttr(self, name); else { Py_INCREF(getattribute); res = call_attribute(self, getattribute, name); Py_DECREF(getattribute); } - if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); + if (res == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + } res = call_attribute(self, getattr, name); } Py_DECREF(getattr); From webhook-mailer at python.org Sat Mar 11 08:20:03 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Sat, 11 Mar 2023 13:20:03 -0000 Subject: [Python-checkins] gh-79940: add introspection API for asynchronous generators to `inspect` module (#11590) Message-ID: https://github.com/python/cpython/commit/ced13c96a4eb9391a9d27e3e13218f70c579670f commit: ced13c96a4eb9391a9d27e3e13218f70c579670f branch: main author: Thomas Krennwallner committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-11T18:49:40+05:30 summary: gh-79940: add introspection API for asynchronous generators to `inspect` module (#11590) files: A Misc/NEWS.d/next/Library/2023-02-26-17-29-57.gh-issue-79940.SAfmAy.rst M Doc/library/inspect.rst M Doc/whatsnew/3.12.rst M Lib/inspect.py M Lib/test/test_inspect.py M Objects/genobject.c diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 789e9839d22f..ccf240193d36 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1440,8 +1440,8 @@ code execution:: pass -Current State of Generators and Coroutines ------------------------------------------- +Current State of Generators, Coroutines, and Asynchronous Generators +-------------------------------------------------------------------- When implementing coroutine schedulers and for other advanced uses of generators, it is useful to determine whether a generator is currently @@ -1476,6 +1476,22 @@ generator to be determined easily. .. versionadded:: 3.5 +.. function:: getasyncgenstate(agen) + + Get current state of an asynchronous generator object. The function is + intended to be used with asynchronous iterator objects created by + :keyword:`async def` functions which use the :keyword:`yield` statement, + but will accept any asynchronous generator-like object that has + ``ag_running`` and ``ag_frame`` attributes. + + Possible states are: + * AGEN_CREATED: Waiting to start execution. + * AGEN_RUNNING: Currently being executed by the interpreter. + * AGEN_SUSPENDED: Currently suspended at a yield expression. + * AGEN_CLOSED: Execution has completed. + + .. versionadded:: 3.12 + The current internal state of the generator can also be queried. This is mostly useful for testing purposes, to ensure that internal state is being updated as expected: @@ -1507,6 +1523,14 @@ updated as expected: .. versionadded:: 3.5 +.. function:: getasyncgenlocals(agen) + + This function is analogous to :func:`~inspect.getgeneratorlocals`, but + works for asynchronous generator objects created by :keyword:`async def` + functions which use the :keyword:`yield` statement. + + .. versionadded:: 3.12 + .. _inspect-module-co-flags: diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 48b7aab0595e..9f33dbc808dd 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -244,6 +244,10 @@ inspect a :term:`coroutine` for use with :func:`iscoroutinefunction`. (Contributed Carlton Gibson in :gh:`99247`.) +* Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals` + for determining the current state of asynchronous generators. + (Contributed by Thomas Krennwallner in :issue:`35759`.) + pathlib ------- diff --git a/Lib/inspect.py b/Lib/inspect.py index edc23b0ffa92..0eceaaf9a24f 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -34,6 +34,10 @@ 'Yury Selivanov ') __all__ = [ + "AGEN_CLOSED", + "AGEN_CREATED", + "AGEN_RUNNING", + "AGEN_SUSPENDED", "ArgInfo", "Arguments", "Attribute", @@ -77,6 +81,8 @@ "getabsfile", "getargs", "getargvalues", + "getasyncgenlocals", + "getasyncgenstate", "getattr_static", "getblock", "getcallargs", @@ -1935,6 +1941,50 @@ def getcoroutinelocals(coroutine): return {} +# ----------------------------------- asynchronous generator introspection + +AGEN_CREATED = 'AGEN_CREATED' +AGEN_RUNNING = 'AGEN_RUNNING' +AGEN_SUSPENDED = 'AGEN_SUSPENDED' +AGEN_CLOSED = 'AGEN_CLOSED' + + +def getasyncgenstate(agen): + """Get current state of an asynchronous generator object. + + Possible states are: + AGEN_CREATED: Waiting to start execution. + AGEN_RUNNING: Currently being executed by the interpreter. + AGEN_SUSPENDED: Currently suspended at a yield expression. + AGEN_CLOSED: Execution has completed. + """ + if agen.ag_running: + return AGEN_RUNNING + if agen.ag_suspended: + return AGEN_SUSPENDED + if agen.ag_frame is None: + return AGEN_CLOSED + return AGEN_CREATED + + +def getasyncgenlocals(agen): + """ + Get the mapping of asynchronous generator local variables to their current + values. + + A dict is returned, with the keys the local variable names and values the + bound values.""" + + if not isasyncgen(agen): + raise TypeError(f"{agen!r} is not a Python async generator") + + frame = getattr(agen, "ag_frame", None) + if frame is not None: + return agen.ag_frame.f_locals + else: + return {} + + ############################################################################### ### Function Signature Object (PEP 362) ############################################################################### diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 02f8378d0413..410a2e5b5468 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -1,3 +1,4 @@ +import asyncio import builtins import collections import datetime @@ -65,6 +66,10 @@ def revise(filename, *args): git = mod.StupidGit() +def tearDownModule(): + asyncio.set_event_loop_policy(None) + + def signatures_with_lexicographic_keyword_only_parameters(): """ Yields a whole bunch of functions with only keyword-only parameters, @@ -2321,6 +2326,108 @@ async def func(a=None): {'a': None, 'gencoro': gencoro, 'b': 'spam'}) +class TestGetAsyncGenState(unittest.IsolatedAsyncioTestCase): + + def setUp(self): + async def number_asyncgen(): + for number in range(5): + yield number + self.asyncgen = number_asyncgen() + + async def asyncTearDown(self): + await self.asyncgen.aclose() + + def _asyncgenstate(self): + return inspect.getasyncgenstate(self.asyncgen) + + def test_created(self): + self.assertEqual(self._asyncgenstate(), inspect.AGEN_CREATED) + + async def test_suspended(self): + value = await anext(self.asyncgen) + self.assertEqual(self._asyncgenstate(), inspect.AGEN_SUSPENDED) + self.assertEqual(value, 0) + + async def test_closed_after_exhaustion(self): + countdown = 7 + with self.assertRaises(StopAsyncIteration): + while countdown := countdown - 1: + await anext(self.asyncgen) + self.assertEqual(countdown, 1) + self.assertEqual(self._asyncgenstate(), inspect.AGEN_CLOSED) + + async def test_closed_after_immediate_exception(self): + with self.assertRaises(RuntimeError): + await self.asyncgen.athrow(RuntimeError) + self.assertEqual(self._asyncgenstate(), inspect.AGEN_CLOSED) + + async def test_running(self): + async def running_check_asyncgen(): + for number in range(5): + self.assertEqual(self._asyncgenstate(), inspect.AGEN_RUNNING) + yield number + self.assertEqual(self._asyncgenstate(), inspect.AGEN_RUNNING) + self.asyncgen = running_check_asyncgen() + # Running up to the first yield + await anext(self.asyncgen) + self.assertEqual(self._asyncgenstate(), inspect.AGEN_SUSPENDED) + # Running after the first yield + await anext(self.asyncgen) + self.assertEqual(self._asyncgenstate(), inspect.AGEN_SUSPENDED) + + def test_easy_debugging(self): + # repr() and str() of a asyncgen state should contain the state name + names = 'AGEN_CREATED AGEN_RUNNING AGEN_SUSPENDED AGEN_CLOSED'.split() + for name in names: + state = getattr(inspect, name) + self.assertIn(name, repr(state)) + self.assertIn(name, str(state)) + + async def test_getasyncgenlocals(self): + async def each(lst, a=None): + b=(1, 2, 3) + for v in lst: + if v == 3: + c = 12 + yield v + + numbers = each([1, 2, 3]) + self.assertEqual(inspect.getasyncgenlocals(numbers), + {'a': None, 'lst': [1, 2, 3]}) + await anext(numbers) + self.assertEqual(inspect.getasyncgenlocals(numbers), + {'a': None, 'lst': [1, 2, 3], 'v': 1, + 'b': (1, 2, 3)}) + await anext(numbers) + self.assertEqual(inspect.getasyncgenlocals(numbers), + {'a': None, 'lst': [1, 2, 3], 'v': 2, + 'b': (1, 2, 3)}) + await anext(numbers) + self.assertEqual(inspect.getasyncgenlocals(numbers), + {'a': None, 'lst': [1, 2, 3], 'v': 3, + 'b': (1, 2, 3), 'c': 12}) + with self.assertRaises(StopAsyncIteration): + await anext(numbers) + self.assertEqual(inspect.getasyncgenlocals(numbers), {}) + + async def test_getasyncgenlocals_empty(self): + async def yield_one(): + yield 1 + one = yield_one() + self.assertEqual(inspect.getasyncgenlocals(one), {}) + await anext(one) + self.assertEqual(inspect.getasyncgenlocals(one), {}) + with self.assertRaises(StopAsyncIteration): + await anext(one) + self.assertEqual(inspect.getasyncgenlocals(one), {}) + + def test_getasyncgenlocals_error(self): + self.assertRaises(TypeError, inspect.getasyncgenlocals, 1) + self.assertRaises(TypeError, inspect.getasyncgenlocals, lambda x: True) + self.assertRaises(TypeError, inspect.getasyncgenlocals, set) + self.assertRaises(TypeError, inspect.getasyncgenlocals, (2,3)) + + class MySignature(inspect.Signature): # Top-level to make it picklable; # used in test_signature_object_pickle diff --git a/Misc/NEWS.d/next/Library/2023-02-26-17-29-57.gh-issue-79940.SAfmAy.rst b/Misc/NEWS.d/next/Library/2023-02-26-17-29-57.gh-issue-79940.SAfmAy.rst new file mode 100644 index 000000000000..31b8ead84332 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-26-17-29-57.gh-issue-79940.SAfmAy.rst @@ -0,0 +1,2 @@ +Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals`. +Patch by Thomas Krennwallner. diff --git a/Objects/genobject.c b/Objects/genobject.c index 61463774310f..6316fa9865fe 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1520,6 +1520,15 @@ ag_getcode(PyGenObject *gen, void *Py_UNUSED(ignored)) return _gen_getcode(gen, "ag_code"); } +static PyObject * +ag_getsuspended(PyAsyncGenObject *ag, void *Py_UNUSED(ignored)) +{ + if (ag->ag_frame_state == FRAME_SUSPENDED) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + static PyGetSetDef async_gen_getsetlist[] = { {"__name__", (getter)gen_get_name, (setter)gen_set_name, PyDoc_STR("name of the async generator")}, @@ -1529,6 +1538,7 @@ static PyGetSetDef async_gen_getsetlist[] = { PyDoc_STR("object being awaited on, or None")}, {"ag_frame", (getter)ag_getframe, NULL, NULL}, {"ag_code", (getter)ag_getcode, NULL, NULL}, + {"ag_suspended", (getter)ag_getsuspended, NULL, NULL}, {NULL} /* Sentinel */ }; From webhook-mailer at python.org Sat Mar 11 10:01:14 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sat, 11 Mar 2023 15:01:14 -0000 Subject: [Python-checkins] [3.11] gh-102493: backport unit test for PyErr_SetObject (#102602) Message-ID: https://github.com/python/cpython/commit/fcafc374110f06f84eb5ca093918e00c1120ce30 commit: fcafc374110f06f84eb5ca093918e00c1120ce30 branch: 3.11 author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-11T15:01:01Z summary: [3.11] gh-102493: backport unit test for PyErr_SetObject (#102602) gh-102493: backport unit test for PyErr_SetObject files: M Lib/test/test_capi/test_misc.py M Modules/_testcapimodule.c diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index db7a77416219..67150a8d24cb 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -133,6 +133,34 @@ def test_exc_info(self): else: self.assertTrue(False) + def test_set_object(self): + # new exception as obj is not an exception + with self.assertRaises(ValueError) as e: + _testcapi.exc_set_object(ValueError, 42) + self.assertEqual(e.exception.args, (42,)) + + # wraps the exception because unrelated types + with self.assertRaises(ValueError) as e: + _testcapi.exc_set_object(ValueError, TypeError(1,2,3)) + wrapped = e.exception.args[0] + self.assertIsInstance(wrapped, TypeError) + self.assertEqual(wrapped.args, (1, 2, 3)) + + # is superclass, so does not wrap + with self.assertRaises(PermissionError) as e: + _testcapi.exc_set_object(OSError, PermissionError(24)) + self.assertEqual(e.exception.args, (24,)) + + class Meta(type): + def __subclasscheck__(cls, sub): + 1/0 + + class Broken(Exception, metaclass=Meta): + pass + + with self.assertRaises(ZeroDivisionError) as e: + _testcapi.exc_set_object(Broken, Broken()) + @unittest.skipUnless(_posixsubprocess, '_posixsubprocess required for this test.') def test_seq_bytes_to_charp_array(self): # Issue #15732: crash in _PySequence_BytesToCharpArray() diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 71501b97a8c5..6a38cc17bcc7 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2523,6 +2523,20 @@ pyobject_bytes_from_null(PyObject *self, PyObject *Py_UNUSED(ignored)) return PyObject_Bytes(NULL); } +static PyObject * +exc_set_object(PyObject *self, PyObject *args) +{ + PyObject *exc; + PyObject *obj; + + if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) { + return NULL; + } + + PyErr_SetObject(exc, obj); + return NULL; +} + static PyObject * raise_exception(PyObject *self, PyObject *args) { @@ -6379,6 +6393,7 @@ static PyObject *getargs_s_hash_int2(PyObject *, PyObject *, PyObject*); static PyObject *gh_99240_clear_args(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { + {"exc_set_object", exc_set_object, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", raise_memoryerror, METH_NOARGS}, {"set_errno", set_errno, METH_VARARGS}, From webhook-mailer at python.org Sat Mar 11 13:36:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 11 Mar 2023 18:36:56 -0000 Subject: [Python-checkins] gh-79940: skip `TestGetAsyncGenState` on wasm as it requires working sockets (GH-102605) Message-ID: https://github.com/python/cpython/commit/534660f1680955c7a6a47d5c6bd9649704b74a87 commit: 534660f1680955c7a6a47d5c6bd9649704b74a87 branch: main author: Thomas Krennwallner committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-11T10:36:49-08:00 summary: gh-79940: skip `TestGetAsyncGenState` on wasm as it requires working sockets (GH-102605) Skip `TestGetAsyncGenState` and restoring of the default event loop policy in `test_inspect` if platform lacks working socket support. Fixes #11590 Automerge-Triggered-By: GH:kumaraditya303 files: M Lib/test/test_inspect.py diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 410a2e5b5468..803b259d961f 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -67,7 +67,8 @@ def revise(filename, *args): def tearDownModule(): - asyncio.set_event_loop_policy(None) + if support.has_socket_support: + asyncio.set_event_loop_policy(None) def signatures_with_lexicographic_keyword_only_parameters(): @@ -2326,6 +2327,7 @@ async def func(a=None): {'a': None, 'gencoro': gencoro, 'b': 'spam'}) + at support.requires_working_socket() class TestGetAsyncGenState(unittest.IsolatedAsyncioTestCase): def setUp(self): From webhook-mailer at python.org Sat Mar 11 14:11:09 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 11 Mar 2023 19:11:09 -0000 Subject: [Python-checkins] gh-101821: Test coverage for `ast.main` function (#101822) Message-ID: https://github.com/python/cpython/commit/bb396eece44036a71427e7766fbb8e0247373102 commit: bb396eece44036a71427e7766fbb8e0247373102 branch: main author: Nikita Sobolev committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-11T11:10:52-08:00 summary: gh-101821: Test coverage for `ast.main` function (#101822) files: M Lib/test/test_ast.py diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 7c9a57c685df..6c932e1305e1 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -11,6 +11,7 @@ from textwrap import dedent from test import support +from test.support import os_helper, script_helper from test.support.ast_helper import ASTTestMixin def to_tuple(t): @@ -2564,6 +2565,25 @@ def test_subinterpreter(self): self.assertEqual(res, 0) +class ASTMainTests(unittest.TestCase): + # Tests `ast.main()` function. + + def test_cli_file_input(self): + code = "print(1, 2, 3)" + expected = ast.dump(ast.parse(code), indent=3) + + with os_helper.temp_dir() as tmp_dir: + filename = os.path.join(tmp_dir, "test_module.py") + with open(filename, 'w', encoding='utf-8') as f: + f.write(code) + res, _ = script_helper.run_python_until_end("-m", "ast", filename) + + self.assertEqual(res.err, b"") + self.assertEqual(expected.splitlines(), + res.out.decode("utf8").splitlines()) + self.assertEqual(res.rc, 0) + + def main(): if __name__ != '__main__': return From webhook-mailer at python.org Sun Mar 12 12:58:09 2023 From: webhook-mailer at python.org (gvanrossum) Date: Sun, 12 Mar 2023 16:58:09 -0000 Subject: [Python-checkins] Fixes duplicated word (#102623) Message-ID: https://github.com/python/cpython/commit/e6210621bee4ac10e18b4adc11229b8cc1ee788d commit: e6210621bee4ac10e18b4adc11229b8cc1ee788d branch: main author: Guido van Rossum committer: gvanrossum date: 2023-03-12T09:58:02-07:00 summary: Fixes duplicated word (#102623) In line 1627, the end of the sentence reads "only that that it may be." but it should read "only that it may be" (or alternatively "only that that may be"). Co-authored-by: Hugo Gabriel Eyherabide files: M Doc/library/subprocess.rst diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index ccc431b2d92e..2b5a82e0107f 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -1622,7 +1622,7 @@ that. It is safe to set these to false on any Python version. They will have no effect on older versions when unsupported. Do not assume the attributes are available to read. Despite their names, a true value does not indicate that the -corresponding function will be used, only that that it may be. +corresponding function will be used, only that it may be. Please file issues any time you have to use these private knobs with a way to reproduce the issue you were seeing. Link to that issue from a comment in your From webhook-mailer at python.org Sun Mar 12 13:00:11 2023 From: webhook-mailer at python.org (gvanrossum) Date: Sun, 12 Mar 2023 17:00:11 -0000 Subject: [Python-checkins] [3.11] Fixes duplicated word (GH-102623) (#102624) Message-ID: https://github.com/python/cpython/commit/6829b1256a596301f82e3573214230186a4babfd commit: 6829b1256a596301f82e3573214230186a4babfd branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: gvanrossum date: 2023-03-12T10:00:04-07:00 summary: [3.11] Fixes duplicated word (GH-102623) (#102624) Fixes duplicated word (GH-102623) In line 1627, the end of the sentence reads "only that that it may be." but it should read "only that it may be" (or alternatively "only that that may be"). (cherry picked from commit e6210621bee4ac10e18b4adc11229b8cc1ee788d) Co-authored-by: Guido van Rossum Co-authored-by: Hugo Gabriel Eyherabide files: M Doc/library/subprocess.rst diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 9b153a2def1a..63d52062bc23 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -1624,7 +1624,7 @@ that. It is safe to set these to false on any Python version. They will have no effect on older versions when unsupported. Do not assume the attributes are available to read. Despite their names, a true value does not indicate that the -corresponding function will be used, only that that it may be. +corresponding function will be used, only that it may be. Please file issues any time you have to use these private knobs with a way to reproduce the issue you were seeing. Link to that issue from a comment in your From webhook-mailer at python.org Sun Mar 12 13:48:32 2023 From: webhook-mailer at python.org (rhettinger) Date: Sun, 12 Mar 2023 17:48:32 -0000 Subject: [Python-checkins] Optimize fmean() weighted average (#102626) Message-ID: https://github.com/python/cpython/commit/6cd7572f859a32a1f4626644c3e8139055df59e3 commit: 6cd7572f859a32a1f4626644c3e8139055df59e3 branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-12T12:48:25-05:00 summary: Optimize fmean() weighted average (#102626) files: M Lib/statistics.py diff --git a/Lib/statistics.py b/Lib/statistics.py index 07d1fd5ba6e9..7d5d750193a5 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -136,9 +136,9 @@ from decimal import Decimal from itertools import count, groupby, repeat from bisect import bisect_left, bisect_right -from math import hypot, sqrt, fabs, exp, erf, tau, log, fsum +from math import hypot, sqrt, fabs, exp, erf, tau, log, fsum, sumprod from functools import reduce -from operator import mul, itemgetter +from operator import itemgetter from collections import Counter, namedtuple, defaultdict _SQRT2 = sqrt(2.0) @@ -496,28 +496,26 @@ def fmean(data, weights=None): >>> fmean([3.5, 4.0, 5.25]) 4.25 """ - try: - n = len(data) - except TypeError: - # Handle iterators that do not define __len__(). - n = 0 - def count(iterable): - nonlocal n - for n, x in enumerate(iterable, start=1): - yield x - data = count(data) if weights is None: + try: + n = len(data) + except TypeError: + # Handle iterators that do not define __len__(). + n = 0 + def count(iterable): + nonlocal n + for n, x in enumerate(iterable, start=1): + yield x + data = count(data) total = fsum(data) if not n: raise StatisticsError('fmean requires at least one data point') return total / n - try: - num_weights = len(weights) - except TypeError: + if not isinstance(weights, (list, tuple)): weights = list(weights) - num_weights = len(weights) - num = fsum(map(mul, data, weights)) - if n != num_weights: + try: + num = sumprod(data, weights) + except ValueError: raise StatisticsError('data and weights must be the same length') den = fsum(weights) if not den: From webhook-mailer at python.org Sun Mar 12 14:04:06 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 12 Mar 2023 18:04:06 -0000 Subject: [Python-checkins] Fix duplicated words in the docs (GH-102629) Message-ID: https://github.com/python/cpython/commit/f6ca71a42268dcd890bd1930501b6c7e6d7ce66e commit: f6ca71a42268dcd890bd1930501b6c7e6d7ce66e branch: main author: ??????? ???????? committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-12T11:03:59-07:00 summary: Fix duplicated words in the docs (GH-102629) With grep utility found some duplicated words Automerge-Triggered-By: GH:AlexWaygood files: M Doc/library/base64.rst M Doc/reference/compound_stmts.rst M Misc/NEWS.d/3.11.0a6.rst M Misc/NEWS.d/3.12.0a1.rst M Misc/NEWS.d/3.12.0a2.rst diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 4ca3768f827c..d5b6af8c1928 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -58,7 +58,7 @@ The modern interface provides: This allows an application to e.g. generate URL or filesystem safe Base64 strings. The default is ``None``, for which the standard Base64 alphabet is used. - May assert or raise a a :exc:`ValueError` if the length of *altchars* is not 2. Raises a + May assert or raise a :exc:`ValueError` if the length of *altchars* is not 2. Raises a :exc:`TypeError` if *altchars* is not a :term:`bytes-like object`. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 52bb0b22b042..f0a8936c35bf 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -816,7 +816,7 @@ keyword against a subject. Syntax: If the OR pattern fails, the AS pattern fails. Otherwise, the AS pattern binds the subject to the name on the right of the as keyword and succeeds. -``capture_pattern`` cannot be a a ``_``. +``capture_pattern`` cannot be a ``_``. In simple terms ``P as NAME`` will match with ``P``, and on success it will set ``NAME = ``. diff --git a/Misc/NEWS.d/3.11.0a6.rst b/Misc/NEWS.d/3.11.0a6.rst index 68b80e46690d..8621edcfb04b 100644 --- a/Misc/NEWS.d/3.11.0a6.rst +++ b/Misc/NEWS.d/3.11.0a6.rst @@ -1055,7 +1055,7 @@ Patch by Victor Stinner. .. section: Build Building Python now requires support for floating point Not-a-Number (NaN): -remove the ``Py_NO_NAN`` macro. Patch by by Victor Stinner. +remove the ``Py_NO_NAN`` macro. Patch by Victor Stinner. .. diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 2a943fe481af..075e8da825a3 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -4559,8 +4559,7 @@ The minimum Sphinx version required to build the documentation is now 3.2. .. section: Documentation Augmented documentation of asyncio.create_task(). Clarified the need to keep -strong references to tasks and added a code snippet detailing how to to -this. +strong references to tasks and added a code snippet detailing how to do this. .. @@ -5066,7 +5065,7 @@ are stubs and not functional. .. nonce: Bsswsc .. section: Build -Add a new ``--with-dsymutil`` configure option to to link debug information +Add a new ``--with-dsymutil`` configure option to link debug information in macOS. Patch by Pablo Galindo. .. diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index 41ad8cd22b5d..117be21a3221 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -546,7 +546,7 @@ Clean up refleak on failed module initialisation in :mod:`_zoneinfo` .. nonce: qc_KHr .. section: Library -Clean up refleaks on failed module initialisation in in :mod:`_pickle` +Clean up refleaks on failed module initialisation in :mod:`_pickle` .. From webhook-mailer at python.org Sun Mar 12 19:10:06 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sun, 12 Mar 2023 23:10:06 -0000 Subject: [Python-checkins] GH-101673: Fix pdb bug where local variable changes are lost after longlist (#101674) Message-ID: https://github.com/python/cpython/commit/5d677c556f03a34d1c2d86e4cc96025870c20c12 commit: 5d677c556f03a34d1c2d86e4cc96025870c20c12 branch: main author: gaogaotiantian committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-12T23:09:55Z summary: GH-101673: Fix pdb bug where local variable changes are lost after longlist (#101674) files: A Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index 78d0ce537f1f..f11fc5553681 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -107,15 +107,6 @@ def find_function(funcname, filename): return funcname, filename, lineno return None -def getsourcelines(obj): - lines, lineno = inspect.findsource(obj) - if inspect.isframe(obj) and obj.f_globals is obj.f_locals: - # must be a module frame: do not try to cut a block out of it - return lines, 1 - elif inspect.ismodule(obj): - return lines, 1 - return inspect.getblock(lines[lineno:]), lineno+1 - def lasti2lineno(code, lasti): linestarts = list(dis.findlinestarts(code)) linestarts.reverse() @@ -1357,7 +1348,7 @@ def do_longlist(self, arg): filename = self.curframe.f_code.co_filename breaklist = self.get_file_breaks(filename) try: - lines, lineno = getsourcelines(self.curframe) + lines, lineno = inspect.getsourcelines(self.curframe) except OSError as err: self.error(err) return @@ -1373,7 +1364,7 @@ def do_source(self, arg): except: return try: - lines, lineno = getsourcelines(obj) + lines, lineno = inspect.getsourcelines(obj) except (OSError, TypeError) as err: self.error(err) return diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 48f419e62fbb..d91bd0b2f03a 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1474,6 +1474,35 @@ def test_pdb_issue_gh_94215(): (Pdb) continue """ +def test_pdb_issue_gh_101673(): + """See GH-101673 + + Make sure ll won't revert local variable assignment + + >>> def test_function(): + ... a = 1 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... '!a = 2', + ... 'll', + ... 'p a', + ... 'continue' + ... ]): + ... test_function() + --Return-- + > (3)test_function()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) !a = 2 + (Pdb) ll + 1 def test_function(): + 2 a = 1 + 3 -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) p a + 2 + (Pdb) continue + """ + @support.requires_subprocess() class PdbTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst b/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst new file mode 100644 index 000000000000..4e673ba98115 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst @@ -0,0 +1 @@ +Fix a :mod:`pdb` bug where ``ll`` clears the changes to local variables. From webhook-mailer at python.org Sun Mar 12 19:41:03 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 12 Mar 2023 23:41:03 -0000 Subject: [Python-checkins] GH-101673: Fix pdb bug where local variable changes are lost after longlist (GH-101674) Message-ID: https://github.com/python/cpython/commit/78560261a24bf337bb0c659cc3288648cf7b4415 commit: 78560261a24bf337bb0c659cc3288648cf7b4415 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-12T16:40:56-07:00 summary: GH-101673: Fix pdb bug where local variable changes are lost after longlist (GH-101674) (cherry picked from commit 5d677c556f03a34d1c2d86e4cc96025870c20c12) Co-authored-by: gaogaotiantian files: A Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index 411ce53115e7..57d070a87e81 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -107,15 +107,6 @@ def find_function(funcname, filename): return funcname, filename, lineno return None -def getsourcelines(obj): - lines, lineno = inspect.findsource(obj) - if inspect.isframe(obj) and obj.f_globals is obj.f_locals: - # must be a module frame: do not try to cut a block out of it - return lines, 1 - elif inspect.ismodule(obj): - return lines, 1 - return inspect.getblock(lines[lineno:]), lineno+1 - def lasti2lineno(code, lasti): linestarts = list(dis.findlinestarts(code)) linestarts.reverse() @@ -1357,7 +1348,7 @@ def do_longlist(self, arg): filename = self.curframe.f_code.co_filename breaklist = self.get_file_breaks(filename) try: - lines, lineno = getsourcelines(self.curframe) + lines, lineno = inspect.getsourcelines(self.curframe) except OSError as err: self.error(err) return @@ -1373,7 +1364,7 @@ def do_source(self, arg): except: return try: - lines, lineno = getsourcelines(obj) + lines, lineno = inspect.getsourcelines(obj) except (OSError, TypeError) as err: self.error(err) return diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 48f419e62fbb..d91bd0b2f03a 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1474,6 +1474,35 @@ def test_pdb_issue_gh_94215(): (Pdb) continue """ +def test_pdb_issue_gh_101673(): + """See GH-101673 + + Make sure ll won't revert local variable assignment + + >>> def test_function(): + ... a = 1 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... '!a = 2', + ... 'll', + ... 'p a', + ... 'continue' + ... ]): + ... test_function() + --Return-- + > (3)test_function()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) !a = 2 + (Pdb) ll + 1 def test_function(): + 2 a = 1 + 3 -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) p a + 2 + (Pdb) continue + """ + @support.requires_subprocess() class PdbTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst b/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst new file mode 100644 index 000000000000..4e673ba98115 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst @@ -0,0 +1 @@ +Fix a :mod:`pdb` bug where ``ll`` clears the changes to local variables. From webhook-mailer at python.org Mon Mar 13 05:25:24 2023 From: webhook-mailer at python.org (hugovk) Date: Mon, 13 Mar 2023 09:25:24 -0000 Subject: [Python-checkins] gh-101100: Fix Sphinx warnings in `turtle` module (#102340) Message-ID: https://github.com/python/cpython/commit/78e4e6c3d71980d4e6687f07afa6ddfc83e29b04 commit: 78e4e6c3d71980d4e6687f07afa6ddfc83e29b04 branch: main author: Hugo van Kemenade committer: hugovk date: 2023-03-13T11:24:52+02:00 summary: gh-101100: Fix Sphinx warnings in `turtle` module (#102340) Co-authored-by: C.A.M. Gerlach files: M Doc/library/turtle.rst M Lib/turtle.py diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index b7eb569c18a6..05392d04e522 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -1214,7 +1214,7 @@ Appearance will be displayed stretched according to its stretchfactors: *stretch_wid* is stretchfactor perpendicular to its orientation, *stretch_len* is stretchfactor in direction of its orientation, *outline* determines the width - of the shapes's outline. + of the shape's outline. .. doctest:: :skipif: _tkinter is None @@ -1545,7 +1545,7 @@ below: 1. Create an empty Shape object of type "compound". 2. Add as many components to this object as desired, using the - :meth:`addcomponent` method. + :meth:`~Shape.addcomponent` method. For example: @@ -2125,7 +2125,7 @@ Public classes :param cv: a :class:`tkinter.Canvas` - Provides screen oriented methods like :func:`setbg` etc. that are described + Provides screen oriented methods like :func:`bgcolor` etc. that are described above. .. class:: Screen() @@ -2315,7 +2315,9 @@ of this module or which better fits to your needs, e.g. for use in a classroom, you can prepare a configuration file ``turtle.cfg`` which will be read at import time and modify the configuration according to its settings. -The built in configuration would correspond to the following turtle.cfg:: +The built in configuration would correspond to the following ``turtle.cfg``: + +.. code-block:: ini width = 0.5 height = 0.75 @@ -2340,15 +2342,15 @@ The built in configuration would correspond to the following turtle.cfg:: Short explanation of selected entries: -- The first four lines correspond to the arguments of the :meth:`Screen.setup` +- The first four lines correspond to the arguments of the :func:`Screen.setup ` method. - Line 5 and 6 correspond to the arguments of the method - :meth:`Screen.screensize`. + :func:`Screen.screensize `. - *shape* can be any of the built-in shapes, e.g: arrow, turtle, etc. For more info try ``help(shape)``. -- If you want to use no fillcolor (i.e. make the turtle transparent), you have +- If you want to use no fill color (i.e. make the turtle transparent), you have to write ``fillcolor = ""`` (but all nonempty strings must not have quotes in - the cfg-file). + the cfg file). - If you want to reflect the turtle its state, you have to use ``resizemode = auto``. - If you set e.g. ``language = italian`` the docstringdict @@ -2398,6 +2400,8 @@ The :mod:`turtledemo` package directory contains: The demo scripts are: +.. currentmodule:: turtle + .. tabularcolumns:: |l|L|L| +----------------+------------------------------+-----------------------+ @@ -2469,20 +2473,20 @@ Have fun! Changes since Python 2.6 ======================== -- The methods :meth:`Turtle.tracer`, :meth:`Turtle.window_width` and - :meth:`Turtle.window_height` have been eliminated. +- The methods :func:`Turtle.tracer `, :func:`Turtle.window_width ` and + :func:`Turtle.window_height ` have been eliminated. Methods with these names and functionality are now available only as methods of :class:`Screen`. The functions derived from these remain available. (In fact already in Python 2.6 these methods were merely duplications of the corresponding - :class:`TurtleScreen`/:class:`Screen`-methods.) + :class:`TurtleScreen`/:class:`Screen` methods.) -- The method :meth:`Turtle.fill` has been eliminated. - The behaviour of :meth:`begin_fill` and :meth:`end_fill` - have changed slightly: now every filling-process must be completed with an +- The method :func:`!Turtle.fill` has been eliminated. + The behaviour of :func:`begin_fill` and :func:`end_fill` + have changed slightly: now every filling process must be completed with an ``end_fill()`` call. -- A method :meth:`Turtle.filling` has been added. It returns a boolean +- A method :func:`Turtle.filling ` has been added. It returns a boolean value: ``True`` if a filling process is under way, ``False`` otherwise. This behaviour corresponds to a ``fill()`` call without arguments in Python 2.6. @@ -2490,23 +2494,23 @@ Changes since Python 2.6 Changes since Python 3.0 ======================== -- The methods :meth:`Turtle.shearfactor`, :meth:`Turtle.shapetransform` and - :meth:`Turtle.get_shapepoly` have been added. Thus the full range of +- The :class:`Turtle` methods :func:`shearfactor`, :func:`shapetransform` and + :func:`get_shapepoly` have been added. Thus the full range of regular linear transforms is now available for transforming turtle shapes. - :meth:`Turtle.tiltangle` has been enhanced in functionality: it now can - be used to get or set the tiltangle. :meth:`Turtle.settiltangle` has been + :func:`tiltangle` has been enhanced in functionality: it now can + be used to get or set the tilt angle. :func:`settiltangle` has been deprecated. -- The method :meth:`Screen.onkeypress` has been added as a complement to - :meth:`Screen.onkey` which in fact binds actions to the keyrelease event. - Accordingly the latter has got an alias: :meth:`Screen.onkeyrelease`. +- The :class:`Screen` method :func:`onkeypress` has been added as a complement to + :func:`onkey`. As the latter binds actions to the key release event, + an alias: :func:`onkeyrelease` was also added for it. -- The method :meth:`Screen.mainloop` has been added. So when working only - with Screen and Turtle objects one must not additionally import - :func:`mainloop` anymore. +- The method :func:`Screen.mainloop ` has been added, + so there is no longer a need to use the standalone :func:`mainloop` function + when working with :class:`Screen` and :class:`Turtle` objects. -- Two input methods has been added :meth:`Screen.textinput` and - :meth:`Screen.numinput`. These popup input dialogs and return +- Two input methods have been added: :func:`Screen.textinput ` and + :func:`Screen.numinput `. These pop up input dialogs and return strings and numbers respectively. - Two example scripts :file:`tdemo_nim.py` and :file:`tdemo_round_dance.py` diff --git a/Lib/turtle.py b/Lib/turtle.py index 6abf9f7f65af..1b369327bc8e 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -954,7 +954,7 @@ def __repr__(self): class TurtleScreen(TurtleScreenBase): - """Provides screen oriented methods like setbg etc. + """Provides screen oriented methods like bgcolor etc. Only relies upon the methods of TurtleScreenBase and NOT upon components of the underlying graphics toolkit - From webhook-mailer at python.org Mon Mar 13 06:35:35 2023 From: webhook-mailer at python.org (markshannon) Date: Mon, 13 Mar 2023 10:35:35 -0000 Subject: [Python-checkins] GH-102300: Reuse objects with refcount == 1 in float specialized binary ops. (GH-102301) Message-ID: https://github.com/python/cpython/commit/233e32f93614255bf5fc7c93cd98af453e58cc98 commit: 233e32f93614255bf5fc7c93cd98af453e58cc98 branch: main author: Mark Shannon committer: markshannon date: 2023-03-13T10:34:54Z summary: GH-102300: Reuse objects with refcount == 1 in float specialized binary ops. (GH-102301) files: A Misc/NEWS.d/next/Core and Builtins/2023-02-27-15-48-31.gh-issue-102300.8o-_Mt.rst M Python/bytecodes.c M Python/ceval_macros.h M Python/generated_cases.c.h diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-27-15-48-31.gh-issue-102300.8o-_Mt.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-27-15-48-31.gh-issue-102300.8o-_Mt.rst new file mode 100644 index 000000000000..4227014582b7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-27-15-48-31.gh-issue-102300.8o-_Mt.rst @@ -0,0 +1 @@ +Reuse operands with refcount of 1 in float specializations of BINARY_OP. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index dc2a20f22b60..178519fcb63c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -195,10 +195,7 @@ dummy_func( STAT_INC(BINARY_OP, hit); double dprod = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; - prod = PyFloat_FromDouble(dprod); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - ERROR_IF(prod == NULL, error); + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod); } inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub)) { @@ -218,10 +215,7 @@ dummy_func( DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; - sub = PyFloat_FromDouble(dsub); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - ERROR_IF(sub == NULL, error); + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsub, sub); } inst(BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res)) { @@ -278,10 +272,7 @@ dummy_func( STAT_INC(BINARY_OP, hit); double dsum = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; - sum = PyFloat_FromDouble(dsum); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - ERROR_IF(sum == NULL, error); + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); } inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index ac1fec77daca..98b72ec1b364 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -350,3 +350,23 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define KWNAMES_LEN() \ (kwnames == NULL ? 0 : ((int)PyTuple_GET_SIZE(kwnames))) + +#define DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dval, result) \ +do { \ + if (Py_REFCNT(left) == 1) { \ + ((PyFloatObject *)left)->ob_fval = (dval); \ + _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);\ + result = (left); \ + } \ + else if (Py_REFCNT(right) == 1) {\ + ((PyFloatObject *)right)->ob_fval = (dval); \ + _Py_DECREF_NO_DEALLOC(left); \ + result = (right); \ + }\ + else { \ + result = PyFloat_FromDouble(dval); \ + if ((result) == NULL) goto error; \ + _Py_DECREF_NO_DEALLOC(left); \ + _Py_DECREF_NO_DEALLOC(right); \ + } \ +} while (0) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 3839aeecb912..21073cbf978c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -263,10 +263,7 @@ STAT_INC(BINARY_OP, hit); double dprod = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; - prod = PyFloat_FromDouble(dprod); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (prod == NULL) goto pop_2_error; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod); STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -300,10 +297,7 @@ DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; - sub = PyFloat_FromDouble(dsub); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (sub == NULL) goto pop_2_error; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsub, sub); STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -372,10 +366,7 @@ STAT_INC(BINARY_OP, hit); double dsum = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; - sum = PyFloat_FromDouble(dsum); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (sum == NULL) goto pop_2_error; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; From webhook-mailer at python.org Mon Mar 13 07:11:17 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 13 Mar 2023 11:11:17 -0000 Subject: [Python-checkins] GH-102537: Handle check for PYTHONTZPATH failing in zoneinfo test (GH-102538) Message-ID: https://github.com/python/cpython/commit/5bdcb08250d00a82f6a537ce1b7b78cd70567225 commit: 5bdcb08250d00a82f6a537ce1b7b78cd70567225 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-13T04:11:09-07:00 summary: GH-102537: Handle check for PYTHONTZPATH failing in zoneinfo test (GH-102538) It is possible but unlikely for the `python_tzpath_context` function to fail between the start of the `try` block and the point where `os.environ.get` succeeds, in which case `old_env` will be undefined. In this case, we want to take no action. Practically speaking this will really only happen in an error condition anyway, so it doesn't really matter, but we should probably do it right anyway. (cherry picked from commit 64bde502cf89963bc7382b03ea9e1c0967d22e35) Co-authored-by: Paul Ganssle <1377457+pganssle at users.noreply.github.com> files: A Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst M Lib/test/test_zoneinfo/test_zoneinfo.py diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index 59b35ef63f98..e3295c606633 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -1530,13 +1530,20 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase): @contextlib.contextmanager def python_tzpath_context(value): path_var = "PYTHONTZPATH" + unset_env_sentinel = object() + old_env = unset_env_sentinel try: with OS_ENV_LOCK: old_env = os.environ.get(path_var, None) os.environ[path_var] = value yield finally: - if old_env is None: + if old_env is unset_env_sentinel: + # In this case, `old_env` was never retrieved from the + # environment for whatever reason, so there's no need to + # reset the environment TZPATH. + pass + elif old_env is None: del os.environ[path_var] else: os.environ[path_var] = old_env # pragma: nocover diff --git a/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst b/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst new file mode 100644 index 000000000000..94d160dd4127 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-03-08-13-54-20.gh-issue-102537.Vfplpb.rst @@ -0,0 +1,2 @@ +Adjust the error handling strategy in +``test_zoneinfo.TzPathTest.python_tzpath_context``. Patch by Paul Ganssle. From webhook-mailer at python.org Mon Mar 13 07:11:42 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 13 Mar 2023 11:11:42 -0000 Subject: [Python-checkins] gh-101100: Fix Sphinx warnings in `turtle` module (GH-102340) Message-ID: https://github.com/python/cpython/commit/a01ad527e7627da9ac3ed9debd4c0e75c5318d11 commit: a01ad527e7627da9ac3ed9debd4c0e75c5318d11 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-13T04:11:34-07:00 summary: gh-101100: Fix Sphinx warnings in `turtle` module (GH-102340) (cherry picked from commit 78e4e6c3d71980d4e6687f07afa6ddfc83e29b04) Co-authored-by: Hugo van Kemenade Co-authored-by: C.A.M. Gerlach files: M Doc/library/turtle.rst M Lib/turtle.py diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index d48db6c6e753..24de8c482ae5 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -1214,7 +1214,7 @@ Appearance will be displayed stretched according to its stretchfactors: *stretch_wid* is stretchfactor perpendicular to its orientation, *stretch_len* is stretchfactor in direction of its orientation, *outline* determines the width - of the shapes's outline. + of the shape's outline. .. doctest:: :skipif: _tkinter is None @@ -1545,7 +1545,7 @@ below: 1. Create an empty Shape object of type "compound". 2. Add as many components to this object as desired, using the - :meth:`addcomponent` method. + :meth:`~Shape.addcomponent` method. For example: @@ -2125,7 +2125,7 @@ Public classes :param cv: a :class:`tkinter.Canvas` - Provides screen oriented methods like :func:`setbg` etc. that are described + Provides screen oriented methods like :func:`bgcolor` etc. that are described above. .. class:: Screen() @@ -2315,7 +2315,9 @@ of this module or which better fits to your needs, e.g. for use in a classroom, you can prepare a configuration file ``turtle.cfg`` which will be read at import time and modify the configuration according to its settings. -The built in configuration would correspond to the following turtle.cfg:: +The built in configuration would correspond to the following ``turtle.cfg``: + +.. code-block:: ini width = 0.5 height = 0.75 @@ -2340,15 +2342,15 @@ The built in configuration would correspond to the following turtle.cfg:: Short explanation of selected entries: -- The first four lines correspond to the arguments of the :meth:`Screen.setup` +- The first four lines correspond to the arguments of the :func:`Screen.setup ` method. - Line 5 and 6 correspond to the arguments of the method - :meth:`Screen.screensize`. + :func:`Screen.screensize `. - *shape* can be any of the built-in shapes, e.g: arrow, turtle, etc. For more info try ``help(shape)``. -- If you want to use no fillcolor (i.e. make the turtle transparent), you have +- If you want to use no fill color (i.e. make the turtle transparent), you have to write ``fillcolor = ""`` (but all nonempty strings must not have quotes in - the cfg-file). + the cfg file). - If you want to reflect the turtle its state, you have to use ``resizemode = auto``. - If you set e.g. ``language = italian`` the docstringdict @@ -2398,6 +2400,8 @@ The :mod:`turtledemo` package directory contains: The demo scripts are: +.. currentmodule:: turtle + .. tabularcolumns:: |l|L|L| +----------------+------------------------------+-----------------------+ @@ -2469,20 +2473,20 @@ Have fun! Changes since Python 2.6 ======================== -- The methods :meth:`Turtle.tracer`, :meth:`Turtle.window_width` and - :meth:`Turtle.window_height` have been eliminated. +- The methods :func:`Turtle.tracer `, :func:`Turtle.window_width ` and + :func:`Turtle.window_height ` have been eliminated. Methods with these names and functionality are now available only as methods of :class:`Screen`. The functions derived from these remain available. (In fact already in Python 2.6 these methods were merely duplications of the corresponding - :class:`TurtleScreen`/:class:`Screen`-methods.) + :class:`TurtleScreen`/:class:`Screen` methods.) -- The method :meth:`Turtle.fill` has been eliminated. - The behaviour of :meth:`begin_fill` and :meth:`end_fill` - have changed slightly: now every filling-process must be completed with an +- The method :func:`!Turtle.fill` has been eliminated. + The behaviour of :func:`begin_fill` and :func:`end_fill` + have changed slightly: now every filling process must be completed with an ``end_fill()`` call. -- A method :meth:`Turtle.filling` has been added. It returns a boolean +- A method :func:`Turtle.filling ` has been added. It returns a boolean value: ``True`` if a filling process is under way, ``False`` otherwise. This behaviour corresponds to a ``fill()`` call without arguments in Python 2.6. @@ -2490,23 +2494,23 @@ Changes since Python 2.6 Changes since Python 3.0 ======================== -- The methods :meth:`Turtle.shearfactor`, :meth:`Turtle.shapetransform` and - :meth:`Turtle.get_shapepoly` have been added. Thus the full range of +- The :class:`Turtle` methods :func:`shearfactor`, :func:`shapetransform` and + :func:`get_shapepoly` have been added. Thus the full range of regular linear transforms is now available for transforming turtle shapes. - :meth:`Turtle.tiltangle` has been enhanced in functionality: it now can - be used to get or set the tiltangle. :meth:`Turtle.settiltangle` has been + :func:`tiltangle` has been enhanced in functionality: it now can + be used to get or set the tilt angle. :func:`settiltangle` has been deprecated. -- The method :meth:`Screen.onkeypress` has been added as a complement to - :meth:`Screen.onkey` which in fact binds actions to the keyrelease event. - Accordingly the latter has got an alias: :meth:`Screen.onkeyrelease`. +- The :class:`Screen` method :func:`onkeypress` has been added as a complement to + :func:`onkey`. As the latter binds actions to the key release event, + an alias: :func:`onkeyrelease` was also added for it. -- The method :meth:`Screen.mainloop` has been added. So when working only - with Screen and Turtle objects one must not additionally import - :func:`mainloop` anymore. +- The method :func:`Screen.mainloop ` has been added, + so there is no longer a need to use the standalone :func:`mainloop` function + when working with :class:`Screen` and :class:`Turtle` objects. -- Two input methods has been added :meth:`Screen.textinput` and - :meth:`Screen.numinput`. These popup input dialogs and return +- Two input methods have been added: :func:`Screen.textinput ` and + :func:`Screen.numinput `. These pop up input dialogs and return strings and numbers respectively. - Two example scripts :file:`tdemo_nim.py` and :file:`tdemo_round_dance.py` diff --git a/Lib/turtle.py b/Lib/turtle.py index 11272835f914..d287c1554352 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -953,7 +953,7 @@ def __repr__(self): class TurtleScreen(TurtleScreenBase): - """Provides screen oriented methods like setbg etc. + """Provides screen oriented methods like bgcolor etc. Only relies upon the methods of TurtleScreenBase and NOT upon components of the underlying graphics toolkit - From webhook-mailer at python.org Mon Mar 13 07:33:49 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 13 Mar 2023 11:33:49 -0000 Subject: [Python-checkins] gh-101100: Fix Sphinx warnings in `turtle` module (GH-102340) Message-ID: https://github.com/python/cpython/commit/c39a1d0ba97e1892035faaaf7b6958603bfcde56 commit: c39a1d0ba97e1892035faaaf7b6958603bfcde56 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-13T04:33:38-07:00 summary: gh-101100: Fix Sphinx warnings in `turtle` module (GH-102340) (cherry picked from commit 78e4e6c3d71980d4e6687f07afa6ddfc83e29b04) Co-authored-by: Hugo van Kemenade Co-authored-by: C.A.M. Gerlach files: M Doc/library/turtle.rst M Lib/turtle.py diff --git a/Doc/library/turtle.rst b/Doc/library/turtle.rst index 62acfff5a793..55d9130de8e2 100644 --- a/Doc/library/turtle.rst +++ b/Doc/library/turtle.rst @@ -1214,7 +1214,7 @@ Appearance will be displayed stretched according to its stretchfactors: *stretch_wid* is stretchfactor perpendicular to its orientation, *stretch_len* is stretchfactor in direction of its orientation, *outline* determines the width - of the shapes's outline. + of the shape's outline. .. doctest:: :skipif: _tkinter is None @@ -1545,7 +1545,7 @@ below: 1. Create an empty Shape object of type "compound". 2. Add as many components to this object as desired, using the - :meth:`addcomponent` method. + :meth:`~Shape.addcomponent` method. For example: @@ -2125,7 +2125,7 @@ Public classes :param cv: a :class:`tkinter.Canvas` - Provides screen oriented methods like :func:`setbg` etc. that are described + Provides screen oriented methods like :func:`bgcolor` etc. that are described above. .. class:: Screen() @@ -2315,7 +2315,9 @@ of this module or which better fits to your needs, e.g. for use in a classroom, you can prepare a configuration file ``turtle.cfg`` which will be read at import time and modify the configuration according to its settings. -The built in configuration would correspond to the following turtle.cfg:: +The built in configuration would correspond to the following ``turtle.cfg``: + +.. code-block:: ini width = 0.5 height = 0.75 @@ -2340,15 +2342,15 @@ The built in configuration would correspond to the following turtle.cfg:: Short explanation of selected entries: -- The first four lines correspond to the arguments of the :meth:`Screen.setup` +- The first four lines correspond to the arguments of the :func:`Screen.setup ` method. - Line 5 and 6 correspond to the arguments of the method - :meth:`Screen.screensize`. + :func:`Screen.screensize `. - *shape* can be any of the built-in shapes, e.g: arrow, turtle, etc. For more info try ``help(shape)``. -- If you want to use no fillcolor (i.e. make the turtle transparent), you have +- If you want to use no fill color (i.e. make the turtle transparent), you have to write ``fillcolor = ""`` (but all nonempty strings must not have quotes in - the cfg-file). + the cfg file). - If you want to reflect the turtle its state, you have to use ``resizemode = auto``. - If you set e.g. ``language = italian`` the docstringdict @@ -2398,6 +2400,8 @@ The :mod:`turtledemo` package directory contains: The demo scripts are: +.. currentmodule:: turtle + .. tabularcolumns:: |l|L|L| +----------------+------------------------------+-----------------------+ @@ -2469,20 +2473,20 @@ Have fun! Changes since Python 2.6 ======================== -- The methods :meth:`Turtle.tracer`, :meth:`Turtle.window_width` and - :meth:`Turtle.window_height` have been eliminated. +- The methods :func:`Turtle.tracer `, :func:`Turtle.window_width ` and + :func:`Turtle.window_height ` have been eliminated. Methods with these names and functionality are now available only as methods of :class:`Screen`. The functions derived from these remain available. (In fact already in Python 2.6 these methods were merely duplications of the corresponding - :class:`TurtleScreen`/:class:`Screen`-methods.) + :class:`TurtleScreen`/:class:`Screen` methods.) -- The method :meth:`Turtle.fill` has been eliminated. - The behaviour of :meth:`begin_fill` and :meth:`end_fill` - have changed slightly: now every filling-process must be completed with an +- The method :func:`!Turtle.fill` has been eliminated. + The behaviour of :func:`begin_fill` and :func:`end_fill` + have changed slightly: now every filling process must be completed with an ``end_fill()`` call. -- A method :meth:`Turtle.filling` has been added. It returns a boolean +- A method :func:`Turtle.filling ` has been added. It returns a boolean value: ``True`` if a filling process is under way, ``False`` otherwise. This behaviour corresponds to a ``fill()`` call without arguments in Python 2.6. @@ -2490,23 +2494,23 @@ Changes since Python 2.6 Changes since Python 3.0 ======================== -- The methods :meth:`Turtle.shearfactor`, :meth:`Turtle.shapetransform` and - :meth:`Turtle.get_shapepoly` have been added. Thus the full range of +- The :class:`Turtle` methods :func:`shearfactor`, :func:`shapetransform` and + :func:`get_shapepoly` have been added. Thus the full range of regular linear transforms is now available for transforming turtle shapes. - :meth:`Turtle.tiltangle` has been enhanced in functionality: it now can - be used to get or set the tiltangle. :meth:`Turtle.settiltangle` has been + :func:`tiltangle` has been enhanced in functionality: it now can + be used to get or set the tilt angle. :func:`settiltangle` has been deprecated. -- The method :meth:`Screen.onkeypress` has been added as a complement to - :meth:`Screen.onkey` which in fact binds actions to the keyrelease event. - Accordingly the latter has got an alias: :meth:`Screen.onkeyrelease`. +- The :class:`Screen` method :func:`onkeypress` has been added as a complement to + :func:`onkey`. As the latter binds actions to the key release event, + an alias: :func:`onkeyrelease` was also added for it. -- The method :meth:`Screen.mainloop` has been added. So when working only - with Screen and Turtle objects one must not additionally import - :func:`mainloop` anymore. +- The method :func:`Screen.mainloop ` has been added, + so there is no longer a need to use the standalone :func:`mainloop` function + when working with :class:`Screen` and :class:`Turtle` objects. -- Two input methods has been added :meth:`Screen.textinput` and - :meth:`Screen.numinput`. These popup input dialogs and return +- Two input methods have been added: :func:`Screen.textinput ` and + :func:`Screen.numinput `. These pop up input dialogs and return strings and numbers respectively. - Two example scripts :file:`tdemo_nim.py` and :file:`tdemo_round_dance.py` diff --git a/Lib/turtle.py b/Lib/turtle.py index 6abf9f7f65af..1b369327bc8e 100644 --- a/Lib/turtle.py +++ b/Lib/turtle.py @@ -954,7 +954,7 @@ def __repr__(self): class TurtleScreen(TurtleScreenBase): - """Provides screen oriented methods like setbg etc. + """Provides screen oriented methods like bgcolor etc. Only relies upon the methods of TurtleScreenBase and NOT upon components of the underlying graphics toolkit - From webhook-mailer at python.org Mon Mar 13 09:15:59 2023 From: webhook-mailer at python.org (hugovk) Date: Mon, 13 Mar 2023 13:15:59 -0000 Subject: [Python-checkins] Fix broken link to MSDN (#102355) Message-ID: https://github.com/python/cpython/commit/9a8b66b58c74236959a01d579e2c156d9c2e7cb3 commit: 9a8b66b58c74236959a01d579e2c156d9c2e7cb3 branch: main author: ??? <109224573 at qq.com> committer: hugovk date: 2023-03-13T15:15:52+02:00 summary: Fix broken link to MSDN (#102355) files: M Lib/socket.py M Lib/test/support/socket_helper.py diff --git a/Lib/socket.py b/Lib/socket.py index 3a4f94de9cc0..321fcda51505 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -910,7 +910,7 @@ def create_server(address, *, family=AF_INET, backlog=None, reuse_port=False, # address, effectively preventing this one from accepting # connections. Also, it may set the process in a state where # it'll no longer respond to any signals or graceful kills. - # See: msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx + # See: https://learn.microsoft.com/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse if os.name not in ('nt', 'cygwin') and \ hasattr(_socket, 'SO_REUSEADDR'): try: diff --git a/Lib/test/support/socket_helper.py b/Lib/test/support/socket_helper.py index d2960c9e3334..78409238db89 100644 --- a/Lib/test/support/socket_helper.py +++ b/Lib/test/support/socket_helper.py @@ -63,7 +63,7 @@ def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM): http://bugs.python.org/issue2550 for more info. The following site also has a very thorough description about the implications of both REUSEADDR and EXCLUSIVEADDRUSE on Windows: - http://msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx) + https://learn.microsoft.com/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse XXX: although this approach is a vast improvement on previous attempts to elicit unused ports, it rests heavily on the assumption that the ephemeral From webhook-mailer at python.org Mon Mar 13 09:41:09 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 13 Mar 2023 13:41:09 -0000 Subject: [Python-checkins] Fix broken link to MSDN (GH-102355) Message-ID: https://github.com/python/cpython/commit/5e10479ede7329642049603d61cdb45f2c88d69d commit: 5e10479ede7329642049603d61cdb45f2c88d69d branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-13T06:41:01-07:00 summary: Fix broken link to MSDN (GH-102355) (cherry picked from commit 9a8b66b58c74236959a01d579e2c156d9c2e7cb3) Co-authored-by: ??? <109224573 at qq.com> files: M Lib/socket.py M Lib/test/support/socket_helper.py diff --git a/Lib/socket.py b/Lib/socket.py index 310b074ca278..379662903cf8 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -902,7 +902,7 @@ def create_server(address, *, family=AF_INET, backlog=None, reuse_port=False, # address, effectively preventing this one from accepting # connections. Also, it may set the process in a state where # it'll no longer respond to any signals or graceful kills. - # See: msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx + # See: https://learn.microsoft.com/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse if os.name not in ('nt', 'cygwin') and \ hasattr(_socket, 'SO_REUSEADDR'): try: diff --git a/Lib/test/support/socket_helper.py b/Lib/test/support/socket_helper.py index b51677383ebc..38c499bf722e 100644 --- a/Lib/test/support/socket_helper.py +++ b/Lib/test/support/socket_helper.py @@ -58,7 +58,7 @@ def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM): http://bugs.python.org/issue2550 for more info. The following site also has a very thorough description about the implications of both REUSEADDR and EXCLUSIVEADDRUSE on Windows: - http://msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx) + https://learn.microsoft.com/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse XXX: although this approach is a vast improvement on previous attempts to elicit unused ports, it rests heavily on the assumption that the ephemeral From webhook-mailer at python.org Mon Mar 13 09:42:38 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 13 Mar 2023 13:42:38 -0000 Subject: [Python-checkins] Fix broken link to MSDN (GH-102355) Message-ID: https://github.com/python/cpython/commit/8a99debc128fc87379eafcef26c48b7be40b5520 commit: 8a99debc128fc87379eafcef26c48b7be40b5520 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-13T06:42:30-07:00 summary: Fix broken link to MSDN (GH-102355) (cherry picked from commit 9a8b66b58c74236959a01d579e2c156d9c2e7cb3) Co-authored-by: ??? <109224573 at qq.com> files: M Lib/socket.py M Lib/test/support/socket_helper.py diff --git a/Lib/socket.py b/Lib/socket.py index 5a896bee7c49..b5d46eb32bda 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -909,7 +909,7 @@ def create_server(address, *, family=AF_INET, backlog=None, reuse_port=False, # address, effectively preventing this one from accepting # connections. Also, it may set the process in a state where # it'll no longer respond to any signals or graceful kills. - # See: msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx + # See: https://learn.microsoft.com/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse if os.name not in ('nt', 'cygwin') and \ hasattr(_socket, 'SO_REUSEADDR'): try: diff --git a/Lib/test/support/socket_helper.py b/Lib/test/support/socket_helper.py index 42b2a93398cb..50e1d4d56c9b 100644 --- a/Lib/test/support/socket_helper.py +++ b/Lib/test/support/socket_helper.py @@ -61,7 +61,7 @@ def find_unused_port(family=socket.AF_INET, socktype=socket.SOCK_STREAM): http://bugs.python.org/issue2550 for more info. The following site also has a very thorough description about the implications of both REUSEADDR and EXCLUSIVEADDRUSE on Windows: - http://msdn2.microsoft.com/en-us/library/ms740621(VS.85).aspx) + https://learn.microsoft.com/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse XXX: although this approach is a vast improvement on previous attempts to elicit unused ports, it rests heavily on the assumption that the ephemeral From webhook-mailer at python.org Mon Mar 13 10:24:09 2023 From: webhook-mailer at python.org (pablogsal) Date: Mon, 13 Mar 2023 14:24:09 -0000 Subject: [Python-checkins] [3.10] GH-101673: Fix pdb bug where local variable changes are lost after longlist (#101674) (#102633) Message-ID: https://github.com/python/cpython/commit/d4f8fafd2df3a6a1828c96f9347a14595ec438d1 commit: d4f8fafd2df3a6a1828c96f9347a14595ec438d1 branch: 3.10 author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: pablogsal date: 2023-03-13T14:24:01Z summary: [3.10] GH-101673: Fix pdb bug where local variable changes are lost after longlist (#101674) (#102633) GH-101673: Fix pdb bug where local variable changes are lost after longlist (#101674) (cherry picked from commit 5d677c556f03a34d1c2d86e4cc96025870c20c12) Co-authored-by: gaogaotiantian files: A Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index 7401a675253d..3bdb2ac36f71 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -104,15 +104,6 @@ def find_function(funcname, filename): return funcname, filename, lineno return None -def getsourcelines(obj): - lines, lineno = inspect.findsource(obj) - if inspect.isframe(obj) and obj.f_globals is obj.f_locals: - # must be a module frame: do not try to cut a block out of it - return lines, 1 - elif inspect.ismodule(obj): - return lines, 1 - return inspect.getblock(lines[lineno:]), lineno+1 - def lasti2lineno(code, lasti): linestarts = list(dis.findlinestarts(code)) linestarts.reverse() @@ -1273,7 +1264,7 @@ def do_longlist(self, arg): filename = self.curframe.f_code.co_filename breaklist = self.get_file_breaks(filename) try: - lines, lineno = getsourcelines(self.curframe) + lines, lineno = inspect.getsourcelines(self.curframe) except OSError as err: self.error(err) return @@ -1289,7 +1280,7 @@ def do_source(self, arg): except: return try: - lines, lineno = getsourcelines(obj) + lines, lineno = inspect.getsourcelines(obj) except (OSError, TypeError) as err: self.error(err) return diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 7f0bc719f0af..889262b1f193 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -1351,6 +1351,35 @@ def test_pdb_issue_43318(): 4 """ +def test_pdb_issue_gh_101673(): + """See GH-101673 + + Make sure ll won't revert local variable assignment + + >>> def test_function(): + ... a = 1 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... '!a = 2', + ... 'll', + ... 'p a', + ... 'continue' + ... ]): + ... test_function() + --Return-- + > (3)test_function()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) !a = 2 + (Pdb) ll + 1 def test_function(): + 2 a = 1 + 3 -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) p a + 2 + (Pdb) continue + """ + class PdbTestCase(unittest.TestCase): def tearDown(self): diff --git a/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst b/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst new file mode 100644 index 000000000000..4e673ba98115 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-09-19-40-41.gh-issue-101673.mX-Ppq.rst @@ -0,0 +1 @@ +Fix a :mod:`pdb` bug where ``ll`` clears the changes to local variables. From webhook-mailer at python.org Mon Mar 13 10:31:33 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 13 Mar 2023 14:31:33 -0000 Subject: [Python-checkins] [3.10] Fix duplicated words in the docs (#102645) Message-ID: https://github.com/python/cpython/commit/83ccaf2c09b9217622818f63a841892ce6e03508 commit: 83ccaf2c09b9217622818f63a841892ce6e03508 branch: 3.10 author: Alex Waygood committer: AlexWaygood date: 2023-03-13T14:31:25Z summary: [3.10] Fix duplicated words in the docs (#102645) (cherry-picked from commit f6ca71a) With grep utility found some duplicated words Co-authored-by: ??????? ???????? files: M Doc/library/base64.rst M Doc/reference/compound_stmts.rst diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 694c1666d023..244542304c4a 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -58,7 +58,7 @@ The modern interface provides: This allows an application to e.g. generate URL or filesystem safe Base64 strings. The default is ``None``, for which the standard Base64 alphabet is used. - May assert or raise a a :exc:`ValueError` if the length of *altchars* is not 2. Raises a + May assert or raise a :exc:`ValueError` if the length of *altchars* is not 2. Raises a :exc:`TypeError` if *altchars* is not a :term:`bytes-like object`. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 20c85a9c8677..8154147e75b1 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -729,7 +729,7 @@ keyword against a subject. Syntax: If the OR pattern fails, the AS pattern fails. Otherwise, the AS pattern binds the subject to the name on the right of the as keyword and succeeds. -``capture_pattern`` cannot be a a ``_``. +``capture_pattern`` cannot be a ``_``. In simple terms ``P as NAME`` will match with ``P``, and on success it will set ``NAME = ``. From webhook-mailer at python.org Mon Mar 13 10:32:00 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Mon, 13 Mar 2023 14:32:00 -0000 Subject: [Python-checkins] [3.11] Fix duplicated words in the docs (#102644) Message-ID: https://github.com/python/cpython/commit/a4fcd06c50bba8c58ee9fb0192f217b2ed821ae5 commit: a4fcd06c50bba8c58ee9fb0192f217b2ed821ae5 branch: 3.11 author: Alex Waygood committer: AlexWaygood date: 2023-03-13T14:31:50Z summary: [3.11] Fix duplicated words in the docs (#102644) (cherry-picked from commit f6ca71a422) With grep utility found some duplicated words Co-authored-by: ??????? ???????? files: M Doc/library/base64.rst M Doc/reference/compound_stmts.rst M Misc/NEWS.d/3.11.0a6.rst diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 4ca3768f827c..d5b6af8c1928 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -58,7 +58,7 @@ The modern interface provides: This allows an application to e.g. generate URL or filesystem safe Base64 strings. The default is ``None``, for which the standard Base64 alphabet is used. - May assert or raise a a :exc:`ValueError` if the length of *altchars* is not 2. Raises a + May assert or raise a :exc:`ValueError` if the length of *altchars* is not 2. Raises a :exc:`TypeError` if *altchars* is not a :term:`bytes-like object`. diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst index 52bb0b22b042..f0a8936c35bf 100644 --- a/Doc/reference/compound_stmts.rst +++ b/Doc/reference/compound_stmts.rst @@ -816,7 +816,7 @@ keyword against a subject. Syntax: If the OR pattern fails, the AS pattern fails. Otherwise, the AS pattern binds the subject to the name on the right of the as keyword and succeeds. -``capture_pattern`` cannot be a a ``_``. +``capture_pattern`` cannot be a ``_``. In simple terms ``P as NAME`` will match with ``P``, and on success it will set ``NAME = ``. diff --git a/Misc/NEWS.d/3.11.0a6.rst b/Misc/NEWS.d/3.11.0a6.rst index 68b80e46690d..8621edcfb04b 100644 --- a/Misc/NEWS.d/3.11.0a6.rst +++ b/Misc/NEWS.d/3.11.0a6.rst @@ -1055,7 +1055,7 @@ Patch by Victor Stinner. .. section: Build Building Python now requires support for floating point Not-a-Number (NaN): -remove the ``Py_NO_NAN`` macro. Patch by by Victor Stinner. +remove the ``Py_NO_NAN`` macro. Patch by Victor Stinner. .. From webhook-mailer at python.org Mon Mar 13 11:56:32 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 13 Mar 2023 15:56:32 -0000 Subject: [Python-checkins] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102631) Message-ID: https://github.com/python/cpython/commit/ca01cae1e91446c70fa569d4502c7cbba381e7ff commit: ca01cae1e91446c70fa569d4502c7cbba381e7ff branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-13T15:56:24Z summary: gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102631) files: M Python/ceval.c diff --git a/Python/ceval.c b/Python/ceval.c index b422d0ed34ed..92235519c993 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -13,7 +13,7 @@ #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_moduleobject.h" // PyModuleObject #include "pycore_opcode.h" // EXTRA_CASES -#include "pycore_pyerrors.h" // _PyErr_Fetch(), _PyErr_GetRaisedException() +#include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_range.h" // _PyRangeIterObject @@ -1783,18 +1783,15 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause) if (exc == NULL) { /* Reraise */ _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); - value = exc_info->exc_value; - if (Py_IsNone(value) || value == NULL) { + exc = exc_info->exc_value; + if (Py_IsNone(exc) || exc == NULL) { _PyErr_SetString(tstate, PyExc_RuntimeError, "No active exception to reraise"); return 0; } - assert(PyExceptionInstance_Check(value)); - type = PyExceptionInstance_Class(value); - Py_XINCREF(type); - Py_XINCREF(value); - PyObject *tb = PyException_GetTraceback(value); /* new ref */ - _PyErr_Restore(tstate, type, value, tb); + Py_INCREF(exc); + assert(PyExceptionInstance_Check(exc)); + _PyErr_SetRaisedException(tstate, exc); return 1; } @@ -2035,28 +2032,27 @@ call_exc_trace(Py_tracefunc func, PyObject *self, PyThreadState *tstate, _PyInterpreterFrame *f) { - PyObject *type, *value, *traceback, *orig_traceback, *arg; - int err; - _PyErr_Fetch(tstate, &type, &value, &orig_traceback); - if (value == NULL) { - value = Py_NewRef(Py_None); + PyObject *exc = _PyErr_GetRaisedException(tstate); + assert(exc && PyExceptionInstance_Check(exc)); + PyObject *type = PyExceptionInstance_Class(exc); + PyObject *traceback = PyException_GetTraceback(exc); + if (traceback == NULL) { + traceback = Py_NewRef(Py_None); } - _PyErr_NormalizeException(tstate, &type, &value, &orig_traceback); - traceback = (orig_traceback != NULL) ? orig_traceback : Py_None; - arg = PyTuple_Pack(3, type, value, traceback); + PyObject *arg = PyTuple_Pack(3, type, exc, traceback); + Py_XDECREF(traceback); + if (arg == NULL) { - _PyErr_Restore(tstate, type, value, orig_traceback); + _PyErr_SetRaisedException(tstate, exc); return; } - err = call_trace(func, self, tstate, f, PyTrace_EXCEPTION, arg); + int err = call_trace(func, self, tstate, f, PyTrace_EXCEPTION, arg); Py_DECREF(arg); if (err == 0) { - _PyErr_Restore(tstate, type, value, orig_traceback); + _PyErr_SetRaisedException(tstate, exc); } else { - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(orig_traceback); + Py_XDECREF(exc); } } From webhook-mailer at python.org Mon Mar 13 11:59:28 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 13 Mar 2023 15:59:28 -0000 Subject: [Python-checkins] gh-87092: refactor assemble() to a number of separate functions, which do not need the compiler struct (#102562) Message-ID: https://github.com/python/cpython/commit/634cb61909b1392f0eef3e749931777adb54f16e commit: 634cb61909b1392f0eef3e749931777adb54f16e branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-13T15:59:20Z summary: gh-87092: refactor assemble() to a number of separate functions, which do not need the compiler struct (#102562) files: M Lib/test/support/bytecode_helper.py M Lib/test/test_peepholer.py M Python/compile.c diff --git a/Lib/test/support/bytecode_helper.py b/Lib/test/support/bytecode_helper.py index 190fe8723b1f..1d9b889c9209 100644 --- a/Lib/test/support/bytecode_helper.py +++ b/Lib/test/support/bytecode_helper.py @@ -125,7 +125,7 @@ def complete_insts_info(self, insts): assert isinstance(item, tuple) inst = list(reversed(item)) opcode = dis.opmap[inst.pop()] - oparg = inst.pop() if opcode in self.HAS_ARG_OR_TARGET else 0 + oparg = inst.pop() loc = inst + [-1] * (4 - len(inst)) res.append((opcode, oparg, *loc)) return res diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index aea234e38705..9ff017da53c2 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -995,15 +995,19 @@ def test_conditional_jump_forward_non_const_condition(self): ('LOAD_CONST', 2, 13), lbl, ('LOAD_CONST', 3, 14), + ('RETURN_VALUE', 14), ] - expected = [ + expected_insts = [ ('LOAD_NAME', 1, 11), ('POP_JUMP_IF_TRUE', lbl := self.Label(), 12), - ('LOAD_CONST', 2, 13), + ('LOAD_CONST', 1, 13), lbl, - ('LOAD_CONST', 3, 14) + ('RETURN_CONST', 2, 14), ] - self.cfg_optimization_test(insts, expected, consts=list(range(5))) + self.cfg_optimization_test(insts, + expected_insts, + consts=[0, 1, 2, 3, 4], + expected_consts=[0, 2, 3]) def test_conditional_jump_forward_const_condition(self): # The unreachable branch of the jump is removed, the jump @@ -1015,26 +1019,32 @@ def test_conditional_jump_forward_const_condition(self): ('LOAD_CONST', 2, 13), lbl, ('LOAD_CONST', 3, 14), + ('RETURN_VALUE', 14), ] - expected = [ - ('NOP', None, 11), - ('NOP', None, 12), - ('LOAD_CONST', 3, 14) + expected_insts = [ + ('NOP', 11), + ('NOP', 12), + ('RETURN_CONST', 1, 14), ] - self.cfg_optimization_test(insts, expected, consts=list(range(5))) + self.cfg_optimization_test(insts, + expected_insts, + consts=[0, 1, 2, 3, 4], + expected_consts=[0, 3]) def test_conditional_jump_backward_non_const_condition(self): insts = [ lbl1 := self.Label(), ('LOAD_NAME', 1, 11), ('POP_JUMP_IF_TRUE', lbl1, 12), - ('LOAD_CONST', 2, 13), + ('LOAD_NAME', 2, 13), + ('RETURN_VALUE', 13), ] expected = [ lbl := self.Label(), ('LOAD_NAME', 1, 11), ('POP_JUMP_IF_TRUE', lbl, 12), - ('LOAD_CONST', 2, 13) + ('LOAD_NAME', 2, 13), + ('RETURN_VALUE', 13), ] self.cfg_optimization_test(insts, expected, consts=list(range(5))) @@ -1042,16 +1052,17 @@ def test_conditional_jump_backward_const_condition(self): # The unreachable branch of the jump is removed insts = [ lbl1 := self.Label(), - ('LOAD_CONST', 1, 11), + ('LOAD_CONST', 3, 11), ('POP_JUMP_IF_TRUE', lbl1, 12), ('LOAD_CONST', 2, 13), + ('RETURN_VALUE', 13), ] - expected = [ + expected_insts = [ lbl := self.Label(), - ('NOP', None, 11), - ('JUMP', lbl, 12) + ('NOP', 11), + ('JUMP', lbl, 12), ] - self.cfg_optimization_test(insts, expected, consts=list(range(5))) + self.cfg_optimization_test(insts, expected_insts, consts=list(range(5))) if __name__ == "__main__": diff --git a/Python/compile.c b/Python/compile.c index 45c97b4f8ef0..29e55b8b30c5 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -308,7 +308,7 @@ typedef struct basicblock_ { block, not to be confused with b_next, which is next by control flow. */ struct basicblock_ *b_list; /* The label of this block if it is a jump target, -1 otherwise */ - int b_label; + jump_target_label b_label; /* Exception stack at start of block, used by assembler to create the exception handling table */ ExceptStack *b_exceptstack; /* pointer to an array of instructions, initially NULL */ @@ -501,7 +501,7 @@ instr_sequence_next_inst(instr_sequence *seq) { static jump_target_label instr_sequence_new_label(instr_sequence *seq) { - jump_target_label lbl = {seq->s_next_free_label++}; + jump_target_label lbl = {++seq->s_next_free_label}; return lbl; } @@ -606,6 +606,14 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { instruction *instr = &seq->s_instrs[i]; RETURN_IF_ERROR(cfg_builder_addop(g, instr->i_opcode, instr->i_oparg, instr->i_loc)); } + int nblocks = 0; + for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { + nblocks++; + } + if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { + PyErr_NoMemory(); + return ERROR; + } return SUCCESS; } @@ -937,6 +945,7 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset) static bool cfg_builder_check(cfg_builder *g) { + assert(g->g_entryblock->b_iused > 0); for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) { assert(!_PyMem_IsPtrFreed(block)); if (block->b_instr != NULL) { @@ -1086,7 +1095,7 @@ cfg_builder_new_block(cfg_builder *g) /* Extend the singly linked list of blocks with new block. */ b->b_list = g->g_block_list; g->g_block_list = b; - b->b_label = -1; + b->b_label = NO_LABEL; return b; } @@ -1267,11 +1276,21 @@ basicblock_addop(basicblock *b, int opcode, int oparg, location loc) static bool cfg_builder_current_block_is_terminated(cfg_builder *g) { - if (IS_LABEL(g->g_current_label)) { + struct cfg_instr *last = basicblock_last_instr(g->g_curblock); + if (last && IS_TERMINATOR_OPCODE(last->i_opcode)) { return true; } - struct cfg_instr *last = basicblock_last_instr(g->g_curblock); - return last && IS_TERMINATOR_OPCODE(last->i_opcode); + if (IS_LABEL(g->g_current_label)) { + if (last || IS_LABEL(g->g_curblock->b_label)) { + return true; + } + else { + /* current block is empty, label it */ + g->g_curblock->b_label = g->g_current_label; + g->g_current_label = NO_LABEL; + } + } + return false; } static int @@ -1282,7 +1301,7 @@ cfg_builder_maybe_start_new_block(cfg_builder *g) if (b == NULL) { return ERROR; } - b->b_label = g->g_current_label.id; + b->b_label = g->g_current_label; g->g_current_label = NO_LABEL; cfg_builder_use_next_block(g, b); } @@ -1432,50 +1451,49 @@ merge_consts_recursive(PyObject *const_cache, PyObject *o) } static Py_ssize_t -compiler_add_const(struct compiler *c, PyObject *o) +compiler_add_const(PyObject *const_cache, struct compiler_unit *u, PyObject *o) { - PyObject *key = merge_consts_recursive(c->c_const_cache, o); + assert(PyDict_CheckExact(const_cache)); + PyObject *key = merge_consts_recursive(const_cache, o); if (key == NULL) { return ERROR; } - Py_ssize_t arg = dict_add_o(c->u->u_consts, key); + Py_ssize_t arg = dict_add_o(u->u_consts, key); Py_DECREF(key); return arg; } static int -compiler_addop_load_const(struct compiler *c, location loc, PyObject *o) +compiler_addop_load_const(PyObject *const_cache, struct compiler_unit *u, location loc, PyObject *o) { - Py_ssize_t arg = compiler_add_const(c, o); + Py_ssize_t arg = compiler_add_const(const_cache, u, o); if (arg < 0) { return ERROR; } - return codegen_addop_i(INSTR_SEQUENCE(c), LOAD_CONST, arg, loc); + return codegen_addop_i(&u->u_instr_sequence, LOAD_CONST, arg, loc); } static int -compiler_addop_o(struct compiler *c, location loc, +compiler_addop_o(struct compiler_unit *u, location loc, int opcode, PyObject *dict, PyObject *o) { Py_ssize_t arg = dict_add_o(dict, o); if (arg < 0) { return ERROR; } - return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc); + return codegen_addop_i(&u->u_instr_sequence, opcode, arg, loc); } static int -compiler_addop_name(struct compiler *c, location loc, +compiler_addop_name(struct compiler_unit *u, location loc, int opcode, PyObject *dict, PyObject *o) { - Py_ssize_t arg; - - PyObject *mangled = _Py_Mangle(c->u->u_private, o); + PyObject *mangled = _Py_Mangle(u->u_private, o); if (!mangled) { return ERROR; } - arg = dict_add_o(dict, mangled); + Py_ssize_t arg = dict_add_o(dict, mangled); Py_DECREF(mangled); if (arg < 0) { return ERROR; @@ -1488,7 +1506,7 @@ compiler_addop_name(struct compiler *c, location loc, arg <<= 1; arg |= 1; } - return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc); + return codegen_addop_i(&u->u_instr_sequence, opcode, arg, loc); } /* Add an opcode with an integer argument */ @@ -1509,7 +1527,7 @@ codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc) static int codegen_addop_j(instr_sequence *seq, location loc, - int opcode, jump_target_label target) + int opcode, jump_target_label target) { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); @@ -1527,7 +1545,7 @@ codegen_addop_j(instr_sequence *seq, location loc, } #define ADDOP_LOAD_CONST(C, LOC, O) \ - RETURN_IF_ERROR(compiler_addop_load_const((C), (LOC), (O))) + RETURN_IF_ERROR(compiler_addop_load_const((C)->c_const_cache, (C)->u, (LOC), (O))) /* Same as ADDOP_LOAD_CONST, but steals a reference. */ #define ADDOP_LOAD_CONST_NEW(C, LOC, O) { \ @@ -1535,7 +1553,7 @@ codegen_addop_j(instr_sequence *seq, location loc, if (__new_const == NULL) { \ return ERROR; \ } \ - if (compiler_addop_load_const((C), (LOC), __new_const) < 0) { \ + if (compiler_addop_load_const((C)->c_const_cache, (C)->u, (LOC), __new_const) < 0) { \ Py_DECREF(__new_const); \ return ERROR; \ } \ @@ -1544,7 +1562,7 @@ codegen_addop_j(instr_sequence *seq, location loc, #define ADDOP_N(C, LOC, OP, O, TYPE) { \ assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ - if (compiler_addop_o((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O)) < 0) { \ + if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_ ## TYPE, (O)) < 0) { \ Py_DECREF((O)); \ return ERROR; \ } \ @@ -1552,7 +1570,7 @@ codegen_addop_j(instr_sequence *seq, location loc, } #define ADDOP_NAME(C, LOC, OP, O, TYPE) \ - RETURN_IF_ERROR(compiler_addop_name((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O))) + RETURN_IF_ERROR(compiler_addop_name((C)->u, (LOC), (OP), (C)->u->u_ ## TYPE, (O))) #define ADDOP_I(C, LOC, OP, O) \ RETURN_IF_ERROR(codegen_addop_i(INSTR_SEQUENCE(C), (OP), (O), (LOC))) @@ -2556,7 +2574,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) if (c->c_optimize < 2) { docstring = _PyAST_GetDocString(body); } - if (compiler_add_const(c, docstring ? docstring : Py_None) < 0) { + if (compiler_add_const(c->c_const_cache, c->u, docstring ? docstring : Py_None) < 0) { compiler_exit_scope(c); return ERROR; } @@ -2924,7 +2942,7 @@ compiler_lambda(struct compiler *c, expr_ty e) /* Make None the first constant, so the lambda can't have a docstring. */ - RETURN_IF_ERROR(compiler_add_const(c, Py_None)); + RETURN_IF_ERROR(compiler_add_const(c->c_const_cache, c->u, Py_None)); c->u->u_argcount = asdl_seq_LEN(args->args); c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); @@ -4915,7 +4933,7 @@ compiler_call_simple_kw_helper(struct compiler *c, location loc, keyword_ty kw = asdl_seq_GET(keywords, i); PyTuple_SET_ITEM(names, i, Py_NewRef(kw->arg)); } - Py_ssize_t arg = compiler_add_const(c, names); + Py_ssize_t arg = compiler_add_const(c->c_const_cache, c->u, names); if (arg < 0) { return ERROR; } @@ -7372,7 +7390,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { if (explicit_jump == NULL) { return ERROR; } - basicblock_addop(explicit_jump, JUMP, b->b_next->b_label, NO_LOCATION); + basicblock_addop(explicit_jump, JUMP, b->b_next->b_label.id, NO_LOCATION); explicit_jump->b_cold = 1; explicit_jump->b_next = b->b_next; b->b_next = explicit_jump; @@ -7676,13 +7694,33 @@ assemble_emit_location(struct assembler* a, location loc, int isize) return write_location_info_entry(a, loc, isize); } -/* assemble_emit() +static int +assemble_location_info(struct assembler *a, basicblock *entryblock, int firstlineno) +{ + a->a_lineno = firstlineno; + location loc = NO_LOCATION; + int size = 0; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int j = 0; j < b->b_iused; j++) { + if (!same_location(loc, b->b_instr[j].i_loc)) { + RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); + loc = b->b_instr[j].i_loc; + size = 0; + } + size += instr_size(&b->b_instr[j]); + } + } + RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); + return SUCCESS; +} + +/* assemble_emit_instr() Extend the bytecode with a new instruction. Update lnotab if necessary. */ static int -assemble_emit(struct assembler *a, struct cfg_instr *i) +assemble_emit_instr(struct assembler *a, struct cfg_instr *i) { Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); _Py_CODEUNIT *code; @@ -7700,6 +7738,35 @@ assemble_emit(struct assembler *a, struct cfg_instr *i) return SUCCESS; } +static int merge_const_one(PyObject *const_cache, PyObject **obj); + +static int +assemble_emit(struct assembler *a, basicblock *entryblock, int first_lineno, + PyObject *const_cache) +{ + RETURN_IF_ERROR(assemble_init(a, first_lineno)); + + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int j = 0; j < b->b_iused; j++) { + RETURN_IF_ERROR(assemble_emit_instr(a, &b->b_instr[j])); + } + } + + RETURN_IF_ERROR(assemble_location_info(a, entryblock, a->a_lineno)); + + RETURN_IF_ERROR(assemble_exception_table(a, entryblock)); + + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off)); + RETURN_IF_ERROR(merge_const_one(const_cache, &a->a_except_table)); + + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, a->a_location_off)); + RETURN_IF_ERROR(merge_const_one(const_cache, &a->a_linetable)); + + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT))); + RETURN_IF_ERROR(merge_const_one(const_cache, &a->a_bytecode)); + return SUCCESS; +} + static int normalize_jumps_in_block(cfg_builder *g, basicblock *b) { struct cfg_instr *last = basicblock_last_instr(b); @@ -7760,7 +7827,7 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) { if (backwards_jump == NULL) { return ERROR; } - basicblock_addop(backwards_jump, JUMP, target->b_label, NO_LOCATION); + basicblock_addop(backwards_jump, JUMP, target->b_label.id, NO_LOCATION); backwards_jump->b_instr[0].i_target = target; last->i_opcode = reversed_opcode; last->i_target = b->b_next; @@ -7963,9 +8030,9 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals) static int add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock, - struct compiler *c) + int nlocals, + int nparams) { - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); if (nlocals == 0) { return SUCCESS; } @@ -7986,7 +8053,6 @@ add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock, // First origin of being uninitialized: // The non-parameter locals in the entry block. - int nparams = (int)PyList_GET_SIZE(c->u->u_ste->ste_varnames); uint64_t start_mask = 0; for (int i = nparams; i < nlocals; i++) { start_mask |= (uint64_t)1 << i; @@ -8092,7 +8158,7 @@ compute_code_flags(struct compiler *c) static int merge_const_one(PyObject *const_cache, PyObject **obj) { - PyDict_CheckExact(const_cache); + assert(PyDict_CheckExact(const_cache)); PyObject *key = _PyCode_ConstantKey(*obj); if (key == NULL) { return ERROR; @@ -8122,29 +8188,29 @@ extern void _Py_set_localsplus_info(int, PyObject *, unsigned char, PyObject *, PyObject *); static void -compute_localsplus_info(struct compiler *c, int nlocalsplus, +compute_localsplus_info(struct compiler_unit *u, int nlocalsplus, PyObject *names, PyObject *kinds) { PyObject *k, *v; Py_ssize_t pos = 0; - while (PyDict_Next(c->u->u_varnames, &pos, &k, &v)) { + while (PyDict_Next(u->u_varnames, &pos, &k, &v)) { int offset = (int)PyLong_AS_LONG(v); assert(offset >= 0); assert(offset < nlocalsplus); // For now we do not distinguish arg kinds. _PyLocals_Kind kind = CO_FAST_LOCAL; - if (PyDict_GetItem(c->u->u_cellvars, k) != NULL) { + if (PyDict_GetItem(u->u_cellvars, k) != NULL) { kind |= CO_FAST_CELL; } _Py_set_localsplus_info(offset, k, kind, names, kinds); } - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); // This counter mirrors the fix done in fix_cell_offsets(). int numdropped = 0; pos = 0; - while (PyDict_Next(c->u->u_cellvars, &pos, &k, &v)) { - if (PyDict_GetItem(c->u->u_varnames, k) != NULL) { + while (PyDict_Next(u->u_cellvars, &pos, &k, &v)) { + if (PyDict_GetItem(u->u_varnames, k) != NULL) { // Skip cells that are already covered by locals. numdropped += 1; continue; @@ -8157,7 +8223,7 @@ compute_localsplus_info(struct compiler *c, int nlocalsplus, } pos = 0; - while (PyDict_Next(c->u->u_freevars, &pos, &k, &v)) { + while (PyDict_Next(u->u_freevars, &pos, &k, &v)) { int offset = (int)PyLong_AS_LONG(v); assert(offset >= 0); offset += nlocals - numdropped; @@ -8167,19 +8233,20 @@ compute_localsplus_info(struct compiler *c, int nlocalsplus, } static PyCodeObject * -makecode(struct compiler *c, struct assembler *a, PyObject *constslist, - int maxdepth, int nlocalsplus, int code_flags) +makecode(struct compiler_unit *u, struct assembler *a, PyObject *const_cache, + PyObject *constslist, int maxdepth, int nlocalsplus, int code_flags, + PyObject *filename) { PyCodeObject *co = NULL; PyObject *names = NULL; PyObject *consts = NULL; PyObject *localsplusnames = NULL; PyObject *localspluskinds = NULL; - names = dict_keys_inorder(c->u->u_names, 0); + names = dict_keys_inorder(u->u_names, 0); if (!names) { goto error; } - if (merge_const_one(c->c_const_cache, &names) < 0) { + if (merge_const_one(const_cache, &names) < 0) { goto error; } @@ -8187,17 +8254,17 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, if (consts == NULL) { goto error; } - if (merge_const_one(c->c_const_cache, &consts) < 0) { + if (merge_const_one(const_cache, &consts) < 0) { goto error; } - assert(c->u->u_posonlyargcount < INT_MAX); - assert(c->u->u_argcount < INT_MAX); - assert(c->u->u_kwonlyargcount < INT_MAX); - int posonlyargcount = (int)c->u->u_posonlyargcount; - int posorkwargcount = (int)c->u->u_argcount; + assert(u->u_posonlyargcount < INT_MAX); + assert(u->u_argcount < INT_MAX); + assert(u->u_kwonlyargcount < INT_MAX); + int posonlyargcount = (int)u->u_posonlyargcount; + int posorkwargcount = (int)u->u_argcount; assert(INT_MAX - posonlyargcount - posorkwargcount > 0); - int kwonlyargcount = (int)c->u->u_kwonlyargcount; + int kwonlyargcount = (int)u->u_kwonlyargcount; localsplusnames = PyTuple_New(nlocalsplus); if (localsplusnames == NULL) { @@ -8207,16 +8274,16 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, if (localspluskinds == NULL) { goto error; } - compute_localsplus_info(c, nlocalsplus, localsplusnames, localspluskinds); + compute_localsplus_info(u, nlocalsplus, localsplusnames, localspluskinds); struct _PyCodeConstructor con = { - .filename = c->c_filename, - .name = c->u->u_name, - .qualname = c->u->u_qualname ? c->u->u_qualname : c->u->u_name, + .filename = filename, + .name = u->u_name, + .qualname = u->u_qualname ? u->u_qualname : u->u_name, .flags = code_flags, .code = a->a_bytecode, - .firstlineno = c->u->u_firstlineno, + .firstlineno = u->u_firstlineno, .linetable = a->a_linetable, .consts = consts, @@ -8238,7 +8305,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, goto error; } - if (merge_const_one(c->c_const_cache, &localsplusnames) < 0) { + if (merge_const_one(const_cache, &localsplusnames) < 0) { goto error; } con.localsplusnames = localsplusnames; @@ -8289,7 +8356,7 @@ dump_basicblock(const basicblock *b) { const char *b_return = basicblock_returns(b) ? "return " : ""; fprintf(stderr, "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, offset: %d %s\n", - b->b_label, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, + b->b_label.id, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, b->b_startdepth, b->b_offset, b_return); if (b->b_instr) { int i; @@ -8316,11 +8383,11 @@ static int duplicate_exits_without_lineno(cfg_builder *g); static int * -build_cellfixedoffsets(struct compiler *c) +build_cellfixedoffsets(struct compiler_unit *u) { - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(c->u->u_freevars); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars); int noffsets = ncellvars + nfreevars; int *fixed = PyMem_New(int, noffsets); @@ -8334,8 +8401,8 @@ build_cellfixedoffsets(struct compiler *c) PyObject *varname, *cellindex; Py_ssize_t pos = 0; - while (PyDict_Next(c->u->u_cellvars, &pos, &varname, &cellindex)) { - PyObject *varindex = PyDict_GetItem(c->u->u_varnames, varname); + while (PyDict_Next(u->u_cellvars, &pos, &varname, &cellindex)) { + PyObject *varindex = PyDict_GetItem(u->u_varnames, varname); if (varindex != NULL) { assert(PyLong_AS_LONG(cellindex) < INT_MAX); assert(PyLong_AS_LONG(varindex) < INT_MAX); @@ -8349,17 +8416,17 @@ build_cellfixedoffsets(struct compiler *c) } static int -insert_prefix_instructions(struct compiler *c, basicblock *entryblock, +insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock, int *fixed, int nfreevars, int code_flags) { - assert(c->u->u_firstlineno > 0); + assert(u->u_firstlineno > 0); /* Add the generator prefix instructions. */ if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { struct cfg_instr make_gen = { .i_opcode = RETURN_GENERATOR, .i_oparg = 0, - .i_loc = LOCATION(c->u->u_firstlineno, c->u->u_firstlineno, -1, -1), + .i_loc = LOCATION(u->u_firstlineno, u->u_firstlineno, -1, -1), .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, 0, &make_gen)); @@ -8373,12 +8440,12 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, } /* Set up cells for any variable that escapes, to be put in a closure. */ - const int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars); + const int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); if (ncellvars) { - // c->u->u_cellvars has the cells out of order so we sort them + // u->u_cellvars has the cells out of order so we sort them // before adding the MAKE_CELL instructions. Note that we // adjust for arg cells, which come first. - const int nvars = ncellvars + (int)PyDict_GET_SIZE(c->u->u_varnames); + const int nvars = ncellvars + (int)PyDict_GET_SIZE(u->u_varnames); int *sorted = PyMem_RawCalloc(nvars, sizeof(int)); if (sorted == NULL) { PyErr_NoMemory(); @@ -8447,11 +8514,11 @@ guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) { } static int -fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap) +fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap) { - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(c->u->u_freevars); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars); int noffsets = ncellvars + nfreevars; // First deal with duplicates (arg cells). @@ -8491,8 +8558,6 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap) return numdropped; } -static void -propagate_line_numbers(basicblock *entryblock); #ifndef NDEBUG @@ -8589,30 +8654,30 @@ remove_redundant_jumps(cfg_builder *g) { } static int -prepare_localsplus(struct compiler* c, cfg_builder *g, int code_flags) +prepare_localsplus(struct compiler_unit* u, cfg_builder *g, int code_flags) { - assert(PyDict_GET_SIZE(c->u->u_varnames) < INT_MAX); - assert(PyDict_GET_SIZE(c->u->u_cellvars) < INT_MAX); - assert(PyDict_GET_SIZE(c->u->u_freevars) < INT_MAX); - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(c->u->u_freevars); + assert(PyDict_GET_SIZE(u->u_varnames) < INT_MAX); + assert(PyDict_GET_SIZE(u->u_cellvars) < INT_MAX); + assert(PyDict_GET_SIZE(u->u_freevars) < INT_MAX); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars); assert(INT_MAX - nlocals - ncellvars > 0); assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); int nlocalsplus = nlocals + ncellvars + nfreevars; - int* cellfixedoffsets = build_cellfixedoffsets(c); + int* cellfixedoffsets = build_cellfixedoffsets(u); if (cellfixedoffsets == NULL) { return ERROR; } // This must be called before fix_cell_offsets(). - if (insert_prefix_instructions(c, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { + if (insert_prefix_instructions(u, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { PyMem_Free(cellfixedoffsets); return ERROR; } - int numdropped = fix_cell_offsets(c, g->g_entryblock, cellfixedoffsets); + int numdropped = fix_cell_offsets(u, g->g_entryblock, cellfixedoffsets); PyMem_Free(cellfixedoffsets); // At this point we're done with it. cellfixedoffsets = NULL; if (numdropped < 0) { @@ -8636,176 +8701,127 @@ add_return_at_end(struct compiler *c, int addNone) return SUCCESS; } -static PyCodeObject * -assemble(struct compiler *c, int addNone) -{ - PyCodeObject *co = NULL; - PyObject *consts = NULL; - cfg_builder g_; - cfg_builder *g = &g_; - struct assembler a; - memset(&a, 0, sizeof(struct assembler)); - - int code_flags = compute_code_flags(c); - if (code_flags < 0) { - return NULL; - } - - if (add_return_at_end(c, addNone) < 0) { - return NULL; - } - - /** Preprocessing **/ - if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), g) < 0) { - goto error; - } - assert(cfg_builder_check(g)); - - int nblocks = 0; - for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { - nblocks++; - } - if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { - PyErr_NoMemory(); - goto error; - } +static void propagate_line_numbers(basicblock *entryblock); +static int +resolve_line_numbers(struct compiler_unit *u, cfg_builder *g) +{ /* Set firstlineno if it wasn't explicitly set. */ - if (!c->u->u_firstlineno) { + if (!u->u_firstlineno) { if (g->g_entryblock->b_instr && g->g_entryblock->b_instr->i_loc.lineno) { - c->u->u_firstlineno = g->g_entryblock->b_instr->i_loc.lineno; + u->u_firstlineno = g->g_entryblock->b_instr->i_loc.lineno; } else { - c->u->u_firstlineno = 1; + u->u_firstlineno = 1; } } + RETURN_IF_ERROR(duplicate_exits_without_lineno(g)); + propagate_line_numbers(g->g_entryblock); + guarantee_lineno_for_exits(g->g_entryblock, u->u_firstlineno); + return SUCCESS; +} +static int +optimize_code_unit(cfg_builder *g, PyObject *consts, PyObject *const_cache, + int code_flags, int nlocals, int nparams) +{ + assert(cfg_builder_check(g)); + /** Preprocessing **/ /* Map labels to targets and mark exception handlers */ - if (translate_jump_labels_to_targets(g->g_entryblock) < 0) { - goto error; - } - if (mark_except_handlers(g->g_entryblock) < 0) { - goto error; - } - if (label_exception_targets(g->g_entryblock)) { - goto error; - } + RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock)); + RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock)); + RETURN_IF_ERROR(label_exception_targets(g->g_entryblock)); /** Optimization **/ - consts = consts_dict_keys_inorder(c->u->u_consts); + RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache)); + RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts)); + RETURN_IF_ERROR( + add_checks_for_loads_of_uninitialized_variables( + g->g_entryblock, nlocals, nparams)); + + RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags)); + return SUCCESS; +} + +static PyCodeObject * +assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, + int code_flags, PyObject *filename) +{ + PyCodeObject *co = NULL; + PyObject *consts = consts_dict_keys_inorder(u->u_consts); if (consts == NULL) { goto error; } - if (optimize_cfg(g, consts, c->c_const_cache)) { - goto error; - } - if (remove_unused_consts(g->g_entryblock, consts) < 0) { + cfg_builder g; + if (instr_sequence_to_cfg(&u->u_instr_sequence, &g) < 0) { goto error; } - if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) { + int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); + if (optimize_code_unit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { goto error; } - /** line numbers (TODO: move this before optimization stage) */ - if (duplicate_exits_without_lineno(g) < 0) { - goto error; - } - propagate_line_numbers(g->g_entryblock); - guarantee_lineno_for_exits(g->g_entryblock, c->u->u_firstlineno); + /** Assembly **/ - if (push_cold_blocks_to_end(g, code_flags) < 0) { + if (resolve_line_numbers(u, &g) < 0) { goto error; } - /** Assembly **/ - - int nlocalsplus = prepare_localsplus(c, g, code_flags); + int nlocalsplus = prepare_localsplus(u, &g, code_flags); if (nlocalsplus < 0) { goto error; } - int maxdepth = stackdepth(g->g_entryblock, code_flags); + int maxdepth = stackdepth(g.g_entryblock, code_flags); if (maxdepth < 0) { goto error; } /* TO DO -- For 3.12, make sure that `maxdepth <= MAX_ALLOWED_STACK_USE` */ - convert_exception_handlers_to_nops(g->g_entryblock); + convert_exception_handlers_to_nops(g.g_entryblock); /* Order of basic blocks must have been determined by now */ - if (normalize_jumps(g) < 0) { + if (normalize_jumps(&g) < 0) { goto error; } - assert(no_redundant_jumps(g)); - assert(opcode_metadata_is_sane(g)); + assert(no_redundant_jumps(&g)); + assert(opcode_metadata_is_sane(&g)); /* Can't modify the bytecode after computing jump offsets. */ - assemble_jump_offsets(g->g_entryblock); + assemble_jump_offsets(g.g_entryblock); - /* Create assembler */ - if (assemble_init(&a, c->u->u_firstlineno) < 0) { - goto error; - } - - /* Emit code. */ - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - for (int j = 0; j < b->b_iused; j++) { - if (assemble_emit(&a, &b->b_instr[j]) < 0) { - goto error; - } - } + struct assembler a; + int res = assemble_emit(&a, g.g_entryblock, u->u_firstlineno, const_cache); + if (res == SUCCESS) { + co = makecode(u, &a, const_cache, consts, maxdepth, nlocalsplus, + code_flags, filename); } + assemble_free(&a); - /* Emit location info */ - a.a_lineno = c->u->u_firstlineno; - location loc = NO_LOCATION; - int size = 0; - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - for (int j = 0; j < b->b_iused; j++) { - if (!same_location(loc, b->b_instr[j].i_loc)) { - if (assemble_emit_location(&a, loc, size)) { - goto error; - } - loc = b->b_instr[j].i_loc; - size = 0; - } - size += instr_size(&b->b_instr[j]); - } - } - if (assemble_emit_location(&a, loc, size)) { - goto error; - } + error: + Py_XDECREF(consts); + cfg_builder_fini(&g); + return co; +} - if (assemble_exception_table(&a, g->g_entryblock) < 0) { - goto error; - } - if (_PyBytes_Resize(&a.a_except_table, a.a_except_table_off) < 0) { - goto error; - } - if (merge_const_one(c->c_const_cache, &a.a_except_table) < 0) { - goto error; - } +static PyCodeObject * +assemble(struct compiler *c, int addNone) +{ + struct compiler_unit *u = c->u; + PyObject *const_cache = c->c_const_cache; + PyObject *filename = c->c_filename; - if (_PyBytes_Resize(&a.a_linetable, a.a_location_off) < 0) { - goto error; - } - if (merge_const_one(c->c_const_cache, &a.a_linetable) < 0) { - goto error; + int code_flags = compute_code_flags(c); + if (code_flags < 0) { + return NULL; } - if (_PyBytes_Resize(&a.a_bytecode, a.a_offset * sizeof(_Py_CODEUNIT)) < 0) { - goto error; - } - if (merge_const_one(c->c_const_cache, &a.a_bytecode) < 0) { - goto error; + if (add_return_at_end(c, addNone) < 0) { + return NULL; } - co = makecode(c, &a, consts, maxdepth, nlocalsplus, code_flags); - error: - Py_XDECREF(consts); - cfg_builder_fini(g); - assemble_free(&a); - return co; + return assemble_code_unit(u, const_cache, code_flags, filename); } static PyObject* @@ -9529,8 +9545,8 @@ translate_jump_labels_to_targets(basicblock *entryblock) { int max_label = -1; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (b->b_label > max_label) { - max_label = b->b_label; + if (b->b_label.id > max_label) { + max_label = b->b_label.id; } } size_t mapsize = sizeof(basicblock *) * (max_label + 1); @@ -9541,8 +9557,8 @@ translate_jump_labels_to_targets(basicblock *entryblock) } memset(label2block, 0, mapsize); for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (b->b_label >= 0) { - label2block[b->b_label] = b; + if (b->b_label.id >= 0) { + label2block[b->b_label.id] = b; } } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { @@ -9554,7 +9570,7 @@ translate_jump_labels_to_targets(basicblock *entryblock) assert(lbl >= 0 && lbl <= max_label); instr->i_target = label2block[lbl]; assert(instr->i_target != NULL); - assert(instr->i_target->b_label == lbl); + assert(instr->i_target->b_label.id == lbl); } } } @@ -9828,9 +9844,15 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) if (PyErr_Occurred()) { goto error; } - int oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1)); - if (PyErr_Occurred()) { - goto error; + int oparg; + if (HAS_ARG(opcode)) { + oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1)); + if (PyErr_Occurred()) { + goto error; + } + } + else { + oparg = 0; } location loc; loc.lineno = PyLong_AsLong(PyTuple_GET_ITEM(item, 2)); @@ -9851,7 +9873,10 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) } RETURN_IF_ERROR(cfg_builder_addop(g, opcode, oparg, loc)); } - + struct cfg_instr *last = basicblock_last_instr(g->g_curblock); + if (last && !IS_TERMINATOR_OPCODE(last->i_opcode)) { + RETURN_IF_ERROR(cfg_builder_addop(g, RETURN_VALUE, 0, NO_LOCATION)); + } PyMem_Free(is_target); return SUCCESS; error: @@ -9859,6 +9884,38 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) return ERROR; } +static PyObject * +instr_sequence_to_instructions(instr_sequence *seq) { + PyObject *instructions = PyList_New(0); + if (instructions == NULL) { + return NULL; + } + for (int i = 0; i < seq->s_used; i++) { + instruction *instr = &seq->s_instrs[i]; + location loc = instr->i_loc; + int arg = HAS_TARGET(instr->i_opcode) ? + seq->s_labelmap[instr->i_oparg] : instr->i_oparg; + + PyObject *inst_tuple = Py_BuildValue( + "(iiiiii)", instr->i_opcode, arg, + loc.lineno, loc.end_lineno, + loc.col_offset, loc.end_col_offset); + if (inst_tuple == NULL) { + goto error; + } + + int res = PyList_Append(instructions, inst_tuple); + Py_DECREF(inst_tuple); + if (res != 0) { + goto error; + } + } + return instructions; +error: + Py_XDECREF(instructions); + return NULL; +} + static PyObject * cfg_to_instructions(cfg_builder *g) { @@ -9868,7 +9925,7 @@ cfg_to_instructions(cfg_builder *g) } int lbl = 0; for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - b->b_label = lbl; + b->b_label = (jump_target_label){lbl}; lbl += b->b_iused; } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { @@ -9876,7 +9933,7 @@ cfg_to_instructions(cfg_builder *g) struct cfg_instr *instr = &b->b_instr[i]; location loc = instr->i_loc; int arg = HAS_TARGET(instr->i_opcode) ? - instr->i_target->b_label : instr->i_oparg; + instr->i_target->b_label.id : instr->i_oparg; PyObject *inst_tuple = Py_BuildValue( "(iiiiii)", instr->i_opcode, arg, @@ -9932,19 +9989,10 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, goto finally; } - cfg_builder g; - if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), &g) < 0) { - goto finally; - } - if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { - goto finally; - } - - res = cfg_to_instructions(&g); + res = instr_sequence_to_instructions(INSTR_SEQUENCE(c)); finally: compiler_exit_scope(c); - cfg_builder_fini(&g); compiler_free(c); _PyArena_Free(arena); return res; @@ -9954,7 +10002,11 @@ PyObject * _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) { PyObject *res = NULL; - PyObject *const_cache = NULL; + PyObject *const_cache = PyDict_New(); + if (const_cache == NULL) { + return NULL; + } + cfg_builder g; memset(&g, 0, sizeof(cfg_builder)); if (cfg_builder_init(&g) < 0) { @@ -9963,19 +10015,13 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) if (instructions_to_cfg(instructions, &g) < 0) { goto error; } - const_cache = PyDict_New(); - if (const_cache == NULL) { - goto error; - } - if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { - goto error; - } - if (optimize_cfg(&g, consts, const_cache) < 0) { + int code_flags = 0, nlocals = 0, nparams = 0; + if (optimize_code_unit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { goto error; } res = cfg_to_instructions(&g); error: - Py_XDECREF(const_cache); + Py_DECREF(const_cache); cfg_builder_fini(&g); return res; } From webhook-mailer at python.org Mon Mar 13 14:35:46 2023 From: webhook-mailer at python.org (markshannon) Date: Mon, 13 Mar 2023 18:35:46 -0000 Subject: [Python-checkins] GH-100987: Don't cache references to the names and consts array in `_PyEval_EvalFrameDefault`. (#102640) Message-ID: https://github.com/python/cpython/commit/2d370da5702f07d044f0e612df68172852b89f42 commit: 2d370da5702f07d044f0e612df68172852b89f42 branch: main author: Mark Shannon committer: markshannon date: 2023-03-13T18:35:37Z summary: GH-100987: Don't cache references to the names and consts array in `_PyEval_EvalFrameDefault`. (#102640) * Rename local variables, names and consts, from the interpeter loop. Will allow non-code objects in frames for better introspection of C builtins and extensions. * Remove unused dummy variables. files: M Python/bytecodes.c M Python/ceval.c M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 178519fcb63c..a715bfd3289e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -70,8 +70,6 @@ dummy_func( unsigned int oparg, _Py_atomic_int * const eval_breaker, _PyCFrame cframe, - PyObject *names, - PyObject *consts, _Py_CODEUNIT *next_instr, PyObject **stack_pointer, PyObject *kwnames, @@ -115,7 +113,7 @@ dummy_func( } inst(LOAD_CONST, (-- value)) { - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); } @@ -554,7 +552,7 @@ dummy_func( } inst(RETURN_CONST, (--)) { - PyObject *retval = GETITEM(consts, oparg); + PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -844,7 +842,7 @@ dummy_func( } inst(STORE_NAME, (v -- )) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -862,7 +860,7 @@ dummy_func( } inst(DELETE_NAME, (--)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -956,7 +954,7 @@ dummy_func( #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -967,7 +965,7 @@ dummy_func( #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); Py_DECREF(v); Py_DECREF(owner); @@ -975,21 +973,21 @@ dummy_func( } inst(DELETE_ATTR, (owner --)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); Py_DECREF(owner); ERROR_IF(err, error); } inst(STORE_GLOBAL, (v --)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); Py_DECREF(v); ERROR_IF(err, error); } inst(DELETE_GLOBAL, (--)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); // Can't use ERROR_IF here. @@ -1003,7 +1001,7 @@ dummy_func( } inst(LOAD_NAME, ( -- v)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { _PyErr_Format(tstate, PyExc_SystemError, @@ -1074,7 +1072,7 @@ dummy_func( _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); DISPATCH_SAME_OPARG(); @@ -1082,7 +1080,7 @@ dummy_func( STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { @@ -1436,7 +1434,7 @@ dummy_func( _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1444,7 +1442,7 @@ dummy_func( STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg >> 1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ PyObject* meth = NULL; @@ -1525,7 +1523,7 @@ dummy_func( PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, LOAD_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); uint16_t hint = index; DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); if (DK_IS_UNICODE(dict->ma_keys)) { @@ -1616,7 +1614,7 @@ dummy_func( DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - PyObject *name = GETITEM(names, oparg >> 1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). @@ -1661,7 +1659,7 @@ dummy_func( PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, STORE_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *old_value; uint64_t new_version; @@ -1855,14 +1853,14 @@ dummy_func( } inst(IMPORT_NAME, (level, fromlist -- res)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(IMPORT_FROM, (from -- from, res)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); ERROR_IF(res == NULL, error); } @@ -2360,8 +2358,8 @@ dummy_func( inst(KW_NAMES, (--)) { assert(kwnames == NULL); - assert(oparg < PyTuple_GET_SIZE(consts)); - kwnames = GETITEM(consts, oparg); + assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); + kwnames = GETITEM(frame->f_code->co_consts, oparg); } // Cache layout: counter/1, func_version/2, min_args/1 diff --git a/Python/ceval.c b/Python/ceval.c index 92235519c993..7d60cf987e9c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -773,18 +773,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int /* Local "register" variables. * These are cached values from the frame and code object. */ - PyObject *names; - PyObject *consts; _Py_CODEUNIT *next_instr; PyObject **stack_pointer; /* Sets the above local variables from the frame */ #define SET_LOCALS_FROM_FRAME() \ - { \ - PyCodeObject *co = frame->f_code; \ - names = co->co_names; \ - consts = co->co_consts; \ - } \ assert(_PyInterpreterFrame_LASTI(frame) >= -1); \ /* Jump back to the last instruction executed... */ \ next_instr = frame->prev_instr + 1; \ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 21073cbf978c..631b7844f9ed 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -50,7 +50,7 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); STACK_GROW(1); stack_pointer[-1] = value; @@ -101,7 +101,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); _tmp_1 = value; } @@ -150,7 +150,7 @@ PyObject *_tmp_2; { PyObject *value; - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); _tmp_2 = value; } @@ -744,7 +744,7 @@ } TARGET(RETURN_CONST) { - PyObject *retval = GETITEM(consts, oparg); + PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1083,7 +1083,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -1103,7 +1103,7 @@ } TARGET(DELETE_NAME) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -1217,7 +1217,7 @@ #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1228,7 +1228,7 @@ #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); Py_DECREF(v); Py_DECREF(owner); @@ -1240,7 +1240,7 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); Py_DECREF(owner); if (err) goto pop_1_error; @@ -1250,7 +1250,7 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); Py_DECREF(v); if (err) goto pop_1_error; @@ -1259,7 +1259,7 @@ } TARGET(DELETE_GLOBAL) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); // Can't use ERROR_IF here. @@ -1275,7 +1275,7 @@ TARGET(LOAD_NAME) { PyObject *v; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { _PyErr_Format(tstate, PyExc_SystemError, @@ -1347,7 +1347,7 @@ _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); DISPATCH_SAME_OPARG(); @@ -1355,7 +1355,7 @@ STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { @@ -1797,7 +1797,7 @@ _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1805,7 +1805,7 @@ STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg >> 1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ PyObject* meth = NULL; @@ -1916,7 +1916,7 @@ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, LOAD_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); uint16_t hint = index; DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); if (DK_IS_UNICODE(dict->ma_keys)) { @@ -2040,7 +2040,7 @@ DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - PyObject *name = GETITEM(names, oparg >> 1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). @@ -2096,7 +2096,7 @@ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, STORE_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *old_value; uint64_t new_version; @@ -2349,7 +2349,7 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); Py_DECREF(level); Py_DECREF(fromlist); @@ -2362,7 +2362,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; STACK_GROW(1); @@ -2997,8 +2997,8 @@ TARGET(KW_NAMES) { assert(kwnames == NULL); - assert(oparg < PyTuple_GET_SIZE(consts)); - kwnames = GETITEM(consts, oparg); + assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); + kwnames = GETITEM(frame->f_code->co_consts, oparg); DISPATCH(); } From webhook-mailer at python.org Mon Mar 13 15:25:56 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 13 Mar 2023 19:25:56 -0000 Subject: [Python-checkins] gh-102650: Remove duplicate include directives from multiple source files (#102651) Message-ID: https://github.com/python/cpython/commit/85ba8a3e03707092800cbf2a29d95e0b495e3cb7 commit: 85ba8a3e03707092800cbf2a29d95e0b495e3cb7 branch: main author: chgnrdv <52372310+chgnrdv at users.noreply.github.com> committer: carljm date: 2023-03-13T13:25:17-06:00 summary: gh-102650: Remove duplicate include directives from multiple source files (#102651) Remove duplicate include directives from multiple source files files: M Mac/Tools/pythonw.c M Modules/_hashopenssl.c M Modules/arraymodule.c M Modules/signalmodule.c M Programs/_testembed.c diff --git a/Mac/Tools/pythonw.c b/Mac/Tools/pythonw.c index 78813e818e7d..9dfb77f6ff41 100644 --- a/Mac/Tools/pythonw.c +++ b/Mac/Tools/pythonw.c @@ -27,7 +27,6 @@ #include #include #include -#include #include diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 82398547f9b3..ee8c58802011 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -32,12 +32,11 @@ /* EVP is the preferred interface to hashing in OpenSSL */ #include #include -#include +#include // FIPS_mode() /* We use the object interface to discover what hashes OpenSSL supports. */ #include #include -#include // FIPS_mode() #ifndef OPENSSL_THREADS # error "OPENSSL_THREADS is not defined, Python requires thread-safe OpenSSL" diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 114c69a03359..798a76292579 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -13,7 +13,6 @@ #include "pycore_bytesobject.h" // _PyBytes_Repeat #include "structmember.h" // PyMemberDef #include // offsetof() -#include /*[clinic input] module array diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 0e472e1ee4f9..fdd1450050fa 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -13,7 +13,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_pyerrors.h" // _PyErr_SetString() #include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_signal.h" +#include "pycore_signal.h" // Py_NSIG #ifndef MS_WINDOWS # include "posixmodule.h" @@ -28,8 +28,6 @@ # endif #endif -#include "pycore_signal.h" // Py_NSIG - #ifdef HAVE_SIGNAL_H # include #endif diff --git a/Programs/_testembed.c b/Programs/_testembed.c index a6ce3f7b2005..00717114b402 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -9,7 +9,6 @@ #include "pycore_initconfig.h" // _PyConfig_InitCompatConfig() #include "pycore_runtime.h" // _PyRuntime #include "pycore_import.h" // _PyImport_FrozenBootstrap -#include #include #include #include // putenv() From webhook-mailer at python.org Mon Mar 13 16:46:43 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 13 Mar 2023 20:46:43 -0000 Subject: [Python-checkins] gh-98169 dataclasses.astuple support DefaultDict (#98170) Message-ID: https://github.com/python/cpython/commit/71e37d907905b0504c5bb7b25681adeea2157492 commit: 71e37d907905b0504c5bb7b25681adeea2157492 branch: main author: T committer: carljm date: 2023-03-13T14:46:35-06:00 summary: gh-98169 dataclasses.astuple support DefaultDict (#98170) Co-authored-by: Pieter Eendebak files: A Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index f4617b1dbdac..7c3285cf440a 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1321,15 +1321,14 @@ def _asdict_inner(obj, dict_factory): # generator (which is not true for namedtuples, handled # above). return type(obj)(_asdict_inner(v, dict_factory) for v in obj) - elif isinstance(obj, dict) and hasattr(type(obj), 'default_factory'): - # obj is a defaultdict, which has a different constructor from - # dict as it requires the default_factory as its first arg. - # https://bugs.python.org/issue35540 - result = type(obj)(getattr(obj, 'default_factory')) - for k, v in obj.items(): - result[_asdict_inner(k, dict_factory)] = _asdict_inner(v, dict_factory) - return result elif isinstance(obj, dict): + if hasattr(type(obj), 'default_factory'): + # obj is a defaultdict, which has a different constructor from + # dict as it requires the default_factory as its first arg. + result = type(obj)(getattr(obj, 'default_factory')) + for k, v in obj.items(): + result[_asdict_inner(k, dict_factory)] = _asdict_inner(v, dict_factory) + return result return type(obj)((_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory)) for k, v in obj.items()) @@ -1382,7 +1381,15 @@ def _astuple_inner(obj, tuple_factory): # above). return type(obj)(_astuple_inner(v, tuple_factory) for v in obj) elif isinstance(obj, dict): - return type(obj)((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory)) + obj_type = type(obj) + if hasattr(obj_type, 'default_factory'): + # obj is a defaultdict, which has a different constructor from + # dict as it requires the default_factory as its first arg. + result = obj_type(getattr(obj, 'default_factory')) + for k, v in obj.items(): + result[_astuple_inner(k, tuple_factory)] = _astuple_inner(v, tuple_factory) + return result + return obj_type((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory)) for k, v in obj.items()) else: return copy.deepcopy(obj) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 76bed0c33146..46d4e0fedad2 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -1706,19 +1706,17 @@ class C: def test_helper_asdict_defaultdict(self): # Ensure asdict() does not throw exceptions when a # defaultdict is a member of a dataclass - @dataclass class C: mp: DefaultDict[str, List] - dd = defaultdict(list) dd["x"].append(12) c = C(mp=dd) d = asdict(c) - assert d == {"mp": {"x": [12]}} - assert d["mp"] is not c.mp # make sure defaultdict is copied + self.assertEqual(d, {"mp": {"x": [12]}}) + self.assertTrue(d["mp"] is not c.mp) # make sure defaultdict is copied def test_helper_astuple(self): # Basic tests for astuple(), it should return a new tuple. @@ -1847,6 +1845,21 @@ class C: t = astuple(c, tuple_factory=list) self.assertEqual(t, ['outer', T(1, ['inner', T(11, 12, 13)], 2)]) + def test_helper_astuple_defaultdict(self): + # Ensure astuple() does not throw exceptions when a + # defaultdict is a member of a dataclass + @dataclass + class C: + mp: DefaultDict[str, List] + + dd = defaultdict(list) + dd["x"].append(12) + c = C(mp=dd) + t = astuple(c) + + self.assertEqual(t, ({"x": [12]},)) + self.assertTrue(t[0] is not dd) # make sure defaultdict is copied + def test_dynamic_class_creation(self): cls_dict = {'__annotations__': {'x': int, 'y': int}, } diff --git a/Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst b/Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst new file mode 100644 index 000000000000..24c3aeecc83f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst @@ -0,0 +1,2 @@ +Fix :func:`dataclasses.astuple` crash when :class:`collections.defaultdict` +is present in the attributes. From webhook-mailer at python.org Mon Mar 13 17:42:14 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 13 Mar 2023 21:42:14 -0000 Subject: [Python-checkins] gh-102069: Fix `__weakref__` descriptor generation for custom dataclasses (#102075) Message-ID: https://github.com/python/cpython/commit/d97757f793ea53dda3cc6882b4a92d3e921b17c9 commit: d97757f793ea53dda3cc6882b4a92d3e921b17c9 branch: main author: Nikita Sobolev committer: carljm date: 2023-03-13T15:42:05-06:00 summary: gh-102069: Fix `__weakref__` descriptor generation for custom dataclasses (#102075) files: A Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 7c3285cf440a..82b08fc01788 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1189,6 +1189,9 @@ def _add_slots(cls, is_frozen, weakref_slot): # Remove __dict__ itself. cls_dict.pop('__dict__', None) + # Clear existing `__weakref__` descriptor, it belongs to a previous type: + cls_dict.pop('__weakref__', None) # gh-102069 + # And finally create the class. qualname = getattr(cls, '__qualname__', None) cls = type(cls)(cls.__name__, cls.__bases__, cls_dict) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 46d4e0fedad2..46f33043c270 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3175,6 +3175,8 @@ class A: with self.assertRaisesRegex(TypeError, "cannot create weak reference"): weakref.ref(a) + with self.assertRaises(AttributeError): + a.__weakref__ def test_slots_weakref(self): @dataclass(slots=True, weakref_slot=True) @@ -3183,7 +3185,9 @@ class A: self.assertIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + + self.assertIs(a.__weakref__, a_ref) def test_slots_weakref_base_str(self): class Base: @@ -3249,7 +3253,8 @@ class A(Base): self.assertIn("__weakref__", Base.__slots__) self.assertNotIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + self.assertIs(a.__weakref__, a_ref) def test_weakref_slot_subclass_no_weakref_slot(self): @dataclass(slots=True, weakref_slot=True) @@ -3265,7 +3270,8 @@ class A(Base): self.assertIn("__weakref__", Base.__slots__) self.assertNotIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + self.assertIs(a.__weakref__, a_ref) def test_weakref_slot_normal_base_weakref_slot(self): class Base: @@ -3280,7 +3286,8 @@ class A(Base): self.assertIn("__weakref__", Base.__slots__) self.assertNotIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + self.assertIs(a.__weakref__, a_ref) class TestDescriptors(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst b/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst new file mode 100644 index 000000000000..04c87e515cca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst @@ -0,0 +1 @@ +Fix ``__weakref__`` descriptor generation for custom dataclasses. From webhook-mailer at python.org Mon Mar 13 17:50:23 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 13 Mar 2023 21:50:23 -0000 Subject: [Python-checkins] gh-101524: Fix the ChannelID tp_name (gh-102655) Message-ID: https://github.com/python/cpython/commit/74885a08dbc7cc768d15711752957096d6a5a350 commit: 74885a08dbc7cc768d15711752957096d6a5a350 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-13T15:50:16-06:00 summary: gh-101524: Fix the ChannelID tp_name (gh-102655) https://github.com/python/cpython/issues/101524 files: M Modules/_xxinterpchannelsmodule.c diff --git a/Modules/_xxinterpchannelsmodule.c b/Modules/_xxinterpchannelsmodule.c index a0cd4a2363fb..fead12c963da 100644 --- a/Modules/_xxinterpchannelsmodule.c +++ b/Modules/_xxinterpchannelsmodule.c @@ -1806,7 +1806,7 @@ static PyType_Slot ChannelIDType_slots[] = { }; static PyType_Spec ChannelIDType_spec = { - .name = "_xxsubinterpreters.ChannelID", + .name = MODULE_NAME ".ChannelID", .basicsize = sizeof(channelid), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE), From webhook-mailer at python.org Mon Mar 13 18:02:08 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 13 Mar 2023 22:02:08 -0000 Subject: [Python-checkins] gh-101659: Avoid Allocation for Shared Exceptions in the _xxsubinterpreters Module (gh-102659) Message-ID: https://github.com/python/cpython/commit/959ea2f9e967042954878f7af5c85053238212a7 commit: 959ea2f9e967042954878f7af5c85053238212a7 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-13T16:01:44-06:00 summary: gh-101659: Avoid Allocation for Shared Exceptions in the _xxsubinterpreters Module (gh-102659) https://github.com/python/cpython/issues/101659 files: M Modules/_xxsubinterpretersmodule.c diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 79dbe3474ba9..76fb87fa3a34 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -15,14 +15,14 @@ #define MODULE_NAME "_xxsubinterpreters" -static char * +static const char * _copy_raw_string(PyObject *strobj) { const char *str = PyUnicode_AsUTF8(strobj); if (str == NULL) { return NULL; } - char *copied = PyMem_Malloc(strlen(str)+1); + char *copied = PyMem_RawMalloc(strlen(str)+1); if (copied == NULL) { PyErr_NoMemory(); return NULL; @@ -128,7 +128,7 @@ clear_module_state(module_state *state) /* data-sharing-specific code ***********************************************/ struct _sharednsitem { - char *name; + const char *name; _PyCrossInterpreterData data; }; @@ -152,7 +152,7 @@ static void _sharednsitem_clear(struct _sharednsitem *item) { if (item->name != NULL) { - PyMem_Free(item->name); + PyMem_RawFree((void *)item->name); item->name = NULL; } (void)_release_xid_data(&item->data, 1); @@ -258,96 +258,74 @@ _sharedns_apply(_sharedns *shared, PyObject *ns) // of the exception in the calling interpreter. typedef struct _sharedexception { - char *name; - char *msg; + const char *name; + const char *msg; } _sharedexception; -static _sharedexception * -_sharedexception_new(void) -{ - _sharedexception *err = PyMem_NEW(_sharedexception, 1); - if (err == NULL) { - PyErr_NoMemory(); - return NULL; - } - err->name = NULL; - err->msg = NULL; - return err; -} +static const struct _sharedexception no_exception = { + .name = NULL, + .msg = NULL, +}; static void _sharedexception_clear(_sharedexception *exc) { if (exc->name != NULL) { - PyMem_Free(exc->name); + PyMem_RawFree((void *)exc->name); } if (exc->msg != NULL) { - PyMem_Free(exc->msg); + PyMem_RawFree((void *)exc->msg); } } -static void -_sharedexception_free(_sharedexception *exc) -{ - _sharedexception_clear(exc); - PyMem_Free(exc); -} - -static _sharedexception * -_sharedexception_bind(PyObject *exc) +static const char * +_sharedexception_bind(PyObject *exc, _sharedexception *sharedexc) { assert(exc != NULL); - char *failure = NULL; - - _sharedexception *err = _sharedexception_new(); - if (err == NULL) { - goto finally; - } + const char *failure = NULL; - PyObject *name = PyUnicode_FromFormat("%S", Py_TYPE(exc)); - if (name == NULL) { + PyObject *nameobj = PyUnicode_FromFormat("%S", Py_TYPE(exc)); + if (nameobj == NULL) { failure = "unable to format exception type name"; - goto finally; + goto error; } - err->name = _copy_raw_string(name); - Py_DECREF(name); - if (err->name == NULL) { + sharedexc->name = _copy_raw_string(nameobj); + Py_DECREF(nameobj); + if (sharedexc->name == NULL) { if (PyErr_ExceptionMatches(PyExc_MemoryError)) { failure = "out of memory copying exception type name"; } else { failure = "unable to encode and copy exception type name"; } - goto finally; + goto error; } if (exc != NULL) { - PyObject *msg = PyUnicode_FromFormat("%S", exc); - if (msg == NULL) { + PyObject *msgobj = PyUnicode_FromFormat("%S", exc); + if (msgobj == NULL) { failure = "unable to format exception message"; - goto finally; + goto error; } - err->msg = _copy_raw_string(msg); - Py_DECREF(msg); - if (err->msg == NULL) { + sharedexc->msg = _copy_raw_string(msgobj); + Py_DECREF(msgobj); + if (sharedexc->msg == NULL) { if (PyErr_ExceptionMatches(PyExc_MemoryError)) { failure = "out of memory copying exception message"; } else { failure = "unable to encode and copy exception message"; } - goto finally; + goto error; } } -finally: - if (failure != NULL) { - PyErr_Clear(); - if (err->name != NULL) { - PyMem_Free(err->name); - err->name = NULL; - } - err->msg = failure; - } - return err; + return NULL; + +error: + assert(failure != NULL); + PyErr_Clear(); + _sharedexception_clear(sharedexc); + *sharedexc = no_exception; + return failure; } static void @@ -430,7 +408,7 @@ _ensure_not_running(PyInterpreterState *interp) static int _run_script(PyInterpreterState *interp, const char *codestr, - _sharedns *shared, _sharedexception **exc) + _sharedns *shared, _sharedexception *sharedexc) { PyObject *excval = NULL; PyObject *main_mod = _PyInterpreterState_GetMainModule(interp); @@ -462,22 +440,20 @@ _run_script(PyInterpreterState *interp, const char *codestr, Py_DECREF(result); // We throw away the result. } - *exc = NULL; + *sharedexc = no_exception; return 0; error: excval = PyErr_GetRaisedException(); - _sharedexception *sharedexc = _sharedexception_bind(excval); - Py_XDECREF(excval); - if (sharedexc == NULL) { - fprintf(stderr, "RunFailedError: script raised an uncaught exception"); + const char *failure = _sharedexception_bind(excval, sharedexc); + if (failure != NULL) { + fprintf(stderr, + "RunFailedError: script raised an uncaught exception (%s)", + failure); PyErr_Clear(); - sharedexc = NULL; - } - else { - assert(!PyErr_Occurred()); } - *exc = sharedexc; + Py_XDECREF(excval); + assert(!PyErr_Occurred()); return -1; } @@ -505,7 +481,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp, } // Run the script. - _sharedexception *exc = NULL; + _sharedexception exc; int result = _run_script(interp, codestr, shared, &exc); // Switch back. @@ -514,10 +490,9 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp, } // Propagate any exception out to the caller. - if (exc != NULL) { + if (exc.name != NULL) { assert(state != NULL); - _sharedexception_apply(exc, state->RunFailedError); - _sharedexception_free(exc); + _sharedexception_apply(&exc, state->RunFailedError); } else if (result != 0) { // We were unable to allocate a shared exception. From webhook-mailer at python.org Mon Mar 13 18:08:52 2023 From: webhook-mailer at python.org (gvanrossum) Date: Mon, 13 Mar 2023 22:08:52 -0000 Subject: [Python-checkins] gh-98831: Use DECREF_INPUTS() more (#102409) Message-ID: https://github.com/python/cpython/commit/392f2ad3cbf2e1f24656fe0410a9b65882257582 commit: 392f2ad3cbf2e1f24656fe0410a9b65882257582 branch: main author: Guido van Rossum committer: gvanrossum date: 2023-03-13T15:08:45-07:00 summary: gh-98831: Use DECREF_INPUTS() more (#102409) files: M Python/bytecodes.c M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index a715bfd3289e..74582ecbbda1 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -384,8 +384,7 @@ dummy_func( if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - Py_DECREF(dict); - Py_DECREF(sub); + DECREF_INPUTS(); ERROR_IF(true, error); } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -420,7 +419,7 @@ dummy_func( inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) { int err = PySet_Add(set, v); - Py_DECREF(v); + DECREF_INPUTS(); ERROR_IF(err, error); PREDICT(JUMP_BACKWARD); } @@ -899,7 +898,7 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - Py_DECREF(seq); + DECREF_INPUTS(); ERROR_IF(res == 0, error); } @@ -910,7 +909,7 @@ dummy_func( STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - Py_DECREF(seq); + DECREF_INPUTS(); } inst(UNPACK_SEQUENCE_TUPLE, (unused/1, seq -- values[oparg])) { @@ -921,7 +920,7 @@ dummy_func( for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - Py_DECREF(seq); + DECREF_INPUTS(); } inst(UNPACK_SEQUENCE_LIST, (unused/1, seq -- values[oparg])) { @@ -932,14 +931,14 @@ dummy_func( for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - Py_DECREF(seq); + DECREF_INPUTS(); } inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >> 8])) { int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - Py_DECREF(seq); + DECREF_INPUTS(); ERROR_IF(res == 0, error); } @@ -967,22 +966,21 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - Py_DECREF(v); - Py_DECREF(owner); + DECREF_INPUTS(); ERROR_IF(err, error); } inst(DELETE_ATTR, (owner --)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - Py_DECREF(owner); + DECREF_INPUTS(); ERROR_IF(err, error); } inst(STORE_GLOBAL, (v --)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - Py_DECREF(v); + DECREF_INPUTS(); ERROR_IF(err, error); } @@ -1249,9 +1247,7 @@ dummy_func( inst(BUILD_STRING, (pieces[oparg] -- str)) { str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - for (int i = 0; i < oparg; i++) { - Py_DECREF(pieces[i]); - } + DECREF_INPUTS(); ERROR_IF(str == NULL, error); } @@ -1314,10 +1310,7 @@ dummy_func( if (map == NULL) goto error; - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i*2]); - Py_DECREF(values[i*2+1]); - } + DECREF_INPUTS(); ERROR_IF(map == NULL, error); } @@ -1373,10 +1366,7 @@ dummy_func( map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - Py_DECREF(keys); - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i]); - } + DECREF_INPUTS(); ERROR_IF(map == NULL, error); } @@ -1464,7 +1454,7 @@ dummy_func( NULL | meth | arg1 | ... | argN */ - Py_DECREF(owner); + DECREF_INPUTS(); ERROR_IF(meth == NULL, error); res2 = NULL; res = meth; @@ -1473,7 +1463,7 @@ dummy_func( else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - Py_DECREF(owner); + DECREF_INPUTS(); ERROR_IF(res == NULL, error); } } @@ -1492,7 +1482,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - Py_DECREF(owner); + DECREF_INPUTS(); } inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { @@ -1509,7 +1499,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - Py_DECREF(owner); + DECREF_INPUTS(); } inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { @@ -1540,7 +1530,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - Py_DECREF(owner); + DECREF_INPUTS(); } inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { @@ -1554,7 +1544,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - Py_DECREF(owner); + DECREF_INPUTS(); } inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, cls -- res2 if (oparg & 1), res)) { @@ -1570,7 +1560,7 @@ dummy_func( res = descr; assert(res != NULL); Py_INCREF(res); - Py_DECREF(cls); + DECREF_INPUTS(); } inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused if (oparg & 1), unused)) { @@ -1707,8 +1697,7 @@ dummy_func( STAT_INC(COMPARE_OP, deferred); assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - Py_DECREF(left); - Py_DECREF(right); + DECREF_INPUTS(); ERROR_IF(res == NULL, error); } @@ -1734,8 +1723,7 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); - Py_DECREF(left); - Py_DECREF(right); + DECREF_INPUTS(); ERROR_IF(cond == NULL, error); assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || next_instr[1].op.code == POP_JUMP_IF_TRUE); @@ -1885,7 +1873,7 @@ dummy_func( } else { int err = PyObject_IsTrue(cond); - Py_DECREF(cond); + DECREF_INPUTS(); if (err == 0) { JUMPBY(oparg); } @@ -1905,7 +1893,7 @@ dummy_func( } else { int err = PyObject_IsTrue(cond); - Py_DECREF(cond); + DECREF_INPUTS(); if (err > 0) { JUMPBY(oparg); } @@ -1917,7 +1905,7 @@ dummy_func( inst(POP_JUMP_IF_NOT_NONE, (value -- )) { if (!Py_IsNone(value)) { - Py_DECREF(value); + DECREF_INPUTS(); JUMPBY(oparg); } else { @@ -1931,7 +1919,7 @@ dummy_func( JUMPBY(oparg); } else { - Py_DECREF(value); + DECREF_INPUTS(); } } @@ -2065,7 +2053,7 @@ dummy_func( if (iter == NULL) { goto error; } - Py_DECREF(iterable); + DECREF_INPUTS(); } PREDICT(LOAD_CONST); } @@ -2940,9 +2928,7 @@ dummy_func( assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - Py_DECREF(func); - Py_DECREF(callargs); - Py_XDECREF(kwargs); + DECREF_INPUTS(); assert(PEEK(3 + (oparg & 1)) == NULL); ERROR_IF(result == NULL, error); @@ -3009,9 +2995,7 @@ dummy_func( inst(BUILD_SLICE, (start, stop, step if (oparg == 3) -- slice)) { slice = PySlice_New(start, stop, step); - Py_DECREF(start); - Py_DECREF(stop); - Py_XDECREF(step); + DECREF_INPUTS(); ERROR_IF(slice == NULL, error); } @@ -3057,8 +3041,7 @@ dummy_func( } else { /* Actually call format(). */ result = PyObject_Format(value, fmt_spec); - Py_DECREF(value); - Py_XDECREF(fmt_spec); + DECREF_INPUTS(); ERROR_IF(result == NULL, error); } } @@ -3084,8 +3067,7 @@ dummy_func( assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - Py_DECREF(lhs); - Py_DECREF(rhs); + DECREF_INPUTS(); ERROR_IF(res == NULL, error); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 631b7844f9ed..b1dbb58d9563 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1568,8 +1568,8 @@ PyObject **pieces = (stack_pointer - oparg); PyObject *str; str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - for (int i = 0; i < oparg; i++) { - Py_DECREF(pieces[i]); + for (int _i = oparg; --_i >= 0;) { + Py_DECREF(pieces[_i]); } if (str == NULL) { STACK_SHRINK(oparg); goto error; } STACK_SHRINK(oparg); @@ -1665,9 +1665,8 @@ if (map == NULL) goto error; - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i*2]); - Py_DECREF(values[i*2+1]); + for (int _i = oparg*2; --_i >= 0;) { + Py_DECREF(values[_i]); } if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } STACK_SHRINK(oparg*2); @@ -1732,10 +1731,10 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - Py_DECREF(keys); - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i]); + for (int _i = oparg; --_i >= 0;) { + Py_DECREF(values[_i]); } + Py_DECREF(keys); if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } STACK_SHRINK(oparg); stack_pointer[-1] = map; From webhook-mailer at python.org Mon Mar 13 18:17:54 2023 From: webhook-mailer at python.org (carljm) Date: Mon, 13 Mar 2023 22:17:54 -0000 Subject: [Python-checkins] [3.11] gh-102069: Fix `__weakref__` descriptor generation for custom dataclasses (GH-102075) (#102662) Message-ID: https://github.com/python/cpython/commit/b0e221cfc881008212c037f510abab781884f6d9 commit: b0e221cfc881008212c037f510abab781884f6d9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: carljm date: 2023-03-13T16:17:46-06:00 summary: [3.11] gh-102069: Fix `__weakref__` descriptor generation for custom dataclasses (GH-102075) (#102662) gh-102069: Fix `__weakref__` descriptor generation for custom dataclasses (GH-102075) (cherry picked from commit d97757f793ea53dda3cc6882b4a92d3e921b17c9) Co-authored-by: Nikita Sobolev files: A Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 2bfeea515b65..d2af451efed5 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1175,6 +1175,9 @@ def _add_slots(cls, is_frozen, weakref_slot): # Remove __dict__ itself. cls_dict.pop('__dict__', None) + # Clear existing `__weakref__` descriptor, it belongs to a previous type: + cls_dict.pop('__weakref__', None) # gh-102069 + # And finally create the class. qualname = getattr(cls, '__qualname__', None) cls = type(cls)(cls.__name__, cls.__bases__, cls_dict) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 9af43771fac0..3a247776e5f4 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3076,6 +3076,8 @@ class A: with self.assertRaisesRegex(TypeError, "cannot create weak reference"): weakref.ref(a) + with self.assertRaises(AttributeError): + a.__weakref__ def test_slots_weakref(self): @dataclass(slots=True, weakref_slot=True) @@ -3084,7 +3086,9 @@ class A: self.assertIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + + self.assertIs(a.__weakref__, a_ref) def test_slots_weakref_base_str(self): class Base: @@ -3150,7 +3154,8 @@ class A(Base): self.assertIn("__weakref__", Base.__slots__) self.assertNotIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + self.assertIs(a.__weakref__, a_ref) def test_weakref_slot_subclass_no_weakref_slot(self): @dataclass(slots=True, weakref_slot=True) @@ -3166,7 +3171,8 @@ class A(Base): self.assertIn("__weakref__", Base.__slots__) self.assertNotIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + self.assertIs(a.__weakref__, a_ref) def test_weakref_slot_normal_base_weakref_slot(self): class Base: @@ -3181,7 +3187,8 @@ class A(Base): self.assertIn("__weakref__", Base.__slots__) self.assertNotIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + self.assertIs(a.__weakref__, a_ref) class TestDescriptors(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst b/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst new file mode 100644 index 000000000000..04c87e515cca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst @@ -0,0 +1 @@ +Fix ``__weakref__`` descriptor generation for custom dataclasses. From webhook-mailer at python.org Mon Mar 13 18:35:53 2023 From: webhook-mailer at python.org (gpshead) Date: Mon, 13 Mar 2023 22:35:53 -0000 Subject: [Python-checkins] gh-102627: Replace address pointing toward malicious web page (#102630) Message-ID: https://github.com/python/cpython/commit/61479d46848bc7a7f9b571b0b09c4a4b4436d839 commit: 61479d46848bc7a7f9b571b0b09c4a4b4436d839 branch: main author: Blind4Basics <32236948+Blind4Basics at users.noreply.github.com> committer: gpshead date: 2023-03-13T15:35:37-07:00 summary: gh-102627: Replace address pointing toward malicious web page (#102630) * Replace known bad address pointing toward a malicious web page. Co-authored-by: C.A.M. Gerlach Co-authored-by: Hugo van Kemenade files: M Doc/library/concurrent.futures.rst diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index c543c849585b..09c9fc4e6e22 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -202,7 +202,7 @@ ThreadPoolExecutor Example 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', - 'http://some-made-up-domain.com/'] + 'http://nonexistant-subdomain.python.org/'] # Retrieve a single page and report the URL and contents def load_url(url, timeout): From webhook-mailer at python.org Mon Mar 13 18:42:44 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 13 Mar 2023 22:42:44 -0000 Subject: [Python-checkins] gh-102627: Replace address pointing toward malicious web page (GH-102630) Message-ID: https://github.com/python/cpython/commit/0275b12a0fdda3b39f4780727abfb93f59cfad7a commit: 0275b12a0fdda3b39f4780727abfb93f59cfad7a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-13T15:42:37-07:00 summary: gh-102627: Replace address pointing toward malicious web page (GH-102630) * Replace known bad address pointing toward a malicious web page. (cherry picked from commit 61479d46848bc7a7f9b571b0b09c4a4b4436d839) Co-authored-by: Blind4Basics <32236948+Blind4Basics at users.noreply.github.com> Co-authored-by: C.A.M. Gerlach Co-authored-by: Hugo van Kemenade files: M Doc/library/concurrent.futures.rst diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index a25ad09c0a89..2db289e39a7c 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -201,7 +201,7 @@ ThreadPoolExecutor Example 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', - 'http://some-made-up-domain.com/'] + 'http://nonexistant-subdomain.python.org/'] # Retrieve a single page and report the URL and contents def load_url(url, timeout): From webhook-mailer at python.org Mon Mar 13 18:43:23 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 13 Mar 2023 22:43:23 -0000 Subject: [Python-checkins] gh-102627: Replace address pointing toward malicious web page (GH-102630) Message-ID: https://github.com/python/cpython/commit/43f8082b1cbf9fdde2851e20071b5f88638b7574 commit: 43f8082b1cbf9fdde2851e20071b5f88638b7574 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-13T15:43:16-07:00 summary: gh-102627: Replace address pointing toward malicious web page (GH-102630) * Replace known bad address pointing toward a malicious web page. (cherry picked from commit 61479d46848bc7a7f9b571b0b09c4a4b4436d839) Co-authored-by: Blind4Basics <32236948+Blind4Basics at users.noreply.github.com> Co-authored-by: C.A.M. Gerlach Co-authored-by: Hugo van Kemenade files: M Doc/library/concurrent.futures.rst diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 8106cc235e5a..c2c64d9c6ee7 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -202,7 +202,7 @@ ThreadPoolExecutor Example 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', - 'http://some-made-up-domain.com/'] + 'http://nonexistant-subdomain.python.org/'] # Retrieve a single page and report the URL and contents def load_url(url, timeout): From webhook-mailer at python.org Mon Mar 13 19:26:49 2023 From: webhook-mailer at python.org (ned-deily) Date: Mon, 13 Mar 2023 23:26:49 -0000 Subject: [Python-checkins] [3.7] gh-102627: Replace address pointing toward malicious web page (GH-102630) (GH-102668) Message-ID: https://github.com/python/cpython/commit/00d1d3278448503bec6f28527b707d301e937756 commit: 00d1d3278448503bec6f28527b707d301e937756 branch: 3.7 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily date: 2023-03-13T19:26:42-04:00 summary: [3.7] gh-102627: Replace address pointing toward malicious web page (GH-102630) (GH-102668) (cherry picked from commit 61479d46848bc7a7f9b571b0b09c4a4b4436d839) Co-authored-by: Blind4Basics <32236948+Blind4Basics at users.noreply.github.com> Co-authored-by: C.A.M. Gerlach Co-authored-by: Hugo van Kemenade files: M Doc/library/concurrent.futures.rst diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 9295df84278d..e0ec27f00271 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -173,7 +173,7 @@ ThreadPoolExecutor Example 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', - 'http://some-made-up-domain.com/'] + 'http://nonexistant-subdomain.python.org/'] # Retrieve a single page and report the URL and contents def load_url(url, timeout): From webhook-mailer at python.org Mon Mar 13 19:28:43 2023 From: webhook-mailer at python.org (ned-deily) Date: Mon, 13 Mar 2023 23:28:43 -0000 Subject: [Python-checkins] [3.9] gh-102627: Replace address pointing toward malicious web page (GH-102630) (GH-102666) Message-ID: https://github.com/python/cpython/commit/cb0b009cfb4ae2a87a8737250c526b8f95d0551f commit: cb0b009cfb4ae2a87a8737250c526b8f95d0551f branch: 3.9 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily date: 2023-03-13T19:28:36-04:00 summary: [3.9] gh-102627: Replace address pointing toward malicious web page (GH-102630) (GH-102666) (cherry picked from commit 61479d46848bc7a7f9b571b0b09c4a4b4436d839) Co-authored-by: Blind4Basics <32236948+Blind4Basics at users.noreply.github.com> Co-authored-by: C.A.M. Gerlach Co-authored-by: Hugo van Kemenade files: M Doc/library/concurrent.futures.rst diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 70a17a23119c..37c142074fbf 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -194,7 +194,7 @@ ThreadPoolExecutor Example 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', - 'http://some-made-up-domain.com/'] + 'http://nonexistant-subdomain.python.org/'] # Retrieve a single page and report the URL and contents def load_url(url, timeout): From webhook-mailer at python.org Mon Mar 13 19:29:31 2023 From: webhook-mailer at python.org (ned-deily) Date: Mon, 13 Mar 2023 23:29:31 -0000 Subject: [Python-checkins] [3.8] gh-102627: Replace address pointing toward malicious web page (GH-102630) (GH-102667) Message-ID: https://github.com/python/cpython/commit/045b2523ff395efbbbd9369c7becec8e2236bde9 commit: 045b2523ff395efbbbd9369c7becec8e2236bde9 branch: 3.8 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ned-deily date: 2023-03-13T19:29:24-04:00 summary: [3.8] gh-102627: Replace address pointing toward malicious web page (GH-102630) (GH-102667) (cherry picked from commit 61479d46848bc7a7f9b571b0b09c4a4b4436d839) Co-authored-by: Blind4Basics <32236948+Blind4Basics at users.noreply.github.com> Co-authored-by: C.A.M. Gerlach Co-authored-by: Hugo van Kemenade files: M Doc/library/concurrent.futures.rst diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 54c9c2e0fd51..cf9cd4c1ecc0 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -182,7 +182,7 @@ ThreadPoolExecutor Example 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', - 'http://some-made-up-domain.com/'] + 'http://nonexistant-subdomain.python.org/'] # Retrieve a single page and report the URL and contents def load_url(url, timeout): From webhook-mailer at python.org Mon Mar 13 21:06:50 2023 From: webhook-mailer at python.org (rhettinger) Date: Tue, 14 Mar 2023 01:06:50 -0000 Subject: [Python-checkins] GH-102670: Use sumprod() to simplify, speed up, and improve accuracy of statistics functions (GH-102649) Message-ID: https://github.com/python/cpython/commit/457e4d1a516c2b83edeff2f255f4cd6e7b114feb commit: 457e4d1a516c2b83edeff2f255f4cd6e7b114feb branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-13T20:06:43-05:00 summary: GH-102670: Use sumprod() to simplify, speed up, and improve accuracy of statistics functions (GH-102649) files: A Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst M Lib/statistics.py M Lib/test/test_statistics.py diff --git a/Lib/statistics.py b/Lib/statistics.py index 7d5d750193a5..6bd214bbfe2f 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -1036,7 +1036,7 @@ def covariance(x, y, /): raise StatisticsError('covariance requires at least two data points') xbar = fsum(x) / n ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) + sxy = sumprod((xi - xbar for xi in x), (yi - ybar for yi in y)) return sxy / (n - 1) @@ -1074,11 +1074,14 @@ def correlation(x, y, /, *, method='linear'): start = (n - 1) / -2 # Center rankings around zero x = _rank(x, start=start) y = _rank(y, start=start) - xbar = fsum(x) / n - ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) - sxx = fsum((d := xi - xbar) * d for xi in x) - syy = fsum((d := yi - ybar) * d for yi in y) + else: + xbar = fsum(x) / n + ybar = fsum(y) / n + x = [xi - xbar for xi in x] + y = [yi - ybar for yi in y] + sxy = sumprod(x, y) + sxx = sumprod(x, x) + syy = sumprod(y, y) try: return sxy / sqrt(sxx * syy) except ZeroDivisionError: @@ -1131,14 +1134,13 @@ def linear_regression(x, y, /, *, proportional=False): raise StatisticsError('linear regression requires that both inputs have same number of data points') if n < 2: raise StatisticsError('linear regression requires at least two data points') - if proportional: - sxy = fsum(xi * yi for xi, yi in zip(x, y)) - sxx = fsum(xi * xi for xi in x) - else: + if not proportional: xbar = fsum(x) / n ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) - sxx = fsum((d := xi - xbar) * d for xi in x) + x = [xi - xbar for xi in x] # List because used three times below + y = (yi - ybar for yi in y) # Generator because only used once below + sxy = sumprod(x, y) + 0.0 # Add zero to coerce result to a float + sxx = sumprod(x, x) try: slope = sxy / sxx # equivalent to: covariance(x, y) / variance(x) except ZeroDivisionError: diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 31a3cb6b53a6..f0fa6454b1f9 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -1,4 +1,4 @@ -"""Test suite for statistics module, including helper NumericTestCase and +x = """Test suite for statistics module, including helper NumericTestCase and approx_equal function. """ @@ -2610,6 +2610,16 @@ def test_proportional(self): self.assertAlmostEqual(slope, 20 + 1/150) self.assertEqual(intercept, 0.0) + def test_float_output(self): + x = [Fraction(2, 3), Fraction(3, 4)] + y = [Fraction(4, 5), Fraction(5, 6)] + slope, intercept = statistics.linear_regression(x, y) + self.assertTrue(isinstance(slope, float)) + self.assertTrue(isinstance(intercept, float)) + slope, intercept = statistics.linear_regression(x, y, proportional=True) + self.assertTrue(isinstance(slope, float)) + self.assertTrue(isinstance(intercept, float)) + class TestNormalDist: # General note on precision: The pdf(), cdf(), and overlap() methods diff --git a/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst b/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst new file mode 100644 index 000000000000..3de09f86754f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst @@ -0,0 +1,2 @@ +Optimized fmean(), correlation(), covariance(), and linear_regression() +using the new math.sumprod() function. From webhook-mailer at python.org Mon Mar 13 21:36:04 2023 From: webhook-mailer at python.org (pablogsal) Date: Tue, 14 Mar 2023 01:36:04 -0000 Subject: [Python-checkins] gh-102013: Add PyUnstable_GC_VisitObjects (#102014) Message-ID: https://github.com/python/cpython/commit/cbd3fbfb6e5c1cc96bbeb99483a580f165b01671 commit: cbd3fbfb6e5c1cc96bbeb99483a580f165b01671 branch: main author: Jacob Bower <1978924+jbower-fb at users.noreply.github.com> committer: pablogsal date: 2023-03-14T01:35:54Z summary: gh-102013: Add PyUnstable_GC_VisitObjects (#102014) files: A Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst M Doc/c-api/gcsupport.rst M Include/objimpl.h M Modules/_testcapimodule.c M Modules/gcmodule.c diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 8c90d1e8991c..cb5d64a50487 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -228,3 +228,36 @@ garbage collection runs. Returns the current state, 0 for disabled and 1 for enabled. .. versionadded:: 3.10 + + +Querying Garbage Collector State +-------------------------------- + +The C-API provides the following interface for querying information about +the garbage collector. + +.. c:function:: void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) + + Run supplied *callback* on all live GC-capable objects. *arg* is passed through to + all invocations of *callback*. + + .. warning:: + If new objects are (de)allocated by the callback it is undefined if they + will be visited. + + Garbage collection is disabled during operation. Explicitly running a collection + in the callback may lead to undefined behaviour e.g. visiting the same objects + multiple times or not at all. + + .. versionadded:: 3.12 + +.. c:type:: int (*gcvisitobjects_t)(PyObject *object, void *arg) + + Type of the visitor function to be passed to :c:func:`PyUnstable_GC_VisitObjects`. + *arg* is the same as the *arg* passed to ``PyUnstable_GC_VisitObjects``. + Return ``0`` to continue iteration, return ``1`` to stop iteration. Other return + values are reserved for now so behavior on returning anything else is undefined. + + .. versionadded:: 3.12 + + diff --git a/Include/objimpl.h b/Include/objimpl.h index dde8df348353..ef871c5ea93e 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -157,6 +157,25 @@ PyAPI_FUNC(int) PyGC_Enable(void); PyAPI_FUNC(int) PyGC_Disable(void); PyAPI_FUNC(int) PyGC_IsEnabled(void); + +#if !defined(Py_LIMITED_API) +/* Visit all live GC-capable objects, similar to gc.get_objects(None). The + * supplied callback is called on every such object with the void* arg set + * to the supplied arg. Returning 0 from the callback ends iteration, returning + * 1 allows iteration to continue. Returning any other value may result in + * undefined behaviour. + * + * If new objects are (de)allocated by the callback it is undefined if they + * will be visited. + + * Garbage collection is disabled during operation. Explicitly running a + * collection in the callback may lead to undefined behaviour e.g. visiting the + * same objects multiple times or not at all. + */ +typedef int (*gcvisitobjects_t)(PyObject*, void*); +PyAPI_FUNC(void) PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void* arg); +#endif + /* Test if a type has a GC head */ #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) diff --git a/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst new file mode 100644 index 000000000000..0350237ebc73 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst @@ -0,0 +1 @@ +Add a new (unstable) C-API function for iterating over GC'able objects using a callback: ``PyUnstable_VisitObjects``. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index ea67017a1ba3..f45d0312e944 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3310,6 +3310,73 @@ function_set_kw_defaults(PyObject *self, PyObject *args) Py_RETURN_NONE; } +struct gc_visit_state_basic { + PyObject *target; + int found; +}; + +static int +gc_visit_callback_basic(PyObject *obj, void *arg) +{ + struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg; + if (obj == state->target) { + state->found = 1; + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + PyObject *obj; + struct gc_visit_state_basic state; + + obj = PyList_New(0); + if (obj == NULL) { + return NULL; + } + state.target = obj; + state.found = 0; + + PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); + Py_DECREF(obj); + if (!state.found) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_basic: Didn't find live list"); + return NULL; + } + Py_RETURN_NONE; +} + +static int +gc_visit_callback_exit_early(PyObject *obj, void *arg) + { + int *visited_i = (int *)arg; + (*visited_i)++; + if (*visited_i == 2) { + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + int visited_i = 0; + PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); + if (visited_i != 2) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_exit_early: did not exit when expected"); + } + Py_RETURN_NONE; +} + + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { @@ -3452,6 +3519,8 @@ static PyMethodDef TestMethods[] = { {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, + {"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL}, + {"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 5879c5e11fe1..4eaa5490b613 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2401,3 +2401,27 @@ PyObject_GC_IsFinalized(PyObject *obj) } return 0; } + +void +PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) +{ + size_t i; + GCState *gcstate = get_gc_state(); + int origenstate = gcstate->enabled; + gcstate->enabled = 0; + for (i = 0; i < NUM_GENERATIONS; i++) { + PyGC_Head *gc_list, *gc; + gc_list = GEN_HEAD(gcstate, i); + for (gc = GC_NEXT(gc_list); gc != gc_list; gc = GC_NEXT(gc)) { + PyObject *op = FROM_GC(gc); + Py_INCREF(op); + int res = callback(op, arg); + Py_DECREF(op); + if (!res) { + goto done; + } + } + } +done: + gcstate->enabled = origenstate; +} From webhook-mailer at python.org Mon Mar 13 22:08:22 2023 From: webhook-mailer at python.org (corona10) Date: Tue, 14 Mar 2023 02:08:22 -0000 Subject: [Python-checkins] doc: Remove a duplicate 'versionchanged' in library/asyncio-task (gh-102677) Message-ID: https://github.com/python/cpython/commit/7bdb331b67c4aee513e01794ba7dd2c3be43d3ca commit: 7bdb331b67c4aee513e01794ba7dd2c3be43d3ca branch: main author: Joongi Kim committer: corona10 date: 2023-03-14T11:07:59+09:00 summary: doc: Remove a duplicate 'versionchanged' in library/asyncio-task (gh-102677) files: M Doc/library/asyncio-task.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 9b9842432822..5f1449e1b599 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -814,9 +814,6 @@ Waiting Primitives Raises :exc:`TimeoutError` if the timeout occurs before all Futures are done. - .. versionchanged:: 3.10 - Removed the *loop* parameter. - Example:: for coro in as_completed(aws): From webhook-mailer at python.org Mon Mar 13 22:26:18 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 14 Mar 2023 02:26:18 -0000 Subject: [Python-checkins] doc: Remove a duplicate 'versionchanged' in library/asyncio-task (gh-102677) Message-ID: https://github.com/python/cpython/commit/0f46d42eb9fed0f11ec68e8782a3cbcb891d7ba0 commit: 0f46d42eb9fed0f11ec68e8782a3cbcb891d7ba0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-13T19:26:11-07:00 summary: doc: Remove a duplicate 'versionchanged' in library/asyncio-task (gh-102677) (cherry picked from commit 7bdb331b67c4aee513e01794ba7dd2c3be43d3ca) Co-authored-by: Joongi Kim files: M Doc/library/asyncio-task.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index ade5293e7f07..c15d719ff332 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -814,9 +814,6 @@ Waiting Primitives Raises :exc:`TimeoutError` if the timeout occurs before all Futures are done. - .. versionchanged:: 3.10 - Removed the *loop* parameter. - Example:: for coro in as_completed(aws): From webhook-mailer at python.org Mon Mar 13 22:26:31 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 14 Mar 2023 02:26:31 -0000 Subject: [Python-checkins] doc: Remove a duplicate 'versionchanged' in library/asyncio-task (gh-102677) Message-ID: https://github.com/python/cpython/commit/125f75cc133611e6e8ae6c6aeb4ded47a8cd5b1e commit: 125f75cc133611e6e8ae6c6aeb4ded47a8cd5b1e branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-13T19:26:24-07:00 summary: doc: Remove a duplicate 'versionchanged' in library/asyncio-task (gh-102677) (cherry picked from commit 7bdb331b67c4aee513e01794ba7dd2c3be43d3ca) Co-authored-by: Joongi Kim files: M Doc/library/asyncio-task.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index d7e13ea3c6fe..1cfcb7f04278 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -654,9 +654,6 @@ Waiting Primitives Raises :exc:`asyncio.TimeoutError` if the timeout occurs before all Futures are done. - .. versionchanged:: 3.10 - Removed the *loop* parameter. - Example:: for coro in as_completed(aws): From webhook-mailer at python.org Tue Mar 14 04:52:29 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 14 Mar 2023 08:52:29 -0000 Subject: [Python-checkins] GH-100227: cleanup initialization of global interned dict (#102682) Message-ID: https://github.com/python/cpython/commit/3d872a74c8c16d4a077c2223f678b1f8f7e0e988 commit: 3d872a74c8c16d4a077c2223f678b1f8f7e0e988 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-14T14:22:21+05:30 summary: GH-100227: cleanup initialization of global interned dict (#102682) files: M Objects/unicodeobject.c diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 2d50f9c340f2..b9fb53147b9b 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14533,6 +14533,15 @@ _PyUnicode_InitGlobalObjects(PyInterpreterState *interp) return _PyStatus_OK(); } + // Initialize the global interned dict + PyObject *interned = PyDict_New(); + if (interned == NULL) { + PyErr_Clear(); + return _PyStatus_ERR("failed to create interned dict"); + } + + set_interned_dict(interned); + /* Intern statically allocated string identifiers and deepfreeze strings. * This must be done before any module initialization so that statically * allocated string identifiers are used instead of heap allocated strings. @@ -14600,14 +14609,7 @@ PyUnicode_InternInPlace(PyObject **p) } PyObject *interned = get_interned_dict(); - if (interned == NULL) { - interned = PyDict_New(); - if (interned == NULL) { - PyErr_Clear(); /* Don't leave an exception */ - return; - } - set_interned_dict(interned); - } + assert(interned != NULL); PyObject *t = PyDict_SetDefault(interned, s, s); if (t == NULL) { From webhook-mailer at python.org Tue Mar 14 05:24:00 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Tue, 14 Mar 2023 09:24:00 -0000 Subject: [Python-checkins] gh-100315: clarification to `__slots__` docs. (#102621) Message-ID: https://github.com/python/cpython/commit/88c262c086077377b40dfae5e46f597e28ffe3c9 commit: 88c262c086077377b40dfae5e46f597e28ffe3c9 branch: main author: T committer: AlexWaygood date: 2023-03-14T09:23:52Z summary: gh-100315: clarification to `__slots__` docs. (#102621) refer to tp_itemsize in discussion on "variable-length" built-in types files: M Doc/reference/datamodel.rst diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index f447bbb1216d..1865d09fcaa1 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1944,8 +1944,10 @@ Notes on using *__slots__* descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this. -* Nonempty *__slots__* does not work for classes derived from "variable-length" - built-in types such as :class:`int`, :class:`bytes` and :class:`tuple`. +* :exc:`TypeError` will be raised if nonempty *__slots__* are defined for a + class derived from a + :c:member:`"variable-length" built-in type ` such as + :class:`int`, :class:`bytes`, and :class:`tuple`. * Any non-string :term:`iterable` may be assigned to *__slots__*. From webhook-mailer at python.org Tue Mar 14 05:30:41 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 14 Mar 2023 09:30:41 -0000 Subject: [Python-checkins] gh-100315: clarification to `__slots__` docs. (GH-102621) Message-ID: https://github.com/python/cpython/commit/2c015a674d9f983cec0bac627e09ca3e12631bca commit: 2c015a674d9f983cec0bac627e09ca3e12631bca branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-14T02:30:28-07:00 summary: gh-100315: clarification to `__slots__` docs. (GH-102621) refer to tp_itemsize in discussion on "variable-length" built-in types (cherry picked from commit 88c262c086077377b40dfae5e46f597e28ffe3c9) Co-authored-by: T files: M Doc/reference/datamodel.rst diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index e5a1e4d89f74..a5b8009ba9c0 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1876,8 +1876,10 @@ Notes on using *__slots__* descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this. -* Nonempty *__slots__* does not work for classes derived from "variable-length" - built-in types such as :class:`int`, :class:`bytes` and :class:`tuple`. +* :exc:`TypeError` will be raised if nonempty *__slots__* are defined for a + class derived from a + :c:member:`"variable-length" built-in type ` such as + :class:`int`, :class:`bytes`, and :class:`tuple`. * Any non-string :term:`iterable` may be assigned to *__slots__*. From webhook-mailer at python.org Tue Mar 14 05:32:17 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 14 Mar 2023 09:32:17 -0000 Subject: [Python-checkins] gh-100315: clarification to `__slots__` docs. (GH-102621) Message-ID: https://github.com/python/cpython/commit/1f7eb8fe6c1a566caf934a96c6fe2877b2447d5b commit: 1f7eb8fe6c1a566caf934a96c6fe2877b2447d5b branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-14T02:32:09-07:00 summary: gh-100315: clarification to `__slots__` docs. (GH-102621) refer to tp_itemsize in discussion on "variable-length" built-in types (cherry picked from commit 88c262c086077377b40dfae5e46f597e28ffe3c9) Co-authored-by: T files: M Doc/reference/datamodel.rst diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index e94b535901c5..87c538f6f2c1 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1944,8 +1944,10 @@ Notes on using *__slots__* descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this. -* Nonempty *__slots__* does not work for classes derived from "variable-length" - built-in types such as :class:`int`, :class:`bytes` and :class:`tuple`. +* :exc:`TypeError` will be raised if nonempty *__slots__* are defined for a + class derived from a + :c:member:`"variable-length" built-in type ` such as + :class:`int`, :class:`bytes`, and :class:`tuple`. * Any non-string :term:`iterable` may be assigned to *__slots__*. From webhook-mailer at python.org Tue Mar 14 05:51:55 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Tue, 14 Mar 2023 09:51:55 -0000 Subject: [Python-checkins] GH-94851: check unicode consistency of static strings in debug mode (#102684) Message-ID: https://github.com/python/cpython/commit/a703f743dbf2675948e59c44fa9d7112f7825100 commit: a703f743dbf2675948e59c44fa9d7112f7825100 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-14T15:21:38+05:30 summary: GH-94851: check unicode consistency of static strings in debug mode (#102684) files: M Include/internal/pycore_unicodeobject_generated.h M Tools/build/generate_global_objects.py diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 52af37a8e60a..fea9b6dbb1a7 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -13,1332 +13,1996 @@ static inline void _PyUnicode_InitStaticStrings(void) { PyObject *string; string = &_Py_ID(CANCELLED); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(FINISHED); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(False); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(JSONDecodeError); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(PENDING); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(Py_Repr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(TextIOWrapper); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(True); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(WarningMessage); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_WindowsConsoleIO); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__IOBase_closed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__abc_tpflags__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__abs__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__abstractmethods__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__add__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__aenter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__aexit__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__aiter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__all__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__and__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__anext__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__annotations__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__args__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__asyncio_running_event_loop__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__await__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__bases__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__bool__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__build_class__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__builtins__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__bytes__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__call__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__cantrace__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__class__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__class_getitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__classcell__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__complex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__contains__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__copy__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ctypes_from_outparam__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__del__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__delattr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__delete__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__delitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__dict__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__dictoffset__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__dir__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__divmod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__doc__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__enter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__eq__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__exit__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__file__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__float__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__floordiv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__format__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__fspath__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ge__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__get__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getattr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getattribute__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getinitargs__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getnewargs__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getnewargs_ex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getstate__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__gt__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__hash__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__iadd__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__iand__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ifloordiv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ilshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__imatmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__imod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__import__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__imul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__index__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__init__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__init_subclass__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__instancecheck__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__int__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__invert__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ior__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ipow__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__irshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__isabstractmethod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__isub__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__iter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__itruediv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ixor__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__le__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__len__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__length_hint__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__lltrace__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__loader__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__lshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__lt__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__main__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__matmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__missing__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__mod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__module__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__mro_entries__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__mul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__name__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ne__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__neg__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__new__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__newobj__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__newobj_ex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__next__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__notes__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__or__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__orig_class__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__origin__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__package__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__parameters__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__path__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__pos__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__pow__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__prepare__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__qualname__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__radd__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rand__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rdivmod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__reduce__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__reduce_ex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__repr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__reversed__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rfloordiv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rlshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rmatmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rmod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ror__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__round__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rpow__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rrshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rsub__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rtruediv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rxor__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__set__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__set_name__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__setattr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__setitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__setstate__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__sizeof__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__slotnames__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__slots__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__spec__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__str__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__sub__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__subclasscheck__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__subclasshook__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__truediv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__trunc__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_is_unpacked_typevartuple__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_prepare_subst__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_subst__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_unpacked_tuple_args__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__warningregistry__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__weaklistoffset__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__weakref__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__xor__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_abc_impl); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_abstract_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_active); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_annotation); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_anonymous_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_argtypes_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_as_parameter_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_asyncio_future_blocking); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_blksize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_bootstrap); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_check_retval_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_dealloc_warn); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_feature_version); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_fields_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_finalizing); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_find_and_load); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_fix_up_module); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_flags_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_get_sourcefile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_handle_fromlist); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_initializing); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_io); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_is_text_encoding); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_length_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_limbo); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_lock_unlock_module); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_needs_com_addref_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_pack_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_restype_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_showwarnmsg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_shutdown); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_slotnames); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_strptime_datetime); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_swappedbytes_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_type_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_uninitialized_submodules); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_warn_unawaited_coroutine); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_xoptions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(a); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(abs_tol); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(access); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(add); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(add_done_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(after_in_child); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(after_in_parent); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(aggregate_class); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(append); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(argdefs); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(arguments); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(argv); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(as_integer_ratio); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ast); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(attribute); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(authorizer_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(autocommit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(b); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(backtick); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(base); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(before); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(big); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(binary_form); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(block); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffer); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffer_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffer_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffering); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffers); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(bufsize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(builtins); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(byteorder); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(bytes); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(bytes_per_sep); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c_call); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c_exception); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c_return); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cached_statements); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cadata); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cafile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(call); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(call_exception_handler); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(call_soon); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cancel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(capath); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(category); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cb_type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(certfile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(check_same_thread); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(clear); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(close); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(closed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(closefd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(closure); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_argcount); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_cellvars); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_code); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_consts); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_exceptiontable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_filename); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_firstlineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_flags); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_freevars); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_kwonlyargcount); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_linetable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_names); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_nlocals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_posonlyargcount); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_qualname); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_stacksize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_varnames); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(code); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(command); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(comment_factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(consts); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(context); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cookie); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(copy); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(copyreg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(coro); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(count); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cwd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(d); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(data); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(database); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(decode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(decoder); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(default); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(defaultaction); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(delete); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(depth); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(detect_types); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(deterministic); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(device); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dict); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dictcomp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(difference_update); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(digest); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(digest_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(digestmod); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dir_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(discard); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dispatch_table); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(displayhook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dklen); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(doc); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dont_inherit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dst); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dst_dir_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(duration); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(e); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(effective_ids); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(element_factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(encode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(encoding); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(end); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(end_lineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(end_offset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(endpos); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(env); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(errors); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(event); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(eventmask); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exc_type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exc_value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(excepthook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exception); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(extend); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(facility); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(false); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(family); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fanout); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fd2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fdel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fget); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(file); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(file_actions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(filename); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fileno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(filepath); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fillvalue); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(filters); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(final); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(find_class); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fix_imports); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(flags); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(flush); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(follow_symlinks); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(format); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(frequency); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(from_param); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fromlist); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fromtimestamp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fromutc); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(func); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(future); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(generation); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(genexpr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_debug); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_event_loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_source); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(getattr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(getstate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(gid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(globals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(groupindex); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(groups); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(handle); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(hash_name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(header); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(headers); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(hi); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(hook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(id); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ident); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ignore); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(imag); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(importlib); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(in_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(incoming); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(indexgroup); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(inf); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(inheritable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initial); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initial_bytes); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initial_value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initval); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(inner_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(input); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(insert_comments); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(insert_pis); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(instructions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(intern); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(intersection); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isatty); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isinstance); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isoformat); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isolation_level); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(istext); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(item); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(items); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(iter); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(iterable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(iterations); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(join); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(jump); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(keepends); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(key); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(keyfile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(keys); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kind); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kw); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kw1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kw2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(lambda); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_node); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_traceback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(latin1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(leaf_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(len); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(length); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(level); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(limit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(line); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(line_buffering); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(lineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(listcomp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(little); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(lo); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(locale); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(locals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(logoption); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mapping); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(match); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(max_length); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxdigits); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxevents); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxmem); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxsplit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxvalue); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(memLevel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(memlimit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(message); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(metaclass); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(method); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mod); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(module); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(module_globals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(modules); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mro); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(msg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mycmp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_arg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_fields); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_sequence_fields); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_unnamed_fields); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(name_from); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(namespace_separator); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(namespaces); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(narg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ndigits); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(new_limit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(newline); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(newlines); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(next); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(node_depth); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(node_offset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ns); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(nstype); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(nt); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(null); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(number); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(obj); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(object); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(offset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(offset_dst); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(offset_src); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(on_type_read); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(onceregistry); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(only_keys); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(oparg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(opcode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(open); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(opener); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(operation); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(optimize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(options); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(order); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(out_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(outgoing); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(overlapped); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(owner); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(p); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pages); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(parent); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(password); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(path); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pattern); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(peek); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(persistent_id); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(persistent_load); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(person); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pi_factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(policy); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pos); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pos1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pos2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(posix); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(print_file_and_line); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(priority); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(progress); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(progress_handler); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(proto); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(protocol); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ps1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ps2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(query); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(quotetabs); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(r); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(raw); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(read); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(read1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readall); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readinto); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readinto1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readline); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readonly); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(real); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reducer_override); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(registry); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(rel_tol); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reload); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(repl); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(replace); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reserved); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(resetids); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(return); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reverse); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reversed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(s); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(salt); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sched_priority); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(scheduler); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(seek); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(seekable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(selectors); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(self); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(send); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sep); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sequence); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(server_hostname); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(server_side); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(session); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setcomp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setpgroup); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setsid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setsigdef); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setsigmask); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setstate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(shape); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(show_cmd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(signed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sizehint); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(skip_file_prefixes); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sleep); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sock); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sort); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sound); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(source); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(source_traceback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(src); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(src_dir_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stacklevel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(start); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(statement); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(status); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stderr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stdin); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stdout); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(step); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(store_name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strategy); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strftime); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strict); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strict_mode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(string); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sub_key); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(symmetric_difference_update); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tabsize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tag); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(target); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(target_is_directory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(task); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_frame); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_lasti); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_lineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_next); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tell); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(template); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(term); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(text); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(threading); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(throw); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(timeout); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(times); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(timetuple); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(top); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(trace_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(traceback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(trailers); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(translate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(true); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(truncate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(twice); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(txt); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tz); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tzname); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(uid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(unlink); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(unraisablehook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(uri); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(usedforsecurity); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(values); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(version); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(volume); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(warnings); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(warnoptions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(wbits); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(week); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(weekday); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(which); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(who); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(withdata); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(writable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(write); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(write_through); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(x); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(year); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(zdict); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); } /* End auto-generated code */ diff --git a/Tools/build/generate_global_objects.py b/Tools/build/generate_global_objects.py index 9ceae89878cd..1f53f02d41ef 100644 --- a/Tools/build/generate_global_objects.py +++ b/Tools/build/generate_global_objects.py @@ -360,6 +360,7 @@ def generate_static_strings_initializer(identifiers, strings): # This use of _Py_ID() is ignored by iter_global_strings() # since iter_files() ignores .h files. printer.write(f'string = &_Py_ID({i});') + printer.write(f'assert(_PyUnicode_CheckConsistency(string, 1));') printer.write(f'PyUnicode_InternInPlace(&string);') # XXX What about "strings"? printer.write(END) From webhook-mailer at python.org Tue Mar 14 12:06:03 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 14 Mar 2023 16:06:03 -0000 Subject: [Python-checkins] gh-81057: Add a CI Check for New Unsupported C Global Variables (gh-102506) Message-ID: https://github.com/python/cpython/commit/1ff81c0cb67215694f084e51c4d35ae53b9f5cf9 commit: 1ff81c0cb67215694f084e51c4d35ae53b9f5cf9 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-14T10:05:54-06:00 summary: gh-81057: Add a CI Check for New Unsupported C Global Variables (gh-102506) This will keep us from adding new unsupported (i.e. non-const) C global variables, which would break interpreter isolation. FYI, historically it is very uncommon for new global variables to get added. Furthermore, it is rare for new code to break the c-analyzer. So the check should almost always pass unnoticed. Note that I've removed test_check_c_globals. A test wasn't a great fit conceptually and was super slow on debug builds. A CI check is a better fit. This also resolves gh-100237. https://github.com/python/cpython/issues/81057 files: D Lib/test/test_check_c_globals.py M .github/workflows/build.yml M Makefile.pre.in M Tools/c-analyzer/c_parser/preprocessor/common.py M Tools/c-analyzer/c_parser/preprocessor/gcc.py M Tools/c-analyzer/cpython/__main__.py M Tools/c-analyzer/cpython/_parser.py M Tools/c-analyzer/cpython/ignored.tsv diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2241b0b8aa40..4e5328282f12 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -111,6 +111,9 @@ jobs: run: make smelly - name: Check limited ABI symbols run: make check-limited-abi + - name: Check for unsupported C global variables + if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME + run: make check-c-globals build_win32: name: 'Windows (x86)' diff --git a/Lib/test/test_check_c_globals.py b/Lib/test/test_check_c_globals.py deleted file mode 100644 index 670be52422f7..000000000000 --- a/Lib/test/test_check_c_globals.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest -import test.test_tools -from test.support.warnings_helper import save_restore_warnings_filters - - -# TODO: gh-92584: c-analyzer uses distutils which was removed in Python 3.12 -raise unittest.SkipTest("distutils has been removed in Python 3.12") - - -test.test_tools.skip_if_missing('c-analyzer') -with test.test_tools.imports_under_tool('c-analyzer'): - # gh-95349: Save/restore warnings filters to leave them unchanged. - # Importing the c-analyzer imports docutils which imports pkg_resources - # which adds a warnings filter. - with save_restore_warnings_filters(): - from cpython.__main__ import main - - -class ActualChecks(unittest.TestCase): - - # XXX Also run the check in "make check". - #@unittest.expectedFailure - # Failing on one of the buildbots (see https://bugs.python.org/issue36876). - @unittest.skip('activate this once all the globals have been resolved') - def test_check_c_globals(self): - try: - main('check', {}) - except NotImplementedError: - raise unittest.SkipTest('not supported on this host') - - -if __name__ == '__main__': - # Test needs to be a package, so we can do relative imports. - unittest.main() diff --git a/Makefile.pre.in b/Makefile.pre.in index 1a1853bf3d78..59762165c100 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2560,6 +2560,12 @@ distclean: clobber docclean smelly: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/smelly.py +# Check if any unsupported C global variables have been added. +check-c-globals: + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/c-analyzer/check-c-globals.py \ + --format summary \ + --traceback + # Find files with funny names funny: find $(SUBDIRS) $(SUBDIRSTOO) \ diff --git a/Tools/c-analyzer/c_parser/preprocessor/common.py b/Tools/c-analyzer/c_parser/preprocessor/common.py index 4291a0663375..dbe1edeef385 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/common.py +++ b/Tools/c-analyzer/c_parser/preprocessor/common.py @@ -115,15 +115,15 @@ def converted_error(tool, argv, filename): def convert_error(tool, argv, filename, stderr, rc): error = (stderr.splitlines()[0], rc) if (_expected := is_os_mismatch(filename, stderr)): - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise OSMismatchError(filename, _expected, argv, error, tool) elif (_missing := is_missing_dep(stderr)): - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise MissingDependenciesError(filename, (_missing,), argv, error, tool) elif '#error' in stderr: # XXX Ignore incompatible files. error = (stderr.splitlines()[1], rc) - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise ErrorDirectiveError(filename, argv, error, tool) else: # Try one more time, with stderr written to the terminal. diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 7ef1a8afc3b1..24c1b0e9b9d4 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -6,6 +6,11 @@ TOOL = 'gcc' +META_FILES = { + '', + '', +} + # https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html # flags: # 1 start of a new file @@ -75,11 +80,15 @@ def _iter_lines(text, reqfile, samefiles, cwd, raw=False): # The first line is special. # The next two lines are consistent. - for expected in [ - f'# 1 "{reqfile}"', - '# 1 ""', - '# 1 ""', - ]: + firstlines = [ + f'# 0 "{reqfile}"', + '# 0 ""', + '# 0 ""', + ] + if text.startswith('# 1 '): + # Some preprocessors emit a lineno of 1 for line-less entries. + firstlines = [l.replace('# 0 ', '# 1 ') for l in firstlines] + for expected in firstlines: line = next(lines) if line != expected: raise NotImplementedError((line, expected)) @@ -121,7 +130,7 @@ def _iter_top_include_lines(lines, topfile, cwd, # _parse_marker_line() that the preprocessor reported lno as 1. lno = 1 for line in lines: - if line == '# 1 "" 2': + if line == '# 0 "" 2' or line == '# 1 "" 2': # We're done with this top-level include. return @@ -174,8 +183,8 @@ def _parse_marker_line(line, reqfile=None): return None, None, None lno, origfile, flags = m.groups() lno = int(lno) + assert origfile not in META_FILES, (line,) assert lno > 0, (line, lno) - assert origfile not in ('', ''), (line,) flags = set(int(f) for f in flags.split()) if flags else () if 1 in flags: diff --git a/Tools/c-analyzer/cpython/__main__.py b/Tools/c-analyzer/cpython/__main__.py index 2b9e4233b95a..fe7a16726f45 100644 --- a/Tools/c-analyzer/cpython/__main__.py +++ b/Tools/c-analyzer/cpython/__main__.py @@ -1,5 +1,6 @@ import logging import sys +import textwrap from c_common.fsutil import expand_filenames, iter_files_by_suffix from c_common.scriptutil import ( @@ -26,6 +27,39 @@ logger = logging.getLogger(__name__) +CHECK_EXPLANATION = textwrap.dedent(''' + ------------------------- + + Non-constant global variables are generally not supported + in the CPython repo. We use a tool to analyze the C code + and report if any unsupported globals are found. The tool + may be run manually with: + + ./python Tools/c-analyzer/check-c-globals.py --format summary [FILE] + + Occasionally the tool is unable to parse updated code. + If this happens then add the file to the "EXCLUDED" list + in Tools/c-analyzer/cpython/_parser.py and create a new + issue for fixing the tool (and CC ericsnowcurrently + on the issue). + + If the tool reports an unsupported global variable and + it is actually const (and thus supported) then first try + fixing the declaration appropriately in the code. If that + doesn't work then add the variable to the "should be const" + section of Tools/c-analyzer/cpython/ignored.tsv. + + If the tool otherwise reports an unsupported global variable + then first try to make it non-global, possibly adding to + PyInterpreterState (for core code) or module state (for + extension modules). In an emergency, you can add the + variable to Tools/c-analyzer/cpython/globals-to-fix.tsv + to get CI passing, but doing so should be avoided. If + this course it taken, be sure to create an issue for + eliminating the global (and CC ericsnowcurrently). +''') + + def _resolve_filenames(filenames): if filenames: resolved = (_files.resolve_filename(f) for f in filenames) @@ -123,14 +157,26 @@ def _cli_check(parser, **kwargs): def cmd_check(filenames=None, **kwargs): filenames = _resolve_filenames(filenames) kwargs['get_file_preprocessor'] = _parser.get_preprocessor(log_err=print) - c_analyzer.cmd_check( - filenames, - relroot=REPO_ROOT, - _analyze=_analyzer.analyze, - _CHECKS=CHECKS, - file_maxsizes=_parser.MAX_SIZES, - **kwargs - ) + try: + c_analyzer.cmd_check( + filenames, + relroot=REPO_ROOT, + _analyze=_analyzer.analyze, + _CHECKS=CHECKS, + file_maxsizes=_parser.MAX_SIZES, + **kwargs + ) + except SystemExit as exc: + num_failed = exc.args[0] if getattr(exc, 'args', None) else None + if isinstance(num_failed, int): + if num_failed > 0: + sys.stderr.flush() + print(CHECK_EXPLANATION, flush=True) + raise # re-raise + except Exception: + sys.stderr.flush() + print(CHECK_EXPLANATION, flush=True) + raise # re-raise def cmd_analyze(filenames=None, **kwargs): diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index e7764165d36c..6da4fbbf4224 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -106,15 +106,20 @@ def clean_lines(text): * ./Include/internal Modules/_decimal/**/*.c Modules/_decimal/libmpdec +Modules/_elementtree.c Modules/expat Modules/_hacl/*.c Modules/_hacl/include Modules/_hacl/*.h Modules/_hacl/include -Modules/_tkinter.c /usr/include/tcl8.6 Modules/md5module.c Modules/_hacl/include Modules/sha1module.c Modules/_hacl/include Modules/sha2module.c Modules/_hacl/include -Modules/tkappinit.c /usr/include/tcl Objects/stringlib/*.h Objects +# possible system-installed headers, just in case +Modules/_tkinter.c /usr/include/tcl8.6 +Modules/_uuidmodule.c /usr/include/uuid +Modules/nismodule.c /usr/include/tirpc +Modules/tkappinit.c /usr/include/tcl + # @end=tsv@ ''')[1:] diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 700ddf285183..048112dd9925 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -228,6 +228,7 @@ Modules/_xxinterpchannelsmodule.c - _channelid_end_recv - Modules/_xxinterpchannelsmodule.c - _channelid_end_send - Modules/_zoneinfo.c - DAYS_BEFORE_MONTH - Modules/_zoneinfo.c - DAYS_IN_MONTH - +Modules/_xxsubinterpretersmodule.c - no_exception - Modules/arraymodule.c - descriptors - Modules/arraymodule.c - emptybuf - Modules/cjkcodecs/_codecs_cn.c - _mapping_list - From webhook-mailer at python.org Tue Mar 14 14:40:19 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 14 Mar 2023 18:40:19 -0000 Subject: [Python-checkins] gh-102354: change python3 to python in docs examples (#102696) Message-ID: https://github.com/python/cpython/commit/80abd62647b2a36947a11a6a8e395061be6f0c61 commit: 80abd62647b2a36947a11a6a8e395061be6f0c61 branch: main author: Paul Watson committer: carljm date: 2023-03-14T12:40:12-06:00 summary: gh-102354: change python3 to python in docs examples (#102696) files: M Doc/library/__main__.rst M Doc/library/importlib.metadata.rst M Doc/library/pdb.rst M Doc/tutorial/venv.rst M Doc/using/venv-create.inc diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index 6a2a7a7317f7..761c88710f98 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -259,7 +259,7 @@ one mentioned below are preferred. See :mod:`venv` for an example of a package with a minimal ``__main__.py`` in the standard library. It doesn't contain a ``if __name__ == '__main__'`` - block. You can invoke it with ``python3 -m venv [directory]``. + block. You can invoke it with ``python -m venv [directory]``. See :mod:`runpy` for more details on the :option:`-m` flag to the interpreter executable. diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 988d1a317f59..6e084101995e 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -73,7 +73,7 @@ something into it: .. code-block:: shell-session - $ python3 -m venv example + $ python -m venv example $ source example/bin/activate (example) $ python -m pip install wheel diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 4ae12a5d03a7..21c6ca8622dc 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -58,7 +58,7 @@ of the debugger is:: :file:`pdb.py` can also be invoked as a script to debug other scripts. For example:: - python3 -m pdb myscript.py + python -m pdb myscript.py When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or @@ -72,7 +72,7 @@ useful than quitting the debugger upon program's exit. .. versionadded:: 3.7 :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to the way - ``python3 -m`` does. As with a script, the debugger will pause execution just + ``python -m`` does. As with a script, the debugger will pause execution just before the first line of the module. diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst index 05f0e6bbcc1b..d1bba098d7d2 100644 --- a/Doc/tutorial/venv.rst +++ b/Doc/tutorial/venv.rst @@ -44,7 +44,7 @@ whichever version you want. To create a virtual environment, decide upon a directory where you want to place it, and run the :mod:`venv` module as a script with the directory path:: - python3 -m venv tutorial-env + python -m venv tutorial-env This will create the ``tutorial-env`` directory if it doesn't exist, and also create directories inside it containing a copy of the Python diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index d535b254f056..43ee6b7807d5 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -1,7 +1,7 @@ Creation of :ref:`virtual environments ` is done by executing the command ``venv``:: - python3 -m venv /path/to/new/virtual/environment + python -m venv /path/to/new/virtual/environment Running this command creates the target directory (creating any parent directories that don't exist already) and places a ``pyvenv.cfg`` file in it From webhook-mailer at python.org Tue Mar 14 14:52:35 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 14 Mar 2023 18:52:35 -0000 Subject: [Python-checkins] [3.10] gh-102354: change python3 to python in docs examples (GH-102696) (#102698) Message-ID: https://github.com/python/cpython/commit/df38f7c577206bc82090222f36529db680285478 commit: df38f7c577206bc82090222f36529db680285478 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: carljm date: 2023-03-14T12:52:27-06:00 summary: [3.10] gh-102354: change python3 to python in docs examples (GH-102696) (#102698) gh-102354: change python3 to python in docs examples (GH-102696) (cherry picked from commit 80abd62647b2a36947a11a6a8e395061be6f0c61) Co-authored-by: Paul Watson files: M Doc/library/__main__.rst M Doc/library/importlib.metadata.rst M Doc/library/pdb.rst M Doc/tutorial/venv.rst M Doc/using/venv-create.inc diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index d0a65e76b842..0a93efac203c 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -259,7 +259,7 @@ one mentioned below are preferred. See :mod:`venv` for an example of a package with a minimal ``__main__.py`` in the standard library. It doesn't contain a ``if __name__ == '__main__'`` - block. You can invoke it with ``python3 -m venv [directory]``. + block. You can invoke it with ``python -m venv [directory]``. See :mod:`runpy` for more details on the :option:`-m` flag to the interpreter executable. diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index c4c4a7db31f4..56ce8d91bd84 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -41,7 +41,7 @@ something into it: .. code-block:: shell-session - $ python3 -m venv example + $ python -m venv example $ source example/bin/activate (example) $ pip install wheel diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index c87e32779609..3b4a57d86fe7 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -58,7 +58,7 @@ of the debugger is:: :file:`pdb.py` can also be invoked as a script to debug other scripts. For example:: - python3 -m pdb myscript.py + python -m pdb myscript.py When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or @@ -72,7 +72,7 @@ useful than quitting the debugger upon program's exit. .. versionadded:: 3.7 :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to the way - ``python3 -m`` does. As with a script, the debugger will pause execution just + ``python -m`` does. As with a script, the debugger will pause execution just before the first line of the module. diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst index 2cc30f89e95d..1e268df8c397 100644 --- a/Doc/tutorial/venv.rst +++ b/Doc/tutorial/venv.rst @@ -44,7 +44,7 @@ whichever version you want. To create a virtual environment, decide upon a directory where you want to place it, and run the :mod:`venv` module as a script with the directory path:: - python3 -m venv tutorial-env + python -m venv tutorial-env This will create the ``tutorial-env`` directory if it doesn't exist, and also create directories inside it containing a copy of the Python diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index 0422cd2e4e76..9f25563122ef 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -1,7 +1,7 @@ Creation of :ref:`virtual environments ` is done by executing the command ``venv``:: - python3 -m venv /path/to/new/virtual/environment + python -m venv /path/to/new/virtual/environment Running this command creates the target directory (creating any parent directories that don't exist already) and places a ``pyvenv.cfg`` file in it From webhook-mailer at python.org Tue Mar 14 14:52:40 2023 From: webhook-mailer at python.org (carljm) Date: Tue, 14 Mar 2023 18:52:40 -0000 Subject: [Python-checkins] [3.11] gh-102354: change python3 to python in docs examples (GH-102696) (#102697) Message-ID: https://github.com/python/cpython/commit/738dde303b72d3dad8f60b51beab14816b854903 commit: 738dde303b72d3dad8f60b51beab14816b854903 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: carljm date: 2023-03-14T12:52:33-06:00 summary: [3.11] gh-102354: change python3 to python in docs examples (GH-102696) (#102697) gh-102354: change python3 to python in docs examples (GH-102696) (cherry picked from commit 80abd62647b2a36947a11a6a8e395061be6f0c61) Co-authored-by: Paul Watson files: M Doc/library/__main__.rst M Doc/library/importlib.metadata.rst M Doc/library/pdb.rst M Doc/tutorial/venv.rst M Doc/using/venv-create.inc diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index d0a65e76b842..0a93efac203c 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -259,7 +259,7 @@ one mentioned below are preferred. See :mod:`venv` for an example of a package with a minimal ``__main__.py`` in the standard library. It doesn't contain a ``if __name__ == '__main__'`` - block. You can invoke it with ``python3 -m venv [directory]``. + block. You can invoke it with ``python -m venv [directory]``. See :mod:`runpy` for more details on the :option:`-m` flag to the interpreter executable. diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 57991779ccfd..a768e934583b 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -73,7 +73,7 @@ something into it: .. code-block:: shell-session - $ python3 -m venv example + $ python -m venv example $ source example/bin/activate (example) $ python -m pip install wheel diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 4ae12a5d03a7..21c6ca8622dc 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -58,7 +58,7 @@ of the debugger is:: :file:`pdb.py` can also be invoked as a script to debug other scripts. For example:: - python3 -m pdb myscript.py + python -m pdb myscript.py When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or @@ -72,7 +72,7 @@ useful than quitting the debugger upon program's exit. .. versionadded:: 3.7 :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to the way - ``python3 -m`` does. As with a script, the debugger will pause execution just + ``python -m`` does. As with a script, the debugger will pause execution just before the first line of the module. diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst index 8312c5878659..9a3f49d1380d 100644 --- a/Doc/tutorial/venv.rst +++ b/Doc/tutorial/venv.rst @@ -44,7 +44,7 @@ whichever version you want. To create a virtual environment, decide upon a directory where you want to place it, and run the :mod:`venv` module as a script with the directory path:: - python3 -m venv tutorial-env + python -m venv tutorial-env This will create the ``tutorial-env`` directory if it doesn't exist, and also create directories inside it containing a copy of the Python diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index 0422cd2e4e76..9f25563122ef 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -1,7 +1,7 @@ Creation of :ref:`virtual environments ` is done by executing the command ``venv``:: - python3 -m venv /path/to/new/virtual/environment + python -m venv /path/to/new/virtual/environment Running this command creates the target directory (creating any parent directories that don't exist already) and places a ``pyvenv.cfg`` file in it From webhook-mailer at python.org Tue Mar 14 16:01:43 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 14 Mar 2023 20:01:43 -0000 Subject: [Python-checkins] gh-102660: Handle m_copy Specially for the sys and builtins Modules (gh-102661) Message-ID: https://github.com/python/cpython/commit/cdb21ba74d933e262bc1696b6ce78b50cb5a4443 commit: cdb21ba74d933e262bc1696b6ce78b50cb5a4443 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-14T14:01:35-06:00 summary: gh-102660: Handle m_copy Specially for the sys and builtins Modules (gh-102661) It doesn't make sense to use multi-phase init for these modules. Using a per-interpreter "m_copy" (instead of PyModuleDef.m_base.m_copy) makes this work okay. (This came up while working on gh-101660.) Note that we might instead end up disallowing re-load for sys/builtins since they are so special. https://github.com/python/cpython/issues/102660 files: M Include/internal/pycore_interp.h M Python/bltinmodule.c M Python/import.c M Python/pystate.c M Python/sysmodule.c diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 9efed0a1cf90..84303318d218 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -111,6 +111,7 @@ struct _is { PyObject *dict; /* Stores per-interpreter state */ + PyObject *sysdict_copy; PyObject *builtins_copy; // Initialized to _PyEval_EvalFrameDefault(). _PyFrameEvalFunction eval_frame; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 12ca0ba6c487..a8a34620b9bc 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -3098,6 +3098,9 @@ _PyBuiltin_Init(PyInterpreterState *interp) } Py_DECREF(debug); + /* m_copy of Py_None means it is copied some other way. */ + builtinsmodule.m_base.m_copy = Py_NewRef(Py_None); + return mod; #undef ADD_TO_ALL #undef SETBUILTIN diff --git a/Python/import.c b/Python/import.c index 1bf4199e125a..612fee243bd9 100644 --- a/Python/import.c +++ b/Python/import.c @@ -978,6 +978,16 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) return 0; } +static inline int +match_mod_name(PyObject *actual, const char *expected) +{ + if (PyUnicode_CompareWithASCIIString(actual, expected) == 0) { + return 1; + } + assert(!PyErr_Occurred()); + return 0; +} + static int fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) { @@ -1001,7 +1011,8 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) // when the extension module doesn't support sub-interpreters. // XXX Why special-case the main interpreter? if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { - if (def->m_size == -1) { + /* m_copy of Py_None means it is copied some other way. */ + if (def->m_size == -1 && def->m_base.m_copy != Py_None) { if (def->m_base.m_copy) { /* Somebody already imported the module, likely under a different name. @@ -1055,18 +1066,34 @@ import_find_extension(PyThreadState *tstate, PyObject *name, PyObject *modules = MODULES(tstate->interp); if (def->m_size == -1) { + PyObject *m_copy = def->m_base.m_copy; /* Module does not support repeated initialization */ - if (def->m_base.m_copy == NULL) + if (m_copy == NULL) { return NULL; + } + else if (m_copy == Py_None) { + if (match_mod_name(name, "sys")) { + m_copy = tstate->interp->sysdict_copy; + } + else if (match_mod_name(name, "builtins")) { + m_copy = tstate->interp->builtins_copy; + } + else { + _PyErr_SetString(tstate, PyExc_ImportError, "missing m_copy"); + return NULL; + } + } + /* m_copy of Py_None means it is copied some other way. */ mod = import_add_module(tstate, name); - if (mod == NULL) + if (mod == NULL) { return NULL; + } mdict = PyModule_GetDict(mod); if (mdict == NULL) { Py_DECREF(mod); return NULL; } - if (PyDict_Update(mdict, def->m_base.m_copy)) { + if (PyDict_Update(mdict, m_copy)) { Py_DECREF(mod); return NULL; } diff --git a/Python/pystate.c b/Python/pystate.c index 28606e4f32f7..3a2966c54a4c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -805,6 +805,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) assert(interp->imports.importlib == NULL); assert(interp->imports.import_func == NULL); + Py_CLEAR(interp->sysdict_copy); Py_CLEAR(interp->builtins_copy); Py_CLEAR(interp->dict); #ifdef HAVE_FORK diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 764fb70bae6c..fc0550266bf1 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3425,12 +3425,20 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) return _PyStatus_ERR("failed to create a module object"); } + /* m_copy of Py_None means it is copied some other way. */ + sysmodule.m_base.m_copy = Py_NewRef(Py_None); + PyObject *sysdict = PyModule_GetDict(sysmod); if (sysdict == NULL) { goto error; } interp->sysdict = Py_NewRef(sysdict); + interp->sysdict_copy = PyDict_Copy(sysdict); + if (interp->sysdict_copy == NULL) { + goto error; + } + if (PyDict_SetItemString(sysdict, "modules", modules) < 0) { goto error; } From webhook-mailer at python.org Tue Mar 14 16:20:41 2023 From: webhook-mailer at python.org (gvanrossum) Date: Tue, 14 Mar 2023 20:20:41 -0000 Subject: [Python-checkins] gh-102674: Remove _specialization_stats from Lib/opcode.py (#102685) Message-ID: https://github.com/python/cpython/commit/d77c48740f5cd17597693bd0d27e32db725fa3a0 commit: d77c48740f5cd17597693bd0d27e32db725fa3a0 branch: main author: Dong-hee Na committer: gvanrossum date: 2023-03-14T13:20:14-07:00 summary: gh-102674: Remove _specialization_stats from Lib/opcode.py (#102685) It's not use except in a test, so move it there instead. files: M Lib/opcode.py M Lib/test/test__opcode.py diff --git a/Lib/opcode.py b/Lib/opcode.py index 23529d87a09e..d4a2d554cf67 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -377,14 +377,6 @@ def pseudo_op(name, op, real_ops): _specialized_instructions = [ opcode for family in _specializations.values() for opcode in family ] -_specialization_stats = [ - "success", - "failure", - "hit", - "deferred", - "miss", - "deopt", -] _cache_format = { "LOAD_GLOBAL": { diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index db831069c7ae..fb4ab15f7041 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -69,8 +69,7 @@ def test_stack_effect_jump(self): class SpecializationStatsTests(unittest.TestCase): def test_specialization_stats(self): - stat_names = opcode._specialization_stats - + stat_names = ["success", "failure", "hit", "deferred", "miss", "deopt"] specialized_opcodes = [ op.lower() for op in opcode._specializations From webhook-mailer at python.org Tue Mar 14 18:17:08 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Tue, 14 Mar 2023 22:17:08 -0000 Subject: [Python-checkins] Rename redundant enum tests so that they run (#102535) Message-ID: https://github.com/python/cpython/commit/a028778d4c813914ae1e6ef3a04bb96dbf92ace6 commit: a028778d4c813914ae1e6ef3a04bb96dbf92ace6 branch: main author: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-14T15:16:45-07:00 summary: Rename redundant enum tests so that they run (#102535) files: M Lib/test/test_enum.py diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 2b14590b2c21..a11bb441f06e 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -4579,15 +4579,14 @@ class Double(Enum): TWO = 2 self.assertEqual(Double.__doc__, None) - - def test_doc_1(self): + def test_doc_3(self): class Triple(Enum): ONE = 1 TWO = 2 THREE = 3 self.assertEqual(Triple.__doc__, None) - def test_doc_1(self): + def test_doc_4(self): class Quadruple(Enum): ONE = 1 TWO = 2 From webhook-mailer at python.org Tue Mar 14 18:38:23 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 14 Mar 2023 22:38:23 -0000 Subject: [Python-checkins] gh-101578: mention in what's new in 3.12 that exceptions are now normalized before stored (#102702) Message-ID: https://github.com/python/cpython/commit/152292b98fd52f8b3db252e5609d6a605a11cb57 commit: 152292b98fd52f8b3db252e5609d6a605a11cb57 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-14T22:38:15Z summary: gh-101578: mention in what's new in 3.12 that exceptions are now normalized before stored (#102702) files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 9f33dbc808dd..217ffec1ee10 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -982,6 +982,11 @@ Porting to Python 3.12 effects, these side effects are no longer duplicated. (Contributed by Victor Stinner in :gh:`98724`.) +* The interpreter's error indicator is now always normalized. This means + that :c:func:`PyErr_SetObject`, :c:func:`PyErr_SetString` and the other + functions that set the error indicator now normalize the exception + before storing it. (Contributed by Mark Shannon in :gh:`101578`.) + Deprecated ---------- From webhook-mailer at python.org Tue Mar 14 18:46:09 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 14 Mar 2023 22:46:09 -0000 Subject: [Python-checkins] Rename redundant enum tests so that they run (GH-102535) Message-ID: https://github.com/python/cpython/commit/1649f3e591b40e992a72fa2bf7c50dbc1333a820 commit: 1649f3e591b40e992a72fa2bf7c50dbc1333a820 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-14T15:46:01-07:00 summary: Rename redundant enum tests so that they run (GH-102535) (cherry picked from commit a028778d4c813914ae1e6ef3a04bb96dbf92ace6) Co-authored-by: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> files: M Lib/test/test_enum.py diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 0143e8594d6e..72dfb9881779 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -4500,15 +4500,14 @@ class Double(Enum): TWO = 2 self.assertEqual(Double.__doc__, None) - - def test_doc_1(self): + def test_doc_3(self): class Triple(Enum): ONE = 1 TWO = 2 THREE = 3 self.assertEqual(Triple.__doc__, None) - def test_doc_1(self): + def test_doc_4(self): class Quadruple(Enum): ONE = 1 TWO = 2 From webhook-mailer at python.org Tue Mar 14 20:03:50 2023 From: webhook-mailer at python.org (Mariatta) Date: Wed, 15 Mar 2023 00:03:50 -0000 Subject: [Python-checkins] gh-102703: Fix typo in modules tutorial documentation (GH-102707) Message-ID: https://github.com/python/cpython/commit/0a539b5db312d126ff45dd4aa6a53d40a292c512 commit: 0a539b5db312d126ff45dd4aa6a53d40a292c512 branch: main author: Robert Prater (B. Eng) committer: Mariatta date: 2023-03-14T17:03:43-07:00 summary: gh-102703: Fix typo in modules tutorial documentation (GH-102707) **Before** This prevents directories with a common name, such as ``string``, unintentionally hiding ... **After** This prevents directories with a common name, such as ``string``, from unintentionally hiding ... files: M Doc/tutorial/modules.rst diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index ad70d92994af..4daafa49a34d 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -438,7 +438,7 @@ When importing the package, Python searches through the directories on The :file:`__init__.py` files are required to make Python treat directories containing the file as packages. This prevents directories with a common name, -such as ``string``, unintentionally hiding valid modules that occur later +such as ``string``, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, :file:`__init__.py` can just be an empty file, but it can also execute initialization code for the package or set the ``__all__`` variable, described later. From webhook-mailer at python.org Tue Mar 14 20:07:36 2023 From: webhook-mailer at python.org (zooba) Date: Wed, 15 Mar 2023 00:07:36 -0000 Subject: [Python-checkins] gh-102519: Avoid failing tests due to inaccessible volumes (GH-102706) Message-ID: https://github.com/python/cpython/commit/5fce813d8e547d6508daa386b67f230105c3a174 commit: 5fce813d8e547d6508daa386b67f230105c3a174 branch: main author: Steve Dower committer: zooba date: 2023-03-15T00:07:30Z summary: gh-102519: Avoid failing tests due to inaccessible volumes (GH-102706) files: M Lib/test/test_os.py diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 253e2a23238f..42357fef80ec 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2683,12 +2683,17 @@ def test_listvolumes(self): def test_listmounts(self): for volume in os.listvolumes(): - mounts = os.listmounts(volume) - self.assertIsInstance(mounts, list) - self.assertSetEqual( - set(mounts), - self.known_mounts & set(mounts), - ) + try: + mounts = os.listmounts(volume) + except OSError as ex: + if support.verbose: + print("Skipping", volume, "because of", ex) + else: + self.assertIsInstance(mounts, list) + self.assertSetEqual( + set(mounts), + self.known_mounts & set(mounts), + ) @unittest.skipUnless(hasattr(os, 'readlink'), 'needs os.readlink()') From webhook-mailer at python.org Tue Mar 14 20:10:47 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 15 Mar 2023 00:10:47 -0000 Subject: [Python-checkins] gh-102703: Fix typo in modules tutorial documentation (GH-102707) Message-ID: https://github.com/python/cpython/commit/95fd2dfd3f3c0e02cb0ecb21e594663a46d8542c commit: 95fd2dfd3f3c0e02cb0ecb21e594663a46d8542c branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-14T17:10:39-07:00 summary: gh-102703: Fix typo in modules tutorial documentation (GH-102707) **Before** This prevents directories with a common name, such as ``string``, unintentionally hiding ... **After** This prevents directories with a common name, such as ``string``, from unintentionally hiding ... (cherry picked from commit 0a539b5db312d126ff45dd4aa6a53d40a292c512) Co-authored-by: Robert Prater (B. Eng) files: M Doc/tutorial/modules.rst diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index 5282c6860319..11a7c333ac1b 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -434,7 +434,7 @@ When importing the package, Python searches through the directories on The :file:`__init__.py` files are required to make Python treat directories containing the file as packages. This prevents directories with a common name, -such as ``string``, unintentionally hiding valid modules that occur later +such as ``string``, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, :file:`__init__.py` can just be an empty file, but it can also execute initialization code for the package or set the ``__all__`` variable, described later. From webhook-mailer at python.org Tue Mar 14 20:12:04 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 15 Mar 2023 00:12:04 -0000 Subject: [Python-checkins] gh-102703: Fix typo in modules tutorial documentation (GH-102707) Message-ID: https://github.com/python/cpython/commit/a166cb4131587bbab05bde491fc95eb65523b2c9 commit: a166cb4131587bbab05bde491fc95eb65523b2c9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-14T17:11:56-07:00 summary: gh-102703: Fix typo in modules tutorial documentation (GH-102707) **Before** This prevents directories with a common name, such as ``string``, unintentionally hiding ... **After** This prevents directories with a common name, such as ``string``, from unintentionally hiding ... (cherry picked from commit 0a539b5db312d126ff45dd4aa6a53d40a292c512) Co-authored-by: Robert Prater (B. Eng) files: M Doc/tutorial/modules.rst diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index ad70d92994af..4daafa49a34d 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -438,7 +438,7 @@ When importing the package, Python searches through the directories on The :file:`__init__.py` files are required to make Python treat directories containing the file as packages. This prevents directories with a common name, -such as ``string``, unintentionally hiding valid modules that occur later +such as ``string``, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, :file:`__init__.py` can just be an empty file, but it can also execute initialization code for the package or set the ``__all__`` variable, described later. From webhook-mailer at python.org Tue Mar 14 20:33:26 2023 From: webhook-mailer at python.org (gvanrossum) Date: Wed, 15 Mar 2023 00:33:26 -0000 Subject: [Python-checkins] gh-102560 Add docstrings to asyncio.TaskGroup (#102565) Message-ID: https://github.com/python/cpython/commit/e94edab727d07bef851e0e1a345e18a453be863d commit: e94edab727d07bef851e0e1a345e18a453be863d branch: main author: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> committer: gvanrossum date: 2023-03-14T17:33:19-07:00 summary: gh-102560 Add docstrings to asyncio.TaskGroup (#102565) files: M Lib/asyncio/taskgroups.py diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 911419e1769c..0fdea3697ece 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -10,7 +10,21 @@ class TaskGroup: + """Asynchronous context manager for managing groups of tasks. + Example use: + + async with asyncio.TaskGroup() as group: + task1 = group.create_task(some_coroutine(...)) + task2 = group.create_task(other_coroutine(...)) + print("Both tasks have completed now.") + + All tasks are awaited when the context manager exits. + + Any exceptions other than `asyncio.CancelledError` raised within + a task will cancel all remaining tasks and wait for them to exit. + The exceptions are then combined and raised as an `ExceptionGroup`. + """ def __init__(self): self._entered = False self._exiting = False @@ -135,6 +149,10 @@ async def __aexit__(self, et, exc, tb): self._errors = None def create_task(self, coro, *, name=None, context=None): + """Create a new task in this group and return it. + + Similar to `asyncio.create_task`. + """ if not self._entered: raise RuntimeError(f"TaskGroup {self!r} has not been entered") if self._exiting and not self._tasks: From webhook-mailer at python.org Tue Mar 14 22:36:38 2023 From: webhook-mailer at python.org (terryjreedy) Date: Wed, 15 Mar 2023 02:36:38 -0000 Subject: [Python-checkins] gh-101377: improving test_locale_calendar_formatweekday of calendar (#101378) Message-ID: https://github.com/python/cpython/commit/5e0865f22eed9f3f3f0e912c4ada196effbd8ce0 commit: 5e0865f22eed9f3f3f0e912c4ada196effbd8ce0 branch: main author: Andre Hora committer: terryjreedy date: 2023-03-14T22:36:31-04:00 summary: gh-101377: improving test_locale_calendar_formatweekday of calendar (#101378) --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst M Lib/test/test_calendar.py diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 3d9dcf12f2da..ccfbeede0be9 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -568,11 +568,15 @@ def test_locale_calendar_formatweekday(self): try: # formatweekday uses different day names based on the available width. cal = calendar.LocaleTextCalendar(locale='en_US') + # For really short widths, the abbreviated name is truncated. + self.assertEqual(cal.formatweekday(0, 1), "M") + self.assertEqual(cal.formatweekday(0, 2), "Mo") # For short widths, a centered, abbreviated name is used. + self.assertEqual(cal.formatweekday(0, 3), "Mon") self.assertEqual(cal.formatweekday(0, 5), " Mon ") - # For really short widths, even the abbreviated name is truncated. - self.assertEqual(cal.formatweekday(0, 2), "Mo") + self.assertEqual(cal.formatweekday(0, 8), " Mon ") # For long widths, the full day name is used. + self.assertEqual(cal.formatweekday(0, 9), " Monday ") self.assertEqual(cal.formatweekday(0, 10), " Monday ") except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') diff --git a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst new file mode 100644 index 000000000000..a9c19ce060e3 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst @@ -0,0 +1 @@ +Improved test_locale_calendar_formatweekday of calendar. From webhook-mailer at python.org Tue Mar 14 22:59:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 15 Mar 2023 02:59:56 -0000 Subject: [Python-checkins] gh-101377: improving test_locale_calendar_formatweekday of calendar (GH-101378) Message-ID: https://github.com/python/cpython/commit/6f4df729bd0b01ae1221f0aba8775f4e3da337e9 commit: 6f4df729bd0b01ae1221f0aba8775f4e3da337e9 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-14T19:59:49-07:00 summary: gh-101377: improving test_locale_calendar_formatweekday of calendar (GH-101378) --------- (cherry picked from commit 5e0865f22eed9f3f3f0e912c4ada196effbd8ce0) Co-authored-by: Andre Hora Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst M Lib/test/test_calendar.py diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index dc49ac1c0f1e..de54f5af31d5 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -568,11 +568,15 @@ def test_locale_calendar_formatweekday(self): try: # formatweekday uses different day names based on the available width. cal = calendar.LocaleTextCalendar(locale='en_US') + # For really short widths, the abbreviated name is truncated. + self.assertEqual(cal.formatweekday(0, 1), "M") + self.assertEqual(cal.formatweekday(0, 2), "Mo") # For short widths, a centered, abbreviated name is used. + self.assertEqual(cal.formatweekday(0, 3), "Mon") self.assertEqual(cal.formatweekday(0, 5), " Mon ") - # For really short widths, even the abbreviated name is truncated. - self.assertEqual(cal.formatweekday(0, 2), "Mo") + self.assertEqual(cal.formatweekday(0, 8), " Mon ") # For long widths, the full day name is used. + self.assertEqual(cal.formatweekday(0, 9), " Monday ") self.assertEqual(cal.formatweekday(0, 10), " Monday ") except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') diff --git a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst new file mode 100644 index 000000000000..a9c19ce060e3 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst @@ -0,0 +1 @@ +Improved test_locale_calendar_formatweekday of calendar. From webhook-mailer at python.org Tue Mar 14 23:00:35 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 15 Mar 2023 03:00:35 -0000 Subject: [Python-checkins] gh-101377: improving test_locale_calendar_formatweekday of calendar (GH-101378) Message-ID: https://github.com/python/cpython/commit/8aa07b9c8ae0203aa6e85b2b5556ee1700525672 commit: 8aa07b9c8ae0203aa6e85b2b5556ee1700525672 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-14T20:00:28-07:00 summary: gh-101377: improving test_locale_calendar_formatweekday of calendar (GH-101378) --------- (cherry picked from commit 5e0865f22eed9f3f3f0e912c4ada196effbd8ce0) Co-authored-by: Andre Hora Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Terry Jan Reedy files: A Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst M Lib/test/test_calendar.py diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 3d9dcf12f2da..ccfbeede0be9 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -568,11 +568,15 @@ def test_locale_calendar_formatweekday(self): try: # formatweekday uses different day names based on the available width. cal = calendar.LocaleTextCalendar(locale='en_US') + # For really short widths, the abbreviated name is truncated. + self.assertEqual(cal.formatweekday(0, 1), "M") + self.assertEqual(cal.formatweekday(0, 2), "Mo") # For short widths, a centered, abbreviated name is used. + self.assertEqual(cal.formatweekday(0, 3), "Mon") self.assertEqual(cal.formatweekday(0, 5), " Mon ") - # For really short widths, even the abbreviated name is truncated. - self.assertEqual(cal.formatweekday(0, 2), "Mo") + self.assertEqual(cal.formatweekday(0, 8), " Mon ") # For long widths, the full day name is used. + self.assertEqual(cal.formatweekday(0, 9), " Monday ") self.assertEqual(cal.formatweekday(0, 10), " Monday ") except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') diff --git a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst new file mode 100644 index 000000000000..a9c19ce060e3 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst @@ -0,0 +1 @@ +Improved test_locale_calendar_formatweekday of calendar. From webhook-mailer at python.org Wed Mar 15 03:06:50 2023 From: webhook-mailer at python.org (hugovk) Date: Wed, 15 Mar 2023 07:06:50 -0000 Subject: [Python-checkins] Remove misformatted exclamation marks in docs (#102694) Message-ID: https://github.com/python/cpython/commit/8647ba4b639077e201751ae6dbd82e8bfcf80895 commit: 8647ba4b639077e201751ae6dbd82e8bfcf80895 branch: main author: Tom Levy committer: hugovk date: 2023-03-15T09:06:32+02:00 summary: Remove misformatted exclamation marks in docs (#102694) Remove the exclamation mark from :program:`!foo` in .rst files because it inadvertently shows up in the rendered HTML. (Sphinx's cross-referencing roles use a '!' prefix to suppress hyperlinking[1], but :program: is not a cross-referencing role so the '!' is displayed verbatim.) The exclamation marks in venv.rst were introduced in #98350. See comments [2] and [3] for additional discussion. [1]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#cross-referencing-syntax [2]: https://github.com/python/cpython/pull/98350#issuecomment-1285965759 [3]: https://github.com/python/cpython/pull/98350#issuecomment-1286394047 Reported-by: Vinay Sajip files: M Doc/library/venv.rst M Misc/NEWS.d/3.12.0a2.rst diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 8eb0b35eaa12..240ab139838d 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -61,7 +61,7 @@ running from a virtual environment. A virtual environment may be "activated" using a script in its binary directory (``bin`` on POSIX; ``Scripts`` on Windows). This will prepend that directory to your :envvar:`!PATH`, so that running -:program:`!python` will invoke the environment's Python interpreter +:program:`python` will invoke the environment's Python interpreter and you can run installed scripts without having to use their full path. The invocation of the activation script is platform-specific (:samp:`{}` must be replaced by the path to the directory @@ -84,7 +84,7 @@ containing the virtual environment): +-------------+------------+--------------------------------------------------+ .. versionadded:: 3.4 - :program:`!fish` and :program:`!csh` activation scripts. + :program:`fish` and :program:`csh` activation scripts. .. versionadded:: 3.8 PowerShell activation scripts installed under POSIX for PowerShell Core diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index 117be21a3221..d871384903e7 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -959,7 +959,7 @@ Fix ``make regen-test-levenshtein`` for out-of-tree builds. Don't use vendored ``libmpdec`` headers if :option:`--with-system-libmpdec` is passed to :program:`configure`. Don't use vendored ``libexpat`` headers -if :option:`--with-system-expat` is passed to :program:`!configure`. +if :option:`--with-system-expat` is passed to :program:`configure`. .. From webhook-mailer at python.org Wed Mar 15 03:26:03 2023 From: webhook-mailer at python.org (hugovk) Date: Wed, 15 Mar 2023 07:26:03 -0000 Subject: [Python-checkins] [3.11] Remove misformatted exclamation marks in docs (GH-102694) (#102716) Message-ID: https://github.com/python/cpython/commit/6b6c2f53ec7ae216532bd0995c2cfc8f46d69711 commit: 6b6c2f53ec7ae216532bd0995c2cfc8f46d69711 branch: 3.11 author: Hugo van Kemenade committer: hugovk date: 2023-03-15T09:25:55+02:00 summary: [3.11] Remove misformatted exclamation marks in docs (GH-102694) (#102716) Remove the exclamation mark from :program:`!foo` in .rst files because it inadvertently shows up in the rendered HTML. (Sphinx's cross-referencing roles use a '!' prefix to suppress hyperlinking[1], but :program: is not a cross-referencing role so the '!' is displayed verbatim.) The exclamation marks in venv.rst were introduced in #98350. See comments [2] and [3] for additional discussion. [1]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#cross-referencing-syntax [2]: https://github.com/python/cpython/pull/98350#issuecomment-1285965759 [3]: https://github.com/python/cpython/pull/98350#issuecomment-1286394047 Reported-by: Vinay Sajip Co-authored-by: Tom Levy files: M Doc/library/venv.rst diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index adc6cd339ac1..ff3c4b514b59 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -61,7 +61,7 @@ running from a virtual environment. A virtual environment may be "activated" using a script in its binary directory (``bin`` on POSIX; ``Scripts`` on Windows). This will prepend that directory to your :envvar:`!PATH`, so that running -:program:`!python` will invoke the environment's Python interpreter +:program:`python` will invoke the environment's Python interpreter and you can run installed scripts without having to use their full path. The invocation of the activation script is platform-specific (:samp:`{}` must be replaced by the path to the directory @@ -84,7 +84,7 @@ containing the virtual environment): +-------------+------------+--------------------------------------------------+ .. versionadded:: 3.4 - :program:`!fish` and :program:`!csh` activation scripts. + :program:`fish` and :program:`csh` activation scripts. .. versionadded:: 3.8 PowerShell activation scripts installed under POSIX for PowerShell Core From webhook-mailer at python.org Wed Mar 15 03:26:53 2023 From: webhook-mailer at python.org (hugovk) Date: Wed, 15 Mar 2023 07:26:53 -0000 Subject: [Python-checkins] [3.10] Remove misformatted exclamation marks in docs (GH-102694) (#102717) Message-ID: https://github.com/python/cpython/commit/087fb56b9de2eedd5061619eda6fa98ee12738fc commit: 087fb56b9de2eedd5061619eda6fa98ee12738fc branch: 3.10 author: Hugo van Kemenade committer: hugovk date: 2023-03-15T09:26:46+02:00 summary: [3.10] Remove misformatted exclamation marks in docs (GH-102694) (#102717) Remove the exclamation mark from :program:`!foo` in .rst files because it inadvertently shows up in the rendered HTML. (Sphinx's cross-referencing roles use a '!' prefix to suppress hyperlinking[1], but :program: is not a cross-referencing role so the '!' is displayed verbatim.) The exclamation marks in venv.rst were introduced in #98350. See comments [2] and [3] for additional discussion. [1]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#cross-referencing-syntax [2]: https://github.com/python/cpython/pull/98350#issuecomment-1285965759 [3]: https://github.com/python/cpython/pull/98350#issuecomment-1286394047 Reported-by: Vinay Sajip Co-authored-by: Tom Levy files: M Doc/library/venv.rst diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 3ab83a23cf24..401f02cd4753 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -59,7 +59,7 @@ running from a virtual environment. A virtual environment may be "activated" using a script in its binary directory (``bin`` on POSIX; ``Scripts`` on Windows). This will prepend that directory to your :envvar:`!PATH`, so that running -:program:`!python` will invoke the environment's Python interpreter +:program:`python` will invoke the environment's Python interpreter and you can run installed scripts without having to use their full path. The invocation of the activation script is platform-specific (:samp:`{}` must be replaced by the path to the directory @@ -82,7 +82,7 @@ containing the virtual environment): +-------------+------------+--------------------------------------------------+ .. versionadded:: 3.4 - :program:`!fish` and :program:`!csh` activation scripts. + :program:`fish` and :program:`csh` activation scripts. .. versionadded:: 3.8 PowerShell activation scripts installed under POSIX for PowerShell Core From webhook-mailer at python.org Wed Mar 15 03:27:41 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 15 Mar 2023 07:27:41 -0000 Subject: [Python-checkins] gh-102560 Add docstrings to asyncio.TaskGroup (GH-102565) Message-ID: https://github.com/python/cpython/commit/7e5ba351e0702bdff50ff5755082ef2cc5ace381 commit: 7e5ba351e0702bdff50ff5755082ef2cc5ace381 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-15T00:27:33-07:00 summary: gh-102560 Add docstrings to asyncio.TaskGroup (GH-102565) (cherry picked from commit e94edab727d07bef851e0e1a345e18a453be863d) Co-authored-by: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> files: M Lib/asyncio/taskgroups.py diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 911419e1769c..0fdea3697ece 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -10,7 +10,21 @@ class TaskGroup: + """Asynchronous context manager for managing groups of tasks. + Example use: + + async with asyncio.TaskGroup() as group: + task1 = group.create_task(some_coroutine(...)) + task2 = group.create_task(other_coroutine(...)) + print("Both tasks have completed now.") + + All tasks are awaited when the context manager exits. + + Any exceptions other than `asyncio.CancelledError` raised within + a task will cancel all remaining tasks and wait for them to exit. + The exceptions are then combined and raised as an `ExceptionGroup`. + """ def __init__(self): self._entered = False self._exiting = False @@ -135,6 +149,10 @@ async def __aexit__(self, et, exc, tb): self._errors = None def create_task(self, coro, *, name=None, context=None): + """Create a new task in this group and return it. + + Similar to `asyncio.create_task`. + """ if not self._entered: raise RuntimeError(f"TaskGroup {self!r} has not been entered") if self._exiting and not self._tasks: From webhook-mailer at python.org Wed Mar 15 05:34:17 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 15 Mar 2023 09:34:17 -0000 Subject: [Python-checkins] gh-102615: Use `list` instead of `tuple` in `repr` of paramspec (#102637) Message-ID: https://github.com/python/cpython/commit/2b5781d659ce3ffe03d4c1f46e4875e604cf2d88 commit: 2b5781d659ce3ffe03d4c1f46e4875e604cf2d88 branch: main author: Nikita Sobolev committer: AlexWaygood date: 2023-03-15T09:33:41Z summary: gh-102615: Use `list` instead of `tuple` in `repr` of paramspec (#102637) Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c17be6cd0bbc..89c725cda54f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3809,6 +3809,51 @@ class Y(C[int]): self.assertEqual(Y.__qualname__, 'GenericTests.test_repr_2..Y') + def test_repr_3(self): + T = TypeVar('T') + T1 = TypeVar('T1') + P = ParamSpec('P') + P2 = ParamSpec('P2') + Ts = TypeVarTuple('Ts') + + class MyCallable(Generic[P, T]): + pass + + class DoubleSpec(Generic[P, P2, T]): + pass + + class TsP(Generic[*Ts, P]): + pass + + object_to_expected_repr = { + MyCallable[P, T]: "MyCallable[~P, ~T]", + MyCallable[Concatenate[T1, P], T]: "MyCallable[typing.Concatenate[~T1, ~P], ~T]", + MyCallable[[], bool]: "MyCallable[[], bool]", + MyCallable[[int], bool]: "MyCallable[[int], bool]", + MyCallable[[int, str], bool]: "MyCallable[[int, str], bool]", + MyCallable[[int, list[int]], bool]: "MyCallable[[int, list[int]], bool]", + MyCallable[Concatenate[*Ts, P], T]: "MyCallable[typing.Concatenate[*Ts, ~P], ~T]", + + DoubleSpec[P2, P, T]: "DoubleSpec[~P2, ~P, ~T]", + DoubleSpec[[int], [str], bool]: "DoubleSpec[[int], [str], bool]", + DoubleSpec[[int, int], [str, str], bool]: "DoubleSpec[[int, int], [str, str], bool]", + + TsP[*Ts, P]: "TsP[*Ts, ~P]", + TsP[int, str, list[int], []]: "TsP[int, str, list[int], []]", + TsP[int, [str, list[int]]]: "TsP[int, [str, list[int]]]", + + # These lines are just too long to fit: + MyCallable[Concatenate[*Ts, P], int][int, str, [bool, float]]: + "MyCallable[[int, str, bool, float], int]", + } + + for obj, expected_repr in object_to_expected_repr.items(): + with self.subTest(obj=obj, expected_repr=expected_repr): + self.assertRegex( + repr(obj), + fr"^{re.escape(MyCallable.__module__)}.*\.{re.escape(expected_repr)}$", + ) + def test_eq_1(self): self.assertEqual(Generic, Generic) self.assertEqual(Generic[T], Generic[T]) diff --git a/Lib/typing.py b/Lib/typing.py index 8d40e923bb1d..ab3343956761 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -230,16 +230,17 @@ def _type_repr(obj): typically enough to uniquely identify a type. For everything else, we fall back on repr(obj). """ - if isinstance(obj, types.GenericAlias): - return repr(obj) if isinstance(obj, type): if obj.__module__ == 'builtins': return obj.__qualname__ return f'{obj.__module__}.{obj.__qualname__}' if obj is ...: - return('...') + return '...' if isinstance(obj, types.FunctionType): return obj.__name__ + if isinstance(obj, tuple): + # Special case for `repr` of types with `ParamSpec`: + return '[' + ', '.join(_type_repr(t) for t in obj) + ']' return repr(obj) diff --git a/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst b/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst new file mode 100644 index 000000000000..333068369bc4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst @@ -0,0 +1,3 @@ +Typing: Improve the ``repr`` of generic aliases for classes generic over a +:class:`~typing.ParamSpec`. (Use square brackets to represent a parameter +list.) From webhook-mailer at python.org Wed Mar 15 08:59:28 2023 From: webhook-mailer at python.org (corona10) Date: Wed, 15 Mar 2023 12:59:28 -0000 Subject: [Python-checkins] gh-102281: Fix potential nullptr dereference + use of uninitialized memory (gh-102282) Message-ID: https://github.com/python/cpython/commit/afa6092ee4260bacf7bc11905466e4c3f8556cbb commit: afa6092ee4260bacf7bc11905466e4c3f8556cbb branch: main author: Max Bachmann committer: corona10 date: 2023-03-15T21:58:43+09:00 summary: gh-102281: Fix potential nullptr dereference + use of uninitialized memory (gh-102282) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst M Modules/getpath.c M Python/fileutils.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst new file mode 100644 index 000000000000..b0269dd3d92b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst @@ -0,0 +1 @@ +Fix potential nullptr dereference and use of uninitialized memory in fileutils. Patch by Max Bachmann. diff --git a/Modules/getpath.c b/Modules/getpath.c index 2f20521592ce..237fe8c0c2c2 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -446,7 +446,10 @@ getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args) if (s) { *s = L'\0'; } - path2 = _Py_normpath(_Py_join_relfile(path, resolved), -1); + path2 = _Py_join_relfile(path, resolved); + if (path2) { + path2 = _Py_normpath(path2, -1); + } PyMem_RawFree((void *)path); path = path2; } diff --git a/Python/fileutils.c b/Python/fileutils.c index 4ac759c45a3a..f48b626b4440 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -2233,7 +2233,10 @@ _Py_join_relfile(const wchar_t *dirname, const wchar_t *relfile) } assert(wcslen(dirname) < MAXPATHLEN); assert(wcslen(relfile) < MAXPATHLEN - wcslen(dirname)); - join_relfile(filename, bufsize, dirname, relfile); + if (join_relfile(filename, bufsize, dirname, relfile) < 0) { + PyMem_RawFree(filename); + return NULL; + } return filename; } @@ -2271,6 +2274,7 @@ _Py_find_basename(const wchar_t *filename) wchar_t * _Py_normpath(wchar_t *path, Py_ssize_t size) { + assert(path != NULL); if (!path[0] || size == 0) { return path; } From webhook-mailer at python.org Wed Mar 15 11:10:45 2023 From: webhook-mailer at python.org (JulienPalard) Date: Wed, 15 Mar 2023 15:10:45 -0000 Subject: [Python-checkins] gh-101100: Documenting --prefix and --exec-prefix. (GH-102695) Message-ID: https://github.com/python/cpython/commit/61b9ff35cbda0cc59816951a17de073968fc25c6 commit: 61b9ff35cbda0cc59816951a17de073968fc25c6 branch: main author: Julien Palard committer: JulienPalard date: 2023-03-15T16:10:03+01:00 summary: gh-101100: Documenting --prefix and --exec-prefix. (GH-102695) Co-authored-by: Erlend E. Aasland files: M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/library/sys.rst M Doc/using/configure.rst M Doc/using/unix.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index b50ee3b3803e..38e324fb6409 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -513,7 +513,7 @@ Process-wide parameters program name is ``'/usr/local/bin/python'``, the prefix is ``'/usr/local'``. The returned string points into static storage; the caller should not modify its value. This corresponds to the :makevar:`prefix` variable in the top-level - :file:`Makefile` and the ``--prefix`` argument to the :program:`configure` + :file:`Makefile` and the :option:`--prefix` argument to the :program:`configure` script at build time. The value is available to Python code as ``sys.prefix``. It is only useful on Unix. See also the next function. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 85eb24a495b6..acd4e033dfbc 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -78,19 +78,19 @@ used by extension writers. Structure member names do not have a reserved prefix. The header files are typically installed with Python. On Unix, these are located in the directories :file:`{prefix}/include/pythonversion/` and -:file:`{exec_prefix}/include/pythonversion/`, where :envvar:`prefix` and -:envvar:`exec_prefix` are defined by the corresponding parameters to Python's +:file:`{exec_prefix}/include/pythonversion/`, where :option:`prefix <--prefix>` and +:option:`exec_prefix <--exec-prefix>` are defined by the corresponding parameters to Python's :program:`configure` script and *version* is ``'%d.%d' % sys.version_info[:2]``. On Windows, the headers are installed -in :file:`{prefix}/include`, where :envvar:`prefix` is the installation +in :file:`{prefix}/include`, where ``prefix`` is the installation directory specified to the installer. To include the headers, place both directories (if different) on your compiler's search path for includes. Do *not* place the parent directories on the search path and then use ``#include ``; this will break on multi-platform builds since the platform independent headers under -:envvar:`prefix` include the platform specific headers from -:envvar:`exec_prefix`. +:option:`prefix <--prefix>` include the platform specific headers from +:option:`exec_prefix <--exec-prefix>`. C++ users should note that although the API is defined entirely using C, the header files properly declare the entry points to be ``extern "C"``. As a result, diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 23c5bbed0c6f..a53d4908783e 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1323,7 +1323,7 @@ always available. A string giving the site-specific directory prefix where the platform independent Python files are installed; on Unix, the default is - ``'/usr/local'``. This can be set at build time with the ``--prefix`` + :file:`/usr/local`. This can be set at build time with the :option:`--prefix` argument to the :program:`configure` script. See :ref:`installation_paths` for derived paths. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 8936bd381c9d..ce858ab2c8d7 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -216,6 +216,22 @@ WebAssembly Options Install Options --------------- +.. cmdoption:: --prefix=PREFIX + + Install architecture-independent files in PREFIX. On Unix, it + defaults to :file:`/usr/local`. + + This value can be retrived at runtime using :data:`sys.prefix`. + + As an example, one can use ``--prefix="$HOME/.local/"`` to install + a Python in its home directory. + +.. cmdoption:: --exec-prefix=EPREFIX + + Install architecture-dependent files in EPREFIX, defaults to :option:`--prefix`. + + This value can be retrived at runtime using :data:`sys.exec_prefix`. + .. cmdoption:: --disable-test-modules Don't build nor install test modules, like the :mod:`test` package or the diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 24c02c99f871..067ff4cce5e4 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -93,7 +93,7 @@ Python-related paths and files ============================== These are subject to difference depending on local installation conventions; -:envvar:`prefix` (``${prefix}``) and :envvar:`exec_prefix` (``${exec_prefix}``) +:option:`prefix <--prefix>` and :option:`exec_prefix <--exec-prefix>` are installation-dependent and should be interpreted as for GNU software; they may be the same. From webhook-mailer at python.org Wed Mar 15 11:37:47 2023 From: webhook-mailer at python.org (gvanrossum) Date: Wed, 15 Mar 2023 15:37:47 -0000 Subject: [Python-checkins] gh-102654: Insert #line directives in generated_cases.c.h (#102669) Message-ID: https://github.com/python/cpython/commit/70185de1abfe428049a5c43d58fcb656b46db96c commit: 70185de1abfe428049a5c43d58fcb656b46db96c branch: main author: Guido van Rossum committer: gvanrossum date: 2023-03-15T08:37:36-07:00 summary: gh-102654: Insert #line directives in generated_cases.c.h (#102669) This behavior is optional, because in some extreme cases it may just make debugging harder. The tool defaults it to off, but it is on in Makefile.pre.in. Also note that this makes diffs to generated_cases.c.h noisier, since whenever you insert or delete a line in bytecodes.c, all subsequent #line directives will change. files: M Makefile.pre.in M Python/generated_cases.c.h M Tools/cases_generator/generate_cases.py diff --git a/Makefile.pre.in b/Makefile.pre.in index 59762165c100..8f13198e7e34 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1485,6 +1485,7 @@ regen-cases: PYTHONPATH=$(srcdir)/Tools/cases_generator \ $(PYTHON_FOR_REGEN) \ $(srcdir)/Tools/cases_generator/generate_cases.py \ + --emit-line-directives \ -o $(srcdir)/Python/generated_cases.c.h.new \ -m $(srcdir)/Python/opcode_metadata.h.new \ $(srcdir)/Python/bytecodes.c diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b1dbb58d9563..26f6be049b30 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,20 +8,24 @@ } TARGET(RESUME) { + #line 89 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { goto handle_eval_breaker; } + #line 18 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLOSURE) { PyObject *value; + #line 97 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); + #line 29 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -29,9 +33,11 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; + #line 104 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); + #line 41 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -39,9 +45,11 @@ TARGET(LOAD_FAST) { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 53 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -50,8 +58,10 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; + #line 116 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); + #line 65 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -59,7 +69,9 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; + #line 121 "Python/bytecodes.c" SETLOCAL(oparg, value); + #line 75 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -69,17 +81,21 @@ PyObject *_tmp_2; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 89 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 99 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -93,16 +109,20 @@ PyObject *_tmp_2; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 117 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; + #line 116 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); + #line 126 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -115,14 +135,18 @@ PyObject *_tmp_1 = stack_pointer[-1]; { PyObject *value = _tmp_1; + #line 121 "Python/bytecodes.c" SETLOCAL(oparg, value); + #line 141 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 150 "Python/generated_cases.c.h" _tmp_1 = value; } stack_pointer[-1] = _tmp_1; @@ -134,12 +158,16 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; + #line 121 "Python/bytecodes.c" SETLOCAL(oparg, value); + #line 164 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value = _tmp_2; + #line 121 "Python/bytecodes.c" SETLOCAL(oparg, value); + #line 171 "Python/generated_cases.c.h" } STACK_SHRINK(2); DISPATCH(); @@ -150,16 +178,20 @@ PyObject *_tmp_2; { PyObject *value; + #line 116 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); + #line 185 "Python/generated_cases.c.h" _tmp_2 = value; } oparg = (next_instr++)->op.arg; { PyObject *value; + #line 110 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); + #line 195 "Python/generated_cases.c.h" _tmp_1 = value; } STACK_GROW(2); @@ -170,6 +202,8 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; + #line 131 "Python/bytecodes.c" + #line 207 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); DISPATCH(); @@ -177,7 +211,9 @@ TARGET(PUSH_NULL) { PyObject *res; + #line 135 "Python/bytecodes.c" res = NULL; + #line 217 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -188,10 +224,14 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; + #line 131 "Python/bytecodes.c" + #line 229 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; + #line 131 "Python/bytecodes.c" + #line 235 "Python/generated_cases.c.h" Py_DECREF(value); } STACK_SHRINK(2); @@ -201,9 +241,13 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 141 "Python/bytecodes.c" res = PyNumber_Negative(value); + #line 247 "Python/generated_cases.c.h" Py_DECREF(value); + #line 143 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; + #line 251 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -211,8 +255,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 147 "Python/bytecodes.c" int err = PyObject_IsTrue(value); + #line 261 "Python/generated_cases.c.h" Py_DECREF(value); + #line 149 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -221,6 +268,7 @@ res = Py_False; } Py_INCREF(res); + #line 272 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -228,9 +276,13 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 160 "Python/bytecodes.c" res = PyNumber_Invert(value); + #line 282 "Python/generated_cases.c.h" Py_DECREF(value); + #line 162 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; + #line 286 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -239,6 +291,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; + #line 179 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -247,6 +300,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (prod == NULL) goto pop_2_error; + #line 304 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -257,6 +311,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; + #line 190 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); @@ -264,6 +319,7 @@ double dprod = ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod); + #line 323 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = prod; next_instr += 1; @@ -274,6 +330,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; + #line 200 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -282,6 +339,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sub == NULL) goto pop_2_error; + #line 343 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -292,12 +350,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; + #line 211 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); STAT_INC(BINARY_OP, hit); double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsub, sub); + #line 361 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sub; next_instr += 1; @@ -308,6 +368,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 220 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -316,6 +377,7 @@ _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; + #line 381 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -325,6 +387,7 @@ TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 237 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -352,6 +415,7 @@ if (*target_local == NULL) goto pop_2_error; // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); + #line 419 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -360,6 +424,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; + #line 267 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -367,6 +432,7 @@ double dsum = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); + #line 436 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -377,6 +443,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; + #line 277 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -385,6 +452,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (sum == NULL) goto pop_2_error; + #line 456 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -397,6 +465,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; + #line 296 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -409,9 +478,12 @@ DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ res = PyObject_GetItem(container, sub); + #line 482 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); + #line 309 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 487 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 4; @@ -423,6 +495,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; + #line 313 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -435,6 +508,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; + #line 512 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; DISPATCH(); @@ -445,6 +519,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; + #line 328 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -457,6 +532,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; + #line 536 "Python/generated_cases.c.h" STACK_SHRINK(4); DISPATCH(); } @@ -465,6 +541,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; + #line 343 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -480,6 +557,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); + #line 561 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 4; @@ -490,6 +568,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; + #line 361 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -505,6 +584,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); + #line 588 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 4; @@ -515,6 +595,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; + #line 379 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -523,11 +604,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } + #line 608 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); + #line 388 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub + #line 615 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -541,6 +625,7 @@ PyObject *container = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t func_version = read_u16(&next_instr[3].cache); + #line 395 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(tp->tp_version_tag != type_version, BINARY_SUBSCR); assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); @@ -559,12 +644,15 @@ new_frame->localsplus[1] = sub; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); DISPATCH_INLINED(new_frame); + #line 648 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; + #line 416 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; + #line 656 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -573,9 +661,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; + #line 421 "Python/bytecodes.c" int err = PySet_Add(set, v); + #line 667 "Python/generated_cases.c.h" Py_DECREF(v); + #line 423 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 671 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -588,6 +680,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); + #line 434 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -603,10 +696,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); + #line 700 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); + #line 450 "Python/bytecodes.c" if (err) goto pop_3_error; + #line 706 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -616,6 +712,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; + #line 454 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -633,6 +730,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); + #line 734 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -642,12 +740,14 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; + #line 474 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; + #line 751 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -656,11 +756,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; + #line 483 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); + #line 763 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); + #line 486 "Python/bytecodes.c" if (err) goto pop_2_error; + #line 768 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -668,10 +772,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; + #line 490 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); + #line 779 "Python/generated_cases.c.h" Py_DECREF(value); + #line 493 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; + #line 783 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -680,11 +788,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; + #line 497 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); + #line 795 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); + #line 500 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 800 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -692,6 +804,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); + #line 504 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -709,10 +822,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } + #line 826 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; + #line 524 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -724,10 +839,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; + #line 843 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; + #line 538 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -741,9 +858,11 @@ _PyEvalFrameClearAndPop(tstate, dying); _PyFrame_StackPush(frame, retval); goto resume_frame; + #line 862 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { + #line 554 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -758,11 +877,13 @@ _PyEvalFrameClearAndPop(tstate, dying); _PyFrame_StackPush(frame, retval); goto resume_frame; + #line 881 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; + #line 571 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -775,12 +896,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); + #line 900 "Python/generated_cases.c.h" Py_DECREF(obj); + #line 584 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); + #line 907 "Python/generated_cases.c.h" Py_DECREF(obj); + #line 589 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -793,6 +918,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } + #line 922 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -800,6 +926,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; + #line 604 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -843,6 +970,7 @@ } } + #line 974 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; PREDICT(LOAD_CONST); @@ -853,13 +981,16 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; + #line 651 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } + #line 992 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 658 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -877,6 +1008,7 @@ if (iter == NULL) goto pop_1_error; + #line 1012 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -887,6 +1019,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; + #line 684 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -922,6 +1055,7 @@ assert(retval != NULL); } Py_DECREF(v); + #line 1059 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -930,6 +1064,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; + #line 722 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -945,10 +1080,12 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); DISPATCH_INLINED(gen_frame); + #line 1084 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; + #line 740 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -967,12 +1104,15 @@ frame->prev_instr -= frame->yield_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; + #line 1108 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; + #line 761 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); + #line 1116 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -980,6 +1120,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); + #line 766 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -999,15 +1140,19 @@ PyObject *tb = PyException_GetTraceback(exc); _PyErr_Restore(tstate, typ, exc, tb); goto exception_unwind; + #line 1144 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; + #line 788 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { + #line 1153 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); + #line 791 "Python/bytecodes.c" } else { Py_INCREF(exc); @@ -1016,6 +1161,7 @@ _PyErr_Restore(tstate, typ, exc, tb); goto exception_unwind; } + #line 1165 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1026,19 +1172,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; + #line 802 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); + #line 1181 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); + #line 807 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } + #line 1192 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1047,7 +1197,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; + #line 816 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); + #line 1203 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1055,6 +1207,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; + #line 820 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1076,6 +1229,7 @@ if (true) goto error; } } + #line 1233 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1083,26 +1237,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; + #line 844 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); + #line 1248 "Python/generated_cases.c.h" Py_DECREF(v); + #line 851 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); + #line 1257 "Python/generated_cases.c.h" Py_DECREF(v); + #line 858 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 1261 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { + #line 862 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1119,6 +1280,7 @@ name); goto error; } + #line 1284 "Python/generated_cases.c.h" DISPATCH(); } @@ -1126,6 +1288,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; + #line 888 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1139,8 +1302,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); + #line 1306 "Python/generated_cases.c.h" Py_DECREF(seq); + #line 902 "Python/bytecodes.c" if (res == 0) goto pop_1_error; + #line 1310 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1150,12 +1316,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); + #line 906 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); + #line 1327 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1166,6 +1334,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); + #line 916 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1173,6 +1342,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } + #line 1346 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1183,6 +1353,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); + #line 927 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1190,6 +1361,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } + #line 1365 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1199,11 +1371,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; + #line 938 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); + #line 1379 "Python/generated_cases.c.h" Py_DECREF(seq); + #line 942 "Python/bytecodes.c" if (res == 0) goto pop_1_error; + #line 1383 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1214,6 +1390,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); + #line 953 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -1230,9 +1407,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); + #line 1411 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); + #line 970 "Python/bytecodes.c" if (err) goto pop_2_error; + #line 1416 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1240,25 +1420,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; + #line 974 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); + #line 1427 "Python/generated_cases.c.h" Py_DECREF(owner); + #line 977 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 1431 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; + #line 981 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); + #line 1441 "Python/generated_cases.c.h" Py_DECREF(v); + #line 984 "Python/bytecodes.c" if (err) goto pop_1_error; + #line 1445 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { + #line 988 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1270,11 +1459,13 @@ } goto error; } + #line 1463 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_NAME) { PyObject *v; + #line 1002 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1333,6 +1524,7 @@ } } } + #line 1528 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = v; DISPATCH(); @@ -1343,6 +1535,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; + #line 1069 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1395,6 +1588,7 @@ } } null = NULL; + #line 1592 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1408,6 +1602,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); + #line 1124 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -1419,6 +1614,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; + #line 1618 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1433,6 +1629,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); + #line 1138 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); @@ -1447,6 +1644,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; + #line 1648 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1456,13 +1654,16 @@ } TARGET(DELETE_FAST) { + #line 1155 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); + #line 1662 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { + #line 1161 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1471,10 +1672,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); + #line 1676 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { + #line 1172 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1485,11 +1688,13 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); + #line 1692 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLASSDEREF) { PyObject *value; + #line 1185 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1521,6 +1726,7 @@ } Py_INCREF(value); } + #line 1730 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1528,6 +1734,7 @@ TARGET(LOAD_DEREF) { PyObject *value; + #line 1219 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1535,6 +1742,7 @@ if (true) goto error; } Py_INCREF(value); + #line 1746 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1542,15 +1750,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; + #line 1229 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); + #line 1759 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { + #line 1236 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1561,17 +1772,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } + #line 1776 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; + #line 1249 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); + #line 1785 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } + #line 1251 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } + #line 1791 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1581,8 +1797,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; + #line 1255 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } + #line 1804 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1592,8 +1810,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; + #line 1260 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } + #line 1817 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1603,6 +1823,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; + #line 1265 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1613,10 +1834,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } + #line 1838 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 1276 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); + #line 1844 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1625,9 +1849,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; + #line 1283 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); + #line 1855 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 1285 "Python/bytecodes.c" if (err < 0) goto pop_1_error; + #line 1859 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1635,6 +1863,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; + #line 1289 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1649,6 +1878,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } + #line 1882 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1658,6 +1888,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; + #line 1306 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1665,10 +1896,13 @@ if (map == NULL) goto error; + #line 1900 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } + #line 1314 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } + #line 1906 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1676,6 +1910,7 @@ } TARGET(SETUP_ANNOTATIONS) { + #line 1318 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1715,6 +1950,7 @@ Py_DECREF(ann_dict); } } + #line 1954 "Python/generated_cases.c.h" DISPATCH(); } @@ -1722,6 +1958,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; + #line 1360 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1731,11 +1968,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); + #line 1972 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); + #line 1370 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } + #line 1979 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -1743,6 +1983,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; + #line 1374 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1750,9 +1991,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } + #line 1995 "Python/generated_cases.c.h" Py_DECREF(update); + #line 1382 "Python/bytecodes.c" if (true) goto pop_1_error; } + #line 2000 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -1760,13 +2004,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; + #line 1388 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); + #line 2013 "Python/generated_cases.c.h" Py_DECREF(update); + #line 1393 "Python/bytecodes.c" if (true) goto pop_1_error; } + #line 2018 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -1776,11 +2024,13 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; + #line 1400 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; + #line 2034 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -1792,6 +2042,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; + #line 1423 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1826,7 +2077,9 @@ NULL | meth | arg1 | ... | argN */ + #line 2081 "Python/generated_cases.c.h" Py_DECREF(owner); + #line 1458 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -1835,9 +2088,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); + #line 2092 "Python/generated_cases.c.h" Py_DECREF(owner); + #line 1467 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } + #line 2097 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -1851,6 +2107,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1472 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -1864,6 +2121,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; + #line 2125 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1878,6 +2136,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1489 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; @@ -1891,6 +2150,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; + #line 2154 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1905,6 +2165,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1506 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -1932,6 +2193,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; + #line 2197 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1946,6 +2208,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1537 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -1956,6 +2219,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; + #line 2223 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1970,6 +2234,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); + #line 1551 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); @@ -1982,6 +2247,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); + #line 2251 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1995,6 +2261,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); + #line 1567 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); @@ -2018,6 +2285,7 @@ new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); + #line 2289 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2025,6 +2293,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); + #line 1593 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2050,6 +2319,7 @@ new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); + #line 2323 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2057,6 +2327,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1621 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2075,6 +2346,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); + #line 2350 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2085,6 +2357,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); + #line 1642 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2124,6 +2397,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); + #line 2401 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2134,6 +2408,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); + #line 1684 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2144,6 +2419,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); + #line 2423 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2153,12 +2429,16 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; + #line 1697 "Python/bytecodes.c" STAT_INC(COMPARE_OP, deferred); assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); + #line 2437 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 1701 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 2442 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2169,6 +2449,7 @@ PREDICTED(COMPARE_AND_BRANCH); PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 1713 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2182,8 +2463,10 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); + #line 2467 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 1727 "Python/bytecodes.c" if (cond == NULL) goto pop_2_error; assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || next_instr[1].op.code == POP_JUMP_IF_TRUE); @@ -2195,6 +2478,7 @@ if (jump_on_true == (err != 0)) { JUMPBY(offset); } + #line 2482 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2203,6 +2487,7 @@ TARGET(COMPARE_AND_BRANCH_FLOAT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 1741 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); @@ -2217,6 +2502,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } + #line 2506 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2225,6 +2511,7 @@ TARGET(COMPARE_AND_BRANCH_INT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 1759 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); @@ -2242,6 +2529,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } + #line 2533 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2250,6 +2538,7 @@ TARGET(COMPARE_AND_BRANCH_STR) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + #line 1780 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); @@ -2265,6 +2554,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } + #line 2558 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2274,10 +2564,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; + #line 1798 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; + #line 2570 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 1800 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); + #line 2575 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2287,11 +2581,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; + #line 1804 "Python/bytecodes.c" int res = PySequence_Contains(right, left); + #line 2587 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); + #line 1806 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); + #line 2593 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2302,9 +2600,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; + #line 1811 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { + #line 2606 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); + #line 1813 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2312,8 +2613,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); + #line 2617 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); + #line 1821 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2322,6 +2625,7 @@ if (!Py_IsNone(match)) { PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); } + #line 2629 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2331,15 +2635,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; + #line 1832 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { + #line 2642 "Python/generated_cases.c.h" Py_DECREF(right); + #line 1835 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); + #line 2649 "Python/generated_cases.c.h" Py_DECREF(right); + #line 1840 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); + #line 2653 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2348,11 +2658,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; + #line 1844 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); + #line 2665 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); + #line 1847 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 2670 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2361,23 +2675,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; + #line 1851 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; + #line 2683 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { + #line 1857 "Python/bytecodes.c" JUMPBY(oparg); + #line 2692 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); + #line 1861 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); + #line 2701 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2385,6 +2705,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; + #line 1867 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2394,7 +2715,9 @@ } else { int err = PyObject_IsTrue(cond); + #line 2719 "Python/generated_cases.c.h" Py_DECREF(cond); + #line 1877 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2402,12 +2725,14 @@ if (err < 0) goto pop_1_error; } } + #line 2729 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; + #line 1887 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2417,7 +2742,9 @@ } else { int err = PyObject_IsTrue(cond); + #line 2746 "Python/generated_cases.c.h" Py_DECREF(cond); + #line 1897 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2425,38 +2752,48 @@ if (err < 0) goto pop_1_error; } } + #line 2756 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; + #line 1907 "Python/bytecodes.c" if (!Py_IsNone(value)) { + #line 2765 "Python/generated_cases.c.h" Py_DECREF(value); + #line 1909 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } + #line 2773 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; + #line 1917 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { + #line 2786 "Python/generated_cases.c.h" Py_DECREF(value); + #line 1923 "Python/bytecodes.c" } + #line 2790 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_IF_FALSE_OR_POP) { PyObject *cond = stack_pointer[-1]; + #line 1927 "Python/bytecodes.c" bool jump = false; int err; if (Py_IsTrue(cond)) { @@ -2479,6 +2816,7 @@ goto error; } } + #line 2820 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); @@ -2486,6 +2824,7 @@ TARGET(JUMP_IF_TRUE_OR_POP) { PyObject *cond = stack_pointer[-1]; + #line 1952 "Python/bytecodes.c" bool jump = false; int err; if (Py_IsFalse(cond)) { @@ -2508,29 +2847,34 @@ goto error; } } + #line 2851 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { + #line 1977 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); + #line 2865 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; + #line 1986 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; + #line 2878 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2541,13 +2885,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; + #line 1994 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); + #line 2894 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); + #line 1999 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2555,6 +2902,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } + #line 2906 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -2563,8 +2911,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; + #line 2009 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); + #line 2918 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2574,8 +2924,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; + #line 2015 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); + #line 2931 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2586,9 +2938,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; + #line 2021 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; + #line 2946 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -2597,10 +2951,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; + #line 2027 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); + #line 2958 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 2030 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; + #line 2962 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -2608,6 +2966,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; + #line 2034 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2630,8 +2989,11 @@ if (iter == NULL) { goto error; } + #line 2993 "Python/generated_cases.c.h" Py_DECREF(iterable); + #line 2057 "Python/bytecodes.c" } + #line 2997 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -2642,6 +3004,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; + #line 2076 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2674,6 +3037,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator + #line 3041 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2683,6 +3047,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; + #line 2111 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -2703,6 +3068,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator + #line 3072 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2712,6 +3078,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; + #line 2134 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -2732,6 +3099,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator + #line 3103 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2741,6 +3109,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; + #line 2157 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -2759,6 +3128,7 @@ if (next == NULL) { goto error; } + #line 3132 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2767,6 +3137,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; + #line 2178 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -2781,12 +3152,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); assert(next_instr->op.code == END_FOR); DISPATCH_INLINED(gen_frame); + #line 3156 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; + #line 2195 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -2809,13 +3182,16 @@ Py_DECREF(enter); goto error; } + #line 3186 "Python/generated_cases.c.h" Py_DECREF(mgr); + #line 2218 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } + #line 3195 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -2827,6 +3203,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; + #line 2228 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -2852,13 +3229,16 @@ Py_DECREF(enter); goto error; } + #line 3233 "Python/generated_cases.c.h" Py_DECREF(mgr); + #line 2254 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } + #line 3242 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -2870,6 +3250,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; + #line 2263 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -2890,6 +3271,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; + #line 3275 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -2898,6 +3280,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; + #line 2286 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -2907,6 +3290,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); + #line 3294 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -2920,6 +3304,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); + #line 2298 "Python/bytecodes.c" /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -2937,6 +3322,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); + #line 3326 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2950,6 +3336,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); + #line 2318 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2960,6 +3347,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); + #line 3351 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2973,6 +3361,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); + #line 2331 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2987,6 +3376,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); + #line 3380 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2995,9 +3385,11 @@ } TARGET(KW_NAMES) { + #line 2348 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); + #line 3393 "Python/generated_cases.c.h" DISPATCH(); } @@ -3008,6 +3400,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2384 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3079,6 +3472,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3476 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3090,6 +3484,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; + #line 2462 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3099,6 +3494,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); + #line 3498 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3107,6 +3503,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); + #line 2474 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3131,6 +3528,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); + #line 3532 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3139,6 +3537,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); uint16_t min_args = read_u16(&next_instr[3].cache); + #line 2501 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3168,6 +3567,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); + #line 3571 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3175,6 +3575,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2533 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3185,6 +3586,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable + #line 3590 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3197,6 +3599,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2546 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3208,6 +3611,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3615 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3221,6 +3625,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2561 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3231,6 +3636,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3640 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3244,6 +3650,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2575 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3265,6 +3672,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3676 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3278,6 +3686,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2600 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3306,6 +3715,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3719 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3319,6 +3729,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2632 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3351,6 +3762,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ + #line 3766 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3364,6 +3776,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2668 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3396,6 +3809,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3813 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3409,6 +3823,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2704 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3434,6 +3849,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3853 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3446,6 +3862,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2732 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3473,6 +3890,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3894 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3484,6 +3902,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; + #line 2763 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3502,12 +3921,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); + #line 3925 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2784 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3538,6 +3959,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 3963 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3550,6 +3972,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2818 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3578,6 +4001,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 4005 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3590,6 +4014,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2850 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -3618,6 +4043,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 4047 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3630,6 +4056,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; + #line 2882 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3657,6 +4084,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + #line 4088 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3671,6 +4099,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; + #line 2913 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -3689,12 +4118,15 @@ assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); + #line 4122 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); + #line 2932 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } + #line 4130 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -3709,6 +4141,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; + #line 2943 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -3737,12 +4170,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; + #line 4174 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { + #line 2974 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -3763,6 +4198,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; + #line 4202 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -3770,11 +4206,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; + #line 2997 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); + #line 4212 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); + #line 2999 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } + #line 4218 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -3785,6 +4225,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; + #line 3003 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -3826,10 +4267,13 @@ } else { /* Actually call format(). */ result = PyObject_Format(value, fmt_spec); + #line 4271 "Python/generated_cases.c.h" Py_DECREF(value); Py_XDECREF(fmt_spec); + #line 3045 "Python/bytecodes.c" if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } } + #line 4277 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -3838,8 +4282,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; + #line 3050 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); + #line 4289 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -3851,6 +4297,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; + #line 3055 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3866,9 +4313,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); + #line 4317 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); + #line 3071 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; + #line 4322 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -3878,21 +4328,27 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; + #line 3076 "Python/bytecodes.c" assert(oparg >= 2); + #line 4334 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(EXTENDED_ARG) { + #line 3080 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); + #line 4348 "Python/generated_cases.c.h" } TARGET(CACHE) { + #line 3089 "Python/bytecodes.c" Py_UNREACHABLE(); + #line 4354 "Python/generated_cases.c.h" } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 25cf75e4c1c4..b16c927a4a28 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -13,6 +13,7 @@ import sys import typing +import lexer as lx import parser from parser import StackEffect @@ -43,6 +44,9 @@ arg_parser.add_argument( "-m", "--metadata", type=str, help="Generated metadata", default=DEFAULT_METADATA_OUTPUT ) +arg_parser.add_argument( + "-l", "--emit-line-directives", help="Emit #line directives", action="store_true" +) arg_parser.add_argument( "input", nargs=argparse.REMAINDER, help="Instruction definition file(s)" ) @@ -105,13 +109,34 @@ class Formatter: stream: typing.TextIO prefix: str - - def __init__(self, stream: typing.TextIO, indent: int) -> None: + emit_line_directives: bool = False + lineno: int # Next line number, 1-based + filename: str # Slightly improved stream.filename + nominal_lineno: int + nominal_filename: str + + def __init__( + self, stream: typing.TextIO, indent: int, emit_line_directives: bool = False + ) -> None: self.stream = stream self.prefix = " " * indent + self.emit_line_directives = emit_line_directives + self.lineno = 1 + # Make filename more user-friendly and less platform-specific + filename = self.stream.name.replace("\\", "/") + if filename.startswith("./"): + filename = filename[2:] + if filename.endswith(".new"): + filename = filename[:-4] + self.filename = filename + self.nominal_lineno = 1 + self.nominal_filename = filename def write_raw(self, s: str) -> None: self.stream.write(s) + newlines = s.count("\n") + self.lineno += newlines + self.nominal_lineno += newlines def emit(self, arg: str) -> None: if arg: @@ -119,6 +144,17 @@ def emit(self, arg: str) -> None: else: self.write_raw("\n") + def set_lineno(self, lineno: int, filename: str) -> None: + if self.emit_line_directives: + if lineno != self.nominal_lineno or filename != self.nominal_filename: + self.emit(f'#line {lineno} "{filename}"') + self.nominal_lineno = lineno + self.nominal_filename = filename + + def reset_lineno(self) -> None: + if self.lineno != self.nominal_lineno or self.filename != self.nominal_filename: + self.set_lineno(self.lineno + 1, self.filename) + @contextlib.contextmanager def indent(self): self.prefix += " " @@ -199,6 +235,7 @@ class Instruction: block: parser.Block block_text: list[str] # Block.text, less curlies, less PREDICT() calls predictions: list[str] # Prediction targets (instruction names) + block_line: int # First line of block in original code # Computed by constructor always_exits: bool @@ -223,7 +260,7 @@ def __init__(self, inst: parser.InstDef): self.kind = inst.kind self.name = inst.name self.block = inst.block - self.block_text, self.check_eval_breaker, self.predictions = \ + self.block_text, self.check_eval_breaker, self.predictions, self.block_line = \ extract_block_text(self.block) self.always_exits = always_exits(self.block_text) self.cache_effects = [ @@ -388,7 +425,13 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None assert dedent <= 0 extra = " " * -dedent names_to_skip = self.unmoved_names | frozenset({UNUSED, "null"}) + offset = 0 + context = self.block.context + assert context != None + filename = context.owner.filename for line in self.block_text: + out.set_lineno(self.block_line + offset, filename) + offset += 1 if m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*(?://.*)?$", line): space, cond, label = m.groups() space = extra + space @@ -416,6 +459,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None out.write_raw(f"{space}if ({cond}) goto {label};\n") elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*(?://.*)?$", line): if not self.register: + out.reset_lineno() space = extra + m.group(1) for ieff in self.input_effects: if ieff.name in names_to_skip: @@ -431,6 +475,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None out.write_raw(f"{space}Py_{decref}({ieff.name});\n") else: out.write_raw(extra + line) + out.reset_lineno() InstructionOrCacheEffect = Instruction | parser.CacheEffect @@ -501,6 +546,7 @@ class Analyzer: output_filename: str metadata_filename: str errors: int = 0 + emit_line_directives: bool = False def __init__(self, input_filenames: list[str], output_filename: str, metadata_filename: str): """Read the input file.""" @@ -561,6 +607,10 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: with open(filename) as file: src = file.read() + # Make filename more user-friendly and less platform-specific + filename = filename.replace("\\", "/") + if filename.startswith("./"): + filename = filename[2:] psr = parser.Parser(src, filename=filename) # Skip until begin marker @@ -972,13 +1022,14 @@ def write_metadata(self) -> None: format_enums = [INSTR_FMT_PREFIX + format for format in sorted(all_formats)] with open(self.metadata_filename, "w") as f: + # Create formatter + self.out = Formatter(f, 0) + # Write provenance header - f.write(f"// This file is generated by {THIS}\n") - f.write(self.from_source_files()) - f.write(f"// Do not edit!\n") + self.out.write_raw(f"// This file is generated by {THIS}\n") + self.out.write_raw(self.from_source_files()) + self.out.write_raw(f"// Do not edit!\n") - # Create formatter; the rest of the code uses this - self.out = Formatter(f, 0) self.write_stack_effect_functions() @@ -1053,13 +1104,13 @@ def write_metadata_for_macro(self, mac: MacroInstruction) -> None: def write_instructions(self) -> None: """Write instructions to output file.""" with open(self.output_filename, "w") as f: - # Write provenance header - f.write(f"// This file is generated by {THIS}\n") - f.write(self.from_source_files()) - f.write(f"// Do not edit!\n") + # Create formatter + self.out = Formatter(f, 8, self.emit_line_directives) - # Create formatter; the rest of the code uses this - self.out = Formatter(f, 8) + # Write provenance header + self.out.write_raw(f"// This file is generated by {THIS}\n") + self.out.write_raw(self.from_source_files()) + self.out.write_raw(f"// Do not edit!\n") # Write and count instructions of all kinds n_instrs = 0 @@ -1179,13 +1230,16 @@ def wrap_super_or_macro(self, up: SuperOrMacroInstruction): self.out.emit(f"DISPATCH();") -def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str]]: +def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str], int]: # Get lines of text with proper dedent blocklines = block.text.splitlines(True) + first_token: lx.Token = block.tokens[0] # IndexError means the context is broken + block_line = first_token.begin[0] # Remove blank lines from both ends while blocklines and not blocklines[0].strip(): blocklines.pop(0) + block_line += 1 while blocklines and not blocklines[-1].strip(): blocklines.pop() @@ -1194,6 +1248,7 @@ def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str]] assert blocklines and blocklines[-1].strip() == "}" blocklines.pop() blocklines.pop(0) + block_line += 1 # Remove trailing blank lines while blocklines and not blocklines[-1].strip(): @@ -1213,7 +1268,7 @@ def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str]] predictions.insert(0, m.group(1)) blocklines.pop() - return blocklines, check_eval_breaker, predictions + return blocklines, check_eval_breaker, predictions, block_line def always_exits(lines: list[str]) -> bool: @@ -1250,6 +1305,8 @@ def main(): if len(args.input) == 0: args.input.append(DEFAULT_INPUT) a = Analyzer(args.input, args.output, args.metadata) # Raises OSError if input unreadable + if args.emit_line_directives: + a.emit_line_directives = True a.parse() # Raises SyntaxError on failure a.analyze() # Prints messages and sets a.errors on failure if a.errors: From webhook-mailer at python.org Wed Mar 15 14:19:17 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 15 Mar 2023 18:19:17 -0000 Subject: [Python-checkins] Exclude `ceval.c` from the C-analyzer tool (#102735) Message-ID: https://github.com/python/cpython/commit/215007b57619978243b5d5e4d0884f777e8b2715 commit: 215007b57619978243b5d5e4d0884f777e8b2715 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-03-15T18:19:07Z summary: Exclude `ceval.c` from the C-analyzer tool (#102735) The "check if generated files are up to date" CI check appears to be currently failing on all PRs (but not on pushes to main) See, for example: - https://github.com/python/cpython/pull/94468 - https://github.com/python/cpython/pull/94468 - https://github.com/python/cpython/pull/102731 This appears to be because the C-analyzer tool doesn't like the `#line` directives introduced in https://github.com/python/cpython/commit/70185de1abfe428049a5c43d58fcb656b46db96c. I'm advised by the message printed to the terminal in https://github.com/python/cpython/actions/runs/4428706945/jobs/7768216988#step:14:84 that this is the appropriate short-term fix! files: M Tools/c-analyzer/cpython/_parser.py diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index 6da4fbbf4224..a2911e030ffe 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -91,10 +91,15 @@ def clean_lines(text): # XXX Fix the parser. EXCLUDED += clean_lines(''' # The tool should be able to parse these... + # The problem with xmlparse.c is that something # has gone wrong where # we handle "maybe inline actual" # in Tools/c-analyzer/c_parser/parser/_global.py. Modules/expat/xmlparse.c + +# The parser doesn't like the #line directives +# that originate from generated_cases.c.h +Python/ceval.c ''') INCL_DIRS = clean_lines(''' From webhook-mailer at python.org Wed Mar 15 15:18:26 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Wed, 15 Mar 2023 19:18:26 -0000 Subject: [Python-checkins] Fix typo in code comment (#102726) Message-ID: https://github.com/python/cpython/commit/00d1ef73d6799142f90d8e00f3dfcf5d86e6cad8 commit: 00d1ef73d6799142f90d8e00f3dfcf5d86e6cad8 branch: main author: Martin Breuss committer: AlexWaygood date: 2023-03-15T19:18:18Z summary: Fix typo in code comment (#102726) files: M Lib/test/test_traceback.py diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 92c5a0005858..7ef93b3f0ac3 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -2987,7 +2987,7 @@ class MyClass: def test_getattr_suggestions_do_not_trigger_for_big_dicts(self): class A: blech = None - # A class with a very big __dict__ will not be consider + # A class with a very big __dict__ will not be considered # for suggestions. for index in range(2000): setattr(A, f"index_{index}", None) From webhook-mailer at python.org Wed Mar 15 16:15:35 2023 From: webhook-mailer at python.org (rhettinger) Date: Wed, 15 Mar 2023 20:15:35 -0000 Subject: [Python-checkins] Simplify and speed-up math.hypot() and math.dist() (GH-102734) Message-ID: https://github.com/python/cpython/commit/0a22aa0528a4ff590854996b8854e9a79120987a commit: 0a22aa0528a4ff590854996b8854e9a79120987a branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-15T15:15:23-05:00 summary: Simplify and speed-up math.hypot() and math.dist() (GH-102734) files: M Modules/mathmodule.c diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 544560e8322c..ae9e3211c072 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -92,6 +92,113 @@ get_math_module_state(PyObject *module) return (math_module_state *)state; } +/* +Double and triple length extended precision algorithms from: + + Accurate Sum and Dot Product + by Takeshi Ogita, Siegfried M. Rump, and Shin?Ichi Oishi + https://doi.org/10.1137/030601818 + https://www.tuhh.de/ti3/paper/rump/OgRuOi05.pdf + +*/ + +typedef struct{ double hi; double lo; } DoubleLength; + +static DoubleLength +dl_fast_sum(double a, double b) +{ + /* Algorithm 1.1. Compensated summation of two floating point numbers. */ + assert(fabs(a) >= fabs(b)); + double x = a + b; + double y = (a - x) + b; + return (DoubleLength) {x, y}; +} + +static DoubleLength +dl_sum(double a, double b) +{ + /* Algorithm 3.1 Error-free transformation of the sum */ + double x = a + b; + double z = x - a; + double y = (a - (x - z)) + (b - z); + return (DoubleLength) {x, y}; +} + +#ifndef UNRELIABLE_FMA + +static DoubleLength +dl_mul(double x, double y) +{ + /* Algorithm 3.5. Error-free transformation of a product */ + double z = x * y; + double zz = fma(x, y, -z); + return (DoubleLength) {z, zz}; +} + +#else + +/* + The default implementation of dl_mul() depends on the C math library + having an accurate fma() function as required by ? 7.12.13.1 of the + C99 standard. + + The UNRELIABLE_FMA option is provided as a slower but accurate + alternative for builds where the fma() function is found wanting. + The speed penalty may be modest (17% slower on an Apple M1 Max), + so don't hesitate to enable this build option. + + The algorithms are from the T. J. Dekker paper: + A Floating-Point Technique for Extending the Available Precision + https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf +*/ + +static DoubleLength +dl_split(double x) { + // Dekker (5.5) and (5.6). + double t = x * 134217729.0; // Veltkamp constant = 2.0 ** 27 + 1 + double hi = t - (t - x); + double lo = x - hi; + return (DoubleLength) {hi, lo}; +} + +static DoubleLength +dl_mul(double x, double y) +{ + // Dekker (5.12) and mul12() + DoubleLength xx = dl_split(x); + DoubleLength yy = dl_split(y); + double p = xx.hi * yy.hi; + double q = xx.hi * yy.lo + xx.lo * yy.hi; + double z = p + q; + double zz = p - z + q + xx.lo * yy.lo; + return (DoubleLength) {z, zz}; +} + +#endif + +typedef struct { double hi; double lo; double tiny; } TripleLength; + +static const TripleLength tl_zero = {0.0, 0.0, 0.0}; + +static TripleLength +tl_fma(double x, double y, TripleLength total) +{ + /* Algorithm 5.10 with SumKVert for K=3 */ + DoubleLength pr = dl_mul(x, y); + DoubleLength sm = dl_sum(total.hi, pr.hi); + DoubleLength r1 = dl_sum(total.lo, pr.lo); + DoubleLength r2 = dl_sum(r1.hi, sm.lo); + return (TripleLength) {sm.hi, r2.hi, total.tiny + r1.lo + r2.lo}; +} + +static double +tl_to_d(TripleLength total) +{ + DoubleLength last = dl_sum(total.lo, total.hi); + return total.tiny + last.lo + last.hi; +} + + /* sin(pi*x), giving accurate results for all finite x (especially x integral or close to an integer). This is here for use in the @@ -2301,6 +2408,7 @@ that are almost always correctly rounded, four techniques are used: * lossless scaling using a power-of-two scaling factor * accurate squaring using Veltkamp-Dekker splitting [1] + or an equivalent with an fma() call * compensated summation using a variant of the Neumaier algorithm [2] * differential correction of the square root [3] @@ -2359,14 +2467,21 @@ algorithm, effectively doubling the number of accurate bits. This technique is used in Dekker's SQRT2 algorithm and again in Borges' ALGORITHM 4 and 5. -Without proof for all cases, hypot() cannot claim to be always -correctly rounded. However for n <= 1000, prior to the final addition -that rounds the overall result, the internal accuracy of "h" together -with its correction of "x / (2.0 * h)" is at least 100 bits. [6] -Also, hypot() was tested against a Decimal implementation with -prec=300. After 100 million trials, no incorrectly rounded examples -were found. In addition, perfect commutativity (all permutations are -exactly equal) was verified for 1 billion random inputs with n=5. [7] +The hypot() function is faithfully rounded (less than 1 ulp error) +and usually correctly rounded (within 1/2 ulp). The squaring +step is exact. The Neumaier summation computes as if in doubled +precision (106 bits) and has the advantage that its input squares +are non-negative so that the condition number of the sum is one. +The square root with a differential correction is likewise computed +as if in double precision. + +For n <= 1000, prior to the final addition that rounds the overall +result, the internal accuracy of "h" together with its correction of +"x / (2.0 * h)" is at least 100 bits. [6] Also, hypot() was tested +against a Decimal implementation with prec=300. After 100 million +trials, no incorrectly rounded examples were found. In addition, +perfect commutativity (all permutations are exactly equal) was +verified for 1 billion random inputs with n=5. [7] References: @@ -2383,9 +2498,8 @@ exactly equal) was verified for 1 billion random inputs with n=5. [7] static inline double vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) { - const double T27 = 134217729.0; /* ldexp(1.0, 27) + 1.0) */ - double x, scale, oldcsum, csum = 1.0, frac1 = 0.0, frac2 = 0.0, frac3 = 0.0; - double t, hi, lo, h; + double x, h, scale, oldcsum, csum = 1.0, frac1 = 0.0, frac2 = 0.0; + DoubleLength pr, sm; int max_e; Py_ssize_t i; @@ -2410,54 +2524,21 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) x *= scale; assert(fabs(x) < 1.0); - t = x * T27; - hi = t - (t - x); - lo = x - hi; - assert(hi + lo == x); - - x = hi * hi; - assert(x <= 1.0); - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac1 += (oldcsum - csum) + x; - - x = 2.0 * hi * lo; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac2 += (oldcsum - csum) + x; - - assert(csum + lo * lo == csum); - frac3 += lo * lo; - } - h = sqrt(csum - 1.0 + (frac1 + frac2 + frac3)); - - x = h; - t = x * T27; - hi = t - (t - x); - lo = x - hi; - assert (hi + lo == x); + pr = dl_mul(x, x); + assert(pr.hi <= 1.0); - x = -hi * hi; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac1 += (oldcsum - csum) + x; - - x = -2.0 * hi * lo; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac2 += (oldcsum - csum) + x; - - x = -lo * lo; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac3 += (oldcsum - csum) + x; - - x = csum - 1.0 + (frac1 + frac2 + frac3); + sm = dl_fast_sum(csum, pr.hi); + csum = sm.hi; + frac1 += pr.lo; + frac2 += sm.lo; + } + h = sqrt(csum - 1.0 + (frac1 + frac2)); + pr = dl_mul(-h, h); + sm = dl_fast_sum(csum, pr.hi); + csum = sm.hi; + frac1 += pr.lo; + frac2 += sm.lo; + x = csum - 1.0 + (frac1 + frac2); return (h + x / (2.0 * h)) / scale; } /* When max_e < -1023, ldexp(1.0, -max_e) overflows. @@ -2646,102 +2727,6 @@ long_add_would_overflow(long a, long b) return (a > 0) ? (b > LONG_MAX - a) : (b < LONG_MIN - a); } -/* -Double and triple length extended precision algorithms from: - - Accurate Sum and Dot Product - by Takeshi Ogita, Siegfried M. Rump, and Shin?Ichi Oishi - https://doi.org/10.1137/030601818 - https://www.tuhh.de/ti3/paper/rump/OgRuOi05.pdf - -*/ - -typedef struct{ double hi; double lo; } DoubleLength; - -static DoubleLength -dl_sum(double a, double b) -{ - /* Algorithm 3.1 Error-free transformation of the sum */ - double x = a + b; - double z = x - a; - double y = (a - (x - z)) + (b - z); - return (DoubleLength) {x, y}; -} - -#ifndef UNRELIABLE_FMA - -static DoubleLength -dl_mul(double x, double y) -{ - /* Algorithm 3.5. Error-free transformation of a product */ - double z = x * y; - double zz = fma(x, y, -z); - return (DoubleLength) {z, zz}; -} - -#else - -/* - The default implementation of dl_mul() depends on the C math library - having an accurate fma() function as required by ? 7.12.13.1 of the - C99 standard. - - The UNRELIABLE_FMA option is provided as a slower but accurate - alternative for builds where the fma() function is found wanting. - The speed penalty may be modest (17% slower on an Apple M1 Max), - so don't hesitate to enable this build option. - - The algorithms are from the T. J. Dekker paper: - A Floating-Point Technique for Extending the Available Precision - https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf -*/ - -static DoubleLength -dl_split(double x) { - // Dekker (5.5) and (5.6). - double t = x * 134217729.0; // Veltkamp constant = 2.0 ** 27 + 1 - double hi = t - (t - x); - double lo = x - hi; - return (DoubleLength) {hi, lo}; -} - -static DoubleLength -dl_mul(double x, double y) -{ - // Dekker (5.12) and mul12() - DoubleLength xx = dl_split(x); - DoubleLength yy = dl_split(y); - double p = xx.hi * yy.hi; - double q = xx.hi * yy.lo + xx.lo * yy.hi; - double z = p + q; - double zz = p - z + q + xx.lo * yy.lo; - return (DoubleLength) {z, zz}; -} - -#endif - -typedef struct { double hi; double lo; double tiny; } TripleLength; - -static const TripleLength tl_zero = {0.0, 0.0, 0.0}; - -static TripleLength -tl_fma(double x, double y, TripleLength total) -{ - /* Algorithm 5.10 with SumKVert for K=3 */ - DoubleLength pr = dl_mul(x, y); - DoubleLength sm = dl_sum(total.hi, pr.hi); - DoubleLength r1 = dl_sum(total.lo, pr.lo); - DoubleLength r2 = dl_sum(r1.hi, sm.lo); - return (TripleLength) {sm.hi, r2.hi, total.tiny + r1.lo + r2.lo}; -} - -static double -tl_to_d(TripleLength total) -{ - DoubleLength last = dl_sum(total.lo, total.hi); - return total.tiny + last.lo + last.hi; -} - /*[clinic input] math.sumprod From webhook-mailer at python.org Wed Mar 15 17:25:38 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 15 Mar 2023 21:25:38 -0000 Subject: [Python-checkins] gh-102738: remove from cases generator the code related to register instructions (#102739) Message-ID: https://github.com/python/cpython/commit/675b97a6ab483573f07ce6e0b79b0bc370ab76c9 commit: 675b97a6ab483573f07ce6e0b79b0bc370ab76c9 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-15T21:25:31Z summary: gh-102738: remove from cases generator the code related to register instructions (#102739) files: M Python/opcode_metadata.h M Tools/cases_generator/generate_cases.py diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 93f3c76c5b82..ee760ab78af2 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -707,12 +707,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -enum Direction { DIR_NONE, DIR_READ, DIR_WRITE }; enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { - enum Direction dir_op1; - enum Direction dir_op2; - enum Direction dir_op3; bool valid_entry; enum InstructionFormat instr_format; }; @@ -721,175 +717,175 @@ struct opcode_metadata { extern const struct opcode_metadata _PyOpcode_opcode_metadata[256]; #else const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { - [NOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RESUME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CLOSURE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [LOAD_FAST__LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [STORE_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [STORE_FAST__STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [LOAD_CONST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [POP_TOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [PUSH_NULL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [END_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNARY_NEGATIVE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNARY_NOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNARY_INVERT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_MULTIPLY_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_MULTIPLY_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_SUBTRACT_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_SUBTRACT_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [STORE_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_TUPLE_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_GETITEM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SET_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [STORE_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [STORE_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [DELETE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CALL_INTRINSIC_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_INTRINSIC_2] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [RAISE_VARARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [INTERPRETER_EXIT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RETURN_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RETURN_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [GET_AITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_ANEXT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_AWAITABLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [SEND_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [YIELD_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [POP_EXCEPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RERAISE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [END_ASYNC_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CLEANUP_THROW] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ASSERTION_ERROR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_BUILD_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [STORE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNPACK_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_TWO_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [DELETE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [LOAD_GLOBAL_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [LOAD_GLOBAL_BUILTIN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [DELETE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAKE_CELL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CLASSDEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [COPY_FREE_VARS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_STRING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LIST_EXTEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SET_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SETUP_ANNOTATIONS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BUILD_CONST_KEY_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DICT_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DICT_MERGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAP_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_PROPERTY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [STORE_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [STORE_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [STORE_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [COMPARE_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [COMPARE_AND_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_STR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [IS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CONTAINS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CHECK_EG_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CHECK_EXC_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [IMPORT_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [IMPORT_FROM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_FORWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_BACKWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_TRUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_NOT_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_IF_FALSE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_IF_TRUE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_BACKWARD_NO_INTERRUPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [GET_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MATCH_MAPPING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_KEYS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BEFORE_ASYNC_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BEFORE_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [WITH_EXCEPT_START] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [PUSH_EXC_INFO] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_NO_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [KW_NAMES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_PY_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_PY_WITH_DEFAULTS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_TYPE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_STR_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_TUPLE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_BUILTIN_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_BUILTIN_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_BUILTIN_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_ISINSTANCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_FUNCTION_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAKE_FUNCTION] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [RETURN_GENERATOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BUILD_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FORMAT_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [COPY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BINARY_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [SWAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [EXTENDED_ARG] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CACHE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [NOP] = { true, INSTR_FMT_IX }, + [RESUME] = { true, INSTR_FMT_IB }, + [LOAD_CLOSURE] = { true, INSTR_FMT_IB }, + [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB }, + [LOAD_FAST] = { true, INSTR_FMT_IB }, + [LOAD_CONST] = { true, INSTR_FMT_IB }, + [STORE_FAST] = { true, INSTR_FMT_IB }, + [LOAD_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, + [LOAD_FAST__LOAD_CONST] = { true, INSTR_FMT_IBIB }, + [STORE_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, + [STORE_FAST__STORE_FAST] = { true, INSTR_FMT_IBIB }, + [LOAD_CONST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, + [POP_TOP] = { true, INSTR_FMT_IX }, + [PUSH_NULL] = { true, INSTR_FMT_IX }, + [END_FOR] = { true, INSTR_FMT_IB }, + [UNARY_NEGATIVE] = { true, INSTR_FMT_IX }, + [UNARY_NOT] = { true, INSTR_FMT_IX }, + [UNARY_INVERT] = { true, INSTR_FMT_IX }, + [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC }, + [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IX }, + [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC }, + [BINARY_SUBSCR] = { true, INSTR_FMT_IXC000 }, + [BINARY_SLICE] = { true, INSTR_FMT_IX }, + [STORE_SLICE] = { true, INSTR_FMT_IX }, + [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC000 }, + [LIST_APPEND] = { true, INSTR_FMT_IB }, + [SET_ADD] = { true, INSTR_FMT_IB }, + [STORE_SUBSCR] = { true, INSTR_FMT_IXC }, + [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC }, + [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC }, + [DELETE_SUBSCR] = { true, INSTR_FMT_IX }, + [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB }, + [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB }, + [RAISE_VARARGS] = { true, INSTR_FMT_IB }, + [INTERPRETER_EXIT] = { true, INSTR_FMT_IX }, + [RETURN_VALUE] = { true, INSTR_FMT_IX }, + [RETURN_CONST] = { true, INSTR_FMT_IB }, + [GET_AITER] = { true, INSTR_FMT_IX }, + [GET_ANEXT] = { true, INSTR_FMT_IX }, + [GET_AWAITABLE] = { true, INSTR_FMT_IB }, + [SEND] = { true, INSTR_FMT_IBC }, + [SEND_GEN] = { true, INSTR_FMT_IBC }, + [YIELD_VALUE] = { true, INSTR_FMT_IX }, + [POP_EXCEPT] = { true, INSTR_FMT_IX }, + [RERAISE] = { true, INSTR_FMT_IB }, + [END_ASYNC_FOR] = { true, INSTR_FMT_IX }, + [CLEANUP_THROW] = { true, INSTR_FMT_IX }, + [LOAD_ASSERTION_ERROR] = { true, INSTR_FMT_IX }, + [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX }, + [STORE_NAME] = { true, INSTR_FMT_IB }, + [DELETE_NAME] = { true, INSTR_FMT_IB }, + [UNPACK_SEQUENCE] = { true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_LIST] = { true, INSTR_FMT_IBC }, + [UNPACK_EX] = { true, INSTR_FMT_IB }, + [STORE_ATTR] = { true, INSTR_FMT_IBC000 }, + [DELETE_ATTR] = { true, INSTR_FMT_IB }, + [STORE_GLOBAL] = { true, INSTR_FMT_IB }, + [DELETE_GLOBAL] = { true, INSTR_FMT_IB }, + [LOAD_NAME] = { true, INSTR_FMT_IB }, + [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000 }, + [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000 }, + [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000 }, + [DELETE_FAST] = { true, INSTR_FMT_IB }, + [MAKE_CELL] = { true, INSTR_FMT_IB }, + [DELETE_DEREF] = { true, INSTR_FMT_IB }, + [LOAD_CLASSDEREF] = { true, INSTR_FMT_IB }, + [LOAD_DEREF] = { true, INSTR_FMT_IB }, + [STORE_DEREF] = { true, INSTR_FMT_IB }, + [COPY_FREE_VARS] = { true, INSTR_FMT_IB }, + [BUILD_STRING] = { true, INSTR_FMT_IB }, + [BUILD_TUPLE] = { true, INSTR_FMT_IB }, + [BUILD_LIST] = { true, INSTR_FMT_IB }, + [LIST_EXTEND] = { true, INSTR_FMT_IB }, + [SET_UPDATE] = { true, INSTR_FMT_IB }, + [BUILD_SET] = { true, INSTR_FMT_IB }, + [BUILD_MAP] = { true, INSTR_FMT_IB }, + [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX }, + [BUILD_CONST_KEY_MAP] = { true, INSTR_FMT_IB }, + [DICT_UPDATE] = { true, INSTR_FMT_IB }, + [DICT_MERGE] = { true, INSTR_FMT_IB }, + [MAP_ADD] = { true, INSTR_FMT_IB }, + [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000 }, + [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000 }, + [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000 }, + [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000 }, + [COMPARE_OP] = { true, INSTR_FMT_IBC }, + [COMPARE_AND_BRANCH] = { true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_FLOAT] = { true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_INT] = { true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_STR] = { true, INSTR_FMT_IBC0 }, + [IS_OP] = { true, INSTR_FMT_IB }, + [CONTAINS_OP] = { true, INSTR_FMT_IB }, + [CHECK_EG_MATCH] = { true, INSTR_FMT_IX }, + [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX }, + [IMPORT_NAME] = { true, INSTR_FMT_IB }, + [IMPORT_FROM] = { true, INSTR_FMT_IB }, + [JUMP_FORWARD] = { true, INSTR_FMT_IB }, + [JUMP_BACKWARD] = { true, INSTR_FMT_IB }, + [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB }, + [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB }, + [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, + [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, + [JUMP_IF_FALSE_OR_POP] = { true, INSTR_FMT_IB }, + [JUMP_IF_TRUE_OR_POP] = { true, INSTR_FMT_IB }, + [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB }, + [GET_LEN] = { true, INSTR_FMT_IX }, + [MATCH_CLASS] = { true, INSTR_FMT_IB }, + [MATCH_MAPPING] = { true, INSTR_FMT_IX }, + [MATCH_SEQUENCE] = { true, INSTR_FMT_IX }, + [MATCH_KEYS] = { true, INSTR_FMT_IX }, + [GET_ITER] = { true, INSTR_FMT_IX }, + [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX }, + [FOR_ITER] = { true, INSTR_FMT_IBC }, + [FOR_ITER_LIST] = { true, INSTR_FMT_IBC }, + [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC }, + [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC }, + [FOR_ITER_GEN] = { true, INSTR_FMT_IBC }, + [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX }, + [BEFORE_WITH] = { true, INSTR_FMT_IX }, + [WITH_EXCEPT_START] = { true, INSTR_FMT_IX }, + [PUSH_EXC_INFO] = { true, INSTR_FMT_IX }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000 }, + [KW_NAMES] = { true, INSTR_FMT_IB }, + [CALL] = { true, INSTR_FMT_IBC000 }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC000 }, + [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC000 }, + [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC000 }, + [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC000 }, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC000 }, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC000 }, + [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB }, + [MAKE_FUNCTION] = { true, INSTR_FMT_IB }, + [RETURN_GENERATOR] = { true, INSTR_FMT_IX }, + [BUILD_SLICE] = { true, INSTR_FMT_IB }, + [FORMAT_VALUE] = { true, INSTR_FMT_IB }, + [COPY] = { true, INSTR_FMT_IB }, + [BINARY_OP] = { true, INSTR_FMT_IBC }, + [SWAP] = { true, INSTR_FMT_IB }, + [EXTENDED_ARG] = { true, INSTR_FMT_IB }, + [CACHE] = { true, INSTR_FMT_IX }, }; #endif diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index b16c927a4a28..f1b655b8b054 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -229,7 +229,6 @@ class Instruction: # Parts of the underlying instruction definition inst: parser.InstDef - register: bool kind: typing.Literal["inst", "op", "legacy"] # Legacy means no (input -- output) name: str block: parser.Block @@ -246,17 +245,12 @@ class Instruction: unmoved_names: frozenset[str] instr_fmt: str - # Parallel to input_effects; set later - input_registers: list[str] = dataclasses.field(repr=False) - output_registers: list[str] = dataclasses.field(repr=False) - # Set later family: parser.Family | None = None predicted: bool = False def __init__(self, inst: parser.InstDef): self.inst = inst - self.register = inst.register self.kind = inst.kind self.name = inst.name self.block = inst.block @@ -278,15 +272,10 @@ def __init__(self, inst: parser.InstDef): else: break self.unmoved_names = frozenset(unmoved_names) - if self.register: - num_regs = len(self.input_effects) + len(self.output_effects) - num_dummies = (num_regs // 2) * 2 + 1 - num_regs - fmt = "I" + "B" * num_regs + "X" * num_dummies + if variable_used(inst, "oparg"): + fmt = "IB" else: - if variable_used(inst, "oparg"): - fmt = "IB" - else: - fmt = "IX" + fmt = "IX" cache = "C" for ce in self.cache_effects: for _ in range(ce.size): @@ -294,20 +283,6 @@ def __init__(self, inst: parser.InstDef): cache = "0" self.instr_fmt = fmt - def analyze_registers(self, a: "Analyzer") -> None: - regs = iter(("REG(oparg1)", "REG(oparg2)", "REG(oparg3)")) - try: - self.input_registers = [ - next(regs) for ieff in self.input_effects if ieff.name != UNUSED - ] - self.output_registers = [ - next(regs) for oeff in self.output_effects if oeff.name != UNUSED - ] - except StopIteration: # Running out of registers - a.error( - f"Instruction {self.name} has too many register effects", node=self.inst - ) - def write(self, out: Formatter) -> None: """Write one instruction, sans prologue and epilogue.""" # Write a static assertion that a family's cache size is correct @@ -319,25 +294,19 @@ def write(self, out: Formatter) -> None: f'{self.cache_offset}, "incorrect cache size");' ) - if not self.register: - # Write input stack effect variable declarations and initializations - ieffects = list(reversed(self.input_effects)) - for i, ieffect in enumerate(ieffects): - isize = string_effect_size( - list_effect_size([ieff for ieff in ieffects[: i + 1]]) - ) - if ieffect.size: - src = StackEffect(f"(stack_pointer - {maybe_parenthesize(isize)})", "PyObject **") - elif ieffect.cond: - src = StackEffect(f"({ieffect.cond}) ? stack_pointer[-{maybe_parenthesize(isize)}] : NULL", "") - else: - src = StackEffect(f"stack_pointer[-{maybe_parenthesize(isize)}]", "") - out.declare(ieffect, src) - else: - # Write input register variable declarations and initializations - for ieffect, reg in zip(self.input_effects, self.input_registers): - src = StackEffect(reg, "") - out.declare(ieffect, src) + # Write input stack effect variable declarations and initializations + ieffects = list(reversed(self.input_effects)) + for i, ieffect in enumerate(ieffects): + isize = string_effect_size( + list_effect_size([ieff for ieff in ieffects[: i + 1]]) + ) + if ieffect.size: + src = StackEffect(f"(stack_pointer - {maybe_parenthesize(isize)})", "PyObject **") + elif ieffect.cond: + src = StackEffect(f"({ieffect.cond}) ? stack_pointer[-{maybe_parenthesize(isize)}] : NULL", "") + else: + src = StackEffect(f"stack_pointer[-{maybe_parenthesize(isize)}]", "") + out.declare(ieffect, src) # Write output stack effect variable declarations isize = string_effect_size(list_effect_size(self.input_effects)) @@ -367,32 +336,26 @@ def write(self, out: Formatter) -> None: if self.always_exits: return - if not self.register: - # Write net stack growth/shrinkage - out.stack_adjust( - 0, - [ieff for ieff in self.input_effects], - [oeff for oeff in self.output_effects], - ) + # Write net stack growth/shrinkage + out.stack_adjust( + 0, + [ieff for ieff in self.input_effects], + [oeff for oeff in self.output_effects], + ) - # Write output stack effect assignments - oeffects = list(reversed(self.output_effects)) - for i, oeffect in enumerate(oeffects): - if oeffect.name in self.unmoved_names: - continue - osize = string_effect_size( - list_effect_size([oeff for oeff in oeffects[: i + 1]]) - ) - if oeffect.size: - dst = StackEffect(f"stack_pointer - {maybe_parenthesize(osize)}", "PyObject **") - else: - dst = StackEffect(f"stack_pointer[-{maybe_parenthesize(osize)}]", "") - out.assign(dst, oeffect) - else: - # Write output register assignments - for oeffect, reg in zip(self.output_effects, self.output_registers): - dst = StackEffect(reg, "") - out.assign(dst, oeffect) + # Write output stack effect assignments + oeffects = list(reversed(self.output_effects)) + for i, oeffect in enumerate(oeffects): + if oeffect.name in self.unmoved_names: + continue + osize = string_effect_size( + list_effect_size([oeff for oeff in oeffects[: i + 1]]) + ) + if oeffect.size: + dst = StackEffect(f"stack_pointer - {maybe_parenthesize(osize)}", "PyObject **") + else: + dst = StackEffect(f"stack_pointer[-{maybe_parenthesize(osize)}]", "") + out.assign(dst, oeffect) # Write cache effect if self.cache_offset: @@ -438,19 +401,17 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None # ERROR_IF() must pop the inputs from the stack. # The code block is responsible for DECREF()ing them. # NOTE: If the label doesn't exist, just add it to ceval.c. - if not self.register: - # Don't pop common input/output effects at the bottom! - # These aren't DECREF'ed so they can stay. - ieffs = list(self.input_effects) - oeffs = list(self.output_effects) - while ieffs and oeffs and ieffs[0] == oeffs[0]: - ieffs.pop(0) - oeffs.pop(0) - ninputs, symbolic = list_effect_size(ieffs) - if ninputs: - label = f"pop_{ninputs}_{label}" - else: - symbolic = "" + + # Don't pop common input/output effects at the bottom! + # These aren't DECREF'ed so they can stay. + ieffs = list(self.input_effects) + oeffs = list(self.output_effects) + while ieffs and oeffs and ieffs[0] == oeffs[0]: + ieffs.pop(0) + oeffs.pop(0) + ninputs, symbolic = list_effect_size(ieffs) + if ninputs: + label = f"pop_{ninputs}_{label}" if symbolic: out.write_raw( f"{space}if ({cond}) {{ STACK_SHRINK({symbolic}); goto {label}; }}\n" @@ -458,21 +419,20 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None else: out.write_raw(f"{space}if ({cond}) goto {label};\n") elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*(?://.*)?$", line): - if not self.register: - out.reset_lineno() - space = extra + m.group(1) - for ieff in self.input_effects: - if ieff.name in names_to_skip: - continue - if ieff.size: - out.write_raw( - f"{space}for (int _i = {ieff.size}; --_i >= 0;) {{\n" - ) - out.write_raw(f"{space} Py_DECREF({ieff.name}[_i]);\n") - out.write_raw(f"{space}}}\n") - else: - decref = "XDECREF" if ieff.cond else "DECREF" - out.write_raw(f"{space}Py_{decref}({ieff.name});\n") + out.reset_lineno() + space = extra + m.group(1) + for ieff in self.input_effects: + if ieff.name in names_to_skip: + continue + if ieff.size: + out.write_raw( + f"{space}for (int _i = {ieff.size}; --_i >= 0;) {{\n" + ) + out.write_raw(f"{space} Py_DECREF({ieff.name}[_i]);\n") + out.write_raw(f"{space}}}\n") + else: + decref = "XDECREF" if ieff.cond else "DECREF" + out.write_raw(f"{space}Py_{decref}({ieff.name});\n") else: out.write_raw(extra + line) out.reset_lineno() @@ -672,7 +632,6 @@ def analyze(self) -> None: Raises SystemExit if there is an error. """ self.find_predictions() - self.analyze_register_instrs() self.analyze_supers_and_macros() self.map_families() self.check_families() @@ -782,11 +741,6 @@ def effect_counts(self, name: str) -> tuple[int, int, int]: assert False, f"Unknown instruction {name!r}" return cache, input, output - def analyze_register_instrs(self) -> None: - for instr in self.instrs.values(): - if instr.register: - instr.analyze_registers(self) - def analyze_supers_and_macros(self) -> None: """Analyze each super- and macro instruction.""" self.super_instrs = {} @@ -816,7 +770,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: stack, initial_sp = self.stack_analysis(components) sp = initial_sp parts: list[Component | parser.CacheEffect] = [] - format = "IB" # Macros don't support register instructions yet + format = "IB" cache = "C" for component in components: match component: @@ -1034,13 +988,9 @@ def write_metadata(self) -> None: self.write_stack_effect_functions() # Write type definitions - self.out.emit("enum Direction { DIR_NONE, DIR_READ, DIR_WRITE };") self.out.emit(f"enum InstructionFormat {{ {', '.join(format_enums)} }};") self.out.emit("struct opcode_metadata {") with self.out.indent(): - self.out.emit("enum Direction dir_op1;") - self.out.emit("enum Direction dir_op2;") - self.out.emit("enum Direction dir_op3;") self.out.emit("bool valid_entry;") self.out.emit("enum InstructionFormat instr_format;") self.out.emit("};") @@ -1073,32 +1023,20 @@ def write_metadata(self) -> None: def write_metadata_for_inst(self, instr: Instruction) -> None: """Write metadata for a single instruction.""" - dir_op1 = dir_op2 = dir_op3 = "DIR_NONE" - if instr.kind == "legacy": - assert not instr.register - else: - if instr.register: - directions: list[str] = [] - directions.extend("DIR_READ" for _ in instr.input_effects) - directions.extend("DIR_WRITE" for _ in instr.output_effects) - directions.extend("DIR_NONE" for _ in range(3)) - dir_op1, dir_op2, dir_op3 = directions[:3] self.out.emit( - f" [{instr.name}] = {{ {dir_op1}, {dir_op2}, {dir_op3}, true, {INSTR_FMT_PREFIX}{instr.instr_fmt} }}," + f" [{instr.name}] = {{ true, {INSTR_FMT_PREFIX}{instr.instr_fmt} }}," ) def write_metadata_for_super(self, sup: SuperInstruction) -> None: """Write metadata for a super-instruction.""" - dir_op1 = dir_op2 = dir_op3 = "DIR_NONE" self.out.emit( - f" [{sup.name}] = {{ {dir_op1}, {dir_op2}, {dir_op3}, true, {INSTR_FMT_PREFIX}{sup.instr_fmt} }}," + f" [{sup.name}] = {{ true, {INSTR_FMT_PREFIX}{sup.instr_fmt} }}," ) def write_metadata_for_macro(self, mac: MacroInstruction) -> None: """Write metadata for a macro-instruction.""" - dir_op1 = dir_op2 = dir_op3 = "DIR_NONE" self.out.emit( - f" [{mac.name}] = {{ {dir_op1}, {dir_op2}, {dir_op3}, true, {INSTR_FMT_PREFIX}{mac.instr_fmt} }}," + f" [{mac.name}] = {{ true, {INSTR_FMT_PREFIX}{mac.instr_fmt} }}," ) def write_instructions(self) -> None: From webhook-mailer at python.org Wed Mar 15 18:14:22 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 15 Mar 2023 22:14:22 -0000 Subject: [Python-checkins] gh-101100: Documenting --prefix and --exec-prefix. (GH-102695) Message-ID: https://github.com/python/cpython/commit/bef189b5c72a25a80d58c46f9e591a1b6db2187a commit: bef189b5c72a25a80d58c46f9e591a1b6db2187a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-15T15:14:00-07:00 summary: gh-101100: Documenting --prefix and --exec-prefix. (GH-102695) (cherry picked from commit 61b9ff35cbda0cc59816951a17de073968fc25c6) Co-authored-by: Julien Palard Co-authored-by: Erlend E. Aasland files: M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/library/sys.rst M Doc/using/configure.rst M Doc/using/unix.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index e1d2328c5f31..c453f3a14a5a 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -391,7 +391,7 @@ Process-wide parameters program name is ``'/usr/local/bin/python'``, the prefix is ``'/usr/local'``. The returned string points into static storage; the caller should not modify its value. This corresponds to the :makevar:`prefix` variable in the top-level - :file:`Makefile` and the ``--prefix`` argument to the :program:`configure` + :file:`Makefile` and the :option:`--prefix` argument to the :program:`configure` script at build time. The value is available to Python code as ``sys.prefix``. It is only useful on Unix. See also the next function. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 80713c565bb8..7591537fe69f 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -78,19 +78,19 @@ used by extension writers. Structure member names do not have a reserved prefix. The header files are typically installed with Python. On Unix, these are located in the directories :file:`{prefix}/include/pythonversion/` and -:file:`{exec_prefix}/include/pythonversion/`, where :envvar:`prefix` and -:envvar:`exec_prefix` are defined by the corresponding parameters to Python's +:file:`{exec_prefix}/include/pythonversion/`, where :option:`prefix <--prefix>` and +:option:`exec_prefix <--exec-prefix>` are defined by the corresponding parameters to Python's :program:`configure` script and *version* is ``'%d.%d' % sys.version_info[:2]``. On Windows, the headers are installed -in :file:`{prefix}/include`, where :envvar:`prefix` is the installation +in :file:`{prefix}/include`, where ``prefix`` is the installation directory specified to the installer. To include the headers, place both directories (if different) on your compiler's search path for includes. Do *not* place the parent directories on the search path and then use ``#include ``; this will break on multi-platform builds since the platform independent headers under -:envvar:`prefix` include the platform specific headers from -:envvar:`exec_prefix`. +:option:`prefix <--prefix>` include the platform specific headers from +:option:`exec_prefix <--exec-prefix>`. C++ users should note that although the API is defined entirely using C, the header files properly declare the entry points to be ``extern "C"``. As a result, diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 315e570416b6..cf20d33ab6e8 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1254,7 +1254,7 @@ always available. A string giving the site-specific directory prefix where the platform independent Python files are installed; on Unix, the default is - ``'/usr/local'``. This can be set at build time with the ``--prefix`` + :file:`/usr/local`. This can be set at build time with the :option:`--prefix` argument to the :program:`configure` script. See :ref:`installation_paths` for derived paths. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 872283615f64..ab33e0a06f51 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -120,6 +120,22 @@ General Options Install Options --------------- +.. cmdoption:: --prefix=PREFIX + + Install architecture-independent files in PREFIX. On Unix, it + defaults to :file:`/usr/local`. + + This value can be retrived at runtime using :data:`sys.prefix`. + + As an example, one can use ``--prefix="$HOME/.local/"`` to install + a Python in its home directory. + +.. cmdoption:: --exec-prefix=EPREFIX + + Install architecture-dependent files in EPREFIX, defaults to :option:`--prefix`. + + This value can be retrived at runtime using :data:`sys.exec_prefix`. + .. cmdoption:: --disable-test-modules Don't build nor install test modules, like the :mod:`test` package or the diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 24c02c99f871..067ff4cce5e4 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -93,7 +93,7 @@ Python-related paths and files ============================== These are subject to difference depending on local installation conventions; -:envvar:`prefix` (``${prefix}``) and :envvar:`exec_prefix` (``${exec_prefix}``) +:option:`prefix <--prefix>` and :option:`exec_prefix <--exec-prefix>` are installation-dependent and should be interpreted as for GNU software; they may be the same. From webhook-mailer at python.org Wed Mar 15 18:14:22 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 15 Mar 2023 22:14:22 -0000 Subject: [Python-checkins] gh-101100: Documenting --prefix and --exec-prefix. (GH-102695) Message-ID: https://github.com/python/cpython/commit/3ddf3972173bfee557af01680647dca9701bde54 commit: 3ddf3972173bfee557af01680647dca9701bde54 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-15T15:13:48-07:00 summary: gh-101100: Documenting --prefix and --exec-prefix. (GH-102695) (cherry picked from commit 61b9ff35cbda0cc59816951a17de073968fc25c6) Co-authored-by: Julien Palard Co-authored-by: Erlend E. Aasland files: M Doc/c-api/init.rst M Doc/c-api/intro.rst M Doc/library/sys.rst M Doc/using/configure.rst M Doc/using/unix.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 844115a9c691..615708ea2cce 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -404,7 +404,7 @@ Process-wide parameters program name is ``'/usr/local/bin/python'``, the prefix is ``'/usr/local'``. The returned string points into static storage; the caller should not modify its value. This corresponds to the :makevar:`prefix` variable in the top-level - :file:`Makefile` and the ``--prefix`` argument to the :program:`configure` + :file:`Makefile` and the :option:`--prefix` argument to the :program:`configure` script at build time. The value is available to Python code as ``sys.prefix``. It is only useful on Unix. See also the next function. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index ac2afa18b743..a8f9e9b99639 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -78,19 +78,19 @@ used by extension writers. Structure member names do not have a reserved prefix. The header files are typically installed with Python. On Unix, these are located in the directories :file:`{prefix}/include/pythonversion/` and -:file:`{exec_prefix}/include/pythonversion/`, where :envvar:`prefix` and -:envvar:`exec_prefix` are defined by the corresponding parameters to Python's +:file:`{exec_prefix}/include/pythonversion/`, where :option:`prefix <--prefix>` and +:option:`exec_prefix <--exec-prefix>` are defined by the corresponding parameters to Python's :program:`configure` script and *version* is ``'%d.%d' % sys.version_info[:2]``. On Windows, the headers are installed -in :file:`{prefix}/include`, where :envvar:`prefix` is the installation +in :file:`{prefix}/include`, where ``prefix`` is the installation directory specified to the installer. To include the headers, place both directories (if different) on your compiler's search path for includes. Do *not* place the parent directories on the search path and then use ``#include ``; this will break on multi-platform builds since the platform independent headers under -:envvar:`prefix` include the platform specific headers from -:envvar:`exec_prefix`. +:option:`prefix <--prefix>` include the platform specific headers from +:option:`exec_prefix <--exec-prefix>`. C++ users should note that although the API is defined entirely using C, the header files properly declare the entry points to be ``extern "C"``. As a result, diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 36155d632363..79df611a2724 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1307,7 +1307,7 @@ always available. A string giving the site-specific directory prefix where the platform independent Python files are installed; on Unix, the default is - ``'/usr/local'``. This can be set at build time with the ``--prefix`` + :file:`/usr/local`. This can be set at build time with the :option:`--prefix` argument to the :program:`configure` script. See :ref:`installation_paths` for derived paths. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index c387528d87cd..2f31910a5958 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -174,6 +174,22 @@ WebAssembly Options Install Options --------------- +.. cmdoption:: --prefix=PREFIX + + Install architecture-independent files in PREFIX. On Unix, it + defaults to :file:`/usr/local`. + + This value can be retrived at runtime using :data:`sys.prefix`. + + As an example, one can use ``--prefix="$HOME/.local/"`` to install + a Python in its home directory. + +.. cmdoption:: --exec-prefix=EPREFIX + + Install architecture-dependent files in EPREFIX, defaults to :option:`--prefix`. + + This value can be retrived at runtime using :data:`sys.exec_prefix`. + .. cmdoption:: --disable-test-modules Don't build nor install test modules, like the :mod:`test` package or the diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 24c02c99f871..067ff4cce5e4 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -93,7 +93,7 @@ Python-related paths and files ============================== These are subject to difference depending on local installation conventions; -:envvar:`prefix` (``${prefix}``) and :envvar:`exec_prefix` (``${exec_prefix}``) +:option:`prefix <--prefix>` and :option:`exec_prefix <--exec-prefix>` are installation-dependent and should be interpreted as for GNU software; they may be the same. From webhook-mailer at python.org Wed Mar 15 20:44:01 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 16 Mar 2023 00:44:01 -0000 Subject: [Python-checkins] gh-102660: Fix Refleaks in import.c (#102744) Message-ID: https://github.com/python/cpython/commit/2a03ed034edc6bb2db6fb972b2efe08db5145a28 commit: 2a03ed034edc6bb2db6fb972b2efe08db5145a28 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-15T18:43:54-06:00 summary: gh-102660: Fix Refleaks in import.c (#102744) gh-102661 introduced some leaks. This fixes them. https://github.com/python/cpython/issues/102660 files: M Python/bltinmodule.c M Python/import.c M Python/sysmodule.c diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index a8a34620b9bc..12ca0ba6c487 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -3098,9 +3098,6 @@ _PyBuiltin_Init(PyInterpreterState *interp) } Py_DECREF(debug); - /* m_copy of Py_None means it is copied some other way. */ - builtinsmodule.m_base.m_copy = Py_NewRef(Py_None); - return mod; #undef ADD_TO_ALL #undef SETBUILTIN diff --git a/Python/import.c b/Python/import.c index 612fee243bd9..9f80c6d8dd49 100644 --- a/Python/import.c +++ b/Python/import.c @@ -978,14 +978,29 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) return 0; } -static inline int -match_mod_name(PyObject *actual, const char *expected) +static PyObject * +get_core_module_dict(PyInterpreterState *interp, + PyObject *name, PyObject *filename) { - if (PyUnicode_CompareWithASCIIString(actual, expected) == 0) { - return 1; + /* Only builtin modules are core. */ + if (filename == name) { + assert(!PyErr_Occurred()); + if (PyUnicode_CompareWithASCIIString(name, "sys") == 0) { + return interp->sysdict_copy; + } + assert(!PyErr_Occurred()); + if (PyUnicode_CompareWithASCIIString(name, "builtins") == 0) { + return interp->builtins_copy; + } + assert(!PyErr_Occurred()); } - assert(!PyErr_Occurred()); - return 0; + return NULL; +} + +static inline int +is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *filename) +{ + return get_core_module_dict(interp, name, filename) != NULL; } static int @@ -1009,10 +1024,8 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) // bpo-44050: Extensions and def->m_base.m_copy can be updated // when the extension module doesn't support sub-interpreters. - // XXX Why special-case the main interpreter? - if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { - /* m_copy of Py_None means it is copied some other way. */ - if (def->m_size == -1 && def->m_base.m_copy != Py_None) { + if (def->m_size == -1) { + if (!is_core_module(tstate->interp, name, filename)) { if (def->m_base.m_copy) { /* Somebody already imported the module, likely under a different name. @@ -1028,7 +1041,10 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) return -1; } } + } + // XXX Why special-case the main interpreter? + if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { if (_extensions_cache_set(filename, name, def) < 0) { return -1; } @@ -1069,21 +1085,11 @@ import_find_extension(PyThreadState *tstate, PyObject *name, PyObject *m_copy = def->m_base.m_copy; /* Module does not support repeated initialization */ if (m_copy == NULL) { - return NULL; - } - else if (m_copy == Py_None) { - if (match_mod_name(name, "sys")) { - m_copy = tstate->interp->sysdict_copy; - } - else if (match_mod_name(name, "builtins")) { - m_copy = tstate->interp->builtins_copy; - } - else { - _PyErr_SetString(tstate, PyExc_ImportError, "missing m_copy"); + m_copy = get_core_module_dict(tstate->interp, name, filename); + if (m_copy == NULL) { return NULL; } } - /* m_copy of Py_None means it is copied some other way. */ mod = import_add_module(tstate, name); if (mod == NULL) { return NULL; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index fc0550266bf1..d282104dcad4 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3425,9 +3425,6 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) return _PyStatus_ERR("failed to create a module object"); } - /* m_copy of Py_None means it is copied some other way. */ - sysmodule.m_base.m_copy = Py_NewRef(Py_None); - PyObject *sysdict = PyModule_GetDict(sysmod); if (sysdict == NULL) { goto error; From webhook-mailer at python.org Wed Mar 15 22:52:31 2023 From: webhook-mailer at python.org (merwok) Date: Thu, 16 Mar 2023 02:52:31 -0000 Subject: [Python-checkins] gh-102690: Use Edge as fallback in webbrowser instead of IE (#102691) Message-ID: https://github.com/python/cpython/commit/1c9f3391b916939e5ad18213e553f8d6bfbec25e commit: 1c9f3391b916939e5ad18213e553f8d6bfbec25e branch: main author: Jamoo721 <81095953+Jamoo721 at users.noreply.github.com> committer: merwok date: 2023-03-15T22:52:11-04:00 summary: gh-102690: Use Edge as fallback in webbrowser instead of IE (#102691) files: A Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst M Lib/webbrowser.py diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 44974d433b46..a56ff33dbbdc 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -542,11 +542,15 @@ def register_standard_browsers(): # First try to use the default Windows browser register("windows-default", WindowsDefault) - # Detect some common Windows browsers, fallback to IE - iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), - "Internet Explorer\\IEXPLORE.EXE") + # Detect some common Windows browsers, fallback to Microsoft Edge + # location in 64-bit Windows + edge64 = os.path.join(os.environ.get("PROGRAMFILES(x86)", "C:\\Program Files (x86)"), + "Microsoft\\Edge\\Application\\msedge.exe") + # location in 32-bit Windows + edge32 = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), + "Microsoft\\Edge\\Application\\msedge.exe") for browser in ("firefox", "firebird", "seamonkey", "mozilla", - "netscape", "opera", iexplore): + "opera", edge64, edge32): if shutil.which(browser): register(browser, None, BackgroundBrowser(browser)) else: diff --git a/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst b/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst new file mode 100644 index 000000000000..5669ebbb442c --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst @@ -0,0 +1 @@ +Update :mod:`webbrowser` to fall back to Microsoft Edge instead of Internet Explorer. From webhook-mailer at python.org Wed Mar 15 23:51:10 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Thu, 16 Mar 2023 03:51:10 -0000 Subject: [Python-checkins] GH-100112: avoid using iterable coroutines in asyncio internally (#100128) Message-ID: https://github.com/python/cpython/commit/a44553ea9f7745a1119148082edb1fb0372ac0e2 commit: a44553ea9f7745a1119148082edb1fb0372ac0e2 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-16T09:20:43+05:30 summary: GH-100112: avoid using iterable coroutines in asyncio internally (#100128) files: A Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst M Lib/asyncio/tasks.py M Lib/test/test_asyncio/test_tasks.py diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 1c20754b839b..c90d32c97add 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -25,7 +25,6 @@ from . import exceptions from . import futures from . import timeouts -from .coroutines import _is_coroutine # Helper to generate new task names # This uses itertools.count() instead of a "+= 1" operation because the latter @@ -635,11 +634,14 @@ def ensure_future(coro_or_future, *, loop=None): raise ValueError('The future belongs to a different loop than ' 'the one specified as the loop argument') return coro_or_future - called_wrap_awaitable = False + should_close = True if not coroutines.iscoroutine(coro_or_future): if inspect.isawaitable(coro_or_future): + async def _wrap_awaitable(awaitable): + return await awaitable + coro_or_future = _wrap_awaitable(coro_or_future) - called_wrap_awaitable = True + should_close = False else: raise TypeError('An asyncio.Future, a coroutine or an awaitable ' 'is required') @@ -649,23 +651,11 @@ def ensure_future(coro_or_future, *, loop=None): try: return loop.create_task(coro_or_future) except RuntimeError: - if not called_wrap_awaitable: + if should_close: coro_or_future.close() raise - at types.coroutine -def _wrap_awaitable(awaitable): - """Helper for asyncio.ensure_future(). - - Wraps awaitable (an object with __await__) into a coroutine - that will later be wrapped in a Task by ensure_future(). - """ - return (yield from awaitable.__await__()) - -_wrap_awaitable._is_coroutine = _is_coroutine - - class _GatheringFuture(futures.Future): """Helper for gather(). diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index e533d5273e9f..5b935b526541 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -8,6 +8,7 @@ import re import sys import traceback +import types import unittest from unittest import mock from types import GenericAlias @@ -274,6 +275,20 @@ async def coro(): loop.run_until_complete(fut) self.assertEqual(fut.result(), 'ok') + def test_ensure_future_task_awaitable(self): + class Aw: + def __await__(self): + return asyncio.sleep(0, result='ok').__await__() + + loop = asyncio.new_event_loop() + self.set_event_loop(loop) + task = asyncio.ensure_future(Aw(), loop=loop) + loop.run_until_complete(task) + self.assertTrue(task.done()) + self.assertEqual(task.result(), 'ok') + self.assertIsInstance(task.get_coro(), types.CoroutineType) + loop.close() + def test_ensure_future_neither(self): with self.assertRaises(TypeError): asyncio.ensure_future('ok') diff --git a/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst b/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst new file mode 100644 index 000000000000..eff77c40e30c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst @@ -0,0 +1 @@ +:meth:`asyncio.Task.get_coro` now always returns a coroutine when wrapping an awaitable object. Patch by Kumar Aditya. From webhook-mailer at python.org Thu Mar 16 00:45:07 2023 From: webhook-mailer at python.org (gpshead) Date: Thu, 16 Mar 2023 04:45:07 -0000 Subject: [Python-checkins] gh-94440: Fix issue of ProcessPoolExecutor shutdown hanging (#94468) Message-ID: https://github.com/python/cpython/commit/2dc94634b50f0e5e207787e5ac1d56c68b22c3ae commit: 2dc94634b50f0e5e207787e5ac1d56c68b22c3ae branch: main author: yonatanp committer: gpshead date: 2023-03-15T21:44:52-07:00 summary: gh-94440: Fix issue of ProcessPoolExecutor shutdown hanging (#94468) Fix an issue of concurrent.futures ProcessPoolExecutor shutdown hanging. Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst M Lib/concurrent/futures/process.py M Lib/test/test_concurrent_futures.py M Misc/ACKS diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 3a8637b6fa1b..816edab99f63 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -366,6 +366,11 @@ def run(self): if self.is_shutting_down(): self.flag_executor_shutting_down() + # When only canceled futures remain in pending_work_items, our + # next call to wait_result_broken_or_wakeup would hang forever. + # This makes sure we have some running futures or none at all. + self.add_call_item_to_queue() + # Since no new work items can be added, it is safe to shutdown # this thread if there are no pending work items. if not self.pending_work_items: diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index b3520ae3994e..a20cb844a293 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -14,6 +14,7 @@ from logging.handlers import QueueHandler import os import queue +import signal import sys import threading import time @@ -397,6 +398,33 @@ def test_hang_gh83386(self): self.assertFalse(err) self.assertEqual(out.strip(), b"apple") + def test_hang_gh94440(self): + """shutdown(wait=True) doesn't hang when a future was submitted and + quickly canceled right before shutdown. + + See https://github.com/python/cpython/issues/94440. + """ + if not hasattr(signal, 'alarm'): + raise unittest.SkipTest( + "Tested platform does not support the alarm signal") + + def timeout(_signum, _frame): + raise RuntimeError("timed out waiting for shutdown") + + kwargs = {} + if getattr(self, 'ctx', None): + kwargs['mp_context'] = self.get_context() + executor = self.executor_type(max_workers=1, **kwargs) + executor.submit(int).result() + old_handler = signal.signal(signal.SIGALRM, timeout) + try: + signal.alarm(5) + executor.submit(int).cancel() + executor.shutdown(wait=True) + finally: + signal.alarm(0) + signal.signal(signal.SIGALRM, old_handler) + class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase): def test_threads_terminate(self): diff --git a/Misc/ACKS b/Misc/ACKS index 7bbde3af9978..8cf5166a2bb1 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1385,6 +1385,7 @@ Thomas Perl Mathieu Perreault Mark Perrego Trevor Perrin +Yonatan Perry Gabriel de Perthuis Tim Peters Benjamin Peterson diff --git a/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst new file mode 100644 index 000000000000..3eee82e59dfa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst @@ -0,0 +1,2 @@ +Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` shutdown +could hang after a future has been quickly submitted and canceled. From webhook-mailer at python.org Thu Mar 16 01:08:19 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 16 Mar 2023 05:08:19 -0000 Subject: [Python-checkins] gh-94440: Fix issue of ProcessPoolExecutor shutdown hanging (GH-94468) Message-ID: https://github.com/python/cpython/commit/97812403bf01f665b27d7506f209ac9f1e913f24 commit: 97812403bf01f665b27d7506f209ac9f1e913f24 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-15T22:08:11-07:00 summary: gh-94440: Fix issue of ProcessPoolExecutor shutdown hanging (GH-94468) Fix an issue of concurrent.futures ProcessPoolExecutor shutdown hanging. (cherry picked from commit 2dc94634b50f0e5e207787e5ac1d56c68b22c3ae) Co-authored-by: yonatanp Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst M Lib/concurrent/futures/process.py M Lib/test/test_concurrent_futures.py M Misc/ACKS diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 57941e485d81..81cc1fb63026 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -337,6 +337,11 @@ def run(self): if self.is_shutting_down(): self.flag_executor_shutting_down() + # When only canceled futures remain in pending_work_items, our + # next call to wait_result_broken_or_wakeup would hang forever. + # This makes sure we have some running futures or none at all. + self.add_call_item_to_queue() + # Since no new work items can be added, it is safe to shutdown # this thread if there are no pending work items. if not self.pending_work_items: diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index e174d5464d2b..6eae8c9cce38 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -14,6 +14,7 @@ from logging.handlers import QueueHandler import os import queue +import signal import sys import threading import time @@ -397,6 +398,33 @@ def test_hang_gh83386(self): self.assertFalse(err) self.assertEqual(out.strip(), b"apple") + def test_hang_gh94440(self): + """shutdown(wait=True) doesn't hang when a future was submitted and + quickly canceled right before shutdown. + + See https://github.com/python/cpython/issues/94440. + """ + if not hasattr(signal, 'alarm'): + raise unittest.SkipTest( + "Tested platform does not support the alarm signal") + + def timeout(_signum, _frame): + raise RuntimeError("timed out waiting for shutdown") + + kwargs = {} + if getattr(self, 'ctx', None): + kwargs['mp_context'] = self.get_context() + executor = self.executor_type(max_workers=1, **kwargs) + executor.submit(int).result() + old_handler = signal.signal(signal.SIGALRM, timeout) + try: + signal.alarm(5) + executor.submit(int).cancel() + executor.shutdown(wait=True) + finally: + signal.alarm(0) + signal.signal(signal.SIGALRM, old_handler) + class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase): def test_threads_terminate(self): diff --git a/Misc/ACKS b/Misc/ACKS index de1fb148e926..399b1d2cf58c 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1361,6 +1361,7 @@ Thomas Perl Mathieu Perreault Mark Perrego Trevor Perrin +Yonatan Perry Gabriel de Perthuis Tim Peters Benjamin Peterson diff --git a/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst new file mode 100644 index 000000000000..3eee82e59dfa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst @@ -0,0 +1,2 @@ +Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` shutdown +could hang after a future has been quickly submitted and canceled. From webhook-mailer at python.org Thu Mar 16 01:09:27 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 16 Mar 2023 05:09:27 -0000 Subject: [Python-checkins] gh-94440: Fix issue of ProcessPoolExecutor shutdown hanging (GH-94468) Message-ID: https://github.com/python/cpython/commit/0560fe3c1079ea91bb6d7df4c857851364ed3d8a commit: 0560fe3c1079ea91bb6d7df4c857851364ed3d8a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-15T22:09:20-07:00 summary: gh-94440: Fix issue of ProcessPoolExecutor shutdown hanging (GH-94468) Fix an issue of concurrent.futures ProcessPoolExecutor shutdown hanging. (cherry picked from commit 2dc94634b50f0e5e207787e5ac1d56c68b22c3ae) Co-authored-by: yonatanp Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst M Lib/concurrent/futures/process.py M Lib/test/test_concurrent_futures.py M Misc/ACKS diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 7e2f5fa30e826..392d1960e0595 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -364,6 +364,11 @@ def run(self): if self.is_shutting_down(): self.flag_executor_shutting_down() + # When only canceled futures remain in pending_work_items, our + # next call to wait_result_broken_or_wakeup would hang forever. + # This makes sure we have some running futures or none at all. + self.add_call_item_to_queue() + # Since no new work items can be added, it is safe to shutdown # this thread if there are no pending work items. if not self.pending_work_items: diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index 02c2fa06fad4e..1bb6156a18ddb 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -14,6 +14,7 @@ from logging.handlers import QueueHandler import os import queue +import signal import sys import threading import time @@ -396,6 +397,33 @@ def test_hang_gh83386(self): self.assertFalse(err) self.assertEqual(out.strip(), b"apple") + def test_hang_gh94440(self): + """shutdown(wait=True) doesn't hang when a future was submitted and + quickly canceled right before shutdown. + + See https://github.com/python/cpython/issues/94440. + """ + if not hasattr(signal, 'alarm'): + raise unittest.SkipTest( + "Tested platform does not support the alarm signal") + + def timeout(_signum, _frame): + raise RuntimeError("timed out waiting for shutdown") + + kwargs = {} + if getattr(self, 'ctx', None): + kwargs['mp_context'] = self.get_context() + executor = self.executor_type(max_workers=1, **kwargs) + executor.submit(int).result() + old_handler = signal.signal(signal.SIGALRM, timeout) + try: + signal.alarm(5) + executor.submit(int).cancel() + executor.shutdown(wait=True) + finally: + signal.alarm(0) + signal.signal(signal.SIGALRM, old_handler) + class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase): def test_threads_terminate(self): diff --git a/Misc/ACKS b/Misc/ACKS index afe86d37b0a70..dbcff1e15435e 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1372,6 +1372,7 @@ Thomas Perl Mathieu Perreault Mark Perrego Trevor Perrin +Yonatan Perry Gabriel de Perthuis Tim Peters Benjamin Peterson diff --git a/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst new file mode 100644 index 0000000000000..3eee82e59dfaf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst @@ -0,0 +1,2 @@ +Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` shutdown +could hang after a future has been quickly submitted and canceled. From webhook-mailer at python.org Thu Mar 16 06:16:39 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 16 Mar 2023 10:16:39 -0000 Subject: [Python-checkins] gh-102594: PyErr_SetObject adds note to exception raised on normalization error (#102675) Message-ID: https://github.com/python/cpython/commit/51d693c58454a2c525094a7c74ebac86859353fd commit: 51d693c58454a2c525094a7c74ebac86859353fd branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-16T10:16:01Z summary: gh-102594: PyErr_SetObject adds note to exception raised on normalization error (#102675) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst M Include/cpython/pyerrors.h M Lib/test/test_capi/test_exceptions.py M Modules/_testcapi/exceptions.c M Objects/exceptions.c M Python/errors.c diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 0d9cc9922f73..d0300f6ee56a 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -112,6 +112,10 @@ PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause( /* In exceptions.c */ +PyAPI_FUNC(int) _PyException_AddNote( + PyObject *exc, + PyObject *note); + /* Helper that attempts to replace the current exception with one of the * same type but with a prefix added to the exception text. The resulting * exception description looks like: diff --git a/Lib/test/test_capi/test_exceptions.py b/Lib/test/test_capi/test_exceptions.py index 55f131699a25..b1c1a61e2068 100644 --- a/Lib/test/test_capi/test_exceptions.py +++ b/Lib/test/test_capi/test_exceptions.py @@ -169,5 +169,25 @@ class Broken(Exception, metaclass=Meta): with self.assertRaises(ZeroDivisionError) as e: _testcapi.exc_set_object(Broken, Broken()) + def test_set_object_and_fetch(self): + class Broken(Exception): + def __init__(self, *arg): + raise ValueError("Broken __init__") + + exc = _testcapi.exc_set_object_fetch(Broken, 'abcd') + self.assertIsInstance(exc, ValueError) + self.assertEqual(exc.__notes__[0], + "Normalization failed: type=Broken args='abcd'") + + class BadArg: + def __repr__(self): + raise TypeError('Broken arg type') + + exc = _testcapi.exc_set_object_fetch(Broken, BadArg()) + self.assertIsInstance(exc, ValueError) + self.assertEqual(exc.__notes__[0], + 'Normalization failed: type=Broken args=') + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst new file mode 100644 index 000000000000..0b95b5ec98e8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst @@ -0,0 +1 @@ +Add note to exception raised in ``PyErr_SetObject`` when normalization fails. diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index a0575213987f..c64b823663c3 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -92,6 +92,26 @@ exc_set_object(PyObject *self, PyObject *args) return NULL; } +static PyObject * +exc_set_object_fetch(PyObject *self, PyObject *args) +{ + PyObject *exc; + PyObject *obj; + PyObject *type; + PyObject *value; + PyObject *tb; + + if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) { + return NULL; + } + + PyErr_SetObject(exc, obj); + PyErr_Fetch(&type, &value, &tb); + Py_XDECREF(type); + Py_XDECREF(tb); + return value; +} + static PyObject * raise_exception(PyObject *self, PyObject *args) { @@ -262,6 +282,7 @@ static PyMethodDef test_methods[] = { {"make_exception_with_doc", _PyCFunction_CAST(make_exception_with_doc), METH_VARARGS | METH_KEYWORDS}, {"exc_set_object", exc_set_object, METH_VARARGS}, + {"exc_set_object_fetch", exc_set_object_fetch, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", raise_memoryerror, METH_NOARGS}, {"set_exc_info", test_set_exc_info, METH_VARARGS}, diff --git a/Objects/exceptions.c b/Objects/exceptions.c index c6fb6a3f19b2..d69f7400ca60 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3749,6 +3749,21 @@ _PyExc_Fini(PyInterpreterState *interp) _PyExc_FiniTypes(interp); } +int +_PyException_AddNote(PyObject *exc, PyObject *note) +{ + if (!PyExceptionInstance_Check(exc)) { + PyErr_Format(PyExc_TypeError, + "exc must be an exception, not '%s'", + Py_TYPE(exc)->tp_name); + return -1; + } + PyObject *r = BaseException_add_note(exc, note); + int res = r == NULL ? -1 : 0; + Py_XDECREF(r); + return res; +} + /* Helper to do the equivalent of "raise X from Y" in C, but always using * the current exception rather than passing one in. * diff --git a/Python/errors.c b/Python/errors.c index bbf6d397ce80..bdcbac317eb9 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -135,6 +135,28 @@ _PyErr_GetTopmostException(PyThreadState *tstate) return exc_info; } +static PyObject * +get_normalization_failure_note(PyThreadState *tstate, PyObject *exception, PyObject *value) +{ + PyObject *args = PyObject_Repr(value); + if (args == NULL) { + _PyErr_Clear(tstate); + args = PyUnicode_FromFormat(""); + } + PyObject *note; + const char *tpname = ((PyTypeObject*)exception)->tp_name; + if (args == NULL) { + _PyErr_Clear(tstate); + note = PyUnicode_FromFormat("Normalization failed: type=%s", tpname); + } + else { + note = PyUnicode_FromFormat("Normalization failed: type=%s args=%S", + tpname, args); + Py_DECREF(args); + } + return note; +} + void _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) { @@ -160,19 +182,27 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) Py_XINCREF(value); if (!is_subclass) { /* We must normalize the value right now */ - PyObject *fixed_value; /* Issue #23571: functions must not be called with an exception set */ _PyErr_Clear(tstate); - fixed_value = _PyErr_CreateException(exception, value); - Py_XDECREF(value); + PyObject *fixed_value = _PyErr_CreateException(exception, value); if (fixed_value == NULL) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + assert(PyExceptionInstance_Check(exc)); + + PyObject *note = get_normalization_failure_note(tstate, exception, value); + Py_XDECREF(value); + if (note != NULL) { + /* ignore errors in _PyException_AddNote - they will be overwritten below */ + _PyException_AddNote(exc, note); + Py_DECREF(note); + } + _PyErr_SetRaisedException(tstate, exc); return; } - - value = fixed_value; + Py_XSETREF(value, fixed_value); } exc_value = _PyErr_GetTopmostException(tstate)->exc_value; From webhook-mailer at python.org Thu Mar 16 09:05:50 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 16 Mar 2023 13:05:50 -0000 Subject: [Python-checkins] Add comments to `{typing, _collections_abc}._type_repr` about each other (#102752) Message-ID: https://github.com/python/cpython/commit/a297d59609038ccfc3bdf6f350e8401f07b0a931 commit: a297d59609038ccfc3bdf6f350e8401f07b0a931 branch: main author: Nikita Sobolev committer: AlexWaygood date: 2023-03-16T13:05:38Z summary: Add comments to `{typing,_collections_abc}._type_repr` about each other (#102752) Remove `if` condition in `_collections_abc._type_repr` that's no longer needed, bringing it in sync with `typing._type_repr`. files: M Lib/_collections_abc.py M Lib/typing.py diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index c62233b81a5c..f86b91a5e6fb 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -517,9 +517,8 @@ def _type_repr(obj): Copied from :mod:`typing` since collections.abc shouldn't depend on that module. + (Keep this roughly in sync with the typing version.) """ - if isinstance(obj, GenericAlias): - return repr(obj) if isinstance(obj, type): if obj.__module__ == 'builtins': return obj.__qualname__ diff --git a/Lib/typing.py b/Lib/typing.py index ab3343956761..3ee9679e50c0 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -230,6 +230,9 @@ def _type_repr(obj): typically enough to uniquely identify a type. For everything else, we fall back on repr(obj). """ + # When changing this function, don't forget about + # `_collections_abc._type_repr`, which does the same thing + # and must be consistent with this one. if isinstance(obj, type): if obj.__module__ == 'builtins': return obj.__qualname__ From webhook-mailer at python.org Thu Mar 16 10:32:26 2023 From: webhook-mailer at python.org (rhettinger) Date: Thu, 16 Mar 2023 14:32:26 -0000 Subject: [Python-checkins] GH-102653: Make recipe docstring show the correct distribution (#102742) Message-ID: https://github.com/python/cpython/commit/b0ec6253c9cf1b22b87cd99f317dbaeb31263b20 commit: b0ec6253c9cf1b22b87cd99f317dbaeb31263b20 branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-16T09:32:18-05:00 summary: GH-102653: Make recipe docstring show the correct distribution (#102742) files: M Doc/library/random.rst diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 4522f5a8d26b..098684d7270f 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -610,7 +610,8 @@ from the combinatoric iterators in the :mod:`itertools` module: return tuple(pool[i] for i in indices) def random_combination_with_replacement(iterable, r): - "Random selection from itertools.combinations_with_replacement(iterable, r)" + "Choose r elements with replacement. Order the result to match the iterable." + # Result will be in set(itertools.combinations_with_replacement(iterable, r)). pool = tuple(iterable) n = len(pool) indices = sorted(random.choices(range(n), k=r)) From webhook-mailer at python.org Thu Mar 16 10:42:30 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 16 Mar 2023 14:42:30 -0000 Subject: [Python-checkins] GH-102653: Make recipe docstring show the correct distribution (GH-102742) Message-ID: https://github.com/python/cpython/commit/4a7faac5571eb96202a4725604443c564285ebae commit: 4a7faac5571eb96202a4725604443c564285ebae branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-16T07:42:23-07:00 summary: GH-102653: Make recipe docstring show the correct distribution (GH-102742) (cherry picked from commit b0ec6253c9cf1b22b87cd99f317dbaeb31263b20) Co-authored-by: Raymond Hettinger files: M Doc/library/random.rst diff --git a/Doc/library/random.rst b/Doc/library/random.rst index c7d94e0680f0..c7620b032843 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -589,7 +589,8 @@ from the combinatoric iterators in the :mod:`itertools` module: return tuple(pool[i] for i in indices) def random_combination_with_replacement(iterable, r): - "Random selection from itertools.combinations_with_replacement(iterable, r)" + "Choose r elements with replacement. Order the result to match the iterable." + # Result will be in set(itertools.combinations_with_replacement(iterable, r)). pool = tuple(iterable) n = len(pool) indices = sorted(random.choices(range(n), k=r)) From webhook-mailer at python.org Thu Mar 16 10:47:39 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 16 Mar 2023 14:47:39 -0000 Subject: [Python-checkins] gh-102721: Improve coverage of `_collections_abc._CallableGenericAlias` (#102722) Message-ID: https://github.com/python/cpython/commit/fbe82fdd777cead5d6e08ac0d1da19738c19bd81 commit: fbe82fdd777cead5d6e08ac0d1da19738c19bd81 branch: main author: Nikita Sobolev committer: AlexWaygood date: 2023-03-16T14:47:30Z summary: gh-102721: Improve coverage of `_collections_abc._CallableGenericAlias` (#102722) Co-authored-by: Alex Waygood files: M Lib/_collections_abc.py M Lib/test/test_typing.py diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index f86b91a5e6fb..9d7724c33474 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -481,15 +481,8 @@ def __getitem__(self, item): # rather than the default types.GenericAlias object. Most of the # code is copied from typing's _GenericAlias and the builtin # types.GenericAlias. - if not isinstance(item, tuple): item = (item,) - # A special case in PEP 612 where if X = Callable[P, int], - # then X[int, str] == X[[int, str]]. - if (len(self.__parameters__) == 1 - and _is_param_expr(self.__parameters__[0]) - and item and not _is_param_expr(item[0])): - item = (item,) new_args = super().__getitem__(item).__args__ diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 89c725cda54f..c9f55de95c54 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1921,14 +1921,29 @@ def test_weakref(self): self.assertEqual(weakref.ref(alias)(), alias) def test_pickle(self): + global T_pickle, P_pickle, TS_pickle # needed for pickling Callable = self.Callable - alias = Callable[[int, str], float] - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(alias, proto) - loaded = pickle.loads(s) - self.assertEqual(alias.__origin__, loaded.__origin__) - self.assertEqual(alias.__args__, loaded.__args__) - self.assertEqual(alias.__parameters__, loaded.__parameters__) + T_pickle = TypeVar('T_pickle') + P_pickle = ParamSpec('P_pickle') + TS_pickle = TypeVarTuple('TS_pickle') + + samples = [ + Callable[[int, str], float], + Callable[P_pickle, int], + Callable[P_pickle, T_pickle], + Callable[Concatenate[int, P_pickle], int], + Callable[Concatenate[*TS_pickle, P_pickle], int], + ] + for alias in samples: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(alias=alias, proto=proto): + s = pickle.dumps(alias, proto) + loaded = pickle.loads(s) + self.assertEqual(alias.__origin__, loaded.__origin__) + self.assertEqual(alias.__args__, loaded.__args__) + self.assertEqual(alias.__parameters__, loaded.__parameters__) + + del T_pickle, P_pickle, TS_pickle # cleaning up global state def test_var_substitution(self): Callable = self.Callable @@ -1954,6 +1969,16 @@ def test_var_substitution(self): self.assertEqual(C5[int, str, float], Callable[[typing.List[int], tuple[str, int], float], int]) + def test_type_subst_error(self): + Callable = self.Callable + P = ParamSpec('P') + T = TypeVar('T') + + pat = "Expected a list of types, an ellipsis, ParamSpec, or Concatenate." + + with self.assertRaisesRegex(TypeError, pat): + Callable[P, T][0, int] + def test_type_erasure(self): Callable = self.Callable class C1(Callable): From webhook-mailer at python.org Thu Mar 16 10:58:27 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Thu, 16 Mar 2023 14:58:27 -0000 Subject: [Python-checkins] GH-102748: remove legacy support for generator based coroutines from `asyncio.iscoroutine` (#102749) Message-ID: https://github.com/python/cpython/commit/adaed17341e649fabb0f522e9b4f5962fcdf1d48 commit: adaed17341e649fabb0f522e9b4f5962fcdf1d48 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-16T20:28:10+05:30 summary: GH-102748: remove legacy support for generator based coroutines from `asyncio.iscoroutine` (#102749) Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst M Doc/whatsnew/3.12.rst M Lib/asyncio/coroutines.py M Lib/test/test_asyncio/test_pep492.py diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 217ffec1ee10..b9c668543e1b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -237,6 +237,10 @@ asyncio * Add C implementation of :func:`asyncio.current_task` for 4x-6x speedup. (Contributed by Itamar Ostricher and Pranav Thulasiram Bhat in :gh:`100344`.) +* :func:`asyncio.iscoroutine` now returns ``False`` for generators as + :mod:`asyncio` does not support legacy generator-based coroutines. + (Contributed by Kumar Aditya in :gh:`102748`.) + inspect ------- diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py index 7fda0e449d50..ab4f30eb51ba 100644 --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -25,8 +25,7 @@ def iscoroutinefunction(func): # Prioritize native coroutine check to speed-up # asyncio.iscoroutine. -_COROUTINE_TYPES = (types.CoroutineType, types.GeneratorType, - collections.abc.Coroutine) +_COROUTINE_TYPES = (types.CoroutineType, collections.abc.Coroutine) _iscoroutine_typecache = set() diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py index f833f788dcb9..dc25a46985e3 100644 --- a/Lib/test/test_asyncio/test_pep492.py +++ b/Lib/test/test_asyncio/test_pep492.py @@ -119,6 +119,12 @@ async def foo(): pass self.assertTrue(asyncio.iscoroutine(FakeCoro())) + def test_iscoroutine_generator(self): + def foo(): yield + + self.assertFalse(asyncio.iscoroutine(foo())) + + def test_iscoroutinefunction(self): async def foo(): pass self.assertTrue(asyncio.iscoroutinefunction(foo)) diff --git a/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst b/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst new file mode 100644 index 000000000000..b1dc67f38fe8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst @@ -0,0 +1,3 @@ +:func:`asyncio.iscoroutine` now returns ``False`` for generators as +:mod:`asyncio` does not support legacy generator-based coroutines. +Patch by Kumar Aditya. From webhook-mailer at python.org Thu Mar 16 11:27:04 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 16 Mar 2023 15:27:04 -0000 Subject: [Python-checkins] gh-102737: Un-ignore ceval.c in the CI globals check (gh-102745) Message-ID: https://github.com/python/cpython/commit/84e20c689a8b3b6cebfd50d044c62af5d0e7dec1 commit: 84e20c689a8b3b6cebfd50d044c62af5d0e7dec1 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-16T09:26:42-06:00 summary: gh-102737: Un-ignore ceval.c in the CI globals check (gh-102745) The tool now allows user-added #LINE preprocessor directives. https://github.com/python/cpython/issues/102737 files: M Tools/c-analyzer/c_parser/preprocessor/gcc.py M Tools/c-analyzer/cpython/_parser.py diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 24c1b0e9b9d4..c680f351f224 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -153,9 +153,13 @@ def _iter_top_include_lines(lines, topfile, cwd, # XXX How can a file return to line 1? #assert lno > 1, (line, lno) else: - # It's the next line from the file. - assert included == files[-1], (line, files) - assert lno > 1, (line, lno) + if included == files[-1]: + # It's the next line from the file. + assert lno > 1, (line, lno) + else: + # We ran into a user-added #LINE directive, + # which we promptly ignore. + pass elif not files: raise NotImplementedError((line,)) elif filter_reqfile(files[-1]): diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index a2911e030ffe..acf30e2c4020 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -96,10 +96,6 @@ def clean_lines(text): # has gone wrong where # we handle "maybe inline actual" # in Tools/c-analyzer/c_parser/parser/_global.py. Modules/expat/xmlparse.c - -# The parser doesn't like the #line directives -# that originate from generated_cases.c.h -Python/ceval.c ''') INCL_DIRS = clean_lines(''' From webhook-mailer at python.org Thu Mar 16 12:21:57 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 16 Mar 2023 16:21:57 -0000 Subject: [Python-checkins] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102743) Message-ID: https://github.com/python/cpython/commit/61d6c110d6019a7ba79c76cc50aeaa85a1b37c08 commit: 61d6c110d6019a7ba79c76cc50aeaa85a1b37c08 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-16T16:21:49Z summary: gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102743) files: M Python/pythonrun.c diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 34a44dd92847..5381b105a39f 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -698,30 +698,30 @@ _Py_HandleSystemExit(int *exitcode_p) return 0; } - PyObject *exception, *value, *tb; - PyErr_Fetch(&exception, &value, &tb); - fflush(stdout); int exitcode = 0; - if (value == NULL || value == Py_None) { + + PyObject *exc = PyErr_GetRaisedException(); + if (exc == NULL) { goto done; } + assert(PyExceptionInstance_Check(exc)); - if (PyExceptionInstance_Check(value)) { - /* The error code should be in the `code' attribute. */ - PyObject *code = PyObject_GetAttr(value, &_Py_ID(code)); - if (code) { - Py_SETREF(value, code); - if (value == Py_None) - goto done; + /* The error code should be in the `code' attribute. */ + PyObject *code = PyObject_GetAttr(exc, &_Py_ID(code)); + if (code) { + Py_SETREF(exc, code); + if (exc == Py_None) { + goto done; } - /* If we failed to dig out the 'code' attribute, - just let the else clause below print the error. */ } + /* If we failed to dig out the 'code' attribute, + * just let the else clause below print the error. + */ - if (PyLong_Check(value)) { - exitcode = (int)PyLong_AsLong(value); + if (PyLong_Check(exc)) { + exitcode = (int)PyLong_AsLong(exc); } else { PyThreadState *tstate = _PyThreadState_GET(); @@ -732,20 +732,17 @@ _Py_HandleSystemExit(int *exitcode_p) */ PyErr_Clear(); if (sys_stderr != NULL && sys_stderr != Py_None) { - PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW); + PyFile_WriteObject(exc, sys_stderr, Py_PRINT_RAW); } else { - PyObject_Print(value, stderr, Py_PRINT_RAW); + PyObject_Print(exc, stderr, Py_PRINT_RAW); fflush(stderr); } PySys_WriteStderr("\n"); exitcode = 1; } - done: - /* Cleanup the exception */ - Py_CLEAR(exception); - Py_CLEAR(value); - Py_CLEAR(tb); +done: + Py_CLEAR(exc); *exitcode_p = exitcode; return 1; } @@ -1641,35 +1638,29 @@ PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, } - static void -flush_io(void) +flush_io_stream(PyThreadState *tstate, PyObject *name) { - PyObject *f, *r; - PyObject *type, *value, *traceback; - - /* Save the current exception */ - PyErr_Fetch(&type, &value, &traceback); - - PyThreadState *tstate = _PyThreadState_GET(); - f = _PySys_GetAttr(tstate, &_Py_ID(stderr)); - if (f != NULL) { - r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); - if (r) - Py_DECREF(r); - else - PyErr_Clear(); - } - f = _PySys_GetAttr(tstate, &_Py_ID(stdout)); + PyObject *f = _PySys_GetAttr(tstate, name); if (f != NULL) { - r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); - if (r) + PyObject *r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); + if (r) { Py_DECREF(r); - else + } + else { PyErr_Clear(); + } } +} - PyErr_Restore(type, value, traceback); +static void +flush_io(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *exc = _PyErr_GetRaisedException(tstate); + flush_io_stream(tstate, &_Py_ID(stderr)); + flush_io_stream(tstate, &_Py_ID(stdout)); + _PyErr_SetRaisedException(tstate, exc); } static PyObject * From webhook-mailer at python.org Thu Mar 16 12:41:18 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 16 Mar 2023 16:41:18 -0000 Subject: [Python-checkins] gh-102192: remove redundant exception fields from ssl module socket (#102466) Message-ID: https://github.com/python/cpython/commit/e108af6eca9904d177d769281907d12ac6894dfc commit: e108af6eca9904d177d769281907d12ac6894dfc branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-16T16:41:10Z summary: gh-102192: remove redundant exception fields from ssl module socket (#102466) files: M Modules/_ssl.c M Modules/_ssl/debughelpers.c diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 28112317bc28..121d18884d0a 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -318,9 +318,7 @@ typedef struct { * store exception information on the socket. The handshake, read, write, * and shutdown methods check for chained exceptions. */ - PyObject *exc_type; - PyObject *exc_value; - PyObject *exc_tb; + PyObject *exc; } PySSLSocket; typedef struct { @@ -564,13 +562,11 @@ fill_and_set_sslerror(_sslmodulestate *state, static int PySSL_ChainExceptions(PySSLSocket *sslsock) { - if (sslsock->exc_type == NULL) + if (sslsock->exc == NULL) return 0; - _PyErr_ChainExceptions(sslsock->exc_type, sslsock->exc_value, sslsock->exc_tb); - sslsock->exc_type = NULL; - sslsock->exc_value = NULL; - sslsock->exc_tb = NULL; + _PyErr_ChainExceptions1(sslsock->exc); + sslsock->exc = NULL; return -1; } @@ -807,9 +803,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, self->owner = NULL; self->server_hostname = NULL; self->err = err; - self->exc_type = NULL; - self->exc_value = NULL; - self->exc_tb = NULL; + self->exc = NULL; /* Make sure the SSL error state is initialized */ ERR_clear_error(); @@ -2179,9 +2173,7 @@ Passed as \"self\" in servername callback."); static int PySSL_traverse(PySSLSocket *self, visitproc visit, void *arg) { - Py_VISIT(self->exc_type); - Py_VISIT(self->exc_value); - Py_VISIT(self->exc_tb); + Py_VISIT(self->exc); Py_VISIT(Py_TYPE(self)); return 0; } @@ -2189,9 +2181,7 @@ PySSL_traverse(PySSLSocket *self, visitproc visit, void *arg) static int PySSL_clear(PySSLSocket *self) { - Py_CLEAR(self->exc_type); - Py_CLEAR(self->exc_value); - Py_CLEAR(self->exc_tb); + Py_CLEAR(self->exc); return 0; } @@ -2536,7 +2526,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, PySSL_SetError(self, retval, __FILE__, __LINE__); goto error; } - if (self->exc_type != NULL) + if (self->exc != NULL) goto error; done: @@ -2662,7 +2652,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) PySSL_SetError(self, ret, __FILE__, __LINE__); return NULL; } - if (self->exc_type != NULL) + if (self->exc != NULL) goto error; if (sock) /* It's already INCREF'ed */ diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c index 08f3457035b9..217f22494255 100644 --- a/Modules/_ssl/debughelpers.c +++ b/Modules/_ssl/debughelpers.c @@ -74,7 +74,7 @@ _PySSL_msg_callback(int write_p, int version, int content_type, buf, len ); if (res == NULL) { - PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb); + ssl_obj->exc = PyErr_GetRaisedException(); } else { Py_DECREF(res); } @@ -138,8 +138,7 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) lock = PyThread_allocate_lock(); if (lock == NULL) { PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, - &ssl_obj->exc_tb); + ssl_obj->exc = PyErr_GetRaisedException(); return; } } @@ -156,7 +155,7 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) errno = e; PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, ssl_obj->ctx->keylog_filename); - PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb); + ssl_obj->exc = PyErr_GetRaisedException(); } PyGILState_Release(threadstate); } From webhook-mailer at python.org Thu Mar 16 13:27:45 2023 From: webhook-mailer at python.org (zooba) Date: Thu, 16 Mar 2023 17:27:45 -0000 Subject: [Python-checkins] gh-99726: Improves correctness of stat results for Windows, and uses faster API when available (GH-102149) Message-ID: https://github.com/python/cpython/commit/0f175766e27642108c65bba04bbd54dcf8799b0e commit: 0f175766e27642108c65bba04bbd54dcf8799b0e branch: main author: Steve Dower committer: zooba date: 2023-03-16T17:27:21Z summary: gh-99726: Improves correctness of stat results for Windows, and uses faster API when available (GH-102149) This deprecates `st_ctime` fields on Windows, with the intent to change them to contain the correct value in 3.14. For now, they should keep returning the creation time as they always have. files: A Include/internal/pycore_fileutils_windows.h A Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst M Doc/library/os.rst M Doc/whatsnew/3.12.rst M Include/internal/pycore_fileutils.h M Lib/test/test_os.py M Modules/posixmodule.c M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Python/fileutils.c diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 5b9f49be1fad..3153f79e10ce 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2858,6 +2858,12 @@ features: Added support for the :class:`~os.PathLike` interface. Added support for :class:`bytes` paths on Windows. + .. versionchanged:: 3.12 + The ``st_ctime`` attribute of a stat result is deprecated on Windows. + The file creation time is properly available as ``st_birthtime``, and + in the future ``st_ctime`` may be changed to return zero or the + metadata change time, if available. + .. function:: stat(path, *, dir_fd=None, follow_symlinks=True) @@ -2973,10 +2979,12 @@ features: .. attribute:: st_ctime - Platform dependent: + Time of most recent metadata change expressed in seconds. - * the time of most recent metadata change on Unix, - * the time of creation on Windows, expressed in seconds. + .. versionchanged:: 3.12 + ``st_ctime`` is deprecated on Windows. Use ``st_birthtime`` for + the file creation time. In the future, ``st_ctime`` will contain + the time of the most recent metadata change, as for other platforms. .. attribute:: st_atime_ns @@ -2989,29 +2997,48 @@ features: .. attribute:: st_ctime_ns - Platform dependent: + Time of most recent metadata change expressed in nanoseconds as an + integer. + + .. versionchanged:: 3.12 + ``st_ctime_ns`` is deprecated on Windows. Use ``st_birthtime_ns`` + for the file creation time. In the future, ``st_ctime`` will contain + the time of the most recent metadata change, as for other platforms. + + .. attribute:: st_birthtime + + Time of file creation expressed in seconds. This attribute is not + always available, and may raise :exc:`AttributeError`. + + .. versionchanged:: 3.12 + ``st_birthtime`` is now available on Windows. + + .. attribute:: st_birthtime_ns - * the time of most recent metadata change on Unix, - * the time of creation on Windows, expressed in nanoseconds as an - integer. + Time of file creation expressed in nanoseconds as an integer. + This attribute is not always available, and may raise + :exc:`AttributeError`. + + .. versionadded:: 3.12 .. note:: The exact meaning and resolution of the :attr:`st_atime`, - :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating - system and the file system. For example, on Windows systems using the FAT - or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and - :attr:`st_atime` has only 1-day resolution. See your operating system - documentation for details. + :attr:`st_mtime`, :attr:`st_ctime` and :attr:`st_birthtime` attributes + depend on the operating system and the file system. For example, on + Windows systems using the FAT32 file systems, :attr:`st_mtime` has + 2-second resolution, and :attr:`st_atime` has only 1-day resolution. + See your operating system documentation for details. Similarly, although :attr:`st_atime_ns`, :attr:`st_mtime_ns`, - and :attr:`st_ctime_ns` are always expressed in nanoseconds, many - systems do not provide nanosecond precision. On systems that do - provide nanosecond precision, the floating-point object used to - store :attr:`st_atime`, :attr:`st_mtime`, and :attr:`st_ctime` - cannot preserve all of it, and as such will be slightly inexact. - If you need the exact timestamps you should always use - :attr:`st_atime_ns`, :attr:`st_mtime_ns`, and :attr:`st_ctime_ns`. + :attr:`st_ctime_ns` and :attr:`st_birthtime_ns` are always expressed in + nanoseconds, many systems do not provide nanosecond precision. On + systems that do provide nanosecond precision, the floating-point object + used to store :attr:`st_atime`, :attr:`st_mtime`, :attr:`st_ctime` and + :attr:`st_birthtime` cannot preserve all of it, and as such will be + slightly inexact. If you need the exact timestamps you should always use + :attr:`st_atime_ns`, :attr:`st_mtime_ns`, :attr:`st_ctime_ns` and + :attr:`st_birthtime_ns`. On some Unix systems (such as Linux), the following attributes may also be available: @@ -3041,10 +3068,6 @@ features: File generation number. - .. attribute:: st_birthtime - - Time of file creation. - On Solaris and derivatives, the following attributes may also be available: @@ -3117,6 +3140,25 @@ features: files as :const:`S_IFCHR`, :const:`S_IFIFO` or :const:`S_IFBLK` as appropriate. + .. versionchanged:: 3.12 + On Windows, :attr:`st_ctime` is deprecated. Eventually, it will + contain the last metadata change time, for consistency with other + platforms, but for now still contains creation time. + Use :attr:`st_birthtime` for the creation time. + + .. versionchanged:: 3.12 + On Windows, :attr:`st_ino` may now be up to 128 bits, depending + on the file system. Previously it would not be above 64 bits, and + larger file identifiers would be arbitrarily packed. + + .. versionchanged:: 3.12 + On Windows, :attr:`st_rdev` no longer returns a value. Previously + it would contain the same as :attr:`st_dev`, which was incorrect. + + .. versionadded:: 3.12 + Added the :attr:`st_birthtime` member on Windows. + + .. function:: statvfs(path) Perform a :c:func:`statvfs` system call on the given path. The return value is diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b9c668543e1b..03b1f9757467 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -306,6 +306,16 @@ os functions on Windows for enumerating drives, volumes and mount points. (Contributed by Steve Dower in :gh:`102519`.) +* :func:`os.stat` and :func:`os.lstat` are now more accurate on Windows. + The ``st_birthtime`` field will now be filled with the creation time + of the file, and ``st_ctime`` is deprecated but still contains the + creation time (but in the future will return the last metadata change, + for consistency with other platforms). ``st_dev`` may be up to 64 bits + and ``st_ino`` up to 128 bits depending on your file system, and + ``st_rdev`` is always set to zero rather than incorrect values. + Both functions may be significantly faster on newer releases of + Windows. (Contributed by Steve Dower in :gh:`99726`.) + os.path ------- @@ -469,6 +479,12 @@ Deprecated warning at compile time. This field will be removed in Python 3.14. (Contributed by Ramvikrams and Kumar Aditya in :gh:`101193`. PEP by Ken Jin.) +* The ``st_ctime`` fields return by :func:`os.stat` and :func:`os.lstat` on + Windows are deprecated. In a future release, they will contain the last + metadata change time, consistent with other platforms. For now, they still + contain the creation time, which is also available in the new ``st_birthtime`` + field. (Contributed by Steve Dower in :gh:`99726`.) + Pending Removal in Python 3.13 ------------------------------ diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h index 445ac0a3d955..ef6642d00f1b 100644 --- a/Include/internal/pycore_fileutils.h +++ b/Include/internal/pycore_fileutils.h @@ -66,7 +66,7 @@ PyAPI_FUNC(PyObject *) _Py_device_encoding(int); #ifdef MS_WINDOWS struct _Py_stat_struct { - unsigned long st_dev; + uint64_t st_dev; uint64_t st_ino; unsigned short st_mode; int st_nlink; @@ -80,8 +80,11 @@ struct _Py_stat_struct { int st_mtime_nsec; time_t st_ctime; int st_ctime_nsec; + time_t st_birthtime; + int st_birthtime_nsec; unsigned long st_file_attributes; unsigned long st_reparse_tag; + uint64_t st_ino_high; }; #else # define _Py_stat_struct stat diff --git a/Include/internal/pycore_fileutils_windows.h b/Include/internal/pycore_fileutils_windows.h new file mode 100644 index 000000000000..44874903b092 --- /dev/null +++ b/Include/internal/pycore_fileutils_windows.h @@ -0,0 +1,80 @@ +#ifndef Py_INTERNAL_FILEUTILS_WINDOWS_H +#define Py_INTERNAL_FILEUTILS_WINDOWS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "Py_BUILD_CORE must be defined to include this header" +#endif + +#ifdef MS_WINDOWS + +#if !defined(NTDDI_WIN10_NI) || !(NTDDI_VERSION >= NTDDI_WIN10_NI) +typedef struct _FILE_STAT_BASIC_INFORMATION { + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ULONG DeviceType; + ULONG DeviceCharacteristics; + ULONG Reserved; + FILE_ID_128 FileId128; + LARGE_INTEGER VolumeSerialNumber; +} FILE_STAT_BASIC_INFORMATION; + +typedef enum _FILE_INFO_BY_NAME_CLASS { + FileStatByNameInfo, + FileStatLxByNameInfo, + FileCaseSensitiveByNameInfo, + FileStatBasicByNameInfo, + MaximumFileInfoByNameClass +} FILE_INFO_BY_NAME_CLASS; +#endif + +typedef BOOL (WINAPI *PGetFileInformationByName)( + PCWSTR FileName, + FILE_INFO_BY_NAME_CLASS FileInformationClass, + PVOID FileInfoBuffer, + ULONG FileInfoBufferSize +); + +static inline BOOL _Py_GetFileInformationByName( + PCWSTR FileName, + FILE_INFO_BY_NAME_CLASS FileInformationClass, + PVOID FileInfoBuffer, + ULONG FileInfoBufferSize +) { + static PGetFileInformationByName GetFileInformationByName = NULL; + static int GetFileInformationByName_init = -1; + + if (GetFileInformationByName_init < 0) { + HMODULE hMod = LoadLibraryW(L"api-ms-win-core-file-l2-1-4"); + GetFileInformationByName_init = 0; + if (hMod) { + GetFileInformationByName = (PGetFileInformationByName)GetProcAddress( + hMod, "GetFileInformationByName"); + if (GetFileInformationByName) { + GetFileInformationByName_init = 1; + } else { + FreeLibrary(hMod); + } + } + } + + if (GetFileInformationByName_init <= 0) { + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + return GetFileInformationByName(FileName, FileInformationClass, FileInfoBuffer, FileInfoBufferSize); +} + +#endif + +#endif diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 42357fef80ec..74ece3ffb4ed 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -556,6 +556,15 @@ def trunc(x): return x nanosecondy = getattr(result, name + "_ns") // 10000 self.assertAlmostEqual(floaty, nanosecondy, delta=2) + # Ensure both birthtime and birthtime_ns roughly agree, if present + try: + floaty = int(result.st_birthtime * 100000) + nanosecondy = result.st_birthtime_ns // 10000 + except AttributeError: + pass + else: + self.assertAlmostEqual(floaty, nanosecondy, delta=2) + try: result[200] self.fail("No exception raised") @@ -4234,7 +4243,8 @@ def assert_stat_equal(self, stat1, stat2, skip_fields): for attr in dir(stat1): if not attr.startswith("st_"): continue - if attr in ("st_dev", "st_ino", "st_nlink"): + if attr in ("st_dev", "st_ino", "st_nlink", "st_ctime", + "st_ctime_ns"): continue self.assertEqual(getattr(stat1, attr), getattr(stat2, attr), diff --git a/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst b/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst new file mode 100644 index 000000000000..e25786200178 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst @@ -0,0 +1,2 @@ +Improves correctness of stat results for Windows, and uses faster API when +available diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 7d91f7e4bac7..e38caf7cc0ab 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -41,6 +41,7 @@ #ifndef MS_WINDOWS # include "posixmodule.h" #else +# include "pycore_fileutils_windows.h" # include "winreparse.h" #endif @@ -668,8 +669,11 @@ PyOS_AfterFork(void) #ifdef MS_WINDOWS /* defined in fileutils.c */ void _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *); -void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, - ULONG, struct _Py_stat_struct *); +void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, ULONG, + FILE_BASIC_INFO *, FILE_ID_INFO *, + struct _Py_stat_struct *); +void _Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *, + struct _Py_stat_struct *); #endif @@ -1819,12 +1823,39 @@ attributes_from_dir(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *re return TRUE; } + +static void +update_st_mode_from_path(const wchar_t *path, DWORD attr, + struct _Py_stat_struct *result) +{ + if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { + /* Fix the file execute permissions. This hack sets S_IEXEC if + the filename has an extension that is commonly used by files + that CreateProcessW can execute. A real implementation calls + GetSecurityInfo, OpenThreadToken/OpenProcessToken, and + AccessCheck to check for generic read, write, and execute + access. */ + const wchar_t *fileExtension = wcsrchr(path, '.'); + if (fileExtension) { + if (_wcsicmp(fileExtension, L".exe") == 0 || + _wcsicmp(fileExtension, L".bat") == 0 || + _wcsicmp(fileExtension, L".cmd") == 0 || + _wcsicmp(fileExtension, L".com") == 0) { + result->st_mode |= 0111; + } + } + } +} + + static int -win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, - BOOL traverse) +win32_xstat_slow_impl(const wchar_t *path, struct _Py_stat_struct *result, + BOOL traverse) { HANDLE hFile; BY_HANDLE_FILE_INFORMATION fileInfo; + FILE_BASIC_INFO basicInfo; + FILE_ID_INFO idInfo; FILE_ATTRIBUTE_TAG_INFO tagInfo = { 0 }; DWORD fileType, error; BOOL isUnhandledTag = FALSE; @@ -1954,12 +1985,16 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, for an unhandled tag. */ } else if (!isUnhandledTag) { CloseHandle(hFile); - return win32_xstat_impl(path, result, TRUE); + return win32_xstat_slow_impl(path, result, TRUE); } } } - if (!GetFileInformationByHandle(hFile, &fileInfo)) { + if (!GetFileInformationByHandle(hFile, &fileInfo) || + !GetFileInformationByHandleEx(hFile, FileBasicInfo, + &basicInfo, sizeof(basicInfo)) || + !GetFileInformationByHandleEx(hFile, FileIdInfo, + &idInfo, sizeof(idInfo))) { switch (GetLastError()) { case ERROR_INVALID_PARAMETER: case ERROR_INVALID_FUNCTION: @@ -1975,25 +2010,8 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, } } - _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, result); - - if (!(fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - /* Fix the file execute permissions. This hack sets S_IEXEC if - the filename has an extension that is commonly used by files - that CreateProcessW can execute. A real implementation calls - GetSecurityInfo, OpenThreadToken/OpenProcessToken, and - AccessCheck to check for generic read, write, and execute - access. */ - const wchar_t *fileExtension = wcsrchr(path, '.'); - if (fileExtension) { - if (_wcsicmp(fileExtension, L".exe") == 0 || - _wcsicmp(fileExtension, L".bat") == 0 || - _wcsicmp(fileExtension, L".cmd") == 0 || - _wcsicmp(fileExtension, L".com") == 0) { - result->st_mode |= 0111; - } - } - } + _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, &basicInfo, &idInfo, result); + update_st_mode_from_path(path, fileInfo.dwFileAttributes, result); cleanup: if (hFile != INVALID_HANDLE_VALUE) { @@ -2010,6 +2028,39 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, return retval; } +static int +win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, + BOOL traverse) +{ + FILE_STAT_BASIC_INFORMATION statInfo; + if (_Py_GetFileInformationByName(path, FileStatBasicByNameInfo, + &statInfo, sizeof(statInfo))) { + if (// Cannot use fast path for reparse points ... + !(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + // ... unless it's a name surrogate (symlink) and we're not following + || (!traverse && IsReparseTagNameSurrogate(statInfo.ReparseTag)) + ) { + _Py_stat_basic_info_to_stat(&statInfo, result); + update_st_mode_from_path(path, statInfo.FileAttributes, result); + return 0; + } + } else { + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_NOT_READY: + case ERROR_BAD_NET_NAME: + /* These errors aren't worth retrying with the slow path */ + return -1; + case ERROR_NOT_SUPPORTED: + /* indicates the API couldn't be loaded */ + break; + } + } + + return win32_xstat_slow_impl(path, result, traverse); +} + static int win32_xstat(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) { @@ -2017,6 +2068,10 @@ win32_xstat(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) setting it to a POSIX error. Callers should use GetLastError. */ int code = win32_xstat_impl(path, result, traverse); errno = 0; + + /* ctime is only deprecated from 3.12, so we copy birthtime across */ + result->st_ctime = result->st_birthtime; + result->st_ctime_nsec = result->st_birthtime_nsec; return code; } /* About the following functions: win32_lstat_w, win32_stat, win32_stat_w @@ -2087,9 +2142,12 @@ static PyStructSequence_Field stat_result_fields[] = { #ifdef HAVE_STRUCT_STAT_ST_GEN {"st_gen", "generation number"}, #endif -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) || defined(MS_WINDOWS) {"st_birthtime", "time of creation"}, #endif +#ifdef MS_WINDOWS + {"st_birthtime_ns", "time of creation in nanoseconds"}, +#endif #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES {"st_file_attributes", "Windows file attribute bits"}, #endif @@ -2132,16 +2190,22 @@ static PyStructSequence_Field stat_result_fields[] = { #define ST_GEN_IDX ST_FLAGS_IDX #endif -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) || defined(MS_WINDOWS) #define ST_BIRTHTIME_IDX (ST_GEN_IDX+1) #else #define ST_BIRTHTIME_IDX ST_GEN_IDX #endif -#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES -#define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_IDX+1) +#ifdef MS_WINDOWS +#define ST_BIRTHTIME_NS_IDX (ST_BIRTHTIME_IDX+1) #else -#define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_IDX +#define ST_BIRTHTIME_NS_IDX ST_BIRTHTIME_IDX +#endif + +#if defined(HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES) || defined(MS_WINDOWS) +#define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_NS_IDX+1) +#else +#define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_NS_IDX #endif #ifdef HAVE_STRUCT_STAT_ST_FSTYPE @@ -2310,7 +2374,7 @@ _posix_free(void *module) } static void -fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long nsec) +fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec) { PyObject *s = _PyLong_FromTime_t(sec); PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec); @@ -2334,12 +2398,18 @@ fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long ns goto exit; } - PyStructSequence_SET_ITEM(v, index, s); - PyStructSequence_SET_ITEM(v, index+3, float_s); - PyStructSequence_SET_ITEM(v, index+6, ns_total); - s = NULL; - float_s = NULL; - ns_total = NULL; + if (s_index >= 0) { + PyStructSequence_SET_ITEM(v, s_index, s); + s = NULL; + } + if (f_index >= 0) { + PyStructSequence_SET_ITEM(v, f_index, float_s); + float_s = NULL; + } + if (ns_index >= 0) { + PyStructSequence_SET_ITEM(v, ns_index, ns_total); + ns_total = NULL; + } exit: Py_XDECREF(s); Py_XDECREF(ns_fractional); @@ -2348,6 +2418,33 @@ fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long ns Py_XDECREF(float_s); } +#ifdef MS_WINDOWS +static PyObject* +_pystat_l128_from_l64_l64(uint64_t low, uint64_t high) +{ + PyObject *o_low = PyLong_FromUnsignedLongLong(low); + if (!o_low || !high) { + return o_low; + } + PyObject *o_high = PyLong_FromUnsignedLongLong(high); + PyObject *l64 = o_high ? PyLong_FromLong(64) : NULL; + if (!l64) { + Py_XDECREF(o_high); + Py_DECREF(o_low); + return NULL; + } + Py_SETREF(o_high, PyNumber_Lshift(o_high, l64)); + Py_DECREF(l64); + if (!o_high) { + Py_DECREF(o_low); + return NULL; + } + Py_SETREF(o_low, PyNumber_Add(o_low, o_high)); + Py_DECREF(o_high); + return o_low; +} +#endif + /* pack a system stat C structure into the Python stat tuple (used by posix_stat() and posix_fstat()) */ static PyObject* @@ -2360,12 +2457,13 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) return NULL; PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode)); +#ifdef MS_WINDOWS + PyStructSequence_SET_ITEM(v, 1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high)); + PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLongLong(st->st_dev)); +#else static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino), "stat.st_ino is larger than unsigned long long"); PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino)); -#ifdef MS_WINDOWS - PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev)); -#else PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev)); #endif PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink)); @@ -2395,9 +2493,9 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) #else ansec = mnsec = cnsec = 0; #endif - fill_time(module, v, 7, st->st_atime, ansec); - fill_time(module, v, 8, st->st_mtime, mnsec); - fill_time(module, v, 9, st->st_ctime, cnsec); + fill_time(module, v, 7, 10, 13, st->st_atime, ansec); + fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec); + fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec); #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX, @@ -2415,7 +2513,7 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) PyStructSequence_SET_ITEM(v, ST_GEN_IDX, PyLong_FromLong((long)st->st_gen)); #endif -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) { PyObject *val; unsigned long bsec,bnsec; @@ -2429,6 +2527,9 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX, val); } +#elif defined(MS_WINDOWS) + fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, + st->st_birthtime, st->st_birthtime_nsec); #endif #ifdef HAVE_STRUCT_STAT_ST_FLAGS PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, @@ -14639,7 +14740,7 @@ DirEntry_from_find_data(PyObject *module, path_t *path, WIN32_FIND_DATAW *dataW) } find_data_to_file_info(dataW, &file_info, &reparse_tag); - _Py_attribute_data_to_stat(&file_info, reparse_tag, &entry->win32_lstat); + _Py_attribute_data_to_stat(&file_info, reparse_tag, NULL, NULL, &entry->win32_lstat); return (PyObject *)entry; diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 85dc8caa458e..0343d30a42cd 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -216,6 +216,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 98e7d59ba102..359463e1d9af 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -555,6 +555,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/fileutils.c b/Python/fileutils.c index f48b626b4440..969b7163b5ac 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -8,6 +8,8 @@ #ifdef MS_WINDOWS # include # include +# include // FILE_DEVICE_* constants +# include "pycore_fileutils_windows.h" // FILE_STAT_BASIC_INFORMATION # if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) # define PATHCCH_ALLOW_LONG_PATHS 0x01 # else @@ -1056,6 +1058,13 @@ FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); } +static void +LARGE_INTEGER_to_time_t_nsec(LARGE_INTEGER *in_ptr, time_t *time_out, int* nsec_out) +{ + *nsec_out = (int)(in_ptr->QuadPart % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ + *time_out = Py_SAFE_DOWNCAST((in_ptr->QuadPart / 10000000) - secs_between_epochs, __int64, time_t); +} + void _Py_time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) { @@ -1085,33 +1094,126 @@ attributes_to_mode(DWORD attr) return m; } + +typedef union { + FILE_ID_128 id; + struct { + uint64_t st_ino; + uint64_t st_ino_high; + }; +} id_128_to_ino; + + void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, + FILE_BASIC_INFO *basic_info, FILE_ID_INFO *id_info, struct _Py_stat_struct *result) { memset(result, 0, sizeof(*result)); result->st_mode = attributes_to_mode(info->dwFileAttributes); result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; - result->st_dev = info->dwVolumeSerialNumber; - result->st_rdev = result->st_dev; - FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + result->st_dev = id_info ? id_info->VolumeSerialNumber : info->dwVolumeSerialNumber; + result->st_rdev = 0; + /* st_ctime is deprecated, but we preserve the legacy value in our caller, not here */ + if (basic_info) { + LARGE_INTEGER_to_time_t_nsec(&basic_info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&basic_info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec); + LARGE_INTEGER_to_time_t_nsec(&basic_info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&basic_info->LastAccessTime, &result->st_atime, &result->st_atime_nsec); + } else { + FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_birthtime, &result->st_birthtime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + } result->st_nlink = info->nNumberOfLinks; - result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow; + + if (id_info) { + id_128_to_ino file_id; + file_id.id = id_info->FileId; + result->st_ino = file_id.st_ino; + result->st_ino_high = file_id.st_ino_high; + } else { + /* should only occur for DirEntry_from_find_data, in which case the + index is likely to be zero anyway. */ + result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow; + } + /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will open other name surrogate reparse points without traversing them. To detect/handle these, check st_file_attributes and st_reparse_tag. */ result->st_reparse_tag = reparse_tag; if (info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && reparse_tag == IO_REPARSE_TAG_SYMLINK) { - /* first clear the S_IFMT bits */ - result->st_mode ^= (result->st_mode & S_IFMT); - /* now set the bits that make this a symlink */ - result->st_mode |= S_IFLNK; + /* set the bits that make this a symlink */ + result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK; } result->st_file_attributes = info->dwFileAttributes; } + +void +_Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *info, + struct _Py_stat_struct *result) +{ + memset(result, 0, sizeof(*result)); + result->st_mode = attributes_to_mode(info->FileAttributes); + result->st_size = info->EndOfFile.QuadPart; + LARGE_INTEGER_to_time_t_nsec(&info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec); + LARGE_INTEGER_to_time_t_nsec(&info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&info->LastAccessTime, &result->st_atime, &result->st_atime_nsec); + result->st_nlink = info->NumberOfLinks; + result->st_dev = info->VolumeSerialNumber.QuadPart; + /* File systems with less than 128-bits zero pad into this field */ + id_128_to_ino file_id; + file_id.id = info->FileId128; + result->st_ino = file_id.st_ino; + result->st_ino_high = file_id.st_ino_high; + /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will + open other name surrogate reparse points without traversing them. To + detect/handle these, check st_file_attributes and st_reparse_tag. */ + result->st_reparse_tag = info->ReparseTag; + if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && + info->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + /* set the bits that make this a symlink */ + result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK; + } + result->st_file_attributes = info->FileAttributes; + switch (info->DeviceType) { + case FILE_DEVICE_DISK: + case FILE_DEVICE_VIRTUAL_DISK: + case FILE_DEVICE_DFS: + case FILE_DEVICE_CD_ROM: + case FILE_DEVICE_CONTROLLER: + case FILE_DEVICE_DATALINK: + break; + case FILE_DEVICE_DISK_FILE_SYSTEM: + case FILE_DEVICE_CD_ROM_FILE_SYSTEM: + case FILE_DEVICE_NETWORK_FILE_SYSTEM: + result->st_mode = (result->st_mode & ~S_IFMT) | 0x6000; /* _S_IFBLK */ + break; + case FILE_DEVICE_CONSOLE: + case FILE_DEVICE_NULL: + case FILE_DEVICE_KEYBOARD: + case FILE_DEVICE_MODEM: + case FILE_DEVICE_MOUSE: + case FILE_DEVICE_PARALLEL_PORT: + case FILE_DEVICE_PRINTER: + case FILE_DEVICE_SCREEN: + case FILE_DEVICE_SERIAL_PORT: + case FILE_DEVICE_SOUND: + result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFCHR; + break; + case FILE_DEVICE_NAMED_PIPE: + result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFIFO; + break; + default: + if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFDIR; + } + break; + } +} + #endif /* Return information about a file. @@ -1131,6 +1233,8 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status) { #ifdef MS_WINDOWS BY_HANDLE_FILE_INFORMATION info; + FILE_BASIC_INFO basicInfo; + FILE_ID_INFO idInfo; HANDLE h; int type; @@ -1162,14 +1266,16 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status) return 0; } - if (!GetFileInformationByHandle(h, &info)) { + if (!GetFileInformationByHandle(h, &info) || + !GetFileInformationByHandleEx(h, FileBasicInfo, &basicInfo, sizeof(basicInfo)) || + !GetFileInformationByHandleEx(h, FileIdInfo, &idInfo, sizeof(idInfo))) { /* The Win32 error is already set, but we also set errno for callers who expect it */ errno = winerror_to_errno(GetLastError()); return -1; } - _Py_attribute_data_to_stat(&info, 0, status); + _Py_attribute_data_to_stat(&info, 0, &basicInfo, &idInfo, status); return 0; #else return fstat(fd, status); From webhook-mailer at python.org Thu Mar 16 15:04:01 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 16 Mar 2023 19:04:01 -0000 Subject: [Python-checkins] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102760) Message-ID: https://github.com/python/cpython/commit/6372e290c0ac0993e4e2f66b12efdb076f620d09 commit: 6372e290c0ac0993e4e2f66b12efdb076f620d09 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-16T19:03:52Z summary: gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102760) files: M Python/traceback.c diff --git a/Python/traceback.c b/Python/traceback.c index 31b85e77575e..097f69c76abf 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -11,7 +11,7 @@ #include "pycore_interp.h" // PyInterpreterState.gc #include "pycore_parser.h" // _PyParser_ASTFromString #include "pycore_pyarena.h" // _PyArena_Free() -#include "pycore_pyerrors.h" // _PyErr_Fetch() +#include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_traceback.h" // EXCEPTION_TB_HEADER @@ -242,17 +242,18 @@ _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame) int PyTraceBack_Here(PyFrameObject *frame) { - PyObject *exc, *val, *tb, *newtb; - PyErr_Fetch(&exc, &val, &tb); - newtb = _PyTraceBack_FromFrame(tb, frame); + PyObject *exc = PyErr_GetRaisedException(); + assert(PyExceptionInstance_Check(exc)); + PyObject *tb = PyException_GetTraceback(exc); + PyObject *newtb = _PyTraceBack_FromFrame(tb, frame); + Py_XDECREF(tb); if (newtb == NULL) { - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_ChainExceptions1(exc); return -1; } - assert(PyExceptionInstance_Check(val)); - PyException_SetTraceback(val, newtb); - PyErr_Restore(exc, val, newtb); - Py_XDECREF(tb); + PyException_SetTraceback(exc, newtb); + Py_XDECREF(newtb); + PyErr_SetRaisedException(exc); return 0; } From webhook-mailer at python.org Thu Mar 16 16:34:49 2023 From: webhook-mailer at python.org (mdickinson) Date: Thu, 16 Mar 2023 20:34:49 -0000 Subject: [Python-checkins] Fix outdated note about 'int' rounding or truncating (#102736) Message-ID: https://github.com/python/cpython/commit/405739f9166592104a5b0b945de92e28415ae972 commit: 405739f9166592104a5b0b945de92e28415ae972 branch: main author: Mark Dickinson committer: mdickinson date: 2023-03-16T20:34:42Z summary: Fix outdated note about 'int' rounding or truncating (#102736) files: M Doc/library/stdtypes.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 550f808a16df..bcfc6e5cfce6 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -335,11 +335,10 @@ Notes: single: ceil() (in module math) single: trunc() (in module math) pair: numeric; conversions - pair: C; language - Conversion from floating point to integer may round or truncate - as in C; see functions :func:`math.floor` and :func:`math.ceil` for - well-defined conversions. + Conversion from :class:`float` to :class:`int` truncates, discarding the + fractional part. See functions :func:`math.floor` and :func:`math.ceil` for + alternative conversions. (4) float also accepts the strings "nan" and "inf" with an optional prefix "+" From webhook-mailer at python.org Thu Mar 16 16:43:02 2023 From: webhook-mailer at python.org (mdickinson) Date: Thu, 16 Mar 2023 20:43:02 -0000 Subject: [Python-checkins] [3.11] Fix outdated note about 'int' rounding or truncating (GH-102736) (#102766) Message-ID: https://github.com/python/cpython/commit/df399a35d5ef4647ed29ba40ecb4cb609116683d commit: df399a35d5ef4647ed29ba40ecb4cb609116683d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: mdickinson date: 2023-03-16T20:42:54Z summary: [3.11] Fix outdated note about 'int' rounding or truncating (GH-102736) (#102766) Fix outdated note about 'int' rounding or truncating (GH-102736) (cherry picked from commit 405739f9166592104a5b0b945de92e28415ae972) Co-authored-by: Mark Dickinson files: M Doc/library/stdtypes.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 1fb3931902e4..e7d43b2809ac 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -335,11 +335,10 @@ Notes: single: ceil() (in module math) single: trunc() (in module math) pair: numeric; conversions - pair: C; language - Conversion from floating point to integer may round or truncate - as in C; see functions :func:`math.floor` and :func:`math.ceil` for - well-defined conversions. + Conversion from :class:`float` to :class:`int` truncates, discarding the + fractional part. See functions :func:`math.floor` and :func:`math.ceil` for + alternative conversions. (4) float also accepts the strings "nan" and "inf" with an optional prefix "+" From webhook-mailer at python.org Thu Mar 16 16:43:11 2023 From: webhook-mailer at python.org (mdickinson) Date: Thu, 16 Mar 2023 20:43:11 -0000 Subject: [Python-checkins] [3.10] Fix outdated note about 'int' rounding or truncating (GH-102736) (#102767) Message-ID: https://github.com/python/cpython/commit/99b38bebfd92ed8b1c83799345cb6d9120bdf31c commit: 99b38bebfd92ed8b1c83799345cb6d9120bdf31c branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: mdickinson date: 2023-03-16T20:43:03Z summary: [3.10] Fix outdated note about 'int' rounding or truncating (GH-102736) (#102767) Fix outdated note about 'int' rounding or truncating (GH-102736) (cherry picked from commit 405739f9166592104a5b0b945de92e28415ae972) Co-authored-by: Mark Dickinson files: M Doc/library/stdtypes.rst diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 59d64457edcd..6752c475ad7f 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -335,11 +335,10 @@ Notes: single: ceil() (in module math) single: trunc() (in module math) pair: numeric; conversions - pair: C; language - Conversion from floating point to integer may round or truncate - as in C; see functions :func:`math.floor` and :func:`math.ceil` for - well-defined conversions. + Conversion from :class:`float` to :class:`int` truncates, discarding the + fractional part. See functions :func:`math.floor` and :func:`math.ceil` for + alternative conversions. (4) float also accepts the strings "nan" and "inf" with an optional prefix "+" From webhook-mailer at python.org Thu Mar 16 18:18:13 2023 From: webhook-mailer at python.org (iritkatriel) Date: Thu, 16 Mar 2023 22:18:13 -0000 Subject: [Python-checkins] gh-102755: Add PyErr_DisplayException(exc) (#102756) Message-ID: https://github.com/python/cpython/commit/3f9285a8c52bf776c364f0cf4aecdd8f514ac4e1 commit: 3f9285a8c52bf776c364f0cf4aecdd8f514ac4e1 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-16T22:18:04Z summary: gh-102755: Add PyErr_DisplayException(exc) (#102756) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst M Doc/c-api/exceptions.rst M Doc/data/stable_abi.dat M Doc/whatsnew/3.12.rst M Include/internal/pycore_pylifecycle.h M Include/pythonrun.h M Lib/test/test_stable_abi_ctypes.py M Misc/stable_abi.toml M Modules/_testcapi/exceptions.c M PC/python3dll.c M Python/pylifecycle.c M Python/pythonrun.c M Python/sysmodule.c diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 8836c973f1f5..ddf7dc780b27 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -86,6 +86,12 @@ Printing and clearing An exception must be set when calling this function. +.. c:function: void PyErr_DisplayException(PyObject *exc) + + Print the standard traceback display of ``exc`` to ``sys.stderr``, including + chained exceptions and notes. + + .. versionadded:: 3.12 Raising exceptions ================== diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 68ab0b5061f4..4cc06d22baaa 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -133,6 +133,7 @@ function,PyErr_BadInternalCall,3.2,, function,PyErr_CheckSignals,3.2,, function,PyErr_Clear,3.2,, function,PyErr_Display,3.2,, +function,PyErr_DisplayException,3.12,, function,PyErr_ExceptionMatches,3.2,, function,PyErr_Fetch,3.2,, function,PyErr_Format,3.2,, diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 03b1f9757467..a398cd93f731 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -944,6 +944,10 @@ New Features the :attr:`~BaseException.args` passed to the exception's constructor. (Contributed by Mark Shannon in :gh:`101578`.) +* Add :c:func:`PyErr_DisplayException`, which takes an exception instance, + to replace the legacy-api :c:func:`PyErr_Display`. (Contributed by + Irit Katriel in :gh:`102755`). + Porting to Python 3.12 ---------------------- @@ -1077,6 +1081,9 @@ Deprecated :c:func:`PyErr_SetRaisedException` instead. (Contributed by Mark Shannon in :gh:`101578`.) +* :c:func:`PyErr_Display` is deprecated. Use :c:func:`PyErr_DisplayException` + instead. (Contributed by Irit Katriel in :gh:`102755`). + Removed ------- diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index e7a318072052..a899e848bb8b 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -87,6 +87,7 @@ PyAPI_FUNC(PyObject*) _PyErr_WriteUnraisableDefaultHook(PyObject *unraisable); PyAPI_FUNC(void) _PyErr_Print(PyThreadState *tstate); PyAPI_FUNC(void) _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *tb); +PyAPI_FUNC(void) _PyErr_DisplayException(PyObject *file, PyObject *exc); PyAPI_FUNC(void) _PyThreadState_DeleteCurrent(PyThreadState *tstate); diff --git a/Include/pythonrun.h b/Include/pythonrun.h index 1b208b734ab1..41d82e89f848 100644 --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -12,6 +12,7 @@ PyAPI_FUNC(PyObject *) Py_CompileString(const char *, const char *, int); PyAPI_FUNC(void) PyErr_Print(void); PyAPI_FUNC(void) PyErr_PrintEx(int); PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(void) PyErr_DisplayException(PyObject *); /* Stuff with no proper home (yet) */ diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index e77c1c840988..2feaaf8603b8 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -166,6 +166,7 @@ def test_windows_feature_macros(self): "PyErr_CheckSignals", "PyErr_Clear", "PyErr_Display", + "PyErr_DisplayException", "PyErr_ExceptionMatches", "PyErr_Fetch", "PyErr_Format", diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst new file mode 100644 index 000000000000..d09af8d060d4 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst @@ -0,0 +1,3 @@ +Add :c:func:`PyErr_DisplayException` which takes just an exception instance, +to replace the legacy :c:func:`PyErr_Display` which takes the ``(typ, exc, +tb)`` triplet. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 21ff96161334..23baeeeae791 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -609,6 +609,8 @@ added = '3.2' [function.PyErr_Display] added = '3.2' +[function.PyErr_DisplayException] + added = '3.12' [function.PyErr_ExceptionMatches] added = '3.2' [function.PyErr_Fetch] diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index c64b823663c3..1922ca3beb79 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -39,20 +39,13 @@ err_restore(PyObject *self, PyObject *args) { static PyObject * exception_print(PyObject *self, PyObject *args) { - PyObject *value; - PyObject *tb = NULL; + PyObject *exc; - if (!PyArg_ParseTuple(args, "O:exception_print", &value)) { + if (!PyArg_ParseTuple(args, "O:exception_print", &exc)) { return NULL; } - if (PyExceptionInstance_Check(value)) { - tb = PyException_GetTraceback(value); - } - - PyErr_Display((PyObject *) Py_TYPE(value), value, tb); - Py_XDECREF(tb); - + PyErr_DisplayException(exc); Py_RETURN_NONE; } diff --git a/PC/python3dll.c b/PC/python3dll.c index e30081936575..706affa18351 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -192,6 +192,7 @@ EXPORT_FUNC(PyErr_BadInternalCall) EXPORT_FUNC(PyErr_CheckSignals) EXPORT_FUNC(PyErr_Clear) EXPORT_FUNC(PyErr_Display) +EXPORT_FUNC(PyErr_DisplayException) EXPORT_FUNC(PyErr_ExceptionMatches) EXPORT_FUNC(PyErr_Fetch) EXPORT_FUNC(PyErr_Format) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 82e94090a602..d0c65cc1f7fd 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2537,41 +2537,28 @@ _Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp, static int _Py_FatalError_PrintExc(PyThreadState *tstate) { - PyObject *ferr, *res; - PyObject *exception, *v, *tb; - int has_tb; - - _PyErr_Fetch(tstate, &exception, &v, &tb); - if (exception == NULL) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + if (exc == NULL) { /* No current exception */ return 0; } - ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); if (ferr == NULL || ferr == Py_None) { /* sys.stderr is not set yet or set to None, no need to try to display the exception */ return 0; } - _PyErr_NormalizeException(tstate, &exception, &v, &tb); - if (tb == NULL) { - tb = Py_NewRef(Py_None); - } - PyException_SetTraceback(v, tb); - if (exception == NULL) { - /* PyErr_NormalizeException() failed */ - return 0; - } + PyErr_DisplayException(exc); - has_tb = (tb != Py_None); - PyErr_Display(exception, v, tb); - Py_XDECREF(exception); - Py_XDECREF(v); + PyObject *tb = PyException_GetTraceback(exc); + int has_tb = (tb != NULL) && (tb != Py_None); Py_XDECREF(tb); + Py_XDECREF(exc); /* sys.stderr may be buffered: call sys.stderr.flush() */ - res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); + PyObject *res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); if (res == NULL) { _PyErr_Clear(tstate); } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 5381b105a39f..07d119a67847 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -761,39 +761,34 @@ handle_system_exit(void) static void _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) { - PyObject *exception, *v, *tb, *hook; - + PyObject *typ = NULL, *tb = NULL; handle_system_exit(); - _PyErr_Fetch(tstate, &exception, &v, &tb); - if (exception == NULL) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + if (exc == NULL) { goto done; } - - _PyErr_NormalizeException(tstate, &exception, &v, &tb); + assert(PyExceptionInstance_Check(exc)); + typ = Py_NewRef(Py_TYPE(exc)); + tb = PyException_GetTraceback(exc); if (tb == NULL) { tb = Py_NewRef(Py_None); } - PyException_SetTraceback(v, tb); - if (exception == NULL) { - goto done; - } - /* Now we know v != NULL too */ if (set_sys_last_vars) { - if (_PySys_SetAttr(&_Py_ID(last_type), exception) < 0) { + if (_PySys_SetAttr(&_Py_ID(last_type), typ) < 0) { _PyErr_Clear(tstate); } - if (_PySys_SetAttr(&_Py_ID(last_value), v) < 0) { + if (_PySys_SetAttr(&_Py_ID(last_value), exc) < 0) { _PyErr_Clear(tstate); } if (_PySys_SetAttr(&_Py_ID(last_traceback), tb) < 0) { _PyErr_Clear(tstate); } } - hook = _PySys_GetAttr(tstate, &_Py_ID(excepthook)); + PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(excepthook)); if (_PySys_Audit(tstate, "sys.excepthook", "OOOO", hook ? hook : Py_None, - exception, v, tb) < 0) { + typ, exc, tb) < 0) { if (PyErr_ExceptionMatches(PyExc_RuntimeError)) { PyErr_Clear(); goto done; @@ -802,46 +797,34 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) } if (hook) { PyObject* stack[3]; - PyObject *result; - - stack[0] = exception; - stack[1] = v; + stack[0] = typ; + stack[1] = exc; stack[2] = tb; - result = _PyObject_FastCall(hook, stack, 3); + PyObject *result = _PyObject_FastCall(hook, stack, 3); if (result == NULL) { handle_system_exit(); - PyObject *exception2, *v2, *tb2; - _PyErr_Fetch(tstate, &exception2, &v2, &tb2); - _PyErr_NormalizeException(tstate, &exception2, &v2, &tb2); - /* It should not be possible for exception2 or v2 - to be NULL. However PyErr_Display() can't - tolerate NULLs, so just be safe. */ - if (exception2 == NULL) { - exception2 = Py_NewRef(Py_None); - } - if (v2 == NULL) { - v2 = Py_NewRef(Py_None); - } + PyObject *exc2 = _PyErr_GetRaisedException(tstate); + assert(exc2 && PyExceptionInstance_Check(exc2)); fflush(stdout); PySys_WriteStderr("Error in sys.excepthook:\n"); - PyErr_Display(exception2, v2, tb2); + PyErr_DisplayException(exc2); PySys_WriteStderr("\nOriginal exception was:\n"); - PyErr_Display(exception, v, tb); - Py_DECREF(exception2); - Py_DECREF(v2); - Py_XDECREF(tb2); + PyErr_DisplayException(exc); + Py_DECREF(exc2); + } + else { + Py_DECREF(result); } - Py_XDECREF(result); } else { PySys_WriteStderr("sys.excepthook is missing\n"); - PyErr_Display(exception, v, tb); + PyErr_DisplayException(exc); } done: - Py_XDECREF(exception); - Py_XDECREF(v); + Py_XDECREF(typ); + Py_XDECREF(exc); Py_XDECREF(tb); } @@ -1505,7 +1488,7 @@ print_exception_recursive(struct exception_print_context *ctx, PyObject *value) #define PyErr_MAX_GROUP_DEPTH 10 void -_PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *tb) +_PyErr_Display(PyObject *file, PyObject *unused, PyObject *value, PyObject *tb) { assert(file != NULL && file != Py_None); if (PyExceptionInstance_Check(value) @@ -1513,10 +1496,12 @@ _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *t /* Put the traceback on the exception, otherwise it won't get displayed. See issue #18776. */ PyObject *cur_tb = PyException_GetTraceback(value); - if (cur_tb == NULL) + if (cur_tb == NULL) { PyException_SetTraceback(value, tb); - else + } + else { Py_DECREF(cur_tb); + } } struct exception_print_context ctx; @@ -1552,7 +1537,7 @@ _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *t } void -PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb) +PyErr_Display(PyObject *unused, PyObject *value, PyObject *tb) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); @@ -1565,10 +1550,20 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb) return; } Py_INCREF(file); - _PyErr_Display(file, exception, value, tb); + _PyErr_Display(file, NULL, value, tb); Py_DECREF(file); } +void _PyErr_DisplayException(PyObject *file, PyObject *exc) +{ + _PyErr_Display(file, NULL, exc, NULL); +} + +void PyErr_DisplayException(PyObject *exc) +{ + PyErr_Display(NULL, exc, NULL); +} + PyObject * PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index d282104dcad4..cc5b9a6d418b 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -742,7 +742,7 @@ sys_excepthook_impl(PyObject *module, PyObject *exctype, PyObject *value, PyObject *traceback) /*[clinic end generated code: output=18d99fdda21b6b5e input=ecf606fa826f19d9]*/ { - PyErr_Display(exctype, value, traceback); + PyErr_Display(NULL, value, traceback); Py_RETURN_NONE; } From webhook-mailer at python.org Thu Mar 16 21:07:42 2023 From: webhook-mailer at python.org (zooba) Date: Fri, 17 Mar 2023 01:07:42 -0000 Subject: [Python-checkins] Increase stack reserve size for Windows debug builds to avoid test crashes (GH-102764) Message-ID: https://github.com/python/cpython/commit/f33b33eb31c11a32b2955eb1f002f02267bd7d61 commit: f33b33eb31c11a32b2955eb1f002f02267bd7d61 branch: main author: Steve Dower committer: zooba date: 2023-03-17T01:07:07Z summary: Increase stack reserve size for Windows debug builds to avoid test crashes (GH-102764) files: M PCbuild/python.vcxproj M PCbuild/pythonw.vcxproj diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj index d07db3a68150..f4640454a730 100644 --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -95,7 +95,7 @@ Console 2000000 - 4000000 + 8000000 diff --git a/PCbuild/pythonw.vcxproj b/PCbuild/pythonw.vcxproj index e7216dec3a1a..e23635e5ea94 100644 --- a/PCbuild/pythonw.vcxproj +++ b/PCbuild/pythonw.vcxproj @@ -89,7 +89,8 @@ - 2000000 + 2000000 + 8000000 From webhook-mailer at python.org Thu Mar 16 21:28:50 2023 From: webhook-mailer at python.org (kumaraditya303) Date: Fri, 17 Mar 2023 01:28:50 -0000 Subject: [Python-checkins] GH-78530: add support for generators in `asyncio.wait` (#102761) Message-ID: https://github.com/python/cpython/commit/4f5774f648eafd1a7076ecf9af9629fb81baa363 commit: 4f5774f648eafd1a7076ecf9af9629fb81baa363 branch: main author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: kumaraditya303 <59607654+kumaraditya303 at users.noreply.github.com> date: 2023-03-17T06:58:43+05:30 summary: GH-78530: add support for generators in `asyncio.wait` (#102761) files: A Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst M Doc/library/asyncio-task.rst M Doc/whatsnew/3.12.rst M Lib/test/test_asyncio/test_tasks.py diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 5f1449e1b599..a0900cd25a77 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -804,6 +804,10 @@ Waiting Primitives .. versionchanged:: 3.11 Passing coroutine objects to ``wait()`` directly is forbidden. + .. versionchanged:: 3.12 + Added support for generators yielding tasks. + + .. function:: as_completed(aws, *, timeout=None) Run :ref:`awaitable objects ` in the *aws* diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a398cd93f731..b55b9619fac2 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -241,6 +241,9 @@ asyncio :mod:`asyncio` does not support legacy generator-based coroutines. (Contributed by Kumar Aditya in :gh:`102748`.) +* :func:`asyncio.wait` now accepts generators yielding tasks. + (Contributed by Kumar Aditya in :gh:`78530`.) + inspect ------- diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 5b935b526541..731fa0c5a60b 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1373,6 +1373,22 @@ async def foo(): self.assertEqual(res, 42) self.assertAlmostEqual(0.15, loop.time()) + + def test_wait_generator(self): + async def func(a): + return a + + loop = self.new_test_loop() + + async def main(): + tasks = (self.new_task(loop, func(i)) for i in range(10)) + done, pending = await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED) + self.assertEqual(len(done), 10) + self.assertEqual(len(pending), 0) + + loop.run_until_complete(main()) + + def test_as_completed(self): def gen(): diff --git a/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst b/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst new file mode 100644 index 000000000000..bdb46d08c5c4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst @@ -0,0 +1 @@ +:func:`asyncio.wait` now accepts generators yielding tasks. Patch by Kumar Aditya. From webhook-mailer at python.org Thu Mar 16 21:34:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 17 Mar 2023 01:34:56 -0000 Subject: [Python-checkins] Increase stack reserve size for Windows debug builds to avoid test crashes (GH-102764) Message-ID: https://github.com/python/cpython/commit/d025b1d2785ced8d436246aaf7627aa2c33493d4 commit: d025b1d2785ced8d436246aaf7627aa2c33493d4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-16T18:34:49-07:00 summary: Increase stack reserve size for Windows debug builds to avoid test crashes (GH-102764) (cherry picked from commit f33b33eb31c11a32b2955eb1f002f02267bd7d61) Co-authored-by: Steve Dower files: M PCbuild/python.vcxproj M PCbuild/pythonw.vcxproj diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj index d07db3a68150..f4640454a730 100644 --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -95,7 +95,7 @@ Console 2000000 - 4000000 + 8000000 diff --git a/PCbuild/pythonw.vcxproj b/PCbuild/pythonw.vcxproj index e7216dec3a1a..e23635e5ea94 100644 --- a/PCbuild/pythonw.vcxproj +++ b/PCbuild/pythonw.vcxproj @@ -89,7 +89,8 @@ - 2000000 + 2000000 + 8000000 From webhook-mailer at python.org Fri Mar 17 07:38:29 2023 From: webhook-mailer at python.org (zooba) Date: Fri, 17 Mar 2023 11:38:29 -0000 Subject: [Python-checkins] Increase stack reserve size for Windows debug builds to avoid test crashes (GH-102776) Message-ID: https://github.com/python/cpython/commit/744a41bf4963a5346f43ec8632a8becb5c0112e2 commit: 744a41bf4963a5346f43ec8632a8becb5c0112e2 branch: 3.10 author: Steve Dower committer: zooba date: 2023-03-17T11:37:56Z summary: Increase stack reserve size for Windows debug builds to avoid test crashes (GH-102776) files: M PCbuild/python.vcxproj M PCbuild/pythonw.vcxproj diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj index b6dcf1482354..0adce0958b17 100644 --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -94,7 +94,8 @@ Console - 2000000 + 2000000 + 8000000 diff --git a/PCbuild/pythonw.vcxproj b/PCbuild/pythonw.vcxproj index e7216dec3a1a..e23635e5ea94 100644 --- a/PCbuild/pythonw.vcxproj +++ b/PCbuild/pythonw.vcxproj @@ -89,7 +89,8 @@ - 2000000 + 2000000 + 8000000 From webhook-mailer at python.org Fri Mar 17 09:39:51 2023 From: webhook-mailer at python.org (methane) Date: Fri, 17 Mar 2023 13:39:51 -0000 Subject: [Python-checkins] gh-102701: Fix overflow in dictobject.c (GH-102750) Message-ID: https://github.com/python/cpython/commit/65fb7c4055f280caaa970939d16dd947e6df8a8d commit: 65fb7c4055f280caaa970939d16dd947e6df8a8d branch: main author: Inada Naoki committer: methane date: 2023-03-17T22:39:09+09:00 summary: gh-102701: Fix overflow in dictobject.c (GH-102750) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst M Lib/test/test_bigmem.py M Objects/dictobject.c diff --git a/Lib/test/test_bigmem.py b/Lib/test/test_bigmem.py index 859f1539e20b..c9ab1c1de9e1 100644 --- a/Lib/test/test_bigmem.py +++ b/Lib/test/test_bigmem.py @@ -1248,6 +1248,15 @@ def test_sort(self, size): self.assertEqual(l[-10:], [5] * 10) +class DictTest(unittest.TestCase): + + @bigmemtest(size=357913941, memuse=160) + def test_dict(self, size): + # https://github.com/python/cpython/issues/102701 + d = dict.fromkeys(range(size)) + d[size] = 1 + + if __name__ == '__main__': if len(sys.argv) > 1: support.set_memlimit(sys.argv[1]) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst new file mode 100644 index 000000000000..4e1f31893377 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst @@ -0,0 +1 @@ +Fix overflow when creating very large dict. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 227e438a8dff..53f9a380346a 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -596,7 +596,7 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) assert(log2_size >= PyDict_LOG_MINSIZE); - usable = USABLE_FRACTION(1< https://github.com/python/cpython/commit/f967aee4fbb9f417028426568230e2091d95f0fe commit: f967aee4fbb9f417028426568230e2091d95f0fe branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-17T07:54:18-07:00 summary: gh-102701: Fix overflow in dictobject.c (GH-102750) (cherry picked from commit 65fb7c4055f280caaa970939d16dd947e6df8a8d) Co-authored-by: Inada Naoki files: A Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst M Lib/test/test_bigmem.py M Objects/dictobject.c diff --git a/Lib/test/test_bigmem.py b/Lib/test/test_bigmem.py index 859f1539e20b..c9ab1c1de9e1 100644 --- a/Lib/test/test_bigmem.py +++ b/Lib/test/test_bigmem.py @@ -1248,6 +1248,15 @@ def test_sort(self, size): self.assertEqual(l[-10:], [5] * 10) +class DictTest(unittest.TestCase): + + @bigmemtest(size=357913941, memuse=160) + def test_dict(self, size): + # https://github.com/python/cpython/issues/102701 + d = dict.fromkeys(range(size)) + d[size] = 1 + + if __name__ == '__main__': if len(sys.argv) > 1: support.set_memlimit(sys.argv[1]) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst new file mode 100644 index 000000000000..4e1f31893377 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst @@ -0,0 +1 @@ +Fix overflow when creating very large dict. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 4a214f8cf5b7..69a4a865103c 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -600,7 +600,7 @@ new_keys_object(uint8_t log2_size, bool unicode) assert(log2_size >= PyDict_LOG_MINSIZE); - usable = USABLE_FRACTION(1< https://github.com/python/cpython/commit/174c4bfd0fee4622657a604af7a2e7d20a3f0dbc commit: 174c4bfd0fee4622657a604af7a2e7d20a3f0dbc branch: main author: Carl Meyer committer: carljm date: 2023-03-17T11:01:10-06:00 summary: gh-102781: fix cwd dependence in cases generator (#102782) files: M Tools/cases_generator/generate_cases.py diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index f1b655b8b054..a0bba65545d4 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -122,8 +122,9 @@ def __init__( self.prefix = " " * indent self.emit_line_directives = emit_line_directives self.lineno = 1 + filename = os.path.relpath(self.stream.name, ROOT) # Make filename more user-friendly and less platform-specific - filename = self.stream.name.replace("\\", "/") + filename = filename.replace("\\", "/") if filename.startswith("./"): filename = filename[2:] if filename.endswith(".new"): @@ -567,6 +568,7 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: with open(filename) as file: src = file.read() + filename = os.path.relpath(filename, ROOT) # Make filename more user-friendly and less platform-specific filename = filename.replace("\\", "/") if filename.startswith("./"): From webhook-mailer at python.org Fri Mar 17 15:06:59 2023 From: webhook-mailer at python.org (rhettinger) Date: Fri, 17 Mar 2023 19:06:59 -0000 Subject: [Python-checkins] Simplify and improve accuracy for subnormals in hypot() (GH-102785) Message-ID: https://github.com/python/cpython/commit/72186aa637bc88cd5f5e234803af64acab25994c commit: 72186aa637bc88cd5f5e234803af64acab25994c branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-17T14:06:52-05:00 summary: Simplify and improve accuracy for subnormals in hypot() (GH-102785) files: M Modules/mathmodule.c diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index ae9e3211c072..48cd9a642de1 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2498,7 +2498,7 @@ verified for 1 billion random inputs with n=5. [7] static inline double vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) { - double x, h, scale, oldcsum, csum = 1.0, frac1 = 0.0, frac2 = 0.0; + double x, h, scale, csum = 1.0, frac1 = 0.0, frac2 = 0.0; DoubleLength pr, sm; int max_e; Py_ssize_t i; @@ -2513,49 +2513,42 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) return max; } frexp(max, &max_e); - if (max_e >= -1023) { - scale = ldexp(1.0, -max_e); - assert(max * scale >= 0.5); - assert(max * scale < 1.0); + if (max_e < -1023) { + /* When max_e < -1023, ldexp(1.0, -max_e) would overflow. + So we first perform lossless scaling from subnormals back to normals, + then recurse back to vector_norm(), and then finally undo the scaling. + */ for (i=0 ; i < n ; i++) { - x = vec[i]; - assert(Py_IS_FINITE(x) && fabs(x) <= max); + vec[i] /= DBL_MIN; + } + return DBL_MIN * vector_norm(n, vec, max / DBL_MIN, found_nan); + } + scale = ldexp(1.0, -max_e); + assert(max * scale >= 0.5); + assert(max * scale < 1.0); + for (i=0 ; i < n ; i++) { + x = vec[i]; + assert(Py_IS_FINITE(x) && fabs(x) <= max); - x *= scale; - assert(fabs(x) < 1.0); + x *= scale; + assert(fabs(x) < 1.0); - pr = dl_mul(x, x); - assert(pr.hi <= 1.0); + pr = dl_mul(x, x); + assert(pr.hi <= 1.0); - sm = dl_fast_sum(csum, pr.hi); - csum = sm.hi; - frac1 += pr.lo; - frac2 += sm.lo; - } - h = sqrt(csum - 1.0 + (frac1 + frac2)); - pr = dl_mul(-h, h); sm = dl_fast_sum(csum, pr.hi); csum = sm.hi; frac1 += pr.lo; frac2 += sm.lo; - x = csum - 1.0 + (frac1 + frac2); - return (h + x / (2.0 * h)) / scale; } - /* When max_e < -1023, ldexp(1.0, -max_e) overflows. - So instead of multiplying by a scale, we just divide by *max*. - */ - for (i=0 ; i < n ; i++) { - x = vec[i]; - assert(Py_IS_FINITE(x) && fabs(x) <= max); - x /= max; - x = x*x; - assert(x <= 1.0); - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac1 += (oldcsum - csum) + x; - } - return max * sqrt(csum - 1.0 + frac1); + h = sqrt(csum - 1.0 + (frac1 + frac2)); + pr = dl_mul(-h, h); + sm = dl_fast_sum(csum, pr.hi); + csum = sm.hi; + frac1 += pr.lo; + frac2 += sm.lo; + x = csum - 1.0 + (frac1 + frac2); + return (h + x / (2.0 * h)) / scale; } #define NUM_STACK_ELEMS 16 From webhook-mailer at python.org Fri Mar 17 15:48:27 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 17 Mar 2023 19:48:27 -0000 Subject: [Python-checkins] [3.11] gh-102721: Improve coverage of `_collections_abc._CallableGenericAlias` (GH-102788) Message-ID: https://github.com/python/cpython/commit/045c8a1779036172f20d60bf206649c8823bb34b commit: 045c8a1779036172f20d60bf206649c8823bb34b branch: 3.11 author: Nikita Sobolev committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-17T12:48:06-07:00 summary: [3.11] gh-102721: Improve coverage of `_collections_abc._CallableGenericAlias` (GH-102788) This is a backport of https://github.com/python/cpython/pull/102722 without the `typing.py` changes. Automerge-Triggered-By: GH:AlexWaygood files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 96cffdeda9c0..4aa5faf9b3c9 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1916,14 +1916,29 @@ def test_weakref(self): self.assertEqual(weakref.ref(alias)(), alias) def test_pickle(self): + global T_pickle, P_pickle, TS_pickle # needed for pickling Callable = self.Callable - alias = Callable[[int, str], float] - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(alias, proto) - loaded = pickle.loads(s) - self.assertEqual(alias.__origin__, loaded.__origin__) - self.assertEqual(alias.__args__, loaded.__args__) - self.assertEqual(alias.__parameters__, loaded.__parameters__) + T_pickle = TypeVar('T_pickle') + P_pickle = ParamSpec('P_pickle') + TS_pickle = TypeVarTuple('TS_pickle') + + samples = [ + Callable[[int, str], float], + Callable[P_pickle, int], + Callable[P_pickle, T_pickle], + Callable[Concatenate[int, P_pickle], int], + Callable[Concatenate[*TS_pickle, P_pickle], int], + ] + for alias in samples: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(alias=alias, proto=proto): + s = pickle.dumps(alias, proto) + loaded = pickle.loads(s) + self.assertEqual(alias.__origin__, loaded.__origin__) + self.assertEqual(alias.__args__, loaded.__args__) + self.assertEqual(alias.__parameters__, loaded.__parameters__) + + del T_pickle, P_pickle, TS_pickle # cleaning up global state def test_var_substitution(self): Callable = self.Callable @@ -1949,6 +1964,16 @@ def test_var_substitution(self): self.assertEqual(C5[int, str, float], Callable[[typing.List[int], tuple[str, int], float], int]) + def test_type_subst_error(self): + Callable = self.Callable + P = ParamSpec('P') + T = TypeVar('T') + + pat = "Expected a list of types, an ellipsis, ParamSpec, or Concatenate." + + with self.assertRaisesRegex(TypeError, pat): + Callable[P, T][0, int] + def test_type_erasure(self): Callable = self.Callable class C1(Callable): From webhook-mailer at python.org Fri Mar 17 16:12:05 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 17 Mar 2023 20:12:05 -0000 Subject: [Python-checkins] [3.10] gh-102721: Improve coverage of `_collections_abc._CallableGenericAlias` (GH-102790) Message-ID: https://github.com/python/cpython/commit/e732a859340353e982c69a80b753830756ee85bf commit: e732a859340353e982c69a80b753830756ee85bf branch: 3.10 author: Nikita Sobolev committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-17T13:11:58-07:00 summary: [3.10] gh-102721: Improve coverage of `_collections_abc._CallableGenericAlias` (GH-102790) This is a manual backport of https://github.com/python/cpython/pull/102722 but without `typing.py` changes and without `TypeVarTuple` case, because it was added in 3.11 Automerge-Triggered-By: GH:AlexWaygood files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index a4d243400d17..68dfedfb6a0d 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -556,14 +556,27 @@ def test_weakref(self): self.assertEqual(weakref.ref(alias)(), alias) def test_pickle(self): + global T_pickle, P_pickle # needed for pickling Callable = self.Callable - alias = Callable[[int, str], float] - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(alias, proto) - loaded = pickle.loads(s) - self.assertEqual(alias.__origin__, loaded.__origin__) - self.assertEqual(alias.__args__, loaded.__args__) - self.assertEqual(alias.__parameters__, loaded.__parameters__) + T_pickle = TypeVar('T_pickle') + P_pickle = ParamSpec('P_pickle') + + samples = [ + Callable[[int, str], float], + Callable[P_pickle, int], + Callable[P_pickle, T_pickle], + Callable[Concatenate[int, P_pickle], int], + ] + for alias in samples: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(alias=alias, proto=proto): + s = pickle.dumps(alias, proto) + loaded = pickle.loads(s) + self.assertEqual(alias.__origin__, loaded.__origin__) + self.assertEqual(alias.__args__, loaded.__args__) + self.assertEqual(alias.__parameters__, loaded.__parameters__) + + del T_pickle, P_pickle # cleaning up global state def test_var_substitution(self): Callable = self.Callable @@ -590,6 +603,16 @@ def test_var_substitution(self): self.assertEqual(C5[int, str, float], Callable[[typing.List[int], tuple[str, int], float], int]) + def test_type_subst_error(self): + Callable = self.Callable + P = ParamSpec('P') + T = TypeVar('T') + + pat = "Expected a list of types, an ellipsis, ParamSpec, or Concatenate." + + with self.assertRaisesRegex(TypeError, pat): + Callable[P, T][0, int] + def test_type_erasure(self): Callable = self.Callable class C1(Callable): From webhook-mailer at python.org Sat Mar 18 03:19:57 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sat, 18 Mar 2023 07:19:57 -0000 Subject: [Python-checkins] gh-102799: remove unnecessary calls to sys.exc_info() in tests (#102800) Message-ID: https://github.com/python/cpython/commit/b3cc11a08e1e9121ddba3b9afb9fae032e86f449 commit: b3cc11a08e1e9121ddba3b9afb9fae032e86f449 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-18T07:19:38Z summary: gh-102799: remove unnecessary calls to sys.exc_info() in tests (#102800) files: M Lib/test/test_asyncio/test_unix_events.py M Lib/test/test_exceptions.py M Lib/test/test_socket.py M Lib/test/test_sys.py M Lib/test/test_traceback.py diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index 33d0ea15c6de..96999470a7c6 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -1889,8 +1889,8 @@ async def test_fork_not_share_event_loop(self): os.write(w, b'LOOP:' + str(id(loop)).encode()) except RuntimeError: os.write(w, b'NO LOOP') - except: - os.write(w, b'ERROR:' + ascii(sys.exc_info()).encode()) + except BaseException as e: + os.write(w, b'ERROR:' + ascii(e).encode()) finally: os._exit(0) else: diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 4ae71e431c56..284f26be7177 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -599,8 +599,8 @@ def test_notes(self): def testWithTraceback(self): try: raise IndexError(4) - except: - tb = sys.exc_info()[2] + except Exception as e: + tb = e.__traceback__ e = BaseException().with_traceback(tb) self.assertIsInstance(e, BaseException) @@ -653,8 +653,8 @@ def test_invalid_delattr(self): def testNoneClearsTracebackAttr(self): try: raise IndexError(4) - except: - tb = sys.exc_info()[2] + except Exception as e: + tb = e.__traceback__ e = Exception() e.__traceback__ = tb @@ -1337,11 +1337,11 @@ class MyException(Exception, metaclass=Meta): def g(): try: return g() - except RecursionError: - return sys.exc_info() - e, v, tb = g() - self.assertIsInstance(v, RecursionError, type(v)) - self.assertIn("maximum recursion depth exceeded", str(v)) + except RecursionError as e: + return e + exc = g() + self.assertIsInstance(exc, RecursionError, type(exc)) + self.assertIn("maximum recursion depth exceeded", str(exc)) @cpython_only diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index a313da29b4a4..60f106f2d1a1 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -5492,10 +5492,10 @@ def alarm_handler(signal, frame): self.fail("caught timeout instead of Alarm") except Alarm: pass - except: + except BaseException as e: self.fail("caught other exception instead of Alarm:" " %s(%s):\n%s" % - (sys.exc_info()[:2] + (traceback.format_exc(),))) + (type(e), e, traceback.format_exc())) else: self.fail("nothing caught") finally: diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index b839985def9a..fb578c5ae6e5 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1649,8 +1649,8 @@ def test_pythontypes(self): check(_ast.AST(), size('P')) try: raise TypeError - except TypeError: - tb = sys.exc_info()[2] + except TypeError as e: + tb = e.__traceback__ # traceback if tb is not None: check(tb, size('2P2i')) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 7ef93b3f0ac3..1c5d1ab82c8e 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -296,15 +296,15 @@ class PrintExceptionAtExit(object): def __init__(self): try: x = 1 / 0 - except Exception: - self.exc_info = sys.exc_info() - # self.exc_info[1] (traceback) contains frames: + except Exception as e: + self.exc = e + # self.exc.__traceback__ contains frames: # explicitly clear the reference to self in the current # frame to break a reference cycle self = None def __del__(self): - traceback.print_exception(*self.exc_info) + traceback.print_exception(self.exc) # Keep a reference in the module namespace to call the destructor # when the module is unloaded @@ -923,8 +923,8 @@ def check_traceback_format(self, cleanup_func=None): from _testcapi import traceback_print try: self.some_exception() - except KeyError: - type_, value, tb = sys.exc_info() + except KeyError as e: + tb = e.__traceback__ if cleanup_func is not None: # Clear the inner frames, not this one cleanup_func(tb.tb_next) @@ -1228,8 +1228,8 @@ def __eq__(self, other): except UnhashableException: try: raise ex1 - except UnhashableException: - exc_type, exc_val, exc_tb = sys.exc_info() + except UnhashableException as e: + exc_val = e with captured_output("stderr") as stderr_f: exception_print(exc_val) @@ -2133,8 +2133,8 @@ def assertEqualExcept(actual, expected, ignore): def test_extract_tb(self): try: self.last_raises5() - except Exception: - exc_type, exc_value, tb = sys.exc_info() + except Exception as e: + tb = e.__traceback__ def extract(**kwargs): return traceback.extract_tb(tb, **kwargs) @@ -2160,12 +2160,12 @@ def extract(**kwargs): def test_format_exception(self): try: self.last_raises5() - except Exception: - exc_type, exc_value, tb = sys.exc_info() + except Exception as e: + exc = e # [1:-1] to exclude "Traceback (...)" header and # exception type and value def extract(**kwargs): - return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1] + return traceback.format_exception(exc, **kwargs)[1:-1] with support.swap_attr(sys, 'tracebacklimit', 1000): nolim = extract() @@ -2203,8 +2203,8 @@ def inner(): try: outer() - except: - type_, value, tb = sys.exc_info() + except BaseException as e: + tb = e.__traceback__ # Initial assertion: there's one local in the inner frame. inner_frame = tb.tb_next.tb_next.tb_next.tb_frame @@ -2282,8 +2282,8 @@ def deeper(): def test_walk_tb(self): try: 1/0 - except Exception: - _, _, tb = sys.exc_info() + except Exception as e: + tb = e.__traceback__ s = list(traceback.walk_tb(tb)) self.assertEqual(len(s), 1) @@ -2386,10 +2386,10 @@ def f(): def g(): try: f() - except: - return sys.exc_info() + except Exception as e: + return e.__traceback__ - exc_info = g() + tb = g() class Skip_G(traceback.StackSummary): def format_frame_summary(self, frame_summary): @@ -2398,7 +2398,7 @@ def format_frame_summary(self, frame_summary): return super().format_frame_summary(frame_summary) stack = Skip_G.extract( - traceback.walk_tb(exc_info[2])).format() + traceback.walk_tb(tb)).format() self.assertEqual(len(stack), 1) lno = f.__code__.co_firstlineno + 1 @@ -2416,17 +2416,17 @@ class TestTracebackException(unittest.TestCase): def test_smoke(self): try: 1/0 - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(e.__traceback__)) self.assertEqual(None, exc.__cause__) self.assertEqual(None, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_from_exception(self): # Check all the parameters are accepted. @@ -2435,9 +2435,10 @@ def foo(): try: foo() except Exception as e: - exc_info = sys.exc_info() + exc_obj = e + tb = e.__traceback__ self.expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False, + traceback.walk_tb(tb), limit=1, lookup_lines=False, capture_locals=True) self.exc = traceback.TracebackException.from_exception( e, limit=1, lookup_lines=False, capture_locals=True) @@ -2447,8 +2448,8 @@ def foo(): self.assertEqual(None, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_cause(self): try: @@ -2459,18 +2460,18 @@ def test_cause(self): exc_context = traceback.TracebackException(*exc_info_context) cause = Exception("cause") raise Exception("uh oh") from cause - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(e.__traceback__)) exc_cause = traceback.TracebackException(Exception, cause, None) self.assertEqual(exc_cause, exc.__cause__) self.assertEqual(exc_context, exc.__context__) self.assertEqual(True, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_context(self): try: @@ -2480,17 +2481,17 @@ def test_context(self): exc_info_context = sys.exc_info() exc_context = traceback.TracebackException(*exc_info_context) raise Exception("uh oh") - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(e.__traceback__)) self.assertEqual(None, exc.__cause__) self.assertEqual(exc_context, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_long_context_chain(self): def f(): @@ -2501,12 +2502,12 @@ def f(): try: f() - except RecursionError: - exc_info = sys.exc_info() + except RecursionError as e: + exc_obj = e else: self.fail("Exception not raised") - te = traceback.TracebackException(*exc_info) + te = traceback.TracebackException.from_exception(exc_obj) res = list(te.format()) # many ZeroDiv errors followed by the RecursionError @@ -2524,18 +2525,18 @@ def test_compact_with_cause(self): finally: cause = Exception("cause") raise Exception("uh oh") from cause - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info, compact=True) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj, compact=True) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(exc_obj.__traceback__)) exc_cause = traceback.TracebackException(Exception, cause, None) self.assertEqual(exc_cause, exc.__cause__) self.assertEqual(None, exc.__context__) self.assertEqual(True, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_compact_no_cause(self): try: @@ -2545,37 +2546,37 @@ def test_compact_no_cause(self): exc_info_context = sys.exc_info() exc_context = traceback.TracebackException(*exc_info_context) raise Exception("uh oh") - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info, compact=True) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e, compact=True) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(exc_obj.__traceback__)) self.assertEqual(None, exc.__cause__) self.assertEqual(exc_context, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_no_refs_to_exception_and_traceback_objects(self): try: 1/0 - except Exception: - exc_info = sys.exc_info() + except Exception as e: + exc_obj = e - refcnt1 = sys.getrefcount(exc_info[1]) - refcnt2 = sys.getrefcount(exc_info[2]) - exc = traceback.TracebackException(*exc_info) - self.assertEqual(sys.getrefcount(exc_info[1]), refcnt1) - self.assertEqual(sys.getrefcount(exc_info[2]), refcnt2) + refcnt1 = sys.getrefcount(exc_obj) + refcnt2 = sys.getrefcount(exc_obj.__traceback__) + exc = traceback.TracebackException.from_exception(exc_obj) + self.assertEqual(sys.getrefcount(exc_obj), refcnt1) + self.assertEqual(sys.getrefcount(exc_obj.__traceback__), refcnt2) def test_comparison_basic(self): try: 1/0 - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) - exc2 = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj) + exc2 = traceback.TracebackException.from_exception(exc_obj) self.assertIsNot(exc, exc2) self.assertEqual(exc, exc2) self.assertNotEqual(exc, object()) @@ -2594,28 +2595,28 @@ def raise_with_locals(): try: raise_with_locals() - except Exception: - exc_info = sys.exc_info() + except Exception as e: + exc_obj = e - exc = traceback.TracebackException(*exc_info) - exc1 = traceback.TracebackException(*exc_info, limit=10) - exc2 = traceback.TracebackException(*exc_info, limit=2) + exc = traceback.TracebackException.from_exception(exc_obj) + exc1 = traceback.TracebackException.from_exception(exc_obj, limit=10) + exc2 = traceback.TracebackException.from_exception(exc_obj, limit=2) self.assertEqual(exc, exc1) # limit=10 gets all frames self.assertNotEqual(exc, exc2) # limit=2 truncates the output # locals change the output - exc3 = traceback.TracebackException(*exc_info, capture_locals=True) + exc3 = traceback.TracebackException.from_exception(exc_obj, capture_locals=True) self.assertNotEqual(exc, exc3) # there are no locals in the innermost frame - exc4 = traceback.TracebackException(*exc_info, limit=-1) - exc5 = traceback.TracebackException(*exc_info, limit=-1, capture_locals=True) + exc4 = traceback.TracebackException.from_exception(exc_obj, limit=-1) + exc5 = traceback.TracebackException.from_exception(exc_obj, limit=-1, capture_locals=True) self.assertEqual(exc4, exc5) # there are locals in the next-to-innermost frame - exc6 = traceback.TracebackException(*exc_info, limit=-2) - exc7 = traceback.TracebackException(*exc_info, limit=-2, capture_locals=True) + exc6 = traceback.TracebackException.from_exception(exc_obj, limit=-2) + exc7 = traceback.TracebackException.from_exception(exc_obj, limit=-2, capture_locals=True) self.assertNotEqual(exc6, exc7) def test_comparison_equivalent_exceptions_are_equal(self): @@ -2623,8 +2624,8 @@ def test_comparison_equivalent_exceptions_are_equal(self): for _ in range(2): try: 1/0 - except: - excs.append(traceback.TracebackException(*sys.exc_info())) + except Exception as e: + excs.append(traceback.TracebackException.from_exception(e)) self.assertEqual(excs[0], excs[1]) self.assertEqual(list(excs[0].format()), list(excs[1].format())) @@ -2640,9 +2641,9 @@ def __eq__(self, other): except UnhashableException: try: raise ex1 - except UnhashableException: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except UnhashableException as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj) formatted = list(exc.format()) self.assertIn('UnhashableException: ex2\n', formatted[2]) self.assertIn('UnhashableException: ex1\n', formatted[6]) @@ -2655,11 +2656,10 @@ def recurse(n): 1/0 try: recurse(10) - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info, limit=5) + except Exception as e: + exc = traceback.TracebackException.from_exception(e, limit=5) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2]), limit=5) + traceback.walk_tb(e.__traceback__), limit=5) self.assertEqual(expected_stack, exc.stack) def test_lookup_lines(self): @@ -2706,9 +2706,9 @@ def f(): x = 12 try: x/0 - except Exception: - return sys.exc_info() - exc = traceback.TracebackException(*f(), capture_locals=True) + except Exception as e: + return e + exc = traceback.TracebackException.from_exception(f(), capture_locals=True) output = StringIO() exc.print(file=output) self.assertEqual( @@ -2723,7 +2723,7 @@ def f(): class TestTracebackException_ExceptionGroups(unittest.TestCase): def setUp(self): super().setUp() - self.eg_info = self._get_exception_group() + self.eg = self._get_exception_group() def _get_exception_group(self): def f(): @@ -2753,26 +2753,26 @@ def g(v): except Exception as e: exc4 = e raise ExceptionGroup("eg2", [exc3, exc4]) - except ExceptionGroup: - return sys.exc_info() + except ExceptionGroup as eg: + return eg self.fail('Exception Not Raised') def test_exception_group_construction(self): - eg_info = self.eg_info - teg1 = traceback.TracebackException(*eg_info) - teg2 = traceback.TracebackException.from_exception(eg_info[1]) + eg = self.eg + teg1 = traceback.TracebackException(type(eg), eg, eg.__traceback__) + teg2 = traceback.TracebackException.from_exception(eg) self.assertIsNot(teg1, teg2) self.assertEqual(teg1, teg2) def test_exception_group_format_exception_only(self): - teg = traceback.TracebackException(*self.eg_info) + teg = traceback.TracebackException.from_exception(self.eg) formatted = ''.join(teg.format_exception_only()).split('\n') expected = "ExceptionGroup: eg2 (2 sub-exceptions)\n".split('\n') self.assertEqual(formatted, expected) def test_exception_group_format(self): - teg = traceback.TracebackException(*self.eg_info) + teg = traceback.TracebackException.from_exception(self.eg) formatted = ''.join(teg.format()).split('\n') lno_f = self.lno_f @@ -2884,18 +2884,18 @@ def test_max_group_depth(self): def test_comparison(self): try: - raise self.eg_info[1] - except ExceptionGroup: - exc_info = sys.exc_info() + raise self.eg + except ExceptionGroup as e: + exc = e for _ in range(5): try: - raise exc_info[1] - except: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) - exc2 = traceback.TracebackException(*exc_info) - exc3 = traceback.TracebackException(*exc_info, limit=300) - ne = traceback.TracebackException(*exc_info, limit=3) + raise exc + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj) + exc2 = traceback.TracebackException.from_exception(exc_obj) + exc3 = traceback.TracebackException.from_exception(exc_obj, limit=300) + ne = traceback.TracebackException.from_exception(exc_obj, limit=3) self.assertIsNot(exc, exc2) self.assertEqual(exc, exc2) self.assertEqual(exc, exc3) From webhook-mailer at python.org Sat Mar 18 06:59:28 2023 From: webhook-mailer at python.org (markshannon) Date: Sat, 18 Mar 2023 10:59:28 -0000 Subject: [Python-checkins] gh-101975: Fixed a potential SegFault on garbage collection (GH-102803) Message-ID: https://github.com/python/cpython/commit/039714d00f147be4d018fa6aeaf174aad7e8fa32 commit: 039714d00f147be4d018fa6aeaf174aad7e8fa32 branch: main author: gaogaotiantian committer: markshannon date: 2023-03-18T10:59:21Z summary: gh-101975: Fixed a potential SegFault on garbage collection (GH-102803) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst M Python/ceval_macros.h diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst new file mode 100644 index 000000000000..28c9a8465180 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst @@ -0,0 +1 @@ +Fixed ``stacktop`` value on tracing entries to avoid corruption on garbage collection. diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 98b72ec1b364..c2257515a305 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -310,6 +310,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { _PyFrame_SetStackPointer(frame, stack_pointer); \ int err = trace_function_entry(tstate, frame); \ stack_pointer = _PyFrame_GetStackPointer(frame); \ + frame->stacktop = -1; \ if (err) { \ goto error; \ } \ From webhook-mailer at python.org Sat Mar 18 07:47:18 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sat, 18 Mar 2023 11:47:18 -0000 Subject: [Python-checkins] gh-102778: Add sys.last_exc, deprecate sys.last_type, sys.last_value, sys.last_traceback (#102779) Message-ID: https://github.com/python/cpython/commit/e1e9bab0061e8d4bd7b94ed455f3bb7bf8633ae7 commit: e1e9bab0061e8d4bd7b94ed455f3bb7bf8633ae7 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-18T11:47:11Z summary: gh-102778: Add sys.last_exc, deprecate sys.last_type, sys.last_value,sys.last_traceback (#102779) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst M Doc/library/sys.rst M Doc/whatsnew/3.12.rst M Include/internal/pycore_global_objects_fini_generated.h M Include/internal/pycore_global_strings.h M Include/internal/pycore_runtime_init_generated.h M Include/internal/pycore_unicodeobject_generated.h M Lib/code.py M Lib/dis.py M Lib/idlelib/idle_test/test_stackviewer.py M Lib/idlelib/pyshell.py M Lib/idlelib/run.py M Lib/idlelib/stackviewer.py M Lib/pdb.py M Lib/pydoc_data/topics.py M Lib/test/test_dis.py M Lib/test/test_ttk/test_extensions.py M Lib/tkinter/__init__.py M Lib/traceback.py M Python/pylifecycle.c M Python/pythonrun.c M Python/sysmodule.c diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index a53d4908783e..b3b9b5e74ac0 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1102,22 +1102,25 @@ always available. .. versionadded:: 3.5 +.. data:: last_exc + + This variable is not always defined; it is set to the exception instance + when an exception is not handled and the interpreter prints an error message + and a stack traceback. Its intended use is to allow an interactive user to + import a debugger module and engage in post-mortem debugging without having + to re-execute the command that caused the error. (Typical use is + ``import pdb; pdb.pm()`` to enter the post-mortem debugger; see :mod:`pdb` + module for more information.) + + .. versionadded:: 3.12 .. data:: last_type last_value last_traceback - These three variables are not always defined; they are set when an exception is - not handled and the interpreter prints an error message and a stack traceback. - Their intended use is to allow an interactive user to import a debugger module - and engage in post-mortem debugging without having to re-execute the command - that caused the error. (Typical use is ``import pdb; pdb.pm()`` to enter the - post-mortem debugger; see :mod:`pdb` module for - more information.) - - The meaning of the variables is the same as that of the return values from - :func:`exc_info` above. - + These three variables are deprecated; use :data:`sys.last_exc` instead. + They hold the legacy representation of ``sys.last_exc``, as returned + from :func:`exc_info` above. .. data:: maxsize diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b55b9619fac2..32fec962560a 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -397,6 +397,12 @@ sys with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) +* Add :data:`sys.last_exc` which holds the last unhandled exception that + was raised (for post-mortem debugging use cases). Deprecate the + three fields that have the same information in its legacy form: + :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`. + (Contributed by Irit Katriel in :gh:`102778`.) + Optimizations ============= @@ -488,6 +494,10 @@ Deprecated contain the creation time, which is also available in the new ``st_birthtime`` field. (Contributed by Steve Dower in :gh:`99726`.) +* The :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback` + fields are deprecated. Use :data:`sys.last_exc` instead. + (Contributed by Irit Katriel in :gh:`102778`.) + Pending Removal in Python 3.13 ------------------------------ diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4b12ae523c32..14dfd9ea5823 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -995,6 +995,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(kw2)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(lambda)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_exc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_node)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_traceback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_type)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 17fb9ffbbf9f..6f430bb25eb8 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -481,6 +481,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(kw2) STRUCT_FOR_ID(lambda) STRUCT_FOR_ID(last) + STRUCT_FOR_ID(last_exc) STRUCT_FOR_ID(last_node) STRUCT_FOR_ID(last_traceback) STRUCT_FOR_ID(last_type) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index b240be57369d..0452c4c61551 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -987,6 +987,7 @@ extern "C" { INIT_ID(kw2), \ INIT_ID(lambda), \ INIT_ID(last), \ + INIT_ID(last_exc), \ INIT_ID(last_node), \ INIT_ID(last_traceback), \ INIT_ID(last_type), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index fea9b6dbb1a7..0a8865942e6d 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1296,6 +1296,9 @@ _PyUnicode_InitStaticStrings(void) { string = &_Py_ID(last); assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); + string = &_Py_ID(last_exc); + assert(_PyUnicode_CheckConsistency(string, 1)); + PyUnicode_InternInPlace(&string); string = &_Py_ID(last_node); assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); diff --git a/Lib/code.py b/Lib/code.py index 76000f8c8b2c..2bd5fa3e795a 100644 --- a/Lib/code.py +++ b/Lib/code.py @@ -106,6 +106,7 @@ def showsyntaxerror(self, filename=None): """ type, value, tb = sys.exc_info() + sys.last_exc = value sys.last_type = type sys.last_value = value sys.last_traceback = tb @@ -119,7 +120,7 @@ def showsyntaxerror(self, filename=None): else: # Stuff in the right filename value = SyntaxError(msg, (filename, lineno, offset, line)) - sys.last_value = value + sys.last_exc = sys.last_value = value if sys.excepthook is sys.__excepthook__: lines = traceback.format_exception_only(type, value) self.write(''.join(lines)) @@ -138,6 +139,7 @@ def showtraceback(self): """ sys.last_type, sys.last_value, last_tb = ei = sys.exc_info() sys.last_traceback = last_tb + sys.last_exc = ei[1] try: lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next) if sys.excepthook is sys.__excepthook__: diff --git a/Lib/dis.py b/Lib/dis.py index 9edde6ae8258..c3d152b4de04 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -118,7 +118,10 @@ def distb(tb=None, *, file=None, show_caches=False, adaptive=False): """Disassemble a traceback (default: last traceback).""" if tb is None: try: - tb = sys.last_traceback + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback except AttributeError: raise RuntimeError("no last traceback to disassemble") from None while tb.tb_next: tb = tb.tb_next diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py index 98f53f9537bb..f4626bb1702a 100644 --- a/Lib/idlelib/idle_test/test_stackviewer.py +++ b/Lib/idlelib/idle_test/test_stackviewer.py @@ -19,6 +19,7 @@ def setUpClass(cls): except NameError: svs.last_type, svs.last_value, svs.last_traceback = ( sys.exc_info()) + svs.last_exc = svs.last_value requires('gui') cls.root = Tk() @@ -27,7 +28,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): svs = stackviewer.sys - del svs.last_traceback, svs.last_type, svs.last_value + del svs.last_exc, svs.last_traceback, svs.last_type, svs.last_value cls.root.update_idletasks() ## for id in cls.root.tk.call('after', 'info'): diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index e68233a5a413..edc77ff26f62 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1367,11 +1367,14 @@ def open_stack_viewer(self, event=None): if self.interp.rpcclt: return self.interp.remote_stack_viewer() try: - sys.last_traceback + if hasattr(sys, 'last_exc'): + sys.last_exc.__traceback__ + else: + sys.last_traceback except: messagebox.showerror("No stack trace", "There is no stack trace yet.\n" - "(sys.last_traceback is not defined)", + "(sys.last_exc and sys.last_traceback are not defined)", parent=self.text) return from idlelib.stackviewer import StackBrowser diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 577c49eb67b2..6a7b50cf5cfb 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -239,6 +239,7 @@ def print_exception(): efile = sys.stderr typ, val, tb = excinfo = sys.exc_info() sys.last_type, sys.last_value, sys.last_traceback = excinfo + sys.last_exc = val seen = set() def print_exc(typ, exc, tb): @@ -629,6 +630,7 @@ def stackviewer(self, flist_oid=None): flist = self.rpchandler.get_remote_proxy(flist_oid) while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]: tb = tb.tb_next + sys.last_exc = val sys.last_type = typ sys.last_value = val item = stackviewer.StackTreeItem(flist, tb) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 94ffb4eff4dd..702fd32ca5d1 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -27,7 +27,10 @@ def __init__(self, flist=None, tb=None): def get_stack(self, tb): if tb is None: - tb = sys.last_traceback + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback stack = [] if tb and tb.tb_frame is None: tb = tb.tb_next @@ -37,11 +40,15 @@ def get_stack(self, tb): return stack def get_exception(self): - type = sys.last_type - value = sys.last_value - if hasattr(type, "__name__"): - type = type.__name__ - s = str(type) + if hasattr(sys, 'last_exc'): + typ = type(sys.last_exc) + value = sys.last_exc + else: + typ = sys.last_type + value = sys.last_value + if hasattr(typ, "__name__"): + typ = typ.__name__ + s = str(typ) if value is not None: s = s + ": " + str(value) return s @@ -136,6 +143,7 @@ def _stack_viewer(parent): # htest # except NameError: exc_type, exc_value, exc_tb = sys.exc_info() # inject stack trace to sys + sys.last_exc = exc_value sys.last_type = exc_type sys.last_value = exc_value sys.last_traceback = exc_tb @@ -143,6 +151,7 @@ def _stack_viewer(parent): # htest # StackBrowser(top, flist=flist, top=top, tb=exc_tb) # restore sys to original state + del sys.last_exc del sys.last_type del sys.last_value del sys.last_traceback diff --git a/Lib/pdb.py b/Lib/pdb.py index f11fc5553681..3543f53282db 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1739,7 +1739,11 @@ def post_mortem(t=None): def pm(): """Enter post-mortem debugging of the traceback found in sys.last_traceback.""" - post_mortem(sys.last_traceback) + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback + post_mortem(tb) # Main program for testing diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 573065b4b714..ad1b6aca6b95 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -4799,7 +4799,7 @@ 'pdb.pm()\n' '\n' ' Enter post-mortem debugging of the traceback found in\n' - ' "sys.last_traceback".\n' + ' "sys.last_exc".\n' '\n' 'The "run*" functions and "set_trace()" are aliases for ' 'instantiating\n' @@ -13858,7 +13858,7 @@ 'if\n' ' the interpreter is interactive, it is also made available to ' 'the\n' - ' user as "sys.last_traceback".\n' + ' user as "sys.last_exc".\n' '\n' ' For explicitly created tracebacks, it is up to the creator ' 'of\n' diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index b77e3b06d0c1..fa1de1c7ded1 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1026,6 +1026,10 @@ def test_disassemble_try_finally(self): self.do_disassembly_test(_tryfinallyconst, dis_tryfinallyconst) def test_dis_none(self): + try: + del sys.last_exc + except AttributeError: + pass try: del sys.last_traceback except AttributeError: @@ -1043,7 +1047,7 @@ def test_dis_traceback(self): 1/0 except Exception as e: tb = e.__traceback__ - sys.last_traceback = tb + sys.last_exc = e tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti) self.do_disassembly_test(None, tb_dis, True) @@ -1900,6 +1904,10 @@ def test_findlabels(self): class TestDisTraceback(DisTestBase): def setUp(self) -> None: + try: # We need to clean up existing tracebacks + del sys.last_exc + except AttributeError: + pass try: # We need to clean up existing tracebacks del sys.last_traceback except AttributeError: diff --git a/Lib/test/test_ttk/test_extensions.py b/Lib/test/test_ttk/test_extensions.py index 6135c49701f0..d5e069716971 100644 --- a/Lib/test/test_ttk/test_extensions.py +++ b/Lib/test/test_ttk/test_extensions.py @@ -45,7 +45,9 @@ def test_widget_destroy(self): # value which causes the tracing callback to be called and then # it tries calling instance attributes not yet defined. ttk.LabeledScale(self.root, variable=myvar) - if hasattr(sys, 'last_type'): + if hasattr(sys, 'last_exc'): + self.assertNotEqual(type(sys.last_exc), tkinter.TclError) + elif hasattr(sys, 'last_type'): self.assertNotEqual(sys.last_type, tkinter.TclError) def test_initialization(self): diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 7565e0f7e460..479daf0e5abf 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2400,6 +2400,7 @@ def report_callback_exception(self, exc, val, tb): should when sys.stderr is None.""" import traceback print("Exception in Tkinter callback", file=sys.stderr) + sys.last_exc = val sys.last_type = exc sys.last_value = val sys.last_traceback = tb diff --git a/Lib/traceback.py b/Lib/traceback.py index c43c4720ae5a..9e720ac9948f 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -179,7 +179,7 @@ def _safe_string(value, what, func=str): # -- def print_exc(limit=None, file=None, chain=True): - """Shorthand for 'print_exception(*sys.exc_info(), limit, file)'.""" + """Shorthand for 'print_exception(*sys.exc_info(), limit, file, chain)'.""" print_exception(*sys.exc_info(), limit=limit, file=file, chain=chain) def format_exc(limit=None, chain=True): @@ -187,12 +187,16 @@ def format_exc(limit=None, chain=True): return "".join(format_exception(*sys.exc_info(), limit=limit, chain=chain)) def print_last(limit=None, file=None, chain=True): - """This is a shorthand for 'print_exception(sys.last_type, - sys.last_value, sys.last_traceback, limit, file)'.""" - if not hasattr(sys, "last_type"): + """This is a shorthand for 'print_exception(sys.last_exc, limit, file, chain)'.""" + if not hasattr(sys, "last_exc") and not hasattr(sys, "last_type"): raise ValueError("no last exception") - print_exception(sys.last_type, sys.last_value, sys.last_traceback, - limit, file, chain) + + if hasattr(sys, "last_exc"): + print_exception(sys.last_exc, limit, file, chain) + else: + print_exception(sys.last_type, sys.last_value, sys.last_traceback, + limit, file, chain) + # # Printing and Extracting Stacks. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst new file mode 100644 index 000000000000..b5da227afa5a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst @@ -0,0 +1,3 @@ +Add :data:`sys.last_exc` and deprecate :data:`sys.last_type`, :data:`sys.last_value` +and :data:`sys.last_traceback`, +which hold the same information in its legacy form. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d0c65cc1f7fd..7bf12271db23 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1304,7 +1304,7 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose) { // List of names to clear in sys static const char * const sys_deletes[] = { - "path", "argv", "ps1", "ps2", + "path", "argv", "ps1", "ps2", "last_exc", "last_type", "last_value", "last_traceback", "__interactivehook__", // path_hooks and path_importer_cache are cleared diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 07d119a67847..6ea185a1b75b 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -776,6 +776,10 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) } if (set_sys_last_vars) { + if (_PySys_SetAttr(&_Py_ID(last_exc), exc) < 0) { + _PyErr_Clear(tstate); + } + /* Legacy version: */ if (_PySys_SetAttr(&_Py_ID(last_type), typ) < 0) { _PyErr_Clear(tstate); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index cc5b9a6d418b..126b7d422e00 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2670,11 +2670,13 @@ stderr -- standard error object; used for error messages\n\ By assigning other file objects (or objects that behave like files)\n\ to these, it is possible to redirect all of the interpreter's I/O.\n\ \n\ +last_exc - the last uncaught exception\n\ + Only available in an interactive session after a\n\ + traceback has been printed.\n\ last_type -- type of last uncaught exception\n\ last_value -- value of last uncaught exception\n\ last_traceback -- traceback of last uncaught exception\n\ - These three are only available in an interactive session after a\n\ - traceback has been printed.\n\ + These three are the (deprecated) legacy representation of last_exc.\n\ " ) /* concatenating string here */ From webhook-mailer at python.org Sat Mar 18 09:44:54 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sat, 18 Mar 2023 13:44:54 -0000 Subject: [Python-checkins] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102769) Message-ID: https://github.com/python/cpython/commit/1cb75a9ce0c41fb9567f0750b9811268a189ec72 commit: 1cb75a9ce0c41fb9567f0750b9811268a189ec72 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-18T13:44:47Z summary: gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102769) files: M Python/errors.c diff --git a/Python/errors.c b/Python/errors.c index bdcbac317eb9..ab14770c6e81 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -666,17 +666,15 @@ _PyErr_ChainExceptions(PyObject *typ, PyObject *val, PyObject *tb) } if (_PyErr_Occurred(tstate)) { - PyObject *typ2, *val2, *tb2; - _PyErr_Fetch(tstate, &typ2, &val2, &tb2); _PyErr_NormalizeException(tstate, &typ, &val, &tb); if (tb != NULL) { PyException_SetTraceback(val, tb); Py_DECREF(tb); } Py_DECREF(typ); - _PyErr_NormalizeException(tstate, &typ2, &val2, &tb2); - PyException_SetContext(val2, val); - _PyErr_Restore(tstate, typ2, val2, tb2); + PyObject *exc2 = _PyErr_GetRaisedException(tstate); + PyException_SetContext(exc2, val); + _PyErr_SetRaisedException(tstate, exc2); } else { _PyErr_Restore(tstate, typ, val, tb); @@ -757,27 +755,15 @@ static PyObject * _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception, const char *format, va_list vargs) { - PyObject *exc, *val, *val2, *tb; - assert(_PyErr_Occurred(tstate)); - _PyErr_Fetch(tstate, &exc, &val, &tb); - _PyErr_NormalizeException(tstate, &exc, &val, &tb); - if (tb != NULL) { - PyException_SetTraceback(val, tb); - Py_DECREF(tb); - } - Py_DECREF(exc); + PyObject *exc = _PyErr_GetRaisedException(tstate); assert(!_PyErr_Occurred(tstate)); - _PyErr_FormatV(tstate, exception, format, vargs); - - _PyErr_Fetch(tstate, &exc, &val2, &tb); - _PyErr_NormalizeException(tstate, &exc, &val2, &tb); - PyException_SetCause(val2, Py_NewRef(val)); - PyException_SetContext(val2, Py_NewRef(val)); - Py_DECREF(val); - _PyErr_Restore(tstate, exc, val2, tb); - + PyObject *exc2 = _PyErr_GetRaisedException(tstate); + PyException_SetCause(exc2, Py_NewRef(exc)); + PyException_SetContext(exc2, Py_NewRef(exc)); + Py_DECREF(exc); + _PyErr_SetRaisedException(tstate, exc2); return NULL; } @@ -1698,19 +1684,18 @@ static void PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset) { - PyObject *exc, *v, *tb, *tmp; PyThreadState *tstate = _PyThreadState_GET(); /* add attributes for the line number and filename for the error */ - _PyErr_Fetch(tstate, &exc, &v, &tb); - _PyErr_NormalizeException(tstate, &exc, &v, &tb); + PyObject *exc = _PyErr_GetRaisedException(tstate); /* XXX check that it is, indeed, a syntax error. It might not * be, though. */ - tmp = PyLong_FromLong(lineno); - if (tmp == NULL) + PyObject *tmp = PyLong_FromLong(lineno); + if (tmp == NULL) { _PyErr_Clear(tstate); + } else { - if (PyObject_SetAttr(v, &_Py_ID(lineno), tmp)) { + if (PyObject_SetAttr(exc, &_Py_ID(lineno), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); @@ -1722,7 +1707,7 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (PyObject_SetAttr(v, &_Py_ID(offset), tmp ? tmp : Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(offset), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); @@ -1734,7 +1719,7 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (PyObject_SetAttr(v, &_Py_ID(end_lineno), tmp ? tmp : Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(end_lineno), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); @@ -1746,20 +1731,20 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (PyObject_SetAttr(v, &_Py_ID(end_offset), tmp ? tmp : Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(end_offset), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); tmp = NULL; if (filename != NULL) { - if (PyObject_SetAttr(v, &_Py_ID(filename), filename)) { + if (PyObject_SetAttr(exc, &_Py_ID(filename), filename)) { _PyErr_Clear(tstate); } tmp = PyErr_ProgramTextObject(filename, lineno); if (tmp) { - if (PyObject_SetAttr(v, &_Py_ID(text), tmp)) { + if (PyObject_SetAttr(exc, &_Py_ID(text), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); @@ -1768,17 +1753,17 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (exc != PyExc_SyntaxError) { - if (_PyObject_LookupAttr(v, &_Py_ID(msg), &tmp) < 0) { + if ((PyObject *)Py_TYPE(exc) != PyExc_SyntaxError) { + if (_PyObject_LookupAttr(exc, &_Py_ID(msg), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { Py_DECREF(tmp); } else { - tmp = PyObject_Str(v); + tmp = PyObject_Str(exc); if (tmp) { - if (PyObject_SetAttr(v, &_Py_ID(msg), tmp)) { + if (PyObject_SetAttr(exc, &_Py_ID(msg), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); @@ -1788,19 +1773,19 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, } } - if (_PyObject_LookupAttr(v, &_Py_ID(print_file_and_line), &tmp) < 0) { + if (_PyObject_LookupAttr(exc, &_Py_ID(print_file_and_line), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { Py_DECREF(tmp); } else { - if (PyObject_SetAttr(v, &_Py_ID(print_file_and_line), Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(print_file_and_line), Py_None)) { _PyErr_Clear(tstate); } } } - _PyErr_Restore(tstate, exc, v, tb); + _PyErr_SetRaisedException(tstate, exc); } void From webhook-mailer at python.org Sat Mar 18 13:21:55 2023 From: webhook-mailer at python.org (rhettinger) Date: Sat, 18 Mar 2023 17:21:55 -0000 Subject: [Python-checkins] Add more comments to hypot() (GH-102817) Message-ID: https://github.com/python/cpython/commit/3adb23a17d25e36bd80874e860835182d851623f commit: 3adb23a17d25e36bd80874e860835182d851623f branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-18T12:21:48-05:00 summary: Add more comments to hypot() (GH-102817) files: M Modules/mathmodule.c diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 48cd9a642de1..c9a2be668639 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2447,9 +2447,8 @@ Since lo**2 is less than 1/2 ulp(csum), we have csum+lo*lo == csum. To minimize loss of information during the accumulation of fractional values, each term has a separate accumulator. This also breaks up sequential dependencies in the inner loop so the CPU can maximize -floating point throughput. [4] On a 2.6 GHz Haswell, adding one -dimension has an incremental cost of only 5ns -- for example when -moving from hypot(x,y) to hypot(x,y,z). +floating point throughput. [4] On an Apple M1 Max, hypot(*vec) +takes only 3.33 ?sec when len(vec) == 1000. The square root differential correction is needed because a correctly rounded square root of a correctly rounded sum of @@ -2473,7 +2472,7 @@ step is exact. The Neumaier summation computes as if in doubled precision (106 bits) and has the advantage that its input squares are non-negative so that the condition number of the sum is one. The square root with a differential correction is likewise computed -as if in double precision. +as if in doubled precision. For n <= 1000, prior to the final addition that rounds the overall result, the internal accuracy of "h" together with its correction of @@ -2514,12 +2513,9 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) } frexp(max, &max_e); if (max_e < -1023) { - /* When max_e < -1023, ldexp(1.0, -max_e) would overflow. - So we first perform lossless scaling from subnormals back to normals, - then recurse back to vector_norm(), and then finally undo the scaling. - */ + /* When max_e < -1023, ldexp(1.0, -max_e) would overflow. */ for (i=0 ; i < n ; i++) { - vec[i] /= DBL_MIN; + vec[i] /= DBL_MIN; // convert subnormals to normals } return DBL_MIN * vector_norm(n, vec, max / DBL_MIN, found_nan); } @@ -2529,17 +2525,14 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) for (i=0 ; i < n ; i++) { x = vec[i]; assert(Py_IS_FINITE(x) && fabs(x) <= max); - - x *= scale; + x *= scale; // lossless scaling assert(fabs(x) < 1.0); - - pr = dl_mul(x, x); + pr = dl_mul(x, x); // lossless squaring assert(pr.hi <= 1.0); - - sm = dl_fast_sum(csum, pr.hi); + sm = dl_fast_sum(csum, pr.hi); // lossless addition csum = sm.hi; - frac1 += pr.lo; - frac2 += sm.lo; + frac1 += pr.lo; // lossy addition + frac2 += sm.lo; // lossy addition } h = sqrt(csum - 1.0 + (frac1 + frac2)); pr = dl_mul(-h, h); @@ -2548,7 +2541,8 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) frac1 += pr.lo; frac2 += sm.lo; x = csum - 1.0 + (frac1 + frac2); - return (h + x / (2.0 * h)) / scale; + h += x / (2.0 * h); // differential correction + return h / scale; } #define NUM_STACK_ELEMS 16 From webhook-mailer at python.org Sun Mar 19 11:18:08 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sun, 19 Mar 2023 15:18:08 -0000 Subject: [Python-checkins] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102816) Message-ID: https://github.com/python/cpython/commit/ad77b80b0542a71eff54d1a193bd044a71e8e00b commit: ad77b80b0542a71eff54d1a193bd044a71e8e00b branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-19T15:17:59Z summary: gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102816) files: M Python/bytecodes.c M Python/generated_cases.c.h M Python/import.c M Python/pythonrun.c diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 74582ecbbda1..6c448707303e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -778,9 +778,7 @@ dummy_func( } assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } @@ -791,9 +789,7 @@ dummy_func( } else { Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 26f6be049b30..c5a7d90d401a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1136,32 +1136,28 @@ } assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1144 "Python/generated_cases.c.h" + #line 1142 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 788 "Python/bytecodes.c" + #line 786 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1153 "Python/generated_cases.c.h" + #line 1151 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 791 "Python/bytecodes.c" + #line 789 "Python/bytecodes.c" } else { Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1165 "Python/generated_cases.c.h" + #line 1161 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1172,23 +1168,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 802 "Python/bytecodes.c" + #line 798 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1181 "Python/generated_cases.c.h" + #line 1177 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 807 "Python/bytecodes.c" + #line 803 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1192 "Python/generated_cases.c.h" + #line 1188 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1197,9 +1193,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 816 "Python/bytecodes.c" + #line 812 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1203 "Python/generated_cases.c.h" + #line 1199 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1207,7 +1203,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 820 "Python/bytecodes.c" + #line 816 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1229,7 +1225,7 @@ if (true) goto error; } } - #line 1233 "Python/generated_cases.c.h" + #line 1229 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1237,33 +1233,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 844 "Python/bytecodes.c" + #line 840 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1248 "Python/generated_cases.c.h" + #line 1244 "Python/generated_cases.c.h" Py_DECREF(v); - #line 851 "Python/bytecodes.c" + #line 847 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1257 "Python/generated_cases.c.h" + #line 1253 "Python/generated_cases.c.h" Py_DECREF(v); - #line 858 "Python/bytecodes.c" + #line 854 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1261 "Python/generated_cases.c.h" + #line 1257 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 862 "Python/bytecodes.c" + #line 858 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1280,7 +1276,7 @@ name); goto error; } - #line 1284 "Python/generated_cases.c.h" + #line 1280 "Python/generated_cases.c.h" DISPATCH(); } @@ -1288,7 +1284,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 888 "Python/bytecodes.c" + #line 884 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1302,11 +1298,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1306 "Python/generated_cases.c.h" + #line 1302 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 902 "Python/bytecodes.c" + #line 898 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1310 "Python/generated_cases.c.h" + #line 1306 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1316,14 +1312,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 906 "Python/bytecodes.c" + #line 902 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1327 "Python/generated_cases.c.h" + #line 1323 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1334,7 +1330,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 916 "Python/bytecodes.c" + #line 912 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1342,7 +1338,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1346 "Python/generated_cases.c.h" + #line 1342 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1353,7 +1349,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 927 "Python/bytecodes.c" + #line 923 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1361,7 +1357,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1365 "Python/generated_cases.c.h" + #line 1361 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1371,15 +1367,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 938 "Python/bytecodes.c" + #line 934 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1379 "Python/generated_cases.c.h" + #line 1375 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 942 "Python/bytecodes.c" + #line 938 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1383 "Python/generated_cases.c.h" + #line 1379 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1390,7 +1386,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 953 "Python/bytecodes.c" + #line 949 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -1407,12 +1403,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1411 "Python/generated_cases.c.h" + #line 1407 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 970 "Python/bytecodes.c" + #line 966 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1416 "Python/generated_cases.c.h" + #line 1412 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1420,34 +1416,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 974 "Python/bytecodes.c" + #line 970 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1427 "Python/generated_cases.c.h" + #line 1423 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 977 "Python/bytecodes.c" + #line 973 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1431 "Python/generated_cases.c.h" + #line 1427 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 981 "Python/bytecodes.c" + #line 977 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1441 "Python/generated_cases.c.h" + #line 1437 "Python/generated_cases.c.h" Py_DECREF(v); - #line 984 "Python/bytecodes.c" + #line 980 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1445 "Python/generated_cases.c.h" + #line 1441 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 988 "Python/bytecodes.c" + #line 984 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1459,13 +1455,13 @@ } goto error; } - #line 1463 "Python/generated_cases.c.h" + #line 1459 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_NAME) { PyObject *v; - #line 1002 "Python/bytecodes.c" + #line 998 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1524,7 +1520,7 @@ } } } - #line 1528 "Python/generated_cases.c.h" + #line 1524 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = v; DISPATCH(); @@ -1535,7 +1531,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1069 "Python/bytecodes.c" + #line 1065 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1588,7 +1584,7 @@ } } null = NULL; - #line 1592 "Python/generated_cases.c.h" + #line 1588 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1602,7 +1598,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1124 "Python/bytecodes.c" + #line 1120 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -1614,7 +1610,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1618 "Python/generated_cases.c.h" + #line 1614 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1629,7 +1625,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1138 "Python/bytecodes.c" + #line 1134 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); @@ -1644,7 +1640,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1648 "Python/generated_cases.c.h" + #line 1644 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1654,16 +1650,16 @@ } TARGET(DELETE_FAST) { - #line 1155 "Python/bytecodes.c" + #line 1151 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1662 "Python/generated_cases.c.h" + #line 1658 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1161 "Python/bytecodes.c" + #line 1157 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1672,12 +1668,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1676 "Python/generated_cases.c.h" + #line 1672 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1172 "Python/bytecodes.c" + #line 1168 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1688,13 +1684,13 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1692 "Python/generated_cases.c.h" + #line 1688 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLASSDEREF) { PyObject *value; - #line 1185 "Python/bytecodes.c" + #line 1181 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1726,7 +1722,7 @@ } Py_INCREF(value); } - #line 1730 "Python/generated_cases.c.h" + #line 1726 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1734,7 +1730,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1219 "Python/bytecodes.c" + #line 1215 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1742,7 +1738,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1746 "Python/generated_cases.c.h" + #line 1742 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1750,18 +1746,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1229 "Python/bytecodes.c" + #line 1225 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1759 "Python/generated_cases.c.h" + #line 1755 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1236 "Python/bytecodes.c" + #line 1232 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1772,22 +1768,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1776 "Python/generated_cases.c.h" + #line 1772 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1249 "Python/bytecodes.c" + #line 1245 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1785 "Python/generated_cases.c.h" + #line 1781 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1251 "Python/bytecodes.c" + #line 1247 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1791 "Python/generated_cases.c.h" + #line 1787 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1797,10 +1793,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1255 "Python/bytecodes.c" + #line 1251 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1804 "Python/generated_cases.c.h" + #line 1800 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1810,10 +1806,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1260 "Python/bytecodes.c" + #line 1256 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1817 "Python/generated_cases.c.h" + #line 1813 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1823,7 +1819,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1265 "Python/bytecodes.c" + #line 1261 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1834,13 +1830,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1838 "Python/generated_cases.c.h" + #line 1834 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1276 "Python/bytecodes.c" + #line 1272 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); - #line 1844 "Python/generated_cases.c.h" + #line 1840 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1849,13 +1845,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1283 "Python/bytecodes.c" + #line 1279 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1855 "Python/generated_cases.c.h" + #line 1851 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1285 "Python/bytecodes.c" + #line 1281 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1859 "Python/generated_cases.c.h" + #line 1855 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1863,7 +1859,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1289 "Python/bytecodes.c" + #line 1285 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1878,7 +1874,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1882 "Python/generated_cases.c.h" + #line 1878 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1888,7 +1884,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1306 "Python/bytecodes.c" + #line 1302 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1896,13 +1892,13 @@ if (map == NULL) goto error; - #line 1900 "Python/generated_cases.c.h" + #line 1896 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1314 "Python/bytecodes.c" + #line 1310 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1906 "Python/generated_cases.c.h" + #line 1902 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1910,7 +1906,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1318 "Python/bytecodes.c" + #line 1314 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1950,7 +1946,7 @@ Py_DECREF(ann_dict); } } - #line 1954 "Python/generated_cases.c.h" + #line 1950 "Python/generated_cases.c.h" DISPATCH(); } @@ -1958,7 +1954,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1360 "Python/bytecodes.c" + #line 1356 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1968,14 +1964,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1972 "Python/generated_cases.c.h" + #line 1968 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1370 "Python/bytecodes.c" + #line 1366 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1979 "Python/generated_cases.c.h" + #line 1975 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -1983,7 +1979,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1374 "Python/bytecodes.c" + #line 1370 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1991,12 +1987,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1995 "Python/generated_cases.c.h" + #line 1991 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1382 "Python/bytecodes.c" + #line 1378 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2000 "Python/generated_cases.c.h" + #line 1996 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2004,17 +2000,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1388 "Python/bytecodes.c" + #line 1384 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2013 "Python/generated_cases.c.h" + #line 2009 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1393 "Python/bytecodes.c" + #line 1389 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2018 "Python/generated_cases.c.h" + #line 2014 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2024,13 +2020,13 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1400 "Python/bytecodes.c" + #line 1396 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2034 "Python/generated_cases.c.h" + #line 2030 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -2042,7 +2038,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1423 "Python/bytecodes.c" + #line 1419 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2077,9 +2073,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2081 "Python/generated_cases.c.h" + #line 2077 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1458 "Python/bytecodes.c" + #line 1454 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2088,12 +2084,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2092 "Python/generated_cases.c.h" + #line 2088 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1467 "Python/bytecodes.c" + #line 1463 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2097 "Python/generated_cases.c.h" + #line 2093 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2107,7 +2103,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1472 "Python/bytecodes.c" + #line 1468 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2121,7 +2117,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2125 "Python/generated_cases.c.h" + #line 2121 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2136,7 +2132,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1489 "Python/bytecodes.c" + #line 1485 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; @@ -2150,7 +2146,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2154 "Python/generated_cases.c.h" + #line 2150 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2165,7 +2161,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1506 "Python/bytecodes.c" + #line 1502 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2193,7 +2189,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2197 "Python/generated_cases.c.h" + #line 2193 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2208,7 +2204,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1537 "Python/bytecodes.c" + #line 1533 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2219,7 +2215,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2223 "Python/generated_cases.c.h" + #line 2219 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2234,7 +2230,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1551 "Python/bytecodes.c" + #line 1547 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); @@ -2247,7 +2243,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2251 "Python/generated_cases.c.h" + #line 2247 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2261,7 +2257,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1567 "Python/bytecodes.c" + #line 1563 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); @@ -2285,7 +2281,7 @@ new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); - #line 2289 "Python/generated_cases.c.h" + #line 2285 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2293,7 +2289,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1593 "Python/bytecodes.c" + #line 1589 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2319,7 +2315,7 @@ new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); - #line 2323 "Python/generated_cases.c.h" + #line 2319 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2327,7 +2323,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1621 "Python/bytecodes.c" + #line 1617 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2346,7 +2342,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2350 "Python/generated_cases.c.h" + #line 2346 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2357,7 +2353,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1642 "Python/bytecodes.c" + #line 1638 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2397,7 +2393,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2401 "Python/generated_cases.c.h" + #line 2397 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2408,7 +2404,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1684 "Python/bytecodes.c" + #line 1680 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2419,7 +2415,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2423 "Python/generated_cases.c.h" + #line 2419 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2429,16 +2425,16 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1697 "Python/bytecodes.c" + #line 1693 "Python/bytecodes.c" STAT_INC(COMPARE_OP, deferred); assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2437 "Python/generated_cases.c.h" + #line 2433 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1701 "Python/bytecodes.c" + #line 1697 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2442 "Python/generated_cases.c.h" + #line 2438 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2449,7 +2445,7 @@ PREDICTED(COMPARE_AND_BRANCH); PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1713 "Python/bytecodes.c" + #line 1709 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2463,10 +2459,10 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); - #line 2467 "Python/generated_cases.c.h" + #line 2463 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1727 "Python/bytecodes.c" + #line 1723 "Python/bytecodes.c" if (cond == NULL) goto pop_2_error; assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || next_instr[1].op.code == POP_JUMP_IF_TRUE); @@ -2478,7 +2474,7 @@ if (jump_on_true == (err != 0)) { JUMPBY(offset); } - #line 2482 "Python/generated_cases.c.h" + #line 2478 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2487,7 +2483,7 @@ TARGET(COMPARE_AND_BRANCH_FLOAT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1741 "Python/bytecodes.c" + #line 1737 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); @@ -2502,7 +2498,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } - #line 2506 "Python/generated_cases.c.h" + #line 2502 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2511,7 +2507,7 @@ TARGET(COMPARE_AND_BRANCH_INT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1759 "Python/bytecodes.c" + #line 1755 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); @@ -2529,7 +2525,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } - #line 2533 "Python/generated_cases.c.h" + #line 2529 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2538,7 +2534,7 @@ TARGET(COMPARE_AND_BRANCH_STR) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1780 "Python/bytecodes.c" + #line 1776 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); @@ -2554,7 +2550,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } - #line 2558 "Python/generated_cases.c.h" + #line 2554 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2564,14 +2560,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1798 "Python/bytecodes.c" + #line 1794 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2570 "Python/generated_cases.c.h" + #line 2566 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1800 "Python/bytecodes.c" + #line 1796 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2575 "Python/generated_cases.c.h" + #line 2571 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2581,15 +2577,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1804 "Python/bytecodes.c" + #line 1800 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2587 "Python/generated_cases.c.h" + #line 2583 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1806 "Python/bytecodes.c" + #line 1802 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2593 "Python/generated_cases.c.h" + #line 2589 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2600,12 +2596,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1811 "Python/bytecodes.c" + #line 1807 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2606 "Python/generated_cases.c.h" + #line 2602 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1813 "Python/bytecodes.c" + #line 1809 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2613,10 +2609,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2617 "Python/generated_cases.c.h" + #line 2613 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1821 "Python/bytecodes.c" + #line 1817 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2625,7 +2621,7 @@ if (!Py_IsNone(match)) { PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); } - #line 2629 "Python/generated_cases.c.h" + #line 2625 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2635,21 +2631,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1832 "Python/bytecodes.c" + #line 1828 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2642 "Python/generated_cases.c.h" + #line 2638 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1835 "Python/bytecodes.c" + #line 1831 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2649 "Python/generated_cases.c.h" + #line 2645 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1840 "Python/bytecodes.c" + #line 1836 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2653 "Python/generated_cases.c.h" + #line 2649 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2658,15 +2654,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 1844 "Python/bytecodes.c" + #line 1840 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2665 "Python/generated_cases.c.h" + #line 2661 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 1847 "Python/bytecodes.c" + #line 1843 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2670 "Python/generated_cases.c.h" + #line 2666 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2675,29 +2671,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 1851 "Python/bytecodes.c" + #line 1847 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2683 "Python/generated_cases.c.h" + #line 2679 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 1857 "Python/bytecodes.c" + #line 1853 "Python/bytecodes.c" JUMPBY(oparg); - #line 2692 "Python/generated_cases.c.h" + #line 2688 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 1861 "Python/bytecodes.c" + #line 1857 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2701 "Python/generated_cases.c.h" + #line 2697 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2705,7 +2701,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 1867 "Python/bytecodes.c" + #line 1863 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2715,9 +2711,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2719 "Python/generated_cases.c.h" + #line 2715 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1877 "Python/bytecodes.c" + #line 1873 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2725,14 +2721,14 @@ if (err < 0) goto pop_1_error; } } - #line 2729 "Python/generated_cases.c.h" + #line 2725 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 1887 "Python/bytecodes.c" + #line 1883 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2742,9 +2738,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2746 "Python/generated_cases.c.h" + #line 2742 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1897 "Python/bytecodes.c" + #line 1893 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2752,48 +2748,48 @@ if (err < 0) goto pop_1_error; } } - #line 2756 "Python/generated_cases.c.h" + #line 2752 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 1907 "Python/bytecodes.c" + #line 1903 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2765 "Python/generated_cases.c.h" + #line 2761 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1909 "Python/bytecodes.c" + #line 1905 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2773 "Python/generated_cases.c.h" + #line 2769 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 1917 "Python/bytecodes.c" + #line 1913 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 2786 "Python/generated_cases.c.h" + #line 2782 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1923 "Python/bytecodes.c" + #line 1919 "Python/bytecodes.c" } - #line 2790 "Python/generated_cases.c.h" + #line 2786 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_IF_FALSE_OR_POP) { PyObject *cond = stack_pointer[-1]; - #line 1927 "Python/bytecodes.c" + #line 1923 "Python/bytecodes.c" bool jump = false; int err; if (Py_IsTrue(cond)) { @@ -2816,7 +2812,7 @@ goto error; } } - #line 2820 "Python/generated_cases.c.h" + #line 2816 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); @@ -2824,7 +2820,7 @@ TARGET(JUMP_IF_TRUE_OR_POP) { PyObject *cond = stack_pointer[-1]; - #line 1952 "Python/bytecodes.c" + #line 1948 "Python/bytecodes.c" bool jump = false; int err; if (Py_IsFalse(cond)) { @@ -2847,34 +2843,34 @@ goto error; } } - #line 2851 "Python/generated_cases.c.h" + #line 2847 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 1977 "Python/bytecodes.c" + #line 1973 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 2865 "Python/generated_cases.c.h" + #line 2861 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 1986 "Python/bytecodes.c" + #line 1982 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 2878 "Python/generated_cases.c.h" + #line 2874 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2885,16 +2881,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 1994 "Python/bytecodes.c" + #line 1990 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 2894 "Python/generated_cases.c.h" + #line 2890 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 1999 "Python/bytecodes.c" + #line 1995 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2902,7 +2898,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 2906 "Python/generated_cases.c.h" + #line 2902 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -2911,10 +2907,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2009 "Python/bytecodes.c" + #line 2005 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 2918 "Python/generated_cases.c.h" + #line 2914 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2924,10 +2920,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2015 "Python/bytecodes.c" + #line 2011 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 2931 "Python/generated_cases.c.h" + #line 2927 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2938,11 +2934,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2021 "Python/bytecodes.c" + #line 2017 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 2946 "Python/generated_cases.c.h" + #line 2942 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -2951,14 +2947,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2027 "Python/bytecodes.c" + #line 2023 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 2958 "Python/generated_cases.c.h" + #line 2954 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2030 "Python/bytecodes.c" + #line 2026 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 2962 "Python/generated_cases.c.h" + #line 2958 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -2966,7 +2962,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2034 "Python/bytecodes.c" + #line 2030 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2989,11 +2985,11 @@ if (iter == NULL) { goto error; } - #line 2993 "Python/generated_cases.c.h" + #line 2989 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2057 "Python/bytecodes.c" + #line 2053 "Python/bytecodes.c" } - #line 2997 "Python/generated_cases.c.h" + #line 2993 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3004,7 +3000,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2076 "Python/bytecodes.c" + #line 2072 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3037,7 +3033,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3041 "Python/generated_cases.c.h" + #line 3037 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3047,7 +3043,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2111 "Python/bytecodes.c" + #line 2107 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -3068,7 +3064,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3072 "Python/generated_cases.c.h" + #line 3068 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3078,7 +3074,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2134 "Python/bytecodes.c" + #line 2130 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -3099,7 +3095,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3103 "Python/generated_cases.c.h" + #line 3099 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3109,7 +3105,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2157 "Python/bytecodes.c" + #line 2153 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -3128,7 +3124,7 @@ if (next == NULL) { goto error; } - #line 3132 "Python/generated_cases.c.h" + #line 3128 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3137,7 +3133,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2178 "Python/bytecodes.c" + #line 2174 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3152,14 +3148,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); assert(next_instr->op.code == END_FOR); DISPATCH_INLINED(gen_frame); - #line 3156 "Python/generated_cases.c.h" + #line 3152 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2195 "Python/bytecodes.c" + #line 2191 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3182,16 +3178,16 @@ Py_DECREF(enter); goto error; } - #line 3186 "Python/generated_cases.c.h" + #line 3182 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2218 "Python/bytecodes.c" + #line 2214 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3195 "Python/generated_cases.c.h" + #line 3191 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3203,7 +3199,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2228 "Python/bytecodes.c" + #line 2224 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3229,16 +3225,16 @@ Py_DECREF(enter); goto error; } - #line 3233 "Python/generated_cases.c.h" + #line 3229 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2254 "Python/bytecodes.c" + #line 2250 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3242 "Python/generated_cases.c.h" + #line 3238 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3250,7 +3246,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2263 "Python/bytecodes.c" + #line 2259 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3271,7 +3267,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3275 "Python/generated_cases.c.h" + #line 3271 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3280,7 +3276,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2286 "Python/bytecodes.c" + #line 2282 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3290,7 +3286,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3294 "Python/generated_cases.c.h" + #line 3290 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3304,7 +3300,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2298 "Python/bytecodes.c" + #line 2294 "Python/bytecodes.c" /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -3322,7 +3318,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3326 "Python/generated_cases.c.h" + #line 3322 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3336,7 +3332,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2318 "Python/bytecodes.c" + #line 2314 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3347,7 +3343,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3351 "Python/generated_cases.c.h" + #line 3347 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3361,7 +3357,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2331 "Python/bytecodes.c" + #line 2327 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3376,7 +3372,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3380 "Python/generated_cases.c.h" + #line 3376 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3385,11 +3381,11 @@ } TARGET(KW_NAMES) { - #line 2348 "Python/bytecodes.c" + #line 2344 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3393 "Python/generated_cases.c.h" + #line 3389 "Python/generated_cases.c.h" DISPATCH(); } @@ -3400,7 +3396,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2384 "Python/bytecodes.c" + #line 2380 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3472,7 +3468,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3476 "Python/generated_cases.c.h" + #line 3472 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3484,7 +3480,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2462 "Python/bytecodes.c" + #line 2458 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3494,7 +3490,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3498 "Python/generated_cases.c.h" + #line 3494 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3503,7 +3499,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2474 "Python/bytecodes.c" + #line 2470 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3528,7 +3524,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3532 "Python/generated_cases.c.h" + #line 3528 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3537,7 +3533,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); uint16_t min_args = read_u16(&next_instr[3].cache); - #line 2501 "Python/bytecodes.c" + #line 2497 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3567,7 +3563,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3571 "Python/generated_cases.c.h" + #line 3567 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3575,7 +3571,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2533 "Python/bytecodes.c" + #line 2529 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3586,7 +3582,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3590 "Python/generated_cases.c.h" + #line 3586 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3599,7 +3595,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2546 "Python/bytecodes.c" + #line 2542 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3611,7 +3607,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3615 "Python/generated_cases.c.h" + #line 3611 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3625,7 +3621,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2561 "Python/bytecodes.c" + #line 2557 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3636,7 +3632,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3640 "Python/generated_cases.c.h" + #line 3636 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3650,7 +3646,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2575 "Python/bytecodes.c" + #line 2571 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3672,7 +3668,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3676 "Python/generated_cases.c.h" + #line 3672 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3686,7 +3682,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2600 "Python/bytecodes.c" + #line 2596 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3715,7 +3711,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3719 "Python/generated_cases.c.h" + #line 3715 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3729,7 +3725,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2632 "Python/bytecodes.c" + #line 2628 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3762,7 +3758,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3766 "Python/generated_cases.c.h" + #line 3762 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3776,7 +3772,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2668 "Python/bytecodes.c" + #line 2664 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3809,7 +3805,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3813 "Python/generated_cases.c.h" + #line 3809 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3823,7 +3819,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2704 "Python/bytecodes.c" + #line 2700 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3849,7 +3845,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3853 "Python/generated_cases.c.h" + #line 3849 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3862,7 +3858,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2732 "Python/bytecodes.c" + #line 2728 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3890,7 +3886,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3894 "Python/generated_cases.c.h" + #line 3890 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3902,7 +3898,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2763 "Python/bytecodes.c" + #line 2759 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3921,14 +3917,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 3925 "Python/generated_cases.c.h" + #line 3921 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2784 "Python/bytecodes.c" + #line 2780 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3959,7 +3955,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3963 "Python/generated_cases.c.h" + #line 3959 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3972,7 +3968,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2818 "Python/bytecodes.c" + #line 2814 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4001,7 +3997,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4005 "Python/generated_cases.c.h" + #line 4001 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4014,7 +4010,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2850 "Python/bytecodes.c" + #line 2846 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4043,7 +4039,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4047 "Python/generated_cases.c.h" + #line 4043 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4056,7 +4052,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2882 "Python/bytecodes.c" + #line 2878 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4084,7 +4080,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4088 "Python/generated_cases.c.h" + #line 4084 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4099,7 +4095,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 2913 "Python/bytecodes.c" + #line 2909 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -4118,15 +4114,15 @@ assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - #line 4122 "Python/generated_cases.c.h" + #line 4118 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 2932 "Python/bytecodes.c" + #line 2928 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4130 "Python/generated_cases.c.h" + #line 4126 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4141,7 +4137,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 2943 "Python/bytecodes.c" + #line 2939 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4170,14 +4166,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4174 "Python/generated_cases.c.h" + #line 4170 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 2974 "Python/bytecodes.c" + #line 2970 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4198,7 +4194,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4202 "Python/generated_cases.c.h" + #line 4198 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4206,15 +4202,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 2997 "Python/bytecodes.c" + #line 2993 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4212 "Python/generated_cases.c.h" + #line 4208 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 2999 "Python/bytecodes.c" + #line 2995 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4218 "Python/generated_cases.c.h" + #line 4214 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4225,7 +4221,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 3003 "Python/bytecodes.c" + #line 2999 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4267,13 +4263,13 @@ } else { /* Actually call format(). */ result = PyObject_Format(value, fmt_spec); - #line 4271 "Python/generated_cases.c.h" + #line 4267 "Python/generated_cases.c.h" Py_DECREF(value); Py_XDECREF(fmt_spec); - #line 3045 "Python/bytecodes.c" + #line 3041 "Python/bytecodes.c" if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } } - #line 4277 "Python/generated_cases.c.h" + #line 4273 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4282,10 +4278,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3050 "Python/bytecodes.c" + #line 3046 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4289 "Python/generated_cases.c.h" + #line 4285 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4297,7 +4293,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3055 "Python/bytecodes.c" + #line 3051 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4313,12 +4309,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4317 "Python/generated_cases.c.h" + #line 4313 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3071 "Python/bytecodes.c" + #line 3067 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4322 "Python/generated_cases.c.h" + #line 4318 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4328,27 +4324,27 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3076 "Python/bytecodes.c" + #line 3072 "Python/bytecodes.c" assert(oparg >= 2); - #line 4334 "Python/generated_cases.c.h" + #line 4330 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3080 "Python/bytecodes.c" + #line 3076 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4348 "Python/generated_cases.c.h" + #line 4344 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3089 "Python/bytecodes.c" + #line 3085 "Python/bytecodes.c" Py_UNREACHABLE(); - #line 4354 "Python/generated_cases.c.h" + #line 4350 "Python/generated_cases.c.h" } diff --git a/Python/import.c b/Python/import.c index 9f80c6d8dd49..c68bd1f7db42 100644 --- a/Python/import.c +++ b/Python/import.c @@ -389,8 +389,7 @@ PyImport_AddModule(const char *name) static void remove_module(PyThreadState *tstate, PyObject *name) { - PyObject *type, *value, *traceback; - _PyErr_Fetch(tstate, &type, &value, &traceback); + PyObject *exc = _PyErr_GetRaisedException(tstate); PyObject *modules = MODULES(tstate->interp); if (PyDict_CheckExact(modules)) { @@ -403,7 +402,7 @@ remove_module(PyThreadState *tstate, PyObject *name) } } - _PyErr_ChainExceptions(type, value, traceback); + _PyErr_ChainExceptions1(exc); } @@ -2324,32 +2323,34 @@ remove_importlib_frames(PyThreadState *tstate) const char *remove_frames = "_call_with_frames_removed"; int always_trim = 0; int in_importlib = 0; - PyObject *exception, *value, *base_tb, *tb; PyObject **prev_link, **outer_link = NULL; + PyObject *base_tb = NULL; /* Synopsis: if it's an ImportError, we trim all importlib chunks from the traceback. We always trim chunks which end with a call to "_call_with_frames_removed". */ - _PyErr_Fetch(tstate, &exception, &value, &base_tb); - if (!exception || _PyInterpreterState_GetConfig(tstate->interp)->verbose) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + if (exc == NULL || _PyInterpreterState_GetConfig(tstate->interp)->verbose) { goto done; } - if (PyType_IsSubtype((PyTypeObject *) exception, - (PyTypeObject *) PyExc_ImportError)) + if (PyType_IsSubtype(Py_TYPE(exc), (PyTypeObject *) PyExc_ImportError)) { always_trim = 1; + } + assert(PyExceptionInstance_Check(exc)); + base_tb = PyException_GetTraceback(exc); prev_link = &base_tb; - tb = base_tb; + PyObject *tb = base_tb; while (tb != NULL) { + assert(PyTraceBack_Check(tb)); PyTracebackObject *traceback = (PyTracebackObject *)tb; PyObject *next = (PyObject *) traceback->tb_next; PyFrameObject *frame = traceback->tb_frame; PyCodeObject *code = PyFrame_GetCode(frame); int now_in_importlib; - assert(PyTraceBack_Check(tb)); now_in_importlib = _PyUnicode_EqualToASCIIString(code->co_filename, importlib_filename) || _PyUnicode_EqualToASCIIString(code->co_filename, external_filename); if (now_in_importlib && !in_importlib) { @@ -2370,15 +2371,14 @@ remove_importlib_frames(PyThreadState *tstate) Py_DECREF(code); tb = next; } - assert(PyExceptionInstance_Check(value)); - assert((PyObject *)Py_TYPE(value) == exception); if (base_tb == NULL) { base_tb = Py_None; Py_INCREF(Py_None); } - PyException_SetTraceback(value, base_tb); + PyException_SetTraceback(exc, base_tb); done: - _PyErr_Restore(tstate, exception, value, base_tb); + Py_XDECREF(base_tb); + _PyErr_SetRaisedException(tstate, exc); } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 6ea185a1b75b..b16d3f53f89f 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -18,7 +18,7 @@ #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_object.h" // _PyDebug_PrintTotalRefs() #include "pycore_parser.h" // _PyParser_ASTFromString() -#include "pycore_pyerrors.h" // _PyErr_Fetch, _Py_Offer_Suggestions +#include "pycore_pyerrors.h" // _PyErr_GetRaisedException, _Py_Offer_Suggestions #include "pycore_pylifecycle.h" // _Py_UnhandledKeyboardInterrupt #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_sysmodule.h" // _PySys_Audit() From webhook-mailer at python.org Sun Mar 19 11:18:31 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sun, 19 Mar 2023 15:18:31 -0000 Subject: [Python-checkins] gh-102755: fix refleak (#102826) Message-ID: https://github.com/python/cpython/commit/ccb5af7bfee59b72313ccf1fa2c9b0dca347ac96 commit: ccb5af7bfee59b72313ccf1fa2c9b0dca347ac96 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-19T15:18:24Z summary: gh-102755: fix refleak (#102826) files: M Python/pylifecycle.c diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7bf12271db23..317d6966d034 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2547,6 +2547,7 @@ _Py_FatalError_PrintExc(PyThreadState *tstate) if (ferr == NULL || ferr == Py_None) { /* sys.stderr is not set yet or set to None, no need to try to display the exception */ + Py_DECREF(exc); return 0; } @@ -2555,7 +2556,7 @@ _Py_FatalError_PrintExc(PyThreadState *tstate) PyObject *tb = PyException_GetTraceback(exc); int has_tb = (tb != NULL) && (tb != Py_None); Py_XDECREF(tb); - Py_XDECREF(exc); + Py_DECREF(exc); /* sys.stderr may be buffered: call sys.stderr.flush() */ PyObject *res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); From webhook-mailer at python.org Sun Mar 19 12:20:06 2023 From: webhook-mailer at python.org (terryjreedy) Date: Sun, 19 Mar 2023 16:20:06 -0000 Subject: [Python-checkins] gh-102778: revert changes to idlelib (#102825) Message-ID: https://github.com/python/cpython/commit/4d1f033986675b883b9ff14588ae6ff78fdde313 commit: 4d1f033986675b883b9ff14588ae6ff78fdde313 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: terryjreedy date: 2023-03-19T12:19:59-04:00 summary: gh-102778: revert changes to idlelib (#102825) files: M Lib/idlelib/idle_test/test_stackviewer.py M Lib/idlelib/pyshell.py M Lib/idlelib/run.py M Lib/idlelib/stackviewer.py diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py index f4626bb1702a..98f53f9537bb 100644 --- a/Lib/idlelib/idle_test/test_stackviewer.py +++ b/Lib/idlelib/idle_test/test_stackviewer.py @@ -19,7 +19,6 @@ def setUpClass(cls): except NameError: svs.last_type, svs.last_value, svs.last_traceback = ( sys.exc_info()) - svs.last_exc = svs.last_value requires('gui') cls.root = Tk() @@ -28,7 +27,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): svs = stackviewer.sys - del svs.last_exc, svs.last_traceback, svs.last_type, svs.last_value + del svs.last_traceback, svs.last_type, svs.last_value cls.root.update_idletasks() ## for id in cls.root.tk.call('after', 'info'): diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index edc77ff26f62..e68233a5a413 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1367,14 +1367,11 @@ def open_stack_viewer(self, event=None): if self.interp.rpcclt: return self.interp.remote_stack_viewer() try: - if hasattr(sys, 'last_exc'): - sys.last_exc.__traceback__ - else: - sys.last_traceback + sys.last_traceback except: messagebox.showerror("No stack trace", "There is no stack trace yet.\n" - "(sys.last_exc and sys.last_traceback are not defined)", + "(sys.last_traceback is not defined)", parent=self.text) return from idlelib.stackviewer import StackBrowser diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 6a7b50cf5cfb..577c49eb67b2 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -239,7 +239,6 @@ def print_exception(): efile = sys.stderr typ, val, tb = excinfo = sys.exc_info() sys.last_type, sys.last_value, sys.last_traceback = excinfo - sys.last_exc = val seen = set() def print_exc(typ, exc, tb): @@ -630,7 +629,6 @@ def stackviewer(self, flist_oid=None): flist = self.rpchandler.get_remote_proxy(flist_oid) while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]: tb = tb.tb_next - sys.last_exc = val sys.last_type = typ sys.last_value = val item = stackviewer.StackTreeItem(flist, tb) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 702fd32ca5d1..94ffb4eff4dd 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -27,10 +27,7 @@ def __init__(self, flist=None, tb=None): def get_stack(self, tb): if tb is None: - if hasattr(sys, 'last_exc'): - tb = sys.last_exc.__traceback__ - else: - tb = sys.last_traceback + tb = sys.last_traceback stack = [] if tb and tb.tb_frame is None: tb = tb.tb_next @@ -40,15 +37,11 @@ def get_stack(self, tb): return stack def get_exception(self): - if hasattr(sys, 'last_exc'): - typ = type(sys.last_exc) - value = sys.last_exc - else: - typ = sys.last_type - value = sys.last_value - if hasattr(typ, "__name__"): - typ = typ.__name__ - s = str(typ) + type = sys.last_type + value = sys.last_value + if hasattr(type, "__name__"): + type = type.__name__ + s = str(type) if value is not None: s = s + ": " + str(value) return s @@ -143,7 +136,6 @@ def _stack_viewer(parent): # htest # except NameError: exc_type, exc_value, exc_tb = sys.exc_info() # inject stack trace to sys - sys.last_exc = exc_value sys.last_type = exc_type sys.last_value = exc_value sys.last_traceback = exc_tb @@ -151,7 +143,6 @@ def _stack_viewer(parent): # htest # StackBrowser(top, flist=flist, top=top, tb=exc_tb) # restore sys to original state - del sys.last_exc del sys.last_type del sys.last_value del sys.last_traceback From webhook-mailer at python.org Sun Mar 19 14:33:59 2023 From: webhook-mailer at python.org (iritkatriel) Date: Sun, 19 Mar 2023 18:33:59 -0000 Subject: [Python-checkins] gh-102828: add onexc arg to shutil.rmtree. Deprecate onerror. (#102829) Message-ID: https://github.com/python/cpython/commit/d51a6dc28e1b2cd0353a78bd13f46e288fa39aa6 commit: d51a6dc28e1b2cd0353a78bd13f46e288fa39aa6 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-19T18:33:51Z summary: gh-102828: add onexc arg to shutil.rmtree. Deprecate onerror. (#102829) files: A Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst M Doc/library/shutil.rst M Doc/whatsnew/3.12.rst M Lib/shutil.py M Lib/test/test_shutil.py diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index b33dbe21b1fa..acba66258fe8 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -292,15 +292,15 @@ Directory and files operations .. versionadded:: 3.8 The *dirs_exist_ok* parameter. -.. function:: rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None) +.. function:: rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None) .. index:: single: directory; deleting Delete an entire directory tree; *path* must point to a directory (but not a symbolic link to a directory). If *ignore_errors* is true, errors resulting from failed removals will be ignored; if false or omitted, such errors are - handled by calling a handler specified by *onerror* or, if that is omitted, - they raise an exception. + handled by calling a handler specified by *onexc* or *onerror* or, if both + are omitted, exceptions are propagated to the caller. This function can support :ref:`paths relative to directory descriptors `. @@ -315,14 +315,17 @@ Directory and files operations otherwise. Applications can use the :data:`rmtree.avoids_symlink_attacks` function attribute to determine which case applies. - If *onerror* is provided, it must be a callable that accepts three - parameters: *function*, *path*, and *excinfo*. + If *onexc* is provided, it must be a callable that accepts three parameters: + *function*, *path*, and *excinfo*. The first parameter, *function*, is the function which raised the exception; it depends on the platform and implementation. The second parameter, *path*, will be the path name passed to *function*. The third parameter, - *excinfo*, will be the exception information returned by - :func:`sys.exc_info`. Exceptions raised by *onerror* will not be caught. + *excinfo*, is the exception that was raised. Exceptions raised by *onexc* + will not be caught. + + The deprecated *onerror* is similar to *onexc*, except that the third + parameter it receives is the tuple returned from :func:`sys.exc_info`. .. audit-event:: shutil.rmtree path,dir_fd shutil.rmtree @@ -337,6 +340,9 @@ Directory and files operations .. versionchanged:: 3.11 The *dir_fd* parameter. + .. versionchanged:: 3.12 + Added the *onexc* parameter, deprecated *onerror*. + .. attribute:: rmtree.avoids_symlink_attacks Indicates whether the current platform and implementation provides a @@ -509,7 +515,7 @@ rmtree example ~~~~~~~~~~~~~~ This example shows how to remove a directory tree on Windows where some -of the files have their read-only bit set. It uses the onerror callback +of the files have their read-only bit set. It uses the onexc callback to clear the readonly bit and reattempt the remove. Any subsequent failure will propagate. :: @@ -521,7 +527,7 @@ will propagate. :: os.chmod(path, stat.S_IWRITE) func(path) - shutil.rmtree(directory, onerror=remove_readonly) + shutil.rmtree(directory, onexc=remove_readonly) .. _archiving-operations: diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 32fec962560a..a36e68528c4f 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -337,6 +337,11 @@ shutil of the process to *root_dir* to perform archiving. (Contributed by Serhiy Storchaka in :gh:`74696`.) +* :func:`shutil.rmtree` now accepts a new argument *onexc* which is an + error handler like *onerror* but which expects an exception instance + rather than a *(typ, val, tb)* triplet. *onerror* is deprecated. + (Contributed by Irit Katriel in :gh:`102828`.) + sqlite3 ------- @@ -498,6 +503,10 @@ Deprecated fields are deprecated. Use :data:`sys.last_exc` instead. (Contributed by Irit Katriel in :gh:`102778`.) +* The *onerror* argument of :func:`shutil.rmtree` is deprecated. Use *onexc* + instead. (Contributed by Irit Katriel in :gh:`102828`.) + + Pending Removal in Python 3.13 ------------------------------ diff --git a/Lib/shutil.py b/Lib/shutil.py index 867925aa10cc..89a7ac72d983 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -575,12 +575,12 @@ def _rmtree_islink(path): return os.path.islink(path) # version vulnerable to race conditions -def _rmtree_unsafe(path, onerror): +def _rmtree_unsafe(path, onexc): try: with os.scandir(path) as scandir_it: entries = list(scandir_it) - except OSError: - onerror(os.scandir, path, sys.exc_info()) + except OSError as err: + onexc(os.scandir, path, err) entries = [] for entry in entries: fullname = entry.path @@ -596,28 +596,28 @@ def _rmtree_unsafe(path, onerror): # a directory with a symlink after the call to # os.scandir or entry.is_dir above. raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.path.islink, fullname, err) continue - _rmtree_unsafe(fullname, onerror) + _rmtree_unsafe(fullname, onexc) else: try: os.unlink(fullname) - except OSError: - onerror(os.unlink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.unlink, fullname, err) try: os.rmdir(path) - except OSError: - onerror(os.rmdir, path, sys.exc_info()) + except OSError as err: + onexc(os.rmdir, path, err) # Version using fd-based APIs to protect against races -def _rmtree_safe_fd(topfd, path, onerror): +def _rmtree_safe_fd(topfd, path, onexc): try: with os.scandir(topfd) as scandir_it: entries = list(scandir_it) except OSError as err: err.filename = path - onerror(os.scandir, path, sys.exc_info()) + onexc(os.scandir, path, err) return for entry in entries: fullname = os.path.join(path, entry.name) @@ -630,25 +630,25 @@ def _rmtree_safe_fd(topfd, path, onerror): try: orig_st = entry.stat(follow_symlinks=False) is_dir = stat.S_ISDIR(orig_st.st_mode) - except OSError: - onerror(os.lstat, fullname, sys.exc_info()) + except OSError as err: + onexc(os.lstat, fullname, err) continue if is_dir: try: dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd) dirfd_closed = False - except OSError: - onerror(os.open, fullname, sys.exc_info()) + except OSError as err: + onexc(os.open, fullname, err) else: try: if os.path.samestat(orig_st, os.fstat(dirfd)): - _rmtree_safe_fd(dirfd, fullname, onerror) + _rmtree_safe_fd(dirfd, fullname, onexc) try: os.close(dirfd) dirfd_closed = True os.rmdir(entry.name, dir_fd=topfd) - except OSError: - onerror(os.rmdir, fullname, sys.exc_info()) + except OSError as err: + onexc(os.rmdir, fullname, err) else: try: # This can only happen if someone replaces @@ -656,23 +656,23 @@ def _rmtree_safe_fd(topfd, path, onerror): # os.scandir or stat.S_ISDIR above. raise OSError("Cannot call rmtree on a symbolic " "link") - except OSError: - onerror(os.path.islink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.path.islink, fullname, err) finally: if not dirfd_closed: os.close(dirfd) else: try: os.unlink(entry.name, dir_fd=topfd) - except OSError: - onerror(os.unlink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.unlink, fullname, err) _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <= os.supports_dir_fd and os.scandir in os.supports_fd and os.stat in os.supports_follow_symlinks) -def rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None): +def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None): """Recursively delete a directory tree. If dir_fd is not None, it should be a file descriptor open to a directory; @@ -680,21 +680,39 @@ def rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None): dir_fd may not be implemented on your platform. If it is unavailable, using it will raise a NotImplementedError. - If ignore_errors is set, errors are ignored; otherwise, if onerror - is set, it is called to handle the error with arguments (func, + If ignore_errors is set, errors are ignored; otherwise, if onexc or + onerror is set, it is called to handle the error with arguments (func, path, exc_info) where func is platform and implementation dependent; path is the argument to that function that caused it to fail; and - exc_info is a tuple returned by sys.exc_info(). If ignore_errors - is false and onerror is None, an exception is raised. + the value of exc_info describes the exception. For onexc it is the + exception instance, and for onerror it is a tuple as returned by + sys.exc_info(). If ignore_errors is false and both onexc and + onerror are None, the exception is reraised. + onerror is deprecated and only remains for backwards compatibility. + If both onerror and onexc are set, onerror is ignored and onexc is used. """ sys.audit("shutil.rmtree", path, dir_fd) if ignore_errors: - def onerror(*args): + def onexc(*args): pass - elif onerror is None: - def onerror(*args): + elif onerror is None and onexc is None: + def onexc(*args): raise + elif onexc is None: + if onerror is None: + def onexc(*args): + raise + else: + # delegate to onerror + def onexc(*args): + func, path, exc = args + if exc is None: + exc_info = None, None, None + else: + exc_info = type(exc), exc, exc.__traceback__ + return onerror(func, path, exc_info) + if _use_fd_functions: # While the unsafe rmtree works fine on bytes, the fd based does not. if isinstance(path, bytes): @@ -703,30 +721,30 @@ def onerror(*args): # lstat()/open()/fstat() trick. try: orig_st = os.lstat(path, dir_fd=dir_fd) - except Exception: - onerror(os.lstat, path, sys.exc_info()) + except Exception as err: + onexc(os.lstat, path, err) return try: fd = os.open(path, os.O_RDONLY, dir_fd=dir_fd) fd_closed = False - except Exception: - onerror(os.open, path, sys.exc_info()) + except Exception as err: + onexc(os.open, path, err) return try: if os.path.samestat(orig_st, os.fstat(fd)): - _rmtree_safe_fd(fd, path, onerror) + _rmtree_safe_fd(fd, path, onexc) try: os.close(fd) fd_closed = True os.rmdir(path, dir_fd=dir_fd) - except OSError: - onerror(os.rmdir, path, sys.exc_info()) + except OSError as err: + onexc(os.rmdir, path, err) else: try: # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) + except OSError as err: + onexc(os.path.islink, path, err) finally: if not fd_closed: os.close(fd) @@ -737,11 +755,11 @@ def onerror(*args): if _rmtree_islink(path): # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) - # can't continue even if onerror hook returns + except OSError as err: + onexc(os.path.islink, path, err) + # can't continue even if onexc hook returns return - return _rmtree_unsafe(path, onerror) + return _rmtree_unsafe(path, onexc) # Allow introspection of whether or not the hardening against symlink # attacks is supported on the current platform diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 8fe62216ecdc..fee3e7f76563 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -195,7 +195,7 @@ def test_rmtree_works_on_bytes(self): shutil.rmtree(victim) @os_helper.skip_unless_symlink - def test_rmtree_fails_on_symlink(self): + def test_rmtree_fails_on_symlink_onerror(self): tmp = self.mkdtemp() dir_ = os.path.join(tmp, 'dir') os.mkdir(dir_) @@ -213,6 +213,25 @@ def onerror(*args): self.assertEqual(errors[0][1], link) self.assertIsInstance(errors[0][2][1], OSError) + @os_helper.skip_unless_symlink + def test_rmtree_fails_on_symlink_onexc(self): + tmp = self.mkdtemp() + dir_ = os.path.join(tmp, 'dir') + os.mkdir(dir_) + link = os.path.join(tmp, 'link') + os.symlink(dir_, link) + self.assertRaises(OSError, shutil.rmtree, link) + self.assertTrue(os.path.exists(dir_)) + self.assertTrue(os.path.lexists(link)) + errors = [] + def onexc(*args): + errors.append(args) + shutil.rmtree(link, onexc=onexc) + self.assertEqual(len(errors), 1) + self.assertIs(errors[0][0], os.path.islink) + self.assertEqual(errors[0][1], link) + self.assertIsInstance(errors[0][2], OSError) + @os_helper.skip_unless_symlink def test_rmtree_works_on_symlinks(self): tmp = self.mkdtemp() @@ -236,7 +255,7 @@ def test_rmtree_works_on_symlinks(self): self.assertTrue(os.path.exists(file1)) @unittest.skipUnless(_winapi, 'only relevant on Windows') - def test_rmtree_fails_on_junctions(self): + def test_rmtree_fails_on_junctions_onerror(self): tmp = self.mkdtemp() dir_ = os.path.join(tmp, 'dir') os.mkdir(dir_) @@ -255,6 +274,26 @@ def onerror(*args): self.assertEqual(errors[0][1], link) self.assertIsInstance(errors[0][2][1], OSError) + @unittest.skipUnless(_winapi, 'only relevant on Windows') + def test_rmtree_fails_on_junctions_onexc(self): + tmp = self.mkdtemp() + dir_ = os.path.join(tmp, 'dir') + os.mkdir(dir_) + link = os.path.join(tmp, 'link') + _winapi.CreateJunction(dir_, link) + self.addCleanup(os_helper.unlink, link) + self.assertRaises(OSError, shutil.rmtree, link) + self.assertTrue(os.path.exists(dir_)) + self.assertTrue(os.path.lexists(link)) + errors = [] + def onexc(*args): + errors.append(args) + shutil.rmtree(link, onexc=onexc) + self.assertEqual(len(errors), 1) + self.assertIs(errors[0][0], os.path.islink) + self.assertEqual(errors[0][1], link) + self.assertIsInstance(errors[0][2], OSError) + @unittest.skipUnless(_winapi, 'only relevant on Windows') def test_rmtree_works_on_junctions(self): tmp = self.mkdtemp() @@ -277,7 +316,7 @@ def test_rmtree_works_on_junctions(self): self.assertTrue(os.path.exists(dir3)) self.assertTrue(os.path.exists(file1)) - def test_rmtree_errors(self): + def test_rmtree_errors_onerror(self): # filename is guaranteed not to exist filename = tempfile.mktemp(dir=self.mkdtemp()) self.assertRaises(FileNotFoundError, shutil.rmtree, filename) @@ -309,6 +348,37 @@ def onerror(*args): self.assertIsInstance(errors[1][2][1], NotADirectoryError) self.assertEqual(errors[1][2][1].filename, filename) + def test_rmtree_errors_onexc(self): + # filename is guaranteed not to exist + filename = tempfile.mktemp(dir=self.mkdtemp()) + self.assertRaises(FileNotFoundError, shutil.rmtree, filename) + # test that ignore_errors option is honored + shutil.rmtree(filename, ignore_errors=True) + + # existing file + tmpdir = self.mkdtemp() + write_file((tmpdir, "tstfile"), "") + filename = os.path.join(tmpdir, "tstfile") + with self.assertRaises(NotADirectoryError) as cm: + shutil.rmtree(filename) + self.assertEqual(cm.exception.filename, filename) + self.assertTrue(os.path.exists(filename)) + # test that ignore_errors option is honored + shutil.rmtree(filename, ignore_errors=True) + self.assertTrue(os.path.exists(filename)) + errors = [] + def onexc(*args): + errors.append(args) + shutil.rmtree(filename, onexc=onexc) + self.assertEqual(len(errors), 2) + self.assertIs(errors[0][0], os.scandir) + self.assertEqual(errors[0][1], filename) + self.assertIsInstance(errors[0][2], NotADirectoryError) + self.assertEqual(errors[0][2].filename, filename) + self.assertIs(errors[1][0], os.rmdir) + self.assertEqual(errors[1][1], filename) + self.assertIsInstance(errors[1][2], NotADirectoryError) + self.assertEqual(errors[1][2].filename, filename) @unittest.skipIf(sys.platform[:6] == 'cygwin', "This test can't be run on Cygwin (issue #1071513).") @@ -368,6 +438,100 @@ def check_args_to_onerror(self, func, arg, exc): self.assertTrue(issubclass(exc[0], OSError)) self.errorState = 3 + @unittest.skipIf(sys.platform[:6] == 'cygwin', + "This test can't be run on Cygwin (issue #1071513).") + @os_helper.skip_if_dac_override + @os_helper.skip_unless_working_chmod + def test_on_exc(self): + self.errorState = 0 + os.mkdir(TESTFN) + self.addCleanup(shutil.rmtree, TESTFN) + + self.child_file_path = os.path.join(TESTFN, 'a') + self.child_dir_path = os.path.join(TESTFN, 'b') + os_helper.create_empty_file(self.child_file_path) + os.mkdir(self.child_dir_path) + old_dir_mode = os.stat(TESTFN).st_mode + old_child_file_mode = os.stat(self.child_file_path).st_mode + old_child_dir_mode = os.stat(self.child_dir_path).st_mode + # Make unwritable. + new_mode = stat.S_IREAD|stat.S_IEXEC + os.chmod(self.child_file_path, new_mode) + os.chmod(self.child_dir_path, new_mode) + os.chmod(TESTFN, new_mode) + + self.addCleanup(os.chmod, TESTFN, old_dir_mode) + self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) + self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) + + shutil.rmtree(TESTFN, onexc=self.check_args_to_onexc) + # Test whether onexc has actually been called. + self.assertEqual(self.errorState, 3, + "Expected call to onexc function did not happen.") + + def check_args_to_onexc(self, func, arg, exc): + # test_rmtree_errors deliberately runs rmtree + # on a directory that is chmod 500, which will fail. + # This function is run when shutil.rmtree fails. + # 99.9% of the time it initially fails to remove + # a file in the directory, so the first time through + # func is os.remove. + # However, some Linux machines running ZFS on + # FUSE experienced a failure earlier in the process + # at os.listdir. The first failure may legally + # be either. + if self.errorState < 2: + if func is os.unlink: + self.assertEqual(arg, self.child_file_path) + elif func is os.rmdir: + self.assertEqual(arg, self.child_dir_path) + else: + self.assertIs(func, os.listdir) + self.assertIn(arg, [TESTFN, self.child_dir_path]) + self.assertTrue(isinstance(exc, OSError)) + self.errorState += 1 + else: + self.assertEqual(func, os.rmdir) + self.assertEqual(arg, TESTFN) + self.assertTrue(isinstance(exc, OSError)) + self.errorState = 3 + + def test_both_onerror_and_onexc(self): + onerror_called = False + onexc_called = False + + def onerror(*args): + nonlocal onerror_called + onerror_called = True + + def onexc(*args): + nonlocal onexc_called + onexc_called = True + + os.mkdir(TESTFN) + self.addCleanup(shutil.rmtree, TESTFN) + + self.child_file_path = os.path.join(TESTFN, 'a') + self.child_dir_path = os.path.join(TESTFN, 'b') + os_helper.create_empty_file(self.child_file_path) + os.mkdir(self.child_dir_path) + old_dir_mode = os.stat(TESTFN).st_mode + old_child_file_mode = os.stat(self.child_file_path).st_mode + old_child_dir_mode = os.stat(self.child_dir_path).st_mode + # Make unwritable. + new_mode = stat.S_IREAD|stat.S_IEXEC + os.chmod(self.child_file_path, new_mode) + os.chmod(self.child_dir_path, new_mode) + os.chmod(TESTFN, new_mode) + + self.addCleanup(os.chmod, TESTFN, old_dir_mode) + self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) + self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) + + shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc) + self.assertTrue(onexc_called) + self.assertFalse(onerror_called) + def test_rmtree_does_not_choke_on_failing_lstat(self): try: orig_lstat = os.lstat diff --git a/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst b/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst new file mode 100644 index 000000000000..be9b2bab24a3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst @@ -0,0 +1,3 @@ +Add the ``onexc`` arg to :func:`shutil.rmtree`, which is like ``onerror`` +but expects an exception instance rather than an exc_info tuple. Deprecate +``onerror``. From webhook-mailer at python.org Sun Mar 19 16:06:36 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sun, 19 Mar 2023 20:06:36 -0000 Subject: [Python-checkins] gh-102810: Add docstrings to the public-facing methods of `asyncio.Timeout` (#102811) Message-ID: https://github.com/python/cpython/commit/699cb20ae6fdef8b0f13d633cf4858465ef3469f commit: 699cb20ae6fdef8b0f13d633cf4858465ef3469f branch: main author: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> committer: AlexWaygood date: 2023-03-19T20:06:09Z summary: gh-102810: Add docstrings to the public-facing methods of `asyncio.Timeout` (#102811) Co-authored-by: Guido van Rossum Co-authored-by: Alex Waygood files: M Lib/asyncio/timeouts.py diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py index 94d25535fbc0..d07b291005e8 100644 --- a/Lib/asyncio/timeouts.py +++ b/Lib/asyncio/timeouts.py @@ -25,8 +25,18 @@ class _State(enum.Enum): @final class Timeout: + """Asynchronous context manager for cancelling overdue coroutines. + + Use `timeout()` or `timeout_at()` rather than instantiating this class directly. + """ def __init__(self, when: Optional[float]) -> None: + """Schedule a timeout that will trigger at a given loop time. + + - If `when` is `None`, the timeout will never trigger. + - If `when < loop.time()`, the timeout will trigger on the next + iteration of the event loop. + """ self._state = _State.CREATED self._timeout_handler: Optional[events.TimerHandle] = None @@ -34,9 +44,11 @@ def __init__(self, when: Optional[float]) -> None: self._when = when def when(self) -> Optional[float]: + """Return the current deadline.""" return self._when def reschedule(self, when: Optional[float]) -> None: + """Reschedule the timeout.""" assert self._state is not _State.CREATED if self._state is not _State.ENTERED: raise RuntimeError( From webhook-mailer at python.org Sun Mar 19 16:31:29 2023 From: webhook-mailer at python.org (miss-islington) Date: Sun, 19 Mar 2023 20:31:29 -0000 Subject: [Python-checkins] gh-102810: Add docstrings to the public-facing methods of `asyncio.Timeout` (GH-102811) Message-ID: https://github.com/python/cpython/commit/98833563e25c2b9bafce9f9dd1579f169f921ed7 commit: 98833563e25c2b9bafce9f9dd1579f169f921ed7 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-19T13:31:22-07:00 summary: gh-102810: Add docstrings to the public-facing methods of `asyncio.Timeout` (GH-102811) (cherry picked from commit 699cb20ae6fdef8b0f13d633cf4858465ef3469f) Co-authored-by: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> Co-authored-by: Guido van Rossum Co-authored-by: Alex Waygood files: M Lib/asyncio/timeouts.py diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py index 94d25535fbc0..d07b291005e8 100644 --- a/Lib/asyncio/timeouts.py +++ b/Lib/asyncio/timeouts.py @@ -25,8 +25,18 @@ class _State(enum.Enum): @final class Timeout: + """Asynchronous context manager for cancelling overdue coroutines. + + Use `timeout()` or `timeout_at()` rather than instantiating this class directly. + """ def __init__(self, when: Optional[float]) -> None: + """Schedule a timeout that will trigger at a given loop time. + + - If `when` is `None`, the timeout will never trigger. + - If `when < loop.time()`, the timeout will trigger on the next + iteration of the event loop. + """ self._state = _State.CREATED self._timeout_handler: Optional[events.TimerHandle] = None @@ -34,9 +44,11 @@ def __init__(self, when: Optional[float]) -> None: self._when = when def when(self) -> Optional[float]: + """Return the current deadline.""" return self._when def reschedule(self, when: Optional[float]) -> None: + """Reschedule the timeout.""" assert self._state is not _State.CREATED if self._state is not _State.ENTERED: raise RuntimeError( From webhook-mailer at python.org Sun Mar 19 18:52:54 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sun, 19 Mar 2023 22:52:54 -0000 Subject: [Python-checkins] gh-102491: Remove IronPython version check in sys_version (#102492) Message-ID: https://github.com/python/cpython/commit/382ee2f0f2be662fbcabcb4a6b38de416cea0cae commit: 382ee2f0f2be662fbcabcb4a6b38de416cea0cae branch: main author: Pieter Eendebak committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-19T15:52:47-07:00 summary: gh-102491: Remove IronPython version check in sys_version (#102492) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst M Lib/platform.py M Lib/test/test_platform.py diff --git a/Lib/platform.py b/Lib/platform.py index f2b0d1d1bd3f..790ef860bf10 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -1040,20 +1040,6 @@ def processor(): r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)" r'\[([^\]]+)\]?', re.ASCII) # "[compiler]" -_ironpython_sys_version_parser = re.compile( - r'IronPython\s*' - r'([\d\.]+)' - r'(?: \(([\d\.]+)\))?' - r' on (.NET [\d\.]+)', re.ASCII) - -# IronPython covering 2.6 and 2.7 -_ironpython26_sys_version_parser = re.compile( - r'([\d.]+)\s*' - r'\(IronPython\s*' - r'[\d.]+\s*' - r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)' -) - _pypy_sys_version_parser = re.compile( r'([\w.+]+)\s*' r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*' @@ -1090,25 +1076,7 @@ def _sys_version(sys_version=None): if result is not None: return result - # Parse it - if 'IronPython' in sys_version: - # IronPython - name = 'IronPython' - if sys_version.startswith('IronPython'): - match = _ironpython_sys_version_parser.match(sys_version) - else: - match = _ironpython26_sys_version_parser.match(sys_version) - - if match is None: - raise ValueError( - 'failed to parse IronPython sys.version: %s' % - repr(sys_version)) - - version, alt_version, compiler = match.groups() - buildno = '' - builddate = '' - - elif sys.platform.startswith('java'): + if sys.platform.startswith('java'): # Jython name = 'Jython' match = _sys_version_parser.match(sys_version) @@ -1171,7 +1139,6 @@ def python_implementation(): Currently, the following implementations are identified: 'CPython' (C implementation of Python), - 'IronPython' (.NET implementation of Python), 'Jython' (Java implementation of Python), 'PyPy' (Python implementation of Python). diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 72942dda3424..216973350319 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -123,10 +123,6 @@ def test_sys_version(self): for input, output in ( ('2.4.3 (#1, Jun 21 2006, 13:54:21) \n[GCC 3.3.4 (pre 3.3.5 20040809)]', ('CPython', '2.4.3', '', '', '1', 'Jun 21 2006 13:54:21', 'GCC 3.3.4 (pre 3.3.5 20040809)')), - ('IronPython 1.0.60816 on .NET 2.0.50727.42', - ('IronPython', '1.0.60816', '', '', '', '', '.NET 2.0.50727.42')), - ('IronPython 1.0 (1.0.61005.1977) on .NET 2.0.50727.42', - ('IronPython', '1.0.0', '', '', '', '', '.NET 2.0.50727.42')), ('2.4.3 (truncation, date, t) \n[GCC]', ('CPython', '2.4.3', '', '', 'truncation', 'date t', 'GCC')), ('2.4.3 (truncation, date, ) \n[GCC]', @@ -161,20 +157,11 @@ def test_sys_version(self): ('r261:67515', 'Dec 6 2008 15:26:00'), 'GCC 4.0.1 (Apple Computer, Inc. build 5370)'), - ("IronPython 2.0 (2.0.0.0) on .NET 2.0.50727.3053", None, "cli") + ("3.10.8 (tags/v3.10.8:aaaf517424, Feb 14 2023, 16:28:12) [GCC 9.4.0]", + None, "linux") : - ("IronPython", "2.0.0", "", "", ("", ""), - ".NET 2.0.50727.3053"), - - ("2.6.1 (IronPython 2.6.1 (2.6.10920.0) on .NET 2.0.50727.1433)", None, "cli") - : - ("IronPython", "2.6.1", "", "", ("", ""), - ".NET 2.0.50727.1433"), - - ("2.7.4 (IronPython 2.7.4 (2.7.0.40) on Mono 4.0.30319.1 (32-bit))", None, "cli") - : - ("IronPython", "2.7.4", "", "", ("", ""), - "Mono 4.0.30319.1 (32-bit)"), + ('CPython', '3.10.8', '', '', + ('tags/v3.10.8:aaaf517424', 'Feb 14 2023 16:28:12'), 'GCC 9.4.0'), ("2.5 (trunk:6107, Mar 26 2009, 13:02:18) \n[Java HotSpot(TM) Client VM (\"Apple Computer, Inc.\")]", ('Jython', 'trunk', '6107'), "java1.5.0_16") @@ -205,6 +192,9 @@ def test_sys_version(self): self.assertEqual(platform.python_build(), info[4]) self.assertEqual(platform.python_compiler(), info[5]) + with self.assertRaises(ValueError): + platform._sys_version('2. 4.3 (truncation) \n[GCC]') + def test_system_alias(self): res = platform.system_alias( platform.system(), diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst new file mode 100644 index 000000000000..5bdc9ed2f37a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst @@ -0,0 +1,2 @@ +Improve import time of ``platform`` by removing IronPython version parsing. The IronPython version parsing +was not functional (see https://github.com/IronLanguages/ironpython3/issues/1667). From webhook-mailer at python.org Sun Mar 19 20:04:02 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 20 Mar 2023 00:04:02 -0000 Subject: [Python-checkins] gh-102828: fix test failure (add missing skip instructions) (#102835) Message-ID: https://github.com/python/cpython/commit/40d4f1579382a16d95ec67f2f03167bc1181dbd9 commit: 40d4f1579382a16d95ec67f2f03167bc1181dbd9 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-20T00:03:55Z summary: gh-102828: fix test failure (add missing skip instructions) (#102835) files: M Lib/test/test_shutil.py diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index fee3e7f76563..89d65af3bc5b 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -496,6 +496,10 @@ def check_args_to_onexc(self, func, arg, exc): self.assertTrue(isinstance(exc, OSError)) self.errorState = 3 + @unittest.skipIf(sys.platform[:6] == 'cygwin', + "This test can't be run on Cygwin (issue #1071513).") + @os_helper.skip_if_dac_override + @os_helper.skip_unless_working_chmod def test_both_onerror_and_onexc(self): onerror_called = False onexc_called = False From webhook-mailer at python.org Sun Mar 19 20:20:26 2023 From: webhook-mailer at python.org (zware) Date: Mon, 20 Mar 2023 00:20:26 -0000 Subject: [Python-checkins] gh-72346: Added isdst deprecation warning to email.utils.localtime (GH-91450) Message-ID: https://github.com/python/cpython/commit/5e6661bce968173fa45b74fa2111098645ff609c commit: 5e6661bce968173fa45b74fa2111098645ff609c branch: main author: Alan Williams committer: zware date: 2023-03-19T19:20:20-05:00 summary: gh-72346: Added isdst deprecation warning to email.utils.localtime (GH-91450) files: A Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst M Doc/library/email.utils.rst M Doc/whatsnew/3.12.rst M Lib/email/utils.py M Lib/test/test_email/test_utils.py diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst index 0e266b6a4578..345b64001c1a 100644 --- a/Doc/library/email.utils.rst +++ b/Doc/library/email.utils.rst @@ -13,19 +13,17 @@ module: .. function:: localtime(dt=None) - Return local time as an aware datetime object. If called without - arguments, return current time. Otherwise *dt* argument should be a - :class:`~datetime.datetime` instance, and it is converted to the local time - zone according to the system time zone database. If *dt* is naive (that - is, ``dt.tzinfo`` is ``None``), it is assumed to be in local time. In this - case, a positive or zero value for *isdst* causes ``localtime`` to presume - initially that summer time (for example, Daylight Saving Time) is or is not - (respectively) in effect for the specified time. A negative value for - *isdst* causes the ``localtime`` to attempt to divine whether summer time - is in effect for the specified time. - - .. versionadded:: 3.3 + Return local time as an aware datetime object. If called without + arguments, return current time. Otherwise *dt* argument should be a + :class:`~datetime.datetime` instance, and it is converted to the local time + zone according to the system time zone database. If *dt* is naive (that + is, ``dt.tzinfo`` is ``None``), it is assumed to be in local time. The + *isdst* parameter is ignored. + .. versionadded:: 3.3 + + .. deprecated-removed:: 3.12 3.14 + The *isdst* parameter. .. function:: make_msgid(idstring=None, domain=None) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a36e68528c4f..cdd26cd19e72 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -565,6 +565,9 @@ Pending Removal in Python 3.14 * Creating :c:data:`immutable types ` with mutable bases using the C API. +* Deprecated the *isdst* parameter in :func:`email.utils.localtime`. + (Contributed by Alan Williams in :gh:`72346`.) + * ``__package__`` and ``__cached__`` will cease to be set or taken into consideration by the import system (:gh:`97879`). diff --git a/Lib/email/utils.py b/Lib/email/utils.py index cfdfeb3f1a86..4d014bacd618 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -331,41 +331,23 @@ def collapse_rfc2231_value(value, errors='replace', # better than not having it. # -def localtime(dt=None, isdst=-1): +def localtime(dt=None, isdst=None): """Return local time as an aware datetime object. If called without arguments, return current time. Otherwise *dt* argument should be a datetime instance, and it is converted to the local time zone according to the system time zone database. If *dt* is naive (that is, dt.tzinfo is None), it is assumed to be in local time. - In this case, a positive or zero value for *isdst* causes localtime to - presume initially that summer time (for example, Daylight Saving Time) - is or is not (respectively) in effect for the specified time. A - negative value for *isdst* causes the localtime() function to attempt - to divine whether summer time is in effect for the specified time. + The isdst parameter is ignored. """ + if isdst is not None: + import warnings + warnings._deprecated( + "The 'isdst' parameter to 'localtime'", + message='{name} is deprecated and slated for removal in Python {remove}', + remove=(3, 14), + ) if dt is None: - return datetime.datetime.now(datetime.timezone.utc).astimezone() - if dt.tzinfo is not None: - return dt.astimezone() - # We have a naive datetime. Convert to a (localtime) timetuple and pass to - # system mktime together with the isdst hint. System mktime will return - # seconds since epoch. - tm = dt.timetuple()[:-1] + (isdst,) - seconds = time.mktime(tm) - localtm = time.localtime(seconds) - try: - delta = datetime.timedelta(seconds=localtm.tm_gmtoff) - tz = datetime.timezone(delta, localtm.tm_zone) - except AttributeError: - # Compute UTC offset and compare with the value implied by tm_isdst. - # If the values match, use the zone name implied by tm_isdst. - delta = dt - datetime.datetime(*time.gmtime(seconds)[:6]) - dst = time.daylight and localtm.tm_isdst > 0 - gmtoff = -(time.altzone if dst else time.timezone) - if delta == datetime.timedelta(seconds=gmtoff): - tz = datetime.timezone(delta, time.tzname[dst]) - else: - tz = datetime.timezone(delta) - return dt.replace(tzinfo=tz) + dt = datetime.datetime.now() + return dt.astimezone() diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py index 78afb358035e..25fa48c5ee21 100644 --- a/Lib/test/test_email/test_utils.py +++ b/Lib/test/test_email/test_utils.py @@ -83,14 +83,14 @@ def test_localtime_is_tz_aware_daylight_false(self): def test_localtime_daylight_true_dst_false(self): test.support.patch(self, time, 'daylight', True) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=-1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) def test_localtime_daylight_false_dst_false(self): test.support.patch(self, time, 'daylight', False) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=-1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) @@ -98,7 +98,7 @@ def test_localtime_daylight_false_dst_false(self): def test_localtime_daylight_true_dst_true(self): test.support.patch(self, time, 'daylight', True) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) @@ -106,7 +106,7 @@ def test_localtime_daylight_true_dst_true(self): def test_localtime_daylight_false_dst_true(self): test.support.patch(self, time, 'daylight', False) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) @@ -157,6 +157,11 @@ def test_variable_tzname(self): t1 = utils.localtime(t0) self.assertEqual(t1.tzname(), 'EET') + def test_isdst_deprecation(self): + with self.assertWarns(DeprecationWarning): + t0 = datetime.datetime(1990, 1, 1) + t1 = utils.localtime(t0, isdst=True) + # Issue #24836: The timezone files are out of date (pre 2011k) # on Mac OS X Snow Leopard. @test.support.requires_mac_ver(10, 7) diff --git a/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst b/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst new file mode 100644 index 000000000000..149ddd706c35 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst @@ -0,0 +1 @@ +Added deprecation warning to *isdst* parameter of :func:`email.utils.localtime`. From webhook-mailer at python.org Mon Mar 20 10:43:08 2023 From: webhook-mailer at python.org (markshannon) Date: Mon, 20 Mar 2023 14:43:08 -0000 Subject: [Python-checkins] [3.11] gh-101975: Fixed a potential SegFault on garbage collection (GH-102803) (GH-102807) Message-ID: https://github.com/python/cpython/commit/d149f15d637a323ac818a7fa719cad945828a04b commit: d149f15d637a323ac818a7fa719cad945828a04b branch: 3.11 author: Mark Shannon committer: markshannon date: 2023-03-20T14:42:15Z summary: [3.11] gh-101975: Fixed a potential SegFault on garbage collection (GH-102803) (GH-102807) Authored-by: gaogaotiantian files: A Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst M Python/ceval.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst new file mode 100644 index 000000000000..28c9a8465180 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst @@ -0,0 +1 @@ +Fixed ``stacktop`` value on tracing entries to avoid corruption on garbage collection. diff --git a/Python/ceval.c b/Python/ceval.c index 96d215aba800..72f9c8375d07 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1536,6 +1536,7 @@ eval_frame_handle_pending(PyThreadState *tstate) _PyFrame_SetStackPointer(frame, stack_pointer); \ int err = trace_function_entry(tstate, frame); \ stack_pointer = _PyFrame_GetStackPointer(frame); \ + frame->stacktop = -1; \ if (err) { \ goto error; \ } \ From webhook-mailer at python.org Mon Mar 20 11:47:27 2023 From: webhook-mailer at python.org (zooba) Date: Mon, 20 Mar 2023 15:47:27 -0000 Subject: [Python-checkins] gh-102255: Use GetVersionEx instead of GetVersionExW to match argument type (GH-102583) Message-ID: https://github.com/python/cpython/commit/96e05b62e827a6dee6c658fea9b4976dfd8d30e3 commit: 96e05b62e827a6dee6c658fea9b4976dfd8d30e3 branch: main author: Max Bachmann committer: zooba date: 2023-03-20T15:47:17Z summary: gh-102255: Use GetVersionEx instead of GetVersionExW to match argument type (GH-102583) Since we pass a structure of type `OSVERSIONINFOEX`, we need to call `GetVersionEx` instead of `GetVersionExW`. files: M Modules/socketmodule.c diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index b7927750e334..6a6f8cf7392e 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -353,7 +353,7 @@ remove_unusable_flags(PyObject *m) } #ifndef MS_WINDOWS_DESKTOP info.dwOSVersionInfoSize = sizeof(info); - if (!GetVersionExW((OSVERSIONINFOW*) &info)) { + if (!GetVersionEx((OSVERSIONINFO*) &info)) { PyErr_SetFromWindowsErr(0); return -1; } From webhook-mailer at python.org Mon Mar 20 12:03:13 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 20 Mar 2023 16:03:13 -0000 Subject: [Python-checkins] gh-102304: Move _Py_RefTotal to _PyRuntimeState (gh-102543) Message-ID: https://github.com/python/cpython/commit/ad77d16a6252c2e616bf41b981a6d919c1122b4d commit: ad77d16a6252c2e616bf41b981a6d919c1122b4d branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-20T10:03:04-06:00 summary: gh-102304: Move _Py_RefTotal to _PyRuntimeState (gh-102543) The essentially eliminates the global variable, with the associated benefits. This is also a precursor to isolating this bit of state to PyInterpreterState. Folks that currently read _Py_RefTotal directly would have to start using _Py_GetGlobalRefTotal() instead. https://github.com/python/cpython/issues/102304 files: A Include/internal/pycore_object_state.h M Include/cpython/object.h M Include/internal/pycore_object.h M Include/internal/pycore_runtime.h M Include/object.h M Makefile.pre.in M Objects/object.c M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Python/pylifecycle.c M Python/pystate.c M Python/sysmodule.c M Tools/c-analyzer/cpython/ignored.tsv diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 7b687d311359..0438612edd1d 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -11,7 +11,10 @@ PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); #endif #ifdef Py_REF_DEBUG -PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); +/* These are useful as debugging aids when chasing down refleaks. */ +PyAPI_FUNC(Py_ssize_t) _Py_GetGlobalRefTotal(void); +# define _Py_GetRefTotal() _Py_GetGlobalRefTotal() +PyAPI_FUNC(Py_ssize_t) _Py_GetLegacyRefTotal(void); #endif diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 318e6f3371c0..b985eff8a8a0 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -46,7 +46,8 @@ PyAPI_DATA(Py_ssize_t) _Py_RefTotal; extern void _Py_AddRefTotal(Py_ssize_t); extern void _Py_IncRefTotal(void); extern void _Py_DecRefTotal(void); -# define _Py_DEC_REFTOTAL() _Py_RefTotal-- + +# define _Py_DEC_REFTOTAL() _PyRuntime.object_state.reftotal-- #endif // Increment reference count by n @@ -225,6 +226,7 @@ static inline void _PyObject_GC_UNTRACK( #endif #ifdef Py_REF_DEBUG +extern void _Py_FinalizeRefTotal(_PyRuntimeState *); extern void _PyDebug_PrintTotalRefs(void); #endif diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h new file mode 100644 index 000000000000..4e5862a11edd --- /dev/null +++ b/Include/internal/pycore_object_state.h @@ -0,0 +1,23 @@ +#ifndef Py_INTERNAL_OBJECT_STATE_H +#define Py_INTERNAL_OBJECT_STATE_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +struct _py_object_runtime_state { +#ifdef Py_REF_DEBUG + Py_ssize_t reftotal; +#else + int _not_used; +#endif +}; + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_OBJECT_STATE_H */ diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 520109ca4404..de757dfa93bc 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -15,6 +15,7 @@ extern "C" { #include "pycore_global_objects.h" // struct _Py_global_objects #include "pycore_import.h" // struct _import_runtime_state #include "pycore_interp.h" // PyInterpreterState +#include "pycore_object_state.h" // struct _py_object_runtime_state #include "pycore_parser.h" // struct _parser_runtime_state #include "pycore_pymem.h" // struct _pymem_allocators #include "pycore_pyhash.h" // struct pyhash_runtime_state @@ -150,6 +151,7 @@ typedef struct pyruntimestate { void *open_code_userdata; _Py_AuditHookEntry *audit_hook_head; + struct _py_object_runtime_state object_state; struct _Py_float_runtime_state float_state; struct _Py_unicode_runtime_state unicode_state; diff --git a/Include/object.h b/Include/object.h index 844b9c4a51c3..fc577353c1cc 100644 --- a/Include/object.h +++ b/Include/object.h @@ -494,14 +494,9 @@ you can count such references to the type object.) extern Py_ssize_t _Py_RefTotal; # define _Py_INC_REFTOTAL() _Py_RefTotal++ # define _Py_DEC_REFTOTAL() _Py_RefTotal-- -# elif defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -extern void _Py_IncRefTotal(void); -extern void _Py_DecRefTotal(void); -# define _Py_INC_REFTOTAL() _Py_IncRefTotal() -# define _Py_DEC_REFTOTAL() _Py_DecRefTotal() # elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 > 0x030C0000 -extern void _Py_IncRefTotal_DO_NOT_USE_THIS(void); -extern void _Py_DecRefTotal_DO_NOT_USE_THIS(void); +PyAPI_FUNC(void) _Py_IncRefTotal_DO_NOT_USE_THIS(void); +PyAPI_FUNC(void) _Py_DecRefTotal_DO_NOT_USE_THIS(void); # define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS() # define _Py_DEC_REFTOTAL() _Py_DecRefTotal_DO_NOT_USE_THIS() # endif diff --git a/Makefile.pre.in b/Makefile.pre.in index 8f13198e7e34..74e4171b010d 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1699,6 +1699,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_moduleobject.h \ $(srcdir)/Include/internal/pycore_namespace.h \ $(srcdir)/Include/internal/pycore_object.h \ + $(srcdir)/Include/internal/pycore_object_state.h \ $(srcdir)/Include/internal/pycore_obmalloc.h \ $(srcdir)/Include/internal/pycore_obmalloc_init.h \ $(srcdir)/Include/internal/pycore_pathconfig.h \ diff --git a/Objects/object.c b/Objects/object.c index dff5e2afa16a..95f7c966a414 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -54,37 +54,71 @@ _PyObject_CheckConsistency(PyObject *op, int check_content) #ifdef Py_REF_DEBUG +/* We keep the legacy symbol around for backward compatibility. */ Py_ssize_t _Py_RefTotal; +static inline Py_ssize_t +get_legacy_reftotal(void) +{ + return _Py_RefTotal; +} +#endif + +#ifdef Py_REF_DEBUG + +# define REFTOTAL(runtime) \ + (runtime)->object_state.reftotal + +static inline void +reftotal_increment(_PyRuntimeState *runtime) +{ + REFTOTAL(runtime)++; +} + static inline void -reftotal_increment(void) +reftotal_decrement(_PyRuntimeState *runtime) { - _Py_RefTotal++; + REFTOTAL(runtime)--; } static inline void -reftotal_decrement(void) +reftotal_add(_PyRuntimeState *runtime, Py_ssize_t n) { - _Py_RefTotal--; + REFTOTAL(runtime) += n; } +static inline Py_ssize_t get_global_reftotal(_PyRuntimeState *); + +/* We preserve the number of refs leaked during runtime finalization, + so they can be reported if the runtime is initialized again. */ +// XXX We don't lose any information by dropping this, +// so we should consider doing so. +static Py_ssize_t last_final_reftotal = 0; + void -_Py_AddRefTotal(Py_ssize_t n) +_Py_FinalizeRefTotal(_PyRuntimeState *runtime) { - _Py_RefTotal += n; + last_final_reftotal = get_global_reftotal(runtime); + REFTOTAL(runtime) = 0; } -Py_ssize_t -_Py_GetRefTotal(void) +static inline Py_ssize_t +get_global_reftotal(_PyRuntimeState *runtime) { - return _Py_RefTotal; + /* For an update from _Py_RefTotal first. */ + Py_ssize_t legacy = get_legacy_reftotal(); + return REFTOTAL(runtime) + legacy + last_final_reftotal; } +#undef REFTOTAL + void _PyDebug_PrintTotalRefs(void) { + _PyRuntimeState *runtime = &_PyRuntime; fprintf(stderr, "[%zd refs, %zd blocks]\n", - _Py_GetRefTotal(), _Py_GetAllocatedBlocks()); + get_global_reftotal(runtime), _Py_GetAllocatedBlocks()); + /* It may be helpful to also print the "legacy" reftotal separately. */ } #endif /* Py_REF_DEBUG */ @@ -139,30 +173,50 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op) filename, lineno, __func__); } -/* This is exposed strictly for use in Py_INCREF(). */ -PyAPI_FUNC(void) +/* This is used strictly by Py_INCREF(). */ +void _Py_IncRefTotal_DO_NOT_USE_THIS(void) { - reftotal_increment(); + reftotal_increment(&_PyRuntime); } -/* This is exposed strictly for use in Py_DECREF(). */ -PyAPI_FUNC(void) +/* This is used strictly by Py_DECREF(). */ +void _Py_DecRefTotal_DO_NOT_USE_THIS(void) { - reftotal_decrement(); + reftotal_decrement(&_PyRuntime); } void _Py_IncRefTotal(void) { - reftotal_increment(); + reftotal_increment(&_PyRuntime); } void _Py_DecRefTotal(void) { - reftotal_decrement(); + reftotal_decrement(&_PyRuntime); +} + +void +_Py_AddRefTotal(Py_ssize_t n) +{ + reftotal_add(&_PyRuntime, n); +} + +/* This includes the legacy total + and any carried over from the last runtime init/fini cycle. */ +Py_ssize_t +_Py_GetGlobalRefTotal(void) +{ + return get_global_reftotal(&_PyRuntime); +} + +Py_ssize_t +_Py_GetLegacyRefTotal(void) +{ + return get_legacy_reftotal(); } #endif /* Py_REF_DEBUG */ @@ -182,21 +236,18 @@ Py_DecRef(PyObject *o) void _Py_IncRef(PyObject *o) { -#ifdef Py_REF_DEBUG - reftotal_increment(); -#endif Py_INCREF(o); } void _Py_DecRef(PyObject *o) { -#ifdef Py_REF_DEBUG - reftotal_decrement(); -#endif Py_DECREF(o); } + +/**************************************/ + PyObject * PyObject_Init(PyObject *op, PyTypeObject *tp) { @@ -2077,7 +2128,7 @@ void _Py_NewReference(PyObject *op) { #ifdef Py_REF_DEBUG - reftotal_increment(); + reftotal_increment(&_PyRuntime); #endif new_reference(op); } diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 0343d30a42cd..c754b2165745 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -239,6 +239,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 359463e1d9af..90ed0602821b 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -621,6 +621,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 317d6966d034..731f340001b4 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1930,6 +1930,7 @@ Py_FinalizeEx(void) if (show_ref_count) { _PyDebug_PrintTotalRefs(); } + _Py_FinalizeRefTotal(runtime); #endif #ifdef Py_TRACE_REFS diff --git a/Python/pystate.c b/Python/pystate.c index 3a2966c54a4c..4d4213551a8b 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -482,6 +482,9 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) void _PyRuntimeState_Fini(_PyRuntimeState *runtime) { + /* The reftotal is cleared by _Py_FinalizeRefTotal(). */ + assert(runtime->object_state.reftotal == 0); + if (gilstate_tss_initialized(runtime)) { gilstate_tss_fini(runtime); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 126b7d422e00..20761738b527 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1854,7 +1854,7 @@ static Py_ssize_t sys_gettotalrefcount_impl(PyObject *module) /*[clinic end generated code: output=4103886cf17c25bc input=53b744faa5d2e4f6]*/ { - return _Py_GetRefTotal(); + return _Py_GetGlobalRefTotal(); } #endif /* Py_REF_DEBUG */ diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 048112dd9925..14fc32a07b43 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -141,7 +141,6 @@ Modules/syslogmodule.c - S_log_open - ##----------------------- ## kept for stable ABI compatibility -# XXX should be per-interpreter, without impacting stable ABI extensions Objects/object.c - _Py_RefTotal - ##----------------------- @@ -301,6 +300,7 @@ Objects/genobject.c - NON_INIT_CORO_MSG - Objects/longobject.c - _PyLong_DigitValue - Objects/object.c - _Py_SwappedOp - Objects/object.c - _Py_abstract_hack - +Objects/object.c - last_final_reftotal - Objects/object.c - static_types - Objects/obmalloc.c - _PyMem - Objects/obmalloc.c - _PyMem_Debug - From webhook-mailer at python.org Mon Mar 20 12:36:15 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 20 Mar 2023 16:36:15 -0000 Subject: [Python-checkins] gh-102304: Add a What's New Entry About _Py_RefTotal (gh-102845) Message-ID: https://github.com/python/cpython/commit/28d369e070652e8f2274101d72131e3140dfadf7 commit: 28d369e070652e8f2274101d72131e3140dfadf7 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-20T10:35:49-06:00 summary: gh-102304: Add a What's New Entry About _Py_RefTotal (gh-102845) https://github.com/python/cpython/issues/102304 files: M Doc/whatsnew/3.12.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index cdd26cd19e72..af52c7cb670c 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1036,6 +1036,11 @@ Porting to Python 3.12 functions that set the error indicator now normalize the exception before storing it. (Contributed by Mark Shannon in :gh:`101578`.) +* ``_Py_RefTotal`` is no longer authoritative and only kept around + for ABI compabitility. Note that it is an internal global and only + available on debug builds. If you happen to be using it then you'll + need to start using ``_Py_GetGlobalRefTotal()``. + Deprecated ---------- From webhook-mailer at python.org Mon Mar 20 13:28:29 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 20 Mar 2023 17:28:29 -0000 Subject: [Python-checkins] gh-102304: Fix Non-Debug Builds (gh-102846) Message-ID: https://github.com/python/cpython/commit/5c75b7a91ca7ad4133d5a7e9c245268bcfdd993e commit: 5c75b7a91ca7ad4133d5a7e9c245268bcfdd993e branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-20T11:28:13-06:00 summary: gh-102304: Fix Non-Debug Builds (gh-102846) Some debug-only code slipped in with gh-102543. https://github.com/python/cpython/issues/102304 files: M Python/pystate.c diff --git a/Python/pystate.c b/Python/pystate.c index 4d4213551a8b..60adb54685ce 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -482,8 +482,10 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) void _PyRuntimeState_Fini(_PyRuntimeState *runtime) { +#ifdef Py_REF_DEBUG /* The reftotal is cleared by _Py_FinalizeRefTotal(). */ assert(runtime->object_state.reftotal == 0); +#endif if (gilstate_tss_initialized(runtime)) { gilstate_tss_fini(runtime); From webhook-mailer at python.org Mon Mar 20 18:14:36 2023 From: webhook-mailer at python.org (rhettinger) Date: Mon, 20 Mar 2023 22:14:36 -0000 Subject: [Python-checkins] Add itertool recipe for polynomial evaluation. (GH-102852) Message-ID: https://github.com/python/cpython/commit/094cf392f49d3c16fe798863717f6c8e0f3734bb commit: 094cf392f49d3c16fe798863717f6c8e0f3734bb branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-20T17:14:29-05:00 summary: Add itertool recipe for polynomial evaluation. (GH-102852) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index d85a17effb04..9364f72ca456 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -866,6 +866,15 @@ which incur interpreter overhead. window.append(x) yield math.sumprod(kernel, window) + def polynomial_eval(coefficients, x): + "Evaluate a polynomial at a specific value." + # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 x? -4x? -17x + 60 + n = len(coefficients) + if n == 0: + return x * 0 # coerce zero to the type of x + powers = list(accumulate(repeat(x, n - 1), operator.mul, initial=1)) + return math.sumprod(coefficients, reversed(powers)) + def polynomial_from_roots(roots): """Compute a polynomial's coefficients from its roots. @@ -1245,6 +1254,37 @@ which incur interpreter overhead. >>> list(convolve(data, [1, -2, 1])) [20, 0, -36, 24, -20, 20, -20, -4, 16] + >>> from fractions import Fraction + >>> from decimal import Decimal + >>> polynomial_eval([1, -4, -17, 60], x=2) + 18 + >>> x = 2; x**3 - 4*x**2 -17*x + 60 + 18 + >>> polynomial_eval([1, -4, -17, 60], x=2.5) + 8.125 + >>> x = 2.5; x**3 - 4*x**2 -17*x + 60 + 8.125 + >>> polynomial_eval([1, -4, -17, 60], x=Fraction(2, 3)) + Fraction(1274, 27) + >>> x = Fraction(2, 3); x**3 - 4*x**2 -17*x + 60 + Fraction(1274, 27) + >>> polynomial_eval([1, -4, -17, 60], x=Decimal('1.75')) + Decimal('23.359375') + >>> x = Decimal('1.75'); x**3 - 4*x**2 -17*x + 60 + Decimal('23.359375') + >>> polynomial_eval([], 2) + 0 + >>> polynomial_eval([], 2.5) + 0.0 + >>> polynomial_eval([], Fraction(2, 3)) + Fraction(0, 1) + >>> polynomial_eval([], Decimal('1.75')) + Decimal('0.00') + >>> polynomial_eval([11], 7) == 11 + True + >>> polynomial_eval([11, 2], 7) == 11 * 7 + 2 + True + >>> polynomial_from_roots([5, -4, 3]) [1, -4, -17, 60] >>> factored = lambda x: (x - 5) * (x + 4) * (x - 3) From webhook-mailer at python.org Mon Mar 20 19:30:53 2023 From: webhook-mailer at python.org (gpshead) Date: Mon, 20 Mar 2023 23:30:53 -0000 Subject: [Python-checkins] gh-102809: Remove `Misc/gdbinit` (#102854) Message-ID: https://github.com/python/cpython/commit/ef000eb3e2a8d0ecd51b6d44b390fefd820a61a6 commit: ef000eb3e2a8d0ecd51b6d44b390fefd820a61a6 branch: main author: Nikita Sobolev committer: gpshead date: 2023-03-20T16:30:46-07:00 summary: gh-102809: Remove `Misc/gdbinit` (#102854) Looks like the consensus is that we don't need this file anymore. Old version can be always found here: https://github.com/python/cpython/blob/094cf392f49d3c16fe798863717f6c8e0f3734bb/Misc/gdbinit files: A Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst D Misc/gdbinit diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst b/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst new file mode 100644 index 000000000000..5c2827698785 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst @@ -0,0 +1 @@ +``Misc/gdbinit`` was removed. diff --git a/Misc/gdbinit b/Misc/gdbinit deleted file mode 100644 index e8f62ba64764..000000000000 --- a/Misc/gdbinit +++ /dev/null @@ -1,176 +0,0 @@ -# If you use the GNU debugger gdb to debug the Python C runtime, you -# might find some of the following commands useful. Copy this to your -# ~/.gdbinit file and it'll get loaded into gdb automatically when you -# start it up. Then, at the gdb prompt you can do things like: -# -# (gdb) pyo apyobjectptr -# -# refcounts: 1 -# address : 84a7a2c -# $1 = void -# (gdb) -# -# NOTE: If you have gdb 7 or later, it supports debugging of Python directly -# with embedded macros that you may find superior to what is in here. -# See Tools/gdb/libpython.py and http://bugs.python.org/issue8032. - -define pyo - # side effect of calling _PyObject_Dump is to dump the object's - # info - assigning just prevents gdb from printing the - # NULL return value - set $_unused_void = _PyObject_Dump($arg0) -end -document pyo - Prints a representation of the object to stderr, along with the - number of reference counts it currently has and the hex address the - object is allocated at. The argument must be a PyObject* -end - -define pyg - print _PyGC_Dump($arg0) -end -document pyg - Prints a representation of the object to stderr, along with the - number of reference counts it currently has and the hex address the - object is allocated at. The argument must be a PyGC_Head* -end - -define pylocals - set $_i = 0 - while $_i < f->f_code->co_nlocals - if f->f_localsplus + $_i != 0 - set $_names = f->f_code->co_varnames - set $_name = PyUnicode_AsUTF8(PyTuple_GetItem($_names, $_i)) - printf "%s:\n", $_name - pyo f->f_localsplus[$_i] - end - set $_i = $_i + 1 - end -end -document pylocals - Print the local variables of the current frame. -end - -# A rewrite of the Python interpreter's line number calculator in GDB's -# command language -define lineno - set $__continue = 1 - set $__co = f->f_code - set $__lasti = f->f_lasti - set $__sz = ((PyVarObject *)$__co->co_lnotab)->ob_size/2 - set $__p = (unsigned char *)((PyBytesObject *)$__co->co_lnotab)->ob_sval - set $__li = $__co->co_firstlineno - set $__ad = 0 - while ($__sz-1 >= 0 && $__continue) - set $__sz = $__sz - 1 - set $__ad = $__ad + *$__p - set $__p = $__p + 1 - if ($__ad > $__lasti) - set $__continue = 0 - else - set $__li = $__li + *$__p - set $__p = $__p + 1 - end - end - printf "%d", $__li -end - -define pyframev - pyframe - pylocals -end -document pyframev - Print the current frame - verbose -end - -define pyframe - set $__fn = PyUnicode_AsUTF8(f->f_code->co_filename) - set $__n = PyUnicode_AsUTF8(f->f_code->co_name) - printf "%s (", $__fn - lineno - printf "): %s\n", $__n -### Uncomment these lines when using from within Emacs/XEmacs so it will -### automatically track/display the current Python source line -# printf "%c%c%s:", 032, 032, $__fn -# lineno -# printf ":1\n" -end - -### Use these at your own risk. It appears that a bug in gdb causes it -### to crash in certain circumstances. - -#define up -# up-silently 1 -# printframe -#end - -#define down -# down-silently 1 -# printframe -#end - -define printframe - if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault - pyframe - else - frame - end -end - -# Here's a somewhat fragile way to print the entire Python stack from gdb. -# It's fragile because the tests for the value of $pc depend on the layout -# of specific functions in the C source code. - -# Explanation of while and if tests: We want to pop up the stack until we -# land in Py_Main (this is probably an incorrect assumption in an embedded -# interpreter, but the test can be extended by an interested party). If -# Py_Main <= $pc <= Py_GetArgcArv is true, $pc is in Py_Main(), so the while -# tests succeeds as long as it's not true. In a similar fashion the if -# statement tests to see if we are in PyEval_EvalFrameEx(). - -# Note: The name of the main interpreter function and the function which -# follow it has changed over time. This version of pystack works with this -# version of Python. If you try using it with older or newer versions of -# the interpreter you may will have to change the functions you compare with -# $pc. - -define pystack - while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault - pyframe - end - up-silently 1 - end - select-frame 0 -end -document pystack - Print the entire Python call stack -end - -define pystackv - while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault - pyframev - end - up-silently 1 - end - select-frame 0 -end -document pystackv - Print the entire Python call stack - verbose mode -end - -define pu - set $uni = $arg0 - set $i = 0 - while (*$uni && $i++<100) - if (*$uni < 0x80) - print *(char*)$uni++ - else - print /x *(short*)$uni++ - end - end -end -document pu - Generally useful macro to print a Unicode string -end From webhook-mailer at python.org Mon Mar 20 21:40:11 2023 From: webhook-mailer at python.org (rhettinger) Date: Tue, 21 Mar 2023 01:40:11 -0000 Subject: [Python-checkins] Remove itermediate list. Expand docstring. (GH-102862) Message-ID: https://github.com/python/cpython/commit/4075fe1d8d609edbfff11526f2b1a9a7ce817d07 commit: 4075fe1d8d609edbfff11526f2b1a9a7ce817d07 branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-20T20:40:04-05:00 summary: Remove itermediate list. Expand docstring. (GH-102862) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 9364f72ca456..2427a8d85f84 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -867,13 +867,17 @@ which incur interpreter overhead. yield math.sumprod(kernel, window) def polynomial_eval(coefficients, x): - "Evaluate a polynomial at a specific value." - # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 x? -4x? -17x + 60 + """Evaluate a polynomial at a specific value. + + Computes with better numeric stability than Horner's method. + """ + # Evaluate x? -4x? -17x + 60 at x = 2.5 + # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 n = len(coefficients) if n == 0: return x * 0 # coerce zero to the type of x - powers = list(accumulate(repeat(x, n - 1), operator.mul, initial=1)) - return math.sumprod(coefficients, reversed(powers)) + powers = accumulate(repeat(x, n - 1), operator.mul, initial=1) + return math.sumprod(reversed(coefficients), powers) def polynomial_from_roots(roots): """Compute a polynomial's coefficients from its roots. From webhook-mailer at python.org Tue Mar 21 01:02:21 2023 From: webhook-mailer at python.org (rhettinger) Date: Tue, 21 Mar 2023 05:02:21 -0000 Subject: [Python-checkins] The pow() variant further improves accuracy (GH-102866) Message-ID: https://github.com/python/cpython/commit/1a5a14183ec807ead1c6a46464540159124e5260 commit: 1a5a14183ec807ead1c6a46464540159124e5260 branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-21T00:02:14-05:00 summary: The pow() variant further improves accuracy (GH-102866) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 2427a8d85f84..78f64ea67e25 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -876,7 +876,7 @@ which incur interpreter overhead. n = len(coefficients) if n == 0: return x * 0 # coerce zero to the type of x - powers = accumulate(repeat(x, n - 1), operator.mul, initial=1) + powers = map(pow, repeat(x), range(n)) return math.sumprod(reversed(coefficients), powers) def polynomial_from_roots(roots): From webhook-mailer at python.org Tue Mar 21 03:47:53 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Tue, 21 Mar 2023 07:47:53 -0000 Subject: [Python-checkins] gh-102598: Remove obsolete optimization from `FORMAT_VALUE` opcode (#102599) Message-ID: https://github.com/python/cpython/commit/82eb9469e717e0047543732287a8342e646c2262 commit: 82eb9469e717e0047543732287a8342e646c2262 branch: main author: Nikita Sobolev committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-21T00:47:15-07:00 summary: gh-102598: Remove obsolete optimization from `FORMAT_VALUE` opcode (#102599) files: M Python/bytecodes.c M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6c448707303e..ce2a58b6e304 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3026,20 +3026,10 @@ dummy_func( value = result; } - /* If value is a unicode object, and there's no fmt_spec, - then we know the result of format(value) is value - itself. In that case, skip calling format(). I plan to - move this optimization in to PyObject_Format() - itself. */ - if (PyUnicode_CheckExact(value) && fmt_spec == NULL) { - /* Do nothing, just transfer ownership to result. */ - result = value; - } else { - /* Actually call format(). */ - result = PyObject_Format(value, fmt_spec); - DECREF_INPUTS(); - ERROR_IF(result == NULL, error); - } + result = PyObject_Format(value, fmt_spec); + Py_DECREF(value); + Py_XDECREF(fmt_spec); + ERROR_IF(result == NULL, error); } inst(COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c5a7d90d401a..34b608fced04 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4252,24 +4252,11 @@ value = result; } - /* If value is a unicode object, and there's no fmt_spec, - then we know the result of format(value) is value - itself. In that case, skip calling format(). I plan to - move this optimization in to PyObject_Format() - itself. */ - if (PyUnicode_CheckExact(value) && fmt_spec == NULL) { - /* Do nothing, just transfer ownership to result. */ - result = value; - } else { - /* Actually call format(). */ - result = PyObject_Format(value, fmt_spec); - #line 4267 "Python/generated_cases.c.h" - Py_DECREF(value); - Py_XDECREF(fmt_spec); - #line 3041 "Python/bytecodes.c" - if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - } - #line 4273 "Python/generated_cases.c.h" + result = PyObject_Format(value, fmt_spec); + Py_DECREF(value); + Py_XDECREF(fmt_spec); + if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } + #line 4260 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4278,10 +4265,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3046 "Python/bytecodes.c" + #line 3036 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4285 "Python/generated_cases.c.h" + #line 4272 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4293,7 +4280,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3051 "Python/bytecodes.c" + #line 3041 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4309,12 +4296,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4313 "Python/generated_cases.c.h" + #line 4300 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3067 "Python/bytecodes.c" + #line 3057 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4318 "Python/generated_cases.c.h" + #line 4305 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4324,27 +4311,27 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3072 "Python/bytecodes.c" + #line 3062 "Python/bytecodes.c" assert(oparg >= 2); - #line 4330 "Python/generated_cases.c.h" + #line 4317 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3076 "Python/bytecodes.c" + #line 3066 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4344 "Python/generated_cases.c.h" + #line 4331 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3085 "Python/bytecodes.c" + #line 3075 "Python/bytecodes.c" Py_UNREACHABLE(); - #line 4350 "Python/generated_cases.c.h" + #line 4337 "Python/generated_cases.c.h" } From webhook-mailer at python.org Tue Mar 21 05:37:02 2023 From: webhook-mailer at python.org (encukou) Date: Tue, 21 Mar 2023 09:37:02 -0000 Subject: [Python-checkins] gh-102755: PyErr_DisplayException only in ABI >= 3.12. Tests cover PyErr_Display as well (GH-102849) Message-ID: https://github.com/python/cpython/commit/5c471f3f2a74f4ae7764ed025d2ef077d692d608 commit: 5c471f3f2a74f4ae7764ed025d2ef077d692d608 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: encukou date: 2023-03-21T10:36:18+01:00 summary: gh-102755: PyErr_DisplayException only in ABI >= 3.12. Tests cover PyErr_Display as well (GH-102849) files: M Include/pythonrun.h M Lib/test/test_traceback.py M Modules/_testcapi/exceptions.c diff --git a/Include/pythonrun.h b/Include/pythonrun.h index 41d82e89f848..154c7450cb93 100644 --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -12,7 +12,10 @@ PyAPI_FUNC(PyObject *) Py_CompileString(const char *, const char *, int); PyAPI_FUNC(void) PyErr_Print(void); PyAPI_FUNC(void) PyErr_PrintEx(int); PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); + +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000 PyAPI_FUNC(void) PyErr_DisplayException(PyObject *); +#endif /* Stuff with no proper home (yet) */ diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 1c5d1ab82c8e..399c59f8780d 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -394,6 +394,8 @@ def get_exception(self, callable, slice_start=0, slice_end=-1): class CAPIExceptionFormattingMixin: + LEGACY = 0 + def get_exception(self, callable, slice_start=0, slice_end=-1): from _testcapi import exception_print try: @@ -401,11 +403,13 @@ def get_exception(self, callable, slice_start=0, slice_end=-1): self.fail("No exception thrown.") except Exception as e: with captured_output("stderr") as tbstderr: - exception_print(e) + exception_print(e, self.LEGACY) return tbstderr.getvalue().splitlines()[slice_start:slice_end] callable_line = get_exception.__code__.co_firstlineno + 3 +class CAPIExceptionFormattingLegacyMixin(CAPIExceptionFormattingMixin): + LEGACY = 1 @requires_debug_ranges() class TracebackErrorLocationCaretTestBase: @@ -912,6 +916,16 @@ class CPythonTracebackErrorCaretTests( Same set of tests as above but with Python's internal traceback printing. """ + at cpython_only + at requires_debug_ranges() +class CPythonTracebackErrorCaretTests( + CAPIExceptionFormattingLegacyMixin, + TracebackErrorLocationCaretTestBase, + unittest.TestCase, +): + """ + Same set of tests as above but with Python's legacy internal traceback printing. + """ class TracebackFormatTests(unittest.TestCase): diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index 1922ca3beb79..6099f7d20eb5 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -40,12 +40,22 @@ static PyObject * exception_print(PyObject *self, PyObject *args) { PyObject *exc; + int legacy = 0; - if (!PyArg_ParseTuple(args, "O:exception_print", &exc)) { + if (!PyArg_ParseTuple(args, "O|i:exception_print", &exc, &legacy)) { return NULL; } - - PyErr_DisplayException(exc); + if (legacy) { + PyObject *tb = NULL; + if (PyExceptionInstance_Check(exc)) { + tb = PyException_GetTraceback(exc); + } + PyErr_Display((PyObject *) Py_TYPE(exc), exc, tb); + Py_XDECREF(tb); + } + else { + PyErr_DisplayException(exc); + } Py_RETURN_NONE; } From webhook-mailer at python.org Tue Mar 21 07:07:11 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 21 Mar 2023 11:07:11 -0000 Subject: [Python-checkins] gh-102799: Let pydoc use the exception instead of sys.exc_info (#102830) Message-ID: https://github.com/python/cpython/commit/868490e32790eb1f1b44bbae2f12d480a23dbdac commit: 868490e32790eb1f1b44bbae2f12d480a23dbdac branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-21T11:07:03Z summary: gh-102799: Let pydoc use the exception instead of sys.exc_info (#102830) files: M Lib/pydoc.py diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 0a693f45230c..78d8fd5357f7 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -389,8 +389,17 @@ def synopsis(filename, cache={}): class ErrorDuringImport(Exception): """Errors that occurred while trying to import something to document it.""" def __init__(self, filename, exc_info): + if not isinstance(exc_info, tuple): + assert isinstance(exc_info, BaseException) + self.exc = type(exc_info) + self.value = exc_info + self.tb = exc_info.__traceback__ + else: + warnings.warn("A tuple value for exc_info is deprecated, use an exception instance", + DeprecationWarning) + + self.exc, self.value, self.tb = exc_info self.filename = filename - self.exc, self.value, self.tb = exc_info def __str__(self): exc = self.exc.__name__ @@ -411,8 +420,8 @@ def importfile(path): spec = importlib.util.spec_from_file_location(name, path, loader=loader) try: return importlib._bootstrap._load(spec) - except: - raise ErrorDuringImport(path, sys.exc_info()) + except BaseException as err: + raise ErrorDuringImport(path, err) def safeimport(path, forceload=0, cache={}): """Import a module; handle errors; return None if the module isn't found. @@ -440,21 +449,20 @@ def safeimport(path, forceload=0, cache={}): cache[key] = sys.modules[key] del sys.modules[key] module = __import__(path) - except: + except BaseException as err: # Did the error occur before or after the module was found? - (exc, value, tb) = info = sys.exc_info() if path in sys.modules: # An error occurred while executing the imported module. - raise ErrorDuringImport(sys.modules[path].__file__, info) - elif exc is SyntaxError: + raise ErrorDuringImport(sys.modules[path].__file__, err) + elif type(err) is SyntaxError: # A SyntaxError occurred before we could execute the module. - raise ErrorDuringImport(value.filename, info) - elif issubclass(exc, ImportError) and value.name == path: + raise ErrorDuringImport(err.filename, err) + elif isinstance(err, ImportError) and err.name == path: # No such module in the path. return None else: # Some other error occurred during the importing process. - raise ErrorDuringImport(path, sys.exc_info()) + raise ErrorDuringImport(path, err) for part in path.split('.')[1:]: try: module = getattr(module, part) except AttributeError: return None @@ -1997,8 +2005,8 @@ def __call__(self, request=_GoInteractive): if request is not self._GoInteractive: try: self.help(request) - except ImportError as e: - self.output.write(f'{e}\n') + except ImportError as err: + self.output.write(f'{err}\n') else: self.intro() self.interact() @@ -2405,8 +2413,8 @@ def run(self): docsvr = DocServer(self.host, self.port, self.ready) self.docserver = docsvr docsvr.serve_until_quit() - except Exception as e: - self.error = e + except Exception as err: + self.error = err def ready(self, server): self.serving = True From webhook-mailer at python.org Tue Mar 21 07:08:54 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 21 Mar 2023 11:08:54 -0000 Subject: [Python-checkins] gh-102828: emit deprecation warning for onerror arg to shutil.rmtree (#102850) Message-ID: https://github.com/python/cpython/commit/7f760c2fca3dc5f46a518f5b7622783039bc8b7b commit: 7f760c2fca3dc5f46a518f5b7622783039bc8b7b branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-21T11:08:46Z summary: gh-102828: emit deprecation warning for onerror arg to shutil.rmtree (#102850) files: M Doc/whatsnew/3.12.rst M Lib/shutil.py M Lib/tempfile.py M Lib/test/test_shutil.py diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index af52c7cb670c..b7c956d7f784 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -339,7 +339,8 @@ shutil * :func:`shutil.rmtree` now accepts a new argument *onexc* which is an error handler like *onerror* but which expects an exception instance - rather than a *(typ, val, tb)* triplet. *onerror* is deprecated. + rather than a *(typ, val, tb)* triplet. *onerror* is deprecated and + will be removed in Python 3.14. (Contributed by Irit Katriel in :gh:`102828`.) @@ -503,8 +504,8 @@ Deprecated fields are deprecated. Use :data:`sys.last_exc` instead. (Contributed by Irit Katriel in :gh:`102778`.) -* The *onerror* argument of :func:`shutil.rmtree` is deprecated. Use *onexc* - instead. (Contributed by Irit Katriel in :gh:`102828`.) +* The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed + in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.) Pending Removal in Python 3.13 @@ -586,6 +587,9 @@ Pending Removal in Python 3.14 functions that have been deprecated since Python 2 but only gained a proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14. +* The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, + and will be removed in 3.14. + Pending Removal in Future Versions ---------------------------------- diff --git a/Lib/shutil.py b/Lib/shutil.py index 89a7ac72d983..b0576407e02f 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -10,6 +10,7 @@ import fnmatch import collections import errno +import warnings try: import zlib @@ -692,6 +693,11 @@ def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None): onerror is deprecated and only remains for backwards compatibility. If both onerror and onexc are set, onerror is ignored and onexc is used. """ + + if onerror is not None: + warnings.warn("onerror argument is deprecated, use onexc instead", + DeprecationWarning) + sys.audit("shutil.rmtree", path, dir_fd) if ignore_errors: def onexc(*args): diff --git a/Lib/tempfile.py b/Lib/tempfile.py index bb18d60db0d9..cf06092f826b 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -864,8 +864,8 @@ def __init__(self, suffix=None, prefix=None, dir=None, @classmethod def _rmtree(cls, name, ignore_errors=False): - def onerror(func, path, exc_info): - if issubclass(exc_info[0], PermissionError): + def onexc(func, path, exc): + if isinstance(exc, PermissionError): def resetperms(path): try: _os.chflags(path, 0) @@ -885,13 +885,13 @@ def resetperms(path): cls._rmtree(path, ignore_errors=ignore_errors) except FileNotFoundError: pass - elif issubclass(exc_info[0], FileNotFoundError): + elif isinstance(exc, FileNotFoundError): pass else: if not ignore_errors: raise - _shutil.rmtree(name, onerror=onerror) + _shutil.rmtree(name, onexc=onexc) @classmethod def _cleanup(cls, name, warn_message, ignore_errors=False): diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 89d65af3bc5b..1c0589ced9ea 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -23,6 +23,7 @@ unregister_unpack_format, get_unpack_formats, SameFileError, _GiveupOnFastCopy) import tarfile +import warnings import zipfile try: import posix @@ -207,7 +208,8 @@ def test_rmtree_fails_on_symlink_onerror(self): errors = [] def onerror(*args): errors.append(args) - shutil.rmtree(link, onerror=onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(link, onerror=onerror) self.assertEqual(len(errors), 1) self.assertIs(errors[0][0], os.path.islink) self.assertEqual(errors[0][1], link) @@ -268,7 +270,8 @@ def test_rmtree_fails_on_junctions_onerror(self): errors = [] def onerror(*args): errors.append(args) - shutil.rmtree(link, onerror=onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(link, onerror=onerror) self.assertEqual(len(errors), 1) self.assertIs(errors[0][0], os.path.islink) self.assertEqual(errors[0][1], link) @@ -337,7 +340,8 @@ def test_rmtree_errors_onerror(self): errors = [] def onerror(*args): errors.append(args) - shutil.rmtree(filename, onerror=onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(filename, onerror=onerror) self.assertEqual(len(errors), 2) self.assertIs(errors[0][0], os.scandir) self.assertEqual(errors[0][1], filename) @@ -406,7 +410,8 @@ def test_on_error(self): self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) - shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) # Test whether onerror has actually been called. self.assertEqual(self.errorState, 3, "Expected call to onerror function did not happen.") @@ -532,7 +537,8 @@ def onexc(*args): self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) - shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc) self.assertTrue(onexc_called) self.assertFalse(onerror_called) From webhook-mailer at python.org Tue Mar 21 12:46:44 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 21 Mar 2023 16:46:44 -0000 Subject: [Python-checkins] gh-102595: Document `PyObject_Format` c-api function (GH-102596) Message-ID: https://github.com/python/cpython/commit/910a64e3013bce821bfac75377cbe88bedf265de commit: 910a64e3013bce821bfac75377cbe88bedf265de branch: main author: Nikita Sobolev committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-21T09:46:24-07:00 summary: gh-102595: Document `PyObject_Format` c-api function (GH-102596) Def: https://github.com/python/cpython/blame/5ffdaf748d98da6065158534720f1996a45a0072/Include/abstract.h#L389 files: M Doc/c-api/object.rst diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 84c72e7e108b..0a12bb9e8c54 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -179,6 +179,15 @@ Object Protocol If *o1* and *o2* are the same object, :c:func:`PyObject_RichCompareBool` will always return ``1`` for :const:`Py_EQ` and ``0`` for :const:`Py_NE`. +.. c:function:: PyObject* PyObject_Format(PyObject *obj, PyObject *format_spec) + + Format *obj* using *format_spec*. This is equivalent to the Python + expression ``format(obj, format_spec)``. + + *format_spec* may be ``NULL``. In this case the call is equivalent + to ``format(obj)``. + Returns the formatted string on success, ``NULL`` on failure. + .. c:function:: PyObject* PyObject_Repr(PyObject *o) .. index:: builtin: repr From webhook-mailer at python.org Tue Mar 21 12:49:20 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 21 Mar 2023 16:49:20 -0000 Subject: [Python-checkins] gh-98608: Stop Treating All Errors from _Py_NewInterpreterFromConfig() as Fatal (gh-102657) Message-ID: https://github.com/python/cpython/commit/3bb475662ba998e1b2d26fa370794d0804e33927 commit: 3bb475662ba998e1b2d26fa370794d0804e33927 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-21T10:49:12-06:00 summary: gh-98608: Stop Treating All Errors from _Py_NewInterpreterFromConfig() as Fatal (gh-102657) Prior to this change, errors in _Py_NewInterpreterFromConfig() were always fatal. Instead, callers should be able to handle such errors and keep going. That's what this change supports. (This was an oversight in the original implementation of _Py_NewInterpreterFromConfig().) Note that the existing [fatal] behavior of the public Py_NewInterpreter() is preserved. https://github.com/python/cpython/issues/98608 files: M Include/cpython/initconfig.h M Include/cpython/pylifecycle.h M Include/internal/pycore_initconfig.h M Modules/_testcapimodule.c M Modules/_xxsubinterpretersmodule.c M Python/pylifecycle.c diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index a070fa9ff3a0..8bc681b1a93f 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -25,6 +25,7 @@ PyAPI_FUNC(PyStatus) PyStatus_Exit(int exitcode); PyAPI_FUNC(int) PyStatus_IsError(PyStatus err); PyAPI_FUNC(int) PyStatus_IsExit(PyStatus err); PyAPI_FUNC(int) PyStatus_Exception(PyStatus err); +PyAPI_FUNC(PyObject *) _PyErr_SetFromPyStatus(PyStatus status); /* --- PyWideStringList ------------------------------------------------ */ diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index e1f83acbffc3..821b169d7a17 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -62,5 +62,6 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); -PyAPI_FUNC(PyThreadState *) _Py_NewInterpreterFromConfig( - const _PyInterpreterConfig *); +PyAPI_FUNC(PyStatus) _Py_NewInterpreterFromConfig( + PyThreadState **tstate_p, + const _PyInterpreterConfig *config); diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h index 69f88d7d1d46..4cbd14a61d45 100644 --- a/Include/internal/pycore_initconfig.h +++ b/Include/internal/pycore_initconfig.h @@ -44,8 +44,6 @@ struct pyruntimestate; #define _PyStatus_UPDATE_FUNC(err) \ do { (err).func = _PyStatus_GET_FUNC(); } while (0) -PyObject* _PyErr_SetFromPyStatus(PyStatus status); - /* --- PyWideStringList ------------------------------------------------ */ #define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index f45d0312e944..e2ebab5c5b48 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1538,15 +1538,19 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) .allow_daemon_threads = allow_daemon_threads, .check_multi_interp_extensions = check_multi_interp_extensions, }; - substate = _Py_NewInterpreterFromConfig(&config); - if (substate == NULL) { + PyStatus status = _Py_NewInterpreterFromConfig(&substate, &config); + if (PyStatus_Exception(status)) { /* Since no new thread state was created, there is no exception to propagate; raise a fresh one after swapping in the old thread state. */ PyThreadState_Swap(mainstate); + _PyErr_SetFromPyStatus(status); + PyObject *exc = PyErr_GetRaisedException(); PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed"); + _PyErr_ChainExceptions1(exc); return NULL; } + assert(substate != NULL); r = PyRun_SimpleStringFlags(code, &cflags); Py_EndInterpreter(substate); diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 76fb87fa3a34..9648f080cd75 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -526,15 +526,20 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds) ? (_PyInterpreterConfig)_PyInterpreterConfig_INIT : (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT; // XXX Possible GILState issues? - PyThreadState *tstate = _Py_NewInterpreterFromConfig(&config); + PyThreadState *tstate = NULL; + PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config); PyThreadState_Swap(save_tstate); - if (tstate == NULL) { + if (PyStatus_Exception(status)) { /* Since no new thread state was created, there is no exception to propagate; raise a fresh one after swapping in the old thread state. */ + _PyErr_SetFromPyStatus(status); + PyObject *exc = PyErr_GetRaisedException(); PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed"); + _PyErr_ChainExceptions1(exc); return NULL; } + assert(tstate != NULL); PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate); PyObject *idobj = _PyInterpreterState_GetIDObject(interp); if (idobj == NULL) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 731f340001b4..8b58a14c693f 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2065,22 +2065,23 @@ new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config) return status; } -PyThreadState * -_Py_NewInterpreterFromConfig(const _PyInterpreterConfig *config) +PyStatus +_Py_NewInterpreterFromConfig(PyThreadState **tstate_p, + const _PyInterpreterConfig *config) { - PyThreadState *tstate = NULL; - PyStatus status = new_interpreter(&tstate, config); - if (_PyStatus_EXCEPTION(status)) { - Py_ExitStatusException(status); - } - return tstate; + return new_interpreter(tstate_p, config); } PyThreadState * Py_NewInterpreter(void) { + PyThreadState *tstate = NULL; const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; - return _Py_NewInterpreterFromConfig(&config); + PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config); + if (_PyStatus_EXCEPTION(status)) { + Py_ExitStatusException(status); + } + return tstate; } /* Delete an interpreter and its last thread. This requires that the From webhook-mailer at python.org Tue Mar 21 13:06:34 2023 From: webhook-mailer at python.org (rhettinger) Date: Tue, 21 Mar 2023 17:06:34 -0000 Subject: [Python-checkins] gh-102876: remove superfluous parens from itertools.batched recipe (GH-102877) Message-ID: https://github.com/python/cpython/commit/4bb1dd3c5c14338c9d9cea5988431c858b3b76e0 commit: 4bb1dd3c5c14338c9d9cea5988431c858b3b76e0 branch: main author: wim glenn committer: rhettinger date: 2023-03-21T12:06:18-05:00 summary: gh-102876: remove superfluous parens from itertools.batched recipe (GH-102877) remove superfluous parens from itertools.batched recipe files: M Doc/library/itertools.rst M Lib/test/test_itertools.py diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 78f64ea67e25..38bc369d410d 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -195,7 +195,7 @@ loops that truncate the stream. if n < 1: raise ValueError('n must be at least one') it = iter(iterable) - while (batch := tuple(islice(it, n))): + while batch := tuple(islice(it, n)): yield batch .. versionadded:: 3.12 diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 7014bc97100c..9fe559d4b7ee 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -1846,7 +1846,7 @@ def batched_recipe(iterable, n): if n < 1: raise ValueError('n must be at least one') it = iter(iterable) - while (batch := tuple(islice(it, n))): + while batch := tuple(islice(it, n)): yield batch for iterable, n in product( From webhook-mailer at python.org Tue Mar 21 13:46:18 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 21 Mar 2023 17:46:18 -0000 Subject: [Python-checkins] gh-102304: Move the Total Refcount to PyInterpreterState (gh-102545) Message-ID: https://github.com/python/cpython/commit/743687434c5baf01c266320b34c7a828726702a6 commit: 743687434c5baf01c266320b34c7a828726702a6 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-21T11:46:09-06:00 summary: gh-102304: Move the Total Refcount to PyInterpreterState (gh-102545) Moving it valuable with a per-interpreter GIL. However, it is also useful without one, since it allows us to identify refleaks within a single interpreter or where references are escaping an interpreter. This becomes more important as we move the obmalloc state to PyInterpreterState. https://github.com/python/cpython/issues/102304 files: M Include/cpython/object.h M Include/internal/pycore_interp.h M Include/internal/pycore_object.h M Include/internal/pycore_object_state.h M Objects/bytesobject.c M Objects/dictobject.c M Objects/object.c M Objects/structseq.c M Objects/tupleobject.c M Objects/typeobject.c M Python/pylifecycle.c M Python/pystate.c M Python/sysmodule.c diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 0438612edd1d..859ffb91e223 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -15,6 +15,7 @@ PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); PyAPI_FUNC(Py_ssize_t) _Py_GetGlobalRefTotal(void); # define _Py_GetRefTotal() _Py_GetGlobalRefTotal() PyAPI_FUNC(Py_ssize_t) _Py_GetLegacyRefTotal(void); +PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_GetRefTotal(PyInterpreterState *); #endif diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 84303318d218..1f2c0db2eb5f 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -25,6 +25,7 @@ extern "C" { #include "pycore_import.h" // struct _import_state #include "pycore_list.h" // struct _Py_list_state #include "pycore_global_objects.h" // struct _Py_interp_static_objects +#include "pycore_object_state.h" // struct _py_object_state #include "pycore_tuple.h" // struct _Py_tuple_state #include "pycore_typeobject.h" // struct type_cache #include "pycore_unicodeobject.h" // struct _Py_unicode_state @@ -138,6 +139,7 @@ struct _is { // One bit is set for each non-NULL entry in code_watchers uint8_t active_code_watchers; + struct _py_object_state object_state; struct _Py_unicode_state unicode; struct _Py_float_state float_state; struct _Py_long_state long_state; diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index b985eff8a8a0..d6bbafd4b6cc 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -43,18 +43,19 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc( built against the pre-3.12 stable ABI. */ PyAPI_DATA(Py_ssize_t) _Py_RefTotal; -extern void _Py_AddRefTotal(Py_ssize_t); -extern void _Py_IncRefTotal(void); -extern void _Py_DecRefTotal(void); +extern void _Py_AddRefTotal(PyInterpreterState *, Py_ssize_t); +extern void _Py_IncRefTotal(PyInterpreterState *); +extern void _Py_DecRefTotal(PyInterpreterState *); -# define _Py_DEC_REFTOTAL() _PyRuntime.object_state.reftotal-- +# define _Py_DEC_REFTOTAL(interp) \ + interp->object_state.reftotal-- #endif // Increment reference count by n static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) { #ifdef Py_REF_DEBUG - _Py_AddRefTotal(n); + _Py_AddRefTotal(_PyInterpreterState_GET(), n); #endif op->ob_refcnt += n; } @@ -65,7 +66,7 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) { _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG - _Py_DEC_REFTOTAL(); + _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); #endif if (--op->ob_refcnt != 0) { assert(op->ob_refcnt > 0); @@ -83,7 +84,7 @@ _Py_DECREF_NO_DEALLOC(PyObject *op) { _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG - _Py_DEC_REFTOTAL(); + _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); #endif op->ob_refcnt--; #ifdef Py_DEBUG @@ -226,6 +227,7 @@ static inline void _PyObject_GC_UNTRACK( #endif #ifdef Py_REF_DEBUG +extern void _PyInterpreterState_FinalizeRefTotal(PyInterpreterState *); extern void _Py_FinalizeRefTotal(_PyRuntimeState *); extern void _PyDebug_PrintTotalRefs(void); #endif diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h index 4e5862a11edd..94005d778814 100644 --- a/Include/internal/pycore_object_state.h +++ b/Include/internal/pycore_object_state.h @@ -9,6 +9,14 @@ extern "C" { #endif struct _py_object_runtime_state { +#ifdef Py_REF_DEBUG + Py_ssize_t interpreter_leaks; +#else + int _not_used; +#endif +}; + +struct _py_object_state { #ifdef Py_REF_DEBUG Py_ssize_t reftotal; #else diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 687a654bdae1..2d8dab6f3780 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3067,7 +3067,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) PyObject_Realloc(v, PyBytesObject_SIZE + newsize); if (*pv == NULL) { #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif PyObject_Free(v); PyErr_NoMemory(); diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 53f9a380346a..2ef520044340 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -304,7 +304,7 @@ static inline void dictkeys_incref(PyDictKeysObject *dk) { #ifdef Py_REF_DEBUG - _Py_IncRefTotal(); + _Py_IncRefTotal(_PyInterpreterState_GET()); #endif dk->dk_refcnt++; } @@ -314,7 +314,7 @@ dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk) { assert(dk->dk_refcnt > 0); #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif if (--dk->dk_refcnt == 0) { free_keys_object(interp, dk); @@ -634,7 +634,7 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) } } #ifdef Py_REF_DEBUG - _Py_IncRefTotal(); + _Py_IncRefTotal(_PyInterpreterState_GET()); #endif dk->dk_refcnt = 1; dk->dk_log2_size = log2_size; @@ -824,7 +824,7 @@ clone_combined_dict_keys(PyDictObject *orig) we have it now; calling dictkeys_incref would be an error as keys->dk_refcnt is already set to 1 (after memcpy). */ #ifdef Py_REF_DEBUG - _Py_IncRefTotal(); + _Py_IncRefTotal(_PyInterpreterState_GET()); #endif return keys; } @@ -1530,7 +1530,7 @@ dictresize(PyInterpreterState *interp, PyDictObject *mp, // We can not use free_keys_object here because key's reference // are moved already. #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif if (oldkeys == Py_EMPTY_KEYS) { oldkeys->dk_refcnt--; diff --git a/Objects/object.c b/Objects/object.c index 95f7c966a414..9dd5eb998217 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -66,25 +66,25 @@ get_legacy_reftotal(void) #ifdef Py_REF_DEBUG -# define REFTOTAL(runtime) \ - (runtime)->object_state.reftotal +# define REFTOTAL(interp) \ + interp->object_state.reftotal static inline void -reftotal_increment(_PyRuntimeState *runtime) +reftotal_increment(PyInterpreterState *interp) { - REFTOTAL(runtime)++; + REFTOTAL(interp)++; } static inline void -reftotal_decrement(_PyRuntimeState *runtime) +reftotal_decrement(PyInterpreterState *interp) { - REFTOTAL(runtime)--; + REFTOTAL(interp)--; } static inline void -reftotal_add(_PyRuntimeState *runtime, Py_ssize_t n) +reftotal_add(PyInterpreterState *interp, Py_ssize_t n) { - REFTOTAL(runtime) += n; + REFTOTAL(interp) += n; } static inline Py_ssize_t get_global_reftotal(_PyRuntimeState *); @@ -99,15 +99,43 @@ void _Py_FinalizeRefTotal(_PyRuntimeState *runtime) { last_final_reftotal = get_global_reftotal(runtime); - REFTOTAL(runtime) = 0; + runtime->object_state.interpreter_leaks = 0; +} + +void +_PyInterpreterState_FinalizeRefTotal(PyInterpreterState *interp) +{ + interp->runtime->object_state.interpreter_leaks += REFTOTAL(interp); + REFTOTAL(interp) = 0; +} + +static inline Py_ssize_t +get_reftotal(PyInterpreterState *interp) +{ + /* For a single interpreter, we ignore the legacy _Py_RefTotal, + since we can't determine which interpreter updated it. */ + return REFTOTAL(interp); } static inline Py_ssize_t get_global_reftotal(_PyRuntimeState *runtime) { - /* For an update from _Py_RefTotal first. */ - Py_ssize_t legacy = get_legacy_reftotal(); - return REFTOTAL(runtime) + legacy + last_final_reftotal; + Py_ssize_t total = 0; + + /* Add up the total from each interpreter. */ + HEAD_LOCK(&_PyRuntime); + PyInterpreterState *interp = PyInterpreterState_Head(); + for (; interp != NULL; interp = PyInterpreterState_Next(interp)) { + total += REFTOTAL(interp); + } + HEAD_UNLOCK(&_PyRuntime); + + /* Add in the updated value from the legacy _Py_RefTotal. */ + total += get_legacy_reftotal(); + total += last_final_reftotal; + total += runtime->object_state.interpreter_leaks; + + return total; } #undef REFTOTAL @@ -118,7 +146,8 @@ _PyDebug_PrintTotalRefs(void) { fprintf(stderr, "[%zd refs, %zd blocks]\n", get_global_reftotal(runtime), _Py_GetAllocatedBlocks()); - /* It may be helpful to also print the "legacy" reftotal separately. */ + /* It may be helpful to also print the "legacy" reftotal separately. + Likewise for the total for each interpreter. */ } #endif /* Py_REF_DEBUG */ @@ -177,32 +206,32 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op) void _Py_IncRefTotal_DO_NOT_USE_THIS(void) { - reftotal_increment(&_PyRuntime); + reftotal_increment(_PyInterpreterState_GET()); } /* This is used strictly by Py_DECREF(). */ void _Py_DecRefTotal_DO_NOT_USE_THIS(void) { - reftotal_decrement(&_PyRuntime); + reftotal_decrement(_PyInterpreterState_GET()); } void -_Py_IncRefTotal(void) +_Py_IncRefTotal(PyInterpreterState *interp) { - reftotal_increment(&_PyRuntime); + reftotal_increment(interp); } void -_Py_DecRefTotal(void) +_Py_DecRefTotal(PyInterpreterState *interp) { - reftotal_decrement(&_PyRuntime); + reftotal_decrement(interp); } void -_Py_AddRefTotal(Py_ssize_t n) +_Py_AddRefTotal(PyInterpreterState *interp, Py_ssize_t n) { - reftotal_add(&_PyRuntime, n); + reftotal_add(interp, n); } /* This includes the legacy total @@ -219,6 +248,12 @@ _Py_GetLegacyRefTotal(void) return get_legacy_reftotal(); } +Py_ssize_t +_PyInterpreterState_GetRefTotal(PyInterpreterState *interp) +{ + return get_reftotal(interp); +} + #endif /* Py_REF_DEBUG */ void @@ -2128,7 +2163,7 @@ void _Py_NewReference(PyObject *op) { #ifdef Py_REF_DEBUG - reftotal_increment(&_PyRuntime); + reftotal_increment(_PyInterpreterState_GET()); #endif new_reference(op); } diff --git a/Objects/structseq.c b/Objects/structseq.c index c20962ecd825..2a5343815866 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -592,7 +592,7 @@ _PyStructSequence_FiniType(PyTypeObject *type) // Don't use Py_DECREF(): static type must not be deallocated Py_SET_REFCNT(type, 0); #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif // Make sure that _PyStructSequence_InitType() will initialize diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 59c0251639d3..61fab4078d66 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -944,7 +944,7 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) if (sv == NULL) { *pv = NULL; #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif PyObject_GC_Del(v); return -1; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f0654c239f66..a37f97c71ec7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -317,11 +317,27 @@ _PyType_InitCache(PyInterpreterState *interp) entry->version = 0; // Set to None so _PyType_Lookup() can use Py_SETREF(), // rather than using slower Py_XSETREF(). - entry->name = Py_NewRef(Py_None); + // (See _PyType_FixCacheRefcounts() about the refcount.) + entry->name = Py_None; entry->value = NULL; } } +// This is the temporary fix used by pycore_create_interpreter(), +// in pylifecycle.c. _PyType_InitCache() is called before the GIL +// has been created (for the main interpreter) and without the +// "current" thread state set. This causes crashes when the +// reftotal is updated, so we don't modify the refcount in +// _PyType_InitCache(), and instead do it later by calling +// _PyType_FixCacheRefcounts(). +// XXX This workaround should be removed once we have immortal +// objects (PEP 683). +void +_PyType_FixCacheRefcounts(void) +{ + _Py_RefcntAdd(Py_None, (1 << MCACHE_SIZE_EXP)); +} + static unsigned int _PyType_ClearCache(PyInterpreterState *interp) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 8b58a14c693f..0d546d52087e 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -802,6 +802,11 @@ pycore_interp_init(PyThreadState *tstate) PyStatus status; PyObject *sysmod = NULL; + // This is a temporary fix until we have immortal objects. + // (See _PyType_InitCache() in typeobject.c.) + extern void _PyType_FixCacheRefcounts(void); + _PyType_FixCacheRefcounts(); + // Create singletons before the first PyType_Ready() call, since // PyType_Ready() uses singletons like the Unicode empty string (tp_doc) // and the empty tuple singletons (tp_bases). diff --git a/Python/pystate.c b/Python/pystate.c index 60adb54685ce..b17efdbefd12 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -483,8 +483,8 @@ void _PyRuntimeState_Fini(_PyRuntimeState *runtime) { #ifdef Py_REF_DEBUG - /* The reftotal is cleared by _Py_FinalizeRefTotal(). */ - assert(runtime->object_state.reftotal == 0); + /* The count is cleared by _Py_FinalizeRefTotal(). */ + assert(runtime->object_state.interpreter_leaks == 0); #endif if (gilstate_tss_initialized(runtime)) { @@ -904,6 +904,12 @@ PyInterpreterState_Delete(PyInterpreterState *interp) _PyEval_FiniState(&interp->ceval); +#ifdef Py_REF_DEBUG + // XXX This call should be done at the end of clear_interpreter(), + // but currently some objects get decref'ed after that. + _PyInterpreterState_FinalizeRefTotal(interp); +#endif + HEAD_LOCK(runtime); PyInterpreterState **p; for (p = &interpreters->head; ; p = &(*p)->next) { diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 20761738b527..4afb0f1d0b5e 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1854,6 +1854,8 @@ static Py_ssize_t sys_gettotalrefcount_impl(PyObject *module) /*[clinic end generated code: output=4103886cf17c25bc input=53b744faa5d2e4f6]*/ { + /* It may make sense to return the total for the current interpreter + or have a second function that does so. */ return _Py_GetGlobalRefTotal(); } From webhook-mailer at python.org Tue Mar 21 14:22:26 2023 From: webhook-mailer at python.org (rhettinger) Date: Tue, 21 Mar 2023 18:22:26 -0000 Subject: [Python-checkins] Tweak polynomial itertool recipes (GH-102880) Message-ID: https://github.com/python/cpython/commit/0214c7ad90b0afc3d1491c96e22e48d426caf5e2 commit: 0214c7ad90b0afc3d1491c96e22e48d426caf5e2 branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-21T13:21:57-05:00 summary: Tweak polynomial itertool recipes (GH-102880) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 38bc369d410d..5daadfd3759f 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -866,6 +866,17 @@ which incur interpreter overhead. window.append(x) yield math.sumprod(kernel, window) + def polynomial_from_roots(roots): + """Compute a polynomial's coefficients from its roots. + + (x - 5) (x + 4) (x - 3) expands to: x? -4x? -17x + 60 + """ + # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60] + expansion = [1] + for r in roots: + expansion = convolve(expansion, (1, -r)) + return list(expansion) + def polynomial_eval(coefficients, x): """Evaluate a polynomial at a specific value. @@ -876,20 +887,8 @@ which incur interpreter overhead. n = len(coefficients) if n == 0: return x * 0 # coerce zero to the type of x - powers = map(pow, repeat(x), range(n)) - return math.sumprod(reversed(coefficients), powers) - - def polynomial_from_roots(roots): - """Compute a polynomial's coefficients from its roots. - - (x - 5) (x + 4) (x - 3) expands to: x? -4x? -17x + 60 - """ - # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60] - roots = list(map(operator.neg, roots)) - return [ - sum(map(math.prod, combinations(roots, k))) - for k in range(len(roots) + 1) - ] + powers = map(pow, repeat(x), reversed(range(n))) + return math.sumprod(coefficients, powers) def iter_index(iterable, value, start=0): "Return indices where a value occurs in a sequence or iterable." From webhook-mailer at python.org Tue Mar 21 14:44:39 2023 From: webhook-mailer at python.org (rhettinger) Date: Tue, 21 Mar 2023 18:44:39 -0000 Subject: [Python-checkins] [3.11] Backport itertool recipe updates (GH-102881) Message-ID: https://github.com/python/cpython/commit/e6e3b1b27d08bfe77b5e19b41fbb006fe7bfed36 commit: e6e3b1b27d08bfe77b5e19b41fbb006fe7bfed36 branch: 3.11 author: Raymond Hettinger committer: rhettinger date: 2023-03-21T13:44:32-05:00 summary: [3.11] Backport itertool recipe updates (GH-102881) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 5fe93fd3e0e5..e1ffd39b1bd8 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -805,7 +805,7 @@ which incur interpreter overhead. if n < 1: raise ValueError('n must be at least one') it = iter(iterable) - while (batch := tuple(islice(it, n))): + while batch := tuple(islice(it, n)): yield batch def grouper(iterable, n, *, incomplete='fill', fillvalue=None): @@ -861,11 +861,23 @@ which incur interpreter overhead. (x - 5) (x + 4) (x - 3) expands to: x? -4x? -17x + 60 """ # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60] - roots = list(map(operator.neg, roots)) - return [ - sum(map(math.prod, combinations(roots, k))) - for k in range(len(roots) + 1) - ] + expansion = [1] + for r in roots: + expansion = convolve(expansion, (1, -r)) + return list(expansion) + + def polynomial_eval(coefficients, x): + """Evaluate a polynomial at a specific value. + + Computes with better numeric stability than Horner's method. + """ + # Evaluate x? -4x? -17x + 60 at x = 2.5 + # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 + n = len(coefficients) + if n == 0: + return x * 0 # coerce zero to the type of x + powers = map(pow, repeat(x), reversed(range(n))) + return sumprod(coefficients, powers) def iter_index(iterable, value, start=0): "Return indices where a value occurs in a sequence or iterable." From webhook-mailer at python.org Tue Mar 21 14:48:04 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 21 Mar 2023 18:48:04 -0000 Subject: [Python-checkins] gh-98608: Fix Failure-handling in new_interpreter() (gh-102658) Message-ID: https://github.com/python/cpython/commit/d1b883b52a99427d234c20e4a92ddfa6a1da8880 commit: d1b883b52a99427d234c20e4a92ddfa6a1da8880 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-21T12:47:55-06:00 summary: gh-98608: Fix Failure-handling in new_interpreter() (gh-102658) The error-handling code in new_interpreter() has been broken for a while. We hadn't noticed because those code mostly doesn't fail. (I noticed while working on gh-101660.) The problem is that we try to clear/delete the newly-created thread/interpreter using itself, which just failed. The solution is to switch back to the calling thread state first. https://github.com/python/cpython/issues/98608 files: M Python/pylifecycle.c diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 0d546d52087e..d0e85519d234 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2062,10 +2062,10 @@ new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config) /* Oops, it didn't work. Undo it all. */ PyErr_PrintEx(0); + PyThreadState_Swap(save_tstate); PyThreadState_Clear(tstate); PyThreadState_Delete(tstate); PyInterpreterState_Delete(interp); - PyThreadState_Swap(save_tstate); return status; } From webhook-mailer at python.org Tue Mar 21 15:10:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 21 Mar 2023 19:10:56 -0000 Subject: [Python-checkins] gh-98608: Fix Failure-handling in new_interpreter() (gh-102658) Message-ID: https://github.com/python/cpython/commit/d5fdc3f07ec64d6e17a63f995ed03f0f107cda78 commit: d5fdc3f07ec64d6e17a63f995ed03f0f107cda78 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-21T12:10:36-07:00 summary: gh-98608: Fix Failure-handling in new_interpreter() (gh-102658) The error-handling code in new_interpreter() has been broken for a while. We hadn't noticed because those code mostly doesn't fail. (I noticed while working on gh-101660.) The problem is that we try to clear/delete the newly-created thread/interpreter using itself, which just failed. The solution is to switch back to the calling thread state first. (cherry picked from commit d1b883b52a99427d234c20e4a92ddfa6a1da8880) Co-authored-by: Eric Snow https: //github.com/python/cpython/issues/98608 files: M Python/pylifecycle.c diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index eeaf20b4617a..b0c5da56c4ff 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1962,10 +1962,10 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) /* Oops, it didn't work. Undo it all. */ PyErr_PrintEx(0); + PyThreadState_Swap(save_tstate); PyThreadState_Clear(tstate); PyThreadState_Delete(tstate); PyInterpreterState_Delete(interp); - PyThreadState_Swap(save_tstate); return status; } From webhook-mailer at python.org Tue Mar 21 15:13:40 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 21 Mar 2023 19:13:40 -0000 Subject: [Python-checkins] gh-98608: Fix Failure-handling in new_interpreter() (gh-102658) Message-ID: https://github.com/python/cpython/commit/4c6b354699c2967879b9c99fe247c4d97f0e31f9 commit: 4c6b354699c2967879b9c99fe247c4d97f0e31f9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-21T12:13:31-07:00 summary: gh-98608: Fix Failure-handling in new_interpreter() (gh-102658) The error-handling code in new_interpreter() has been broken for a while. We hadn't noticed because those code mostly doesn't fail. (I noticed while working on gh-101660.) The problem is that we try to clear/delete the newly-created thread/interpreter using itself, which just failed. The solution is to switch back to the calling thread state first. (cherry picked from commit d1b883b52a99427d234c20e4a92ddfa6a1da8880) Co-authored-by: Eric Snow https: //github.com/python/cpython/issues/98608 files: M Python/pylifecycle.c diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 4060c23ace1c..9248e971d9c7 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2028,10 +2028,10 @@ new_interpreter(PyThreadState **tstate_p, int isolated_subinterpreter) /* Oops, it didn't work. Undo it all. */ PyErr_PrintEx(0); + PyThreadState_Swap(save_tstate); PyThreadState_Clear(tstate); PyThreadState_Delete(tstate); PyInterpreterState_Delete(interp); - PyThreadState_Swap(save_tstate); return status; } From webhook-mailer at python.org Tue Mar 21 15:13:58 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 21 Mar 2023 19:13:58 -0000 Subject: [Python-checkins] gh-102860: improve performance of compiler's instr_sequence_to_cfg (#102861) Message-ID: https://github.com/python/cpython/commit/8d015fa000db5775d477cd04dc574ba13721e278 commit: 8d015fa000db5775d477cd04dc574ba13721e278 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-21T19:13:49Z summary: gh-102860: improve performance of compiler's instr_sequence_to_cfg (#102861) files: M Python/compile.c diff --git a/Python/compile.c b/Python/compile.c index 29e55b8b30c5..99296050445f 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -595,17 +595,52 @@ static int instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { memset(g, 0, sizeof(cfg_builder)); RETURN_IF_ERROR(cfg_builder_init(g)); - /* Note: there can be more than one label for the same offset */ + + /* There can be more than one label for the same offset. The + * offset2lbl maping selects one of them which we use consistently. + */ + + int *offset2lbl = PyMem_Malloc(seq->s_used * sizeof(int)); + if (offset2lbl == NULL) { + PyErr_NoMemory(); + return ERROR; + } for (int i = 0; i < seq->s_used; i++) { - for (int j=0; j < seq->s_labelmap_size; j++) { - if (seq->s_labelmap[j] == i) { - jump_target_label lbl = {j}; - RETURN_IF_ERROR(cfg_builder_use_label(g, lbl)); + offset2lbl[i] = -1; + } + for (int lbl=0; lbl < seq->s_labelmap_size; lbl++) { + int offset = seq->s_labelmap[lbl]; + if (offset >= 0) { + assert(offset < seq->s_used); + offset2lbl[offset] = lbl; + } + } + + for (int i = 0; i < seq->s_used; i++) { + int lbl = offset2lbl[i]; + if (lbl >= 0) { + assert (lbl < seq->s_labelmap_size); + jump_target_label lbl_ = {lbl}; + if (cfg_builder_use_label(g, lbl_) < 0) { + goto error; } } instruction *instr = &seq->s_instrs[i]; - RETURN_IF_ERROR(cfg_builder_addop(g, instr->i_opcode, instr->i_oparg, instr->i_loc)); + int opcode = instr->i_opcode; + int oparg = instr->i_oparg; + if (HAS_TARGET(opcode)) { + int offset = seq->s_labelmap[oparg]; + assert(offset >= 0 && offset < seq->s_used); + int lbl = offset2lbl[offset]; + assert(lbl >= 0 && lbl < seq->s_labelmap_size); + oparg = lbl; + } + if (cfg_builder_addop(g, opcode, oparg, instr->i_loc) < 0) { + goto error; + } } + PyMem_Free(offset2lbl); + int nblocks = 0; for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { nblocks++; @@ -615,6 +650,9 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { return ERROR; } return SUCCESS; +error: + PyMem_Free(offset2lbl); + return ERROR; } From webhook-mailer at python.org Tue Mar 21 16:01:45 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Tue, 21 Mar 2023 20:01:45 -0000 Subject: [Python-checkins] gh-94673: Isolate the _io module to Each Interpreter (gh-102663) Message-ID: https://github.com/python/cpython/commit/e6ecd3e6b437f3056e0a410a57c52e2639b56353 commit: e6ecd3e6b437f3056e0a410a57c52e2639b56353 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-21T14:01:38-06:00 summary: gh-94673: Isolate the _io module to Each Interpreter (gh-102663) Aside from sys and builtins, _io is the only core builtin module that hasn't been ported to multi-phase init. We may do so later (e.g. gh-101948), but in the meantime we must at least take care of the module's static types properly. (This came up while working on gh-101660.) https://github.com/python/cpython/issues/94673 files: M Modules/_io/_iomodule.c M Python/pylifecycle.c diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1506755427fc..5644cc05c458 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -11,6 +11,7 @@ #include "Python.h" #include "_iomodule.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_initconfig.h" // _PyStatus_OK() #ifdef HAVE_SYS_TYPES_H #include @@ -666,12 +667,40 @@ static PyTypeObject* static_types[] = { }; +PyStatus +_PyIO_InitTypes(PyInterpreterState *interp) +{ + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + + // Set type base classes +#ifdef HAVE_WINDOWS_CONSOLE_IO + PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; +#endif + + for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { + PyTypeObject *type = static_types[i]; + if (_PyStaticType_InitBuiltin(type) < 0) { + return _PyStatus_ERR("Can't initialize builtin type"); + } + } + + return _PyStatus_OK(); +} + void -_PyIO_Fini(void) +_PyIO_FiniTypes(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return; + } + + // Deallocate types in the reverse order to deallocate subclasses before + // their base classes. for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) { - PyTypeObject *exc = static_types[i]; - _PyStaticType_Dealloc(exc); + PyTypeObject *type = static_types[i]; + _PyStaticType_Dealloc(type); } } @@ -717,11 +746,6 @@ PyInit__io(void) goto fail; } - // Set type base classes -#ifdef HAVE_WINDOWS_CONSOLE_IO - PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; -#endif - // Add types for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { PyTypeObject *type = static_types[i]; diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d0e85519d234..8110d94ba175 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -31,7 +31,8 @@ #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() #include "opcode.h" -extern void _PyIO_Fini(void); +extern PyStatus _PyIO_InitTypes(PyInterpreterState *interp); +extern void _PyIO_FiniTypes(PyInterpreterState *interp); #include // setlocale() #include // getenv() @@ -697,6 +698,11 @@ pycore_init_types(PyInterpreterState *interp) return _PyStatus_ERR("failed to initialize an exception type"); } + status = _PyIO_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + status = _PyExc_InitGlobalObjects(interp); if (_PyStatus_EXCEPTION(status)) { return status; @@ -1700,9 +1706,7 @@ finalize_interp_clear(PyThreadState *tstate) /* Clear interpreter state and all thread states */ _PyInterpreterState_Clear(tstate); - if (is_main_interp) { - _PyIO_Fini(); - } + _PyIO_FiniTypes(tstate->interp); /* Clear all loghooks */ /* Both _PySys_Audit function and users still need PyObject, such as tuple. From webhook-mailer at python.org Tue Mar 21 17:36:49 2023 From: webhook-mailer at python.org (iritkatriel) Date: Tue, 21 Mar 2023 21:36:49 -0000 Subject: [Python-checkins] gh-102406: replace exception chaining by PEP-678 notes in codecs (#102407) Message-ID: https://github.com/python/cpython/commit/76350e85ebf96df588384f3d9bdc20d11045bef4 commit: 76350e85ebf96df588384f3d9bdc20d11045bef4 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-21T21:36:31Z summary: gh-102406: replace exception chaining by PEP-678 notes in codecs (#102407) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst M Include/cpython/pyerrors.h M Lib/test/test_codecs.py M Objects/exceptions.c M Python/codecs.c diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index d0300f6ee56a..65bdc942f506 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -116,24 +116,6 @@ PyAPI_FUNC(int) _PyException_AddNote( PyObject *exc, PyObject *note); -/* Helper that attempts to replace the current exception with one of the - * same type but with a prefix added to the exception text. The resulting - * exception description looks like: - * - * prefix (exc_type: original_exc_str) - * - * Only some exceptions can be safely replaced. If the function determines - * it isn't safe to perform the replacement, it will leave the original - * unmodified exception in place. - * - * Returns a borrowed reference to the new exception (if any), NULL if the - * existing exception was left in place. - */ -PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause( - const char *prefix_format, /* ASCII-encoded string */ - ... - ); - /* In signalmodule.c */ int PySignal_SetWakeupFd(int fd); diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index e3add0c1ee92..376175f90f63 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -2819,24 +2819,19 @@ def test_binary_to_text_denylists_text_transforms(self): self.assertIsNone(failure.exception.__cause__) @unittest.skipUnless(zlib, "Requires zlib support") - def test_custom_zlib_error_is_wrapped(self): + def test_custom_zlib_error_is_noted(self): # Check zlib codec gives a good error for malformed input - msg = "^decoding with 'zlib_codec' codec failed" - with self.assertRaisesRegex(Exception, msg) as failure: + msg = "decoding with 'zlib_codec' codec failed" + with self.assertRaises(Exception) as failure: codecs.decode(b"hello", "zlib_codec") - self.assertIsInstance(failure.exception.__cause__, - type(failure.exception)) + self.assertEqual(msg, failure.exception.__notes__[0]) - def test_custom_hex_error_is_wrapped(self): + def test_custom_hex_error_is_noted(self): # Check hex codec gives a good error for malformed input - msg = "^decoding with 'hex_codec' codec failed" - with self.assertRaisesRegex(Exception, msg) as failure: + msg = "decoding with 'hex_codec' codec failed" + with self.assertRaises(Exception) as failure: codecs.decode(b"hello", "hex_codec") - self.assertIsInstance(failure.exception.__cause__, - type(failure.exception)) - - # Unfortunately, the bz2 module throws OSError, which the codec - # machinery currently can't wrap :( + self.assertEqual(msg, failure.exception.__notes__[0]) # Ensure codec aliases from http://bugs.python.org/issue7475 work def test_aliases(self): @@ -2860,11 +2855,8 @@ def test_uu_invalid(self): self.assertRaises(ValueError, codecs.decode, b"", "uu-codec") -# The codec system tries to wrap exceptions in order to ensure the error -# mentions the operation being performed and the codec involved. We -# currently *only* want this to happen for relatively stateless -# exceptions, where the only significant information they contain is their -# type and a single str argument. +# The codec system tries to add notes to exceptions in order to ensure +# the error mentions the operation being performed and the codec involved. # Use a local codec registry to avoid appearing to leak objects when # registering multiple search functions @@ -2874,10 +2866,10 @@ def _get_test_codec(codec_name): return _TEST_CODECS.get(codec_name) -class ExceptionChainingTest(unittest.TestCase): +class ExceptionNotesTest(unittest.TestCase): def setUp(self): - self.codec_name = 'exception_chaining_test' + self.codec_name = 'exception_notes_test' codecs.register(_get_test_codec) self.addCleanup(codecs.unregister, _get_test_codec) @@ -2901,91 +2893,77 @@ def set_codec(self, encode, decode): _TEST_CODECS[self.codec_name] = codec_info @contextlib.contextmanager - def assertWrapped(self, operation, exc_type, msg): - full_msg = r"{} with {!r} codec failed \({}: {}\)".format( - operation, self.codec_name, exc_type.__name__, msg) - with self.assertRaisesRegex(exc_type, full_msg) as caught: + def assertNoted(self, operation, exc_type, msg): + full_msg = r"{} with {!r} codec failed".format( + operation, self.codec_name) + with self.assertRaises(exc_type) as caught: yield caught - self.assertIsInstance(caught.exception.__cause__, exc_type) - self.assertIsNotNone(caught.exception.__cause__.__traceback__) + self.assertIn(full_msg, caught.exception.__notes__[0]) + caught.exception.__notes__.clear() def raise_obj(self, *args, **kwds): # Helper to dynamically change the object raised by a test codec raise self.obj_to_raise - def check_wrapped(self, obj_to_raise, msg, exc_type=RuntimeError): + def check_note(self, obj_to_raise, msg, exc_type=RuntimeError): self.obj_to_raise = obj_to_raise self.set_codec(self.raise_obj, self.raise_obj) - with self.assertWrapped("encoding", exc_type, msg): + with self.assertNoted("encoding", exc_type, msg): "str_input".encode(self.codec_name) - with self.assertWrapped("encoding", exc_type, msg): + with self.assertNoted("encoding", exc_type, msg): codecs.encode("str_input", self.codec_name) - with self.assertWrapped("decoding", exc_type, msg): + with self.assertNoted("decoding", exc_type, msg): b"bytes input".decode(self.codec_name) - with self.assertWrapped("decoding", exc_type, msg): + with self.assertNoted("decoding", exc_type, msg): codecs.decode(b"bytes input", self.codec_name) def test_raise_by_type(self): - self.check_wrapped(RuntimeError, "") + self.check_note(RuntimeError, "") def test_raise_by_value(self): - msg = "This should be wrapped" - self.check_wrapped(RuntimeError(msg), msg) + msg = "This should be noted" + self.check_note(RuntimeError(msg), msg) def test_raise_grandchild_subclass_exact_size(self): - msg = "This should be wrapped" + msg = "This should be noted" class MyRuntimeError(RuntimeError): __slots__ = () - self.check_wrapped(MyRuntimeError(msg), msg, MyRuntimeError) + self.check_note(MyRuntimeError(msg), msg, MyRuntimeError) def test_raise_subclass_with_weakref_support(self): - msg = "This should be wrapped" + msg = "This should be noted" class MyRuntimeError(RuntimeError): pass - self.check_wrapped(MyRuntimeError(msg), msg, MyRuntimeError) - - def check_not_wrapped(self, obj_to_raise, msg): - def raise_obj(*args, **kwds): - raise obj_to_raise - self.set_codec(raise_obj, raise_obj) - with self.assertRaisesRegex(RuntimeError, msg): - "str input".encode(self.codec_name) - with self.assertRaisesRegex(RuntimeError, msg): - codecs.encode("str input", self.codec_name) - with self.assertRaisesRegex(RuntimeError, msg): - b"bytes input".decode(self.codec_name) - with self.assertRaisesRegex(RuntimeError, msg): - codecs.decode(b"bytes input", self.codec_name) + self.check_note(MyRuntimeError(msg), msg, MyRuntimeError) - def test_init_override_is_not_wrapped(self): + def test_init_override(self): class CustomInit(RuntimeError): def __init__(self): pass - self.check_not_wrapped(CustomInit, "") + self.check_note(CustomInit, "") - def test_new_override_is_not_wrapped(self): + def test_new_override(self): class CustomNew(RuntimeError): def __new__(cls): return super().__new__(cls) - self.check_not_wrapped(CustomNew, "") + self.check_note(CustomNew, "") - def test_instance_attribute_is_not_wrapped(self): - msg = "This should NOT be wrapped" + def test_instance_attribute(self): + msg = "This should be noted" exc = RuntimeError(msg) exc.attr = 1 - self.check_not_wrapped(exc, "^{}$".format(msg)) + self.check_note(exc, "^{}$".format(msg)) - def test_non_str_arg_is_not_wrapped(self): - self.check_not_wrapped(RuntimeError(1), "1") + def test_non_str_arg(self): + self.check_note(RuntimeError(1), "1") - def test_multiple_args_is_not_wrapped(self): + def test_multiple_args(self): msg_re = r"^\('a', 'b', 'c'\)$" - self.check_not_wrapped(RuntimeError('a', 'b', 'c'), msg_re) + self.check_note(RuntimeError('a', 'b', 'c'), msg_re) # http://bugs.python.org/issue19609 - def test_codec_lookup_failure_not_wrapped(self): + def test_codec_lookup_failure(self): msg = "^unknown encoding: {}$".format(self.codec_name) - # The initial codec lookup should not be wrapped with self.assertRaisesRegex(LookupError, msg): "str input".encode(self.codec_name) with self.assertRaisesRegex(LookupError, msg): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst new file mode 100644 index 000000000000..e0d061c37299 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst @@ -0,0 +1 @@ +:mod:`codecs` encoding/decoding errors now get the context information (which operation and which codecs) attached as :pep:`678` notes instead of through chaining a new instance of the exception. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index d69f7400ca60..a355244cf997 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3764,113 +3764,3 @@ _PyException_AddNote(PyObject *exc, PyObject *note) return res; } -/* Helper to do the equivalent of "raise X from Y" in C, but always using - * the current exception rather than passing one in. - * - * We currently limit this to *only* exceptions that use the BaseException - * tp_init and tp_new methods, since we can be reasonably sure we can wrap - * those correctly without losing data and without losing backwards - * compatibility. - * - * We also aim to rule out *all* exceptions that might be storing additional - * state, whether by having a size difference relative to BaseException, - * additional arguments passed in during construction or by having a - * non-empty instance dict. - * - * We need to be very careful with what we wrap, since changing types to - * a broader exception type would be backwards incompatible for - * existing codecs, and with different init or new method implementations - * may either not support instantiation with PyErr_Format or lose - * information when instantiated that way. - * - * XXX (ncoghlan): This could be made more comprehensive by exploiting the - * fact that exceptions are expected to support pickling. If more builtin - * exceptions (e.g. AttributeError) start to be converted to rich - * exceptions with additional attributes, that's probably a better approach - * to pursue over adding special cases for particular stateful subclasses. - * - * Returns a borrowed reference to the new exception (if any), NULL if the - * existing exception was left in place. - */ -PyObject * -_PyErr_TrySetFromCause(const char *format, ...) -{ - PyObject* msg_prefix; - PyObject *instance_args; - Py_ssize_t num_args, caught_type_size, base_exc_size; - va_list vargs; - int same_basic_size; - - PyObject *exc = PyErr_GetRaisedException(); - PyTypeObject *caught_type = Py_TYPE(exc); - /* Ensure type info indicates no extra state is stored at the C level - * and that the type can be reinstantiated using PyErr_Format - */ - caught_type_size = caught_type->tp_basicsize; - base_exc_size = _PyExc_BaseException.tp_basicsize; - same_basic_size = ( - caught_type_size == base_exc_size || - (_PyType_SUPPORTS_WEAKREFS(caught_type) && - (caught_type_size == base_exc_size + (Py_ssize_t)sizeof(PyObject *)) - ) - ); - if (caught_type->tp_init != (initproc)BaseException_init || - caught_type->tp_new != BaseException_new || - !same_basic_size || - caught_type->tp_itemsize != _PyExc_BaseException.tp_itemsize) { - /* We can't be sure we can wrap this safely, since it may contain - * more state than just the exception type. Accordingly, we just - * leave it alone. - */ - PyErr_SetRaisedException(exc); - return NULL; - } - - /* Check the args are empty or contain a single string */ - instance_args = ((PyBaseExceptionObject *)exc)->args; - num_args = PyTuple_GET_SIZE(instance_args); - if (num_args > 1 || - (num_args == 1 && - !PyUnicode_CheckExact(PyTuple_GET_ITEM(instance_args, 0)))) { - /* More than 1 arg, or the one arg we do have isn't a string - */ - PyErr_SetRaisedException(exc); - return NULL; - } - - /* Ensure the instance dict is also empty */ - if (!_PyObject_IsInstanceDictEmpty(exc)) { - /* While we could potentially copy a non-empty instance dictionary - * to the replacement exception, for now we take the more - * conservative path of leaving exceptions with attributes set - * alone. - */ - PyErr_SetRaisedException(exc); - return NULL; - } - - /* For exceptions that we can wrap safely, we chain the original - * exception to a new one of the exact same type with an - * error message that mentions the additional details and the - * original exception. - * - * It would be nice to wrap OSError and various other exception - * types as well, but that's quite a bit trickier due to the extra - * state potentially stored on OSError instances. - */ - va_start(vargs, format); - msg_prefix = PyUnicode_FromFormatV(format, vargs); - va_end(vargs); - if (msg_prefix == NULL) { - Py_DECREF(exc); - return NULL; - } - - PyErr_Format((PyObject*)Py_TYPE(exc), "%U (%s: %S)", - msg_prefix, Py_TYPE(exc)->tp_name, exc); - Py_DECREF(msg_prefix); - PyObject *new_exc = PyErr_GetRaisedException(); - PyException_SetCause(new_exc, exc); - PyErr_SetRaisedException(new_exc); - return new_exc; -} diff --git a/Python/codecs.c b/Python/codecs.c index b2087b499dfd..9d800f9856c2 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -382,20 +382,27 @@ PyObject *PyCodec_StreamWriter(const char *encoding, return codec_getstreamcodec(encoding, stream, errors, 3); } -/* Helper that tries to ensure the reported exception chain indicates the - * codec that was invoked to trigger the failure without changing the type - * of the exception raised. - */ static void -wrap_codec_error(const char *operation, - const char *encoding) +add_note_to_codec_error(const char *operation, + const char *encoding) { - /* TrySetFromCause will replace the active exception with a suitably - * updated clone if it can, otherwise it will leave the original - * exception alone. - */ - _PyErr_TrySetFromCause("%s with '%s' codec failed", - operation, encoding); + PyObject *exc = PyErr_GetRaisedException(); + if (exc == NULL) { + return; + } + PyObject *note = PyUnicode_FromFormat("%s with '%s' codec failed", + operation, encoding); + if (note == NULL) { + _PyErr_ChainExceptions1(exc); + return; + } + int res = _PyException_AddNote(exc, note); + Py_DECREF(note); + if (res < 0) { + _PyErr_ChainExceptions1(exc); + return; + } + PyErr_SetRaisedException(exc); } /* Encode an object (e.g. a Unicode object) using the given encoding @@ -418,7 +425,7 @@ _PyCodec_EncodeInternal(PyObject *object, result = PyObject_Call(encoder, args, NULL); if (result == NULL) { - wrap_codec_error("encoding", encoding); + add_note_to_codec_error("encoding", encoding); goto onError; } @@ -463,7 +470,7 @@ _PyCodec_DecodeInternal(PyObject *object, result = PyObject_Call(decoder, args, NULL); if (result == NULL) { - wrap_codec_error("decoding", encoding); + add_note_to_codec_error("decoding", encoding); goto onError; } if (!PyTuple_Check(result) || From webhook-mailer at python.org Tue Mar 21 17:58:43 2023 From: webhook-mailer at python.org (ezio-melotti) Date: Tue, 21 Mar 2023 21:58:43 -0000 Subject: [Python-checkins] Add link to `sys.exit` function documentation (#102805) Message-ID: https://github.com/python/cpython/commit/41ef502d740b96ca6333a2d0202df7cce4a84e7d commit: 41ef502d740b96ca6333a2d0202df7cce4a84e7d branch: main author: David Poirier <1152277+david-poirier at users.noreply.github.com> committer: ezio-melotti date: 2023-03-22T06:58:31+09:00 summary: Add link to `sys.exit` function documentation (#102805) * Add link to `sys.exit` function documentation * Update Doc/library/os.rst Co-authored-by: Ezio Melotti * Update Doc/library/os.rst Co-authored-by: C.A.M. Gerlach --------- Co-authored-by: Ezio Melotti Co-authored-by: C.A.M. Gerlach files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 3153f79e10ce..7bb501c59468 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3951,7 +3951,7 @@ to be ignored. .. note:: - The standard way to exit is ``sys.exit(n)``. :func:`_exit` should + The standard way to exit is :func:`sys.exit(n) `. :func:`!_exit` should normally only be used in the child process after a :func:`fork`. The following exit codes are defined and can be used with :func:`_exit`, From webhook-mailer at python.org Tue Mar 21 18:05:40 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 21 Mar 2023 22:05:40 -0000 Subject: [Python-checkins] Add link to `sys.exit` function documentation (GH-102805) Message-ID: https://github.com/python/cpython/commit/21b94028efc4388a43773bea877a28cf563fab70 commit: 21b94028efc4388a43773bea877a28cf563fab70 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-21T15:05:32-07:00 summary: Add link to `sys.exit` function documentation (GH-102805) * Add link to `sys.exit` function documentation * Update Doc/library/os.rst Co-authored-by: Ezio Melotti * Update Doc/library/os.rst Co-authored-by: C.A.M. Gerlach --------- (cherry picked from commit 41ef502d740b96ca6333a2d0202df7cce4a84e7d) Co-authored-by: David Poirier <1152277+david-poirier at users.noreply.github.com> Co-authored-by: Ezio Melotti Co-authored-by: C.A.M. Gerlach files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 1f1e2fd31454..28990c216af3 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3658,7 +3658,7 @@ to be ignored. .. note:: - The standard way to exit is ``sys.exit(n)``. :func:`_exit` should + The standard way to exit is :func:`sys.exit(n) `. :func:`!_exit` should normally only be used in the child process after a :func:`fork`. The following exit codes are defined and can be used with :func:`_exit`, From webhook-mailer at python.org Tue Mar 21 18:06:17 2023 From: webhook-mailer at python.org (miss-islington) Date: Tue, 21 Mar 2023 22:06:17 -0000 Subject: [Python-checkins] Add link to `sys.exit` function documentation (GH-102805) Message-ID: https://github.com/python/cpython/commit/1eb9b2492907979493af04563a7c0baef374f69a commit: 1eb9b2492907979493af04563a7c0baef374f69a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-21T15:06:10-07:00 summary: Add link to `sys.exit` function documentation (GH-102805) * Add link to `sys.exit` function documentation * Update Doc/library/os.rst Co-authored-by: Ezio Melotti * Update Doc/library/os.rst Co-authored-by: C.A.M. Gerlach --------- (cherry picked from commit 41ef502d740b96ca6333a2d0202df7cce4a84e7d) Co-authored-by: David Poirier <1152277+david-poirier at users.noreply.github.com> Co-authored-by: Ezio Melotti Co-authored-by: C.A.M. Gerlach files: M Doc/library/os.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index e3e20510f809..7b7ab860da8d 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3732,7 +3732,7 @@ to be ignored. .. note:: - The standard way to exit is ``sys.exit(n)``. :func:`_exit` should + The standard way to exit is :func:`sys.exit(n) `. :func:`!_exit` should normally only be used in the child process after a :func:`fork`. The following exit codes are defined and can be used with :func:`_exit`, From webhook-mailer at python.org Tue Mar 21 19:48:26 2023 From: webhook-mailer at python.org (rhettinger) Date: Tue, 21 Mar 2023 23:48:26 -0000 Subject: [Python-checkins] gh-102839: remove AC for math.log (GH-102863) Message-ID: https://github.com/python/cpython/commit/d1a89ce5156cd4e1eff5823ec2200885c43e395e commit: d1a89ce5156cd4e1eff5823ec2200885c43e395e branch: main author: Sergey B Kirpichev committer: rhettinger date: 2023-03-21T18:48:19-05:00 summary: gh-102839: remove AC for math.log (GH-102863) files: A Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst M Modules/clinic/mathmodule.c.h M Modules/mathmodule.c diff --git a/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst b/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst new file mode 100644 index 000000000000..673b38974e4d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst @@ -0,0 +1 @@ +Improve performance of :func:`math.log` arguments handling by removing the argument clinic. diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index 1f9725883b98..bc5bbceb4c92 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -186,49 +186,6 @@ math_modf(PyObject *module, PyObject *arg) return return_value; } -PyDoc_STRVAR(math_log__doc__, -"log(x, [base=math.e])\n" -"Return the logarithm of x to the given base.\n" -"\n" -"If the base not specified, returns the natural logarithm (base e) of x."); - -#define MATH_LOG_METHODDEF \ - {"log", (PyCFunction)math_log, METH_VARARGS, math_log__doc__}, - -static PyObject * -math_log_impl(PyObject *module, PyObject *x, int group_right_1, - PyObject *base); - -static PyObject * -math_log(PyObject *module, PyObject *args) -{ - PyObject *return_value = NULL; - PyObject *x; - int group_right_1 = 0; - PyObject *base = NULL; - - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:log", &x)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:log", &x, &base)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "math.log requires 1 to 2 arguments"); - goto exit; - } - return_value = math_log_impl(module, x, group_right_1, base); - -exit: - return return_value; -} - PyDoc_STRVAR(math_log2__doc__, "log2($module, x, /)\n" "--\n" @@ -954,4 +911,4 @@ math_ulp(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=899211ec70e4506c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a6437a3ba18c486a input=a9049054013a1b77]*/ diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index c9a2be668639..473936edb3f5 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2284,33 +2284,22 @@ loghelper(PyObject* arg, double (*func)(double)) } -/*[clinic input] -math.log - - x: object - [ - base: object(c_default="NULL") = math.e - ] - / - -Return the logarithm of x to the given base. - -If the base not specified, returns the natural logarithm (base e) of x. -[clinic start generated code]*/ - +/* AC: cannot convert yet, see gh-102839 and gh-89381, waiting + for support of multiple signatures */ static PyObject * -math_log_impl(PyObject *module, PyObject *x, int group_right_1, - PyObject *base) -/*[clinic end generated code: output=7b5a39e526b73fc9 input=0f62d5726cbfebbd]*/ +math_log(PyObject *module, PyObject * const *args, Py_ssize_t nargs) { PyObject *num, *den; PyObject *ans; - num = loghelper(x, m_log); - if (num == NULL || base == NULL) + if (!_PyArg_CheckPositional("log", nargs, 1, 2)) + return NULL; + + num = loghelper(args[0], m_log); + if (num == NULL || nargs == 1) return num; - den = loghelper(base, m_log); + den = loghelper(args[1], m_log); if (den == NULL) { Py_DECREF(num); return NULL; @@ -2322,6 +2311,10 @@ math_log_impl(PyObject *module, PyObject *x, int group_right_1, return ans; } +PyDoc_STRVAR(math_log_doc, +"log(x, [base=math.e])\n\ +Return the logarithm of x to the given base.\n\n\ +If the base not specified, returns the natural logarithm (base e) of x."); /*[clinic input] math.log2 @@ -4045,7 +4038,7 @@ static PyMethodDef math_methods[] = { {"lcm", _PyCFunction_CAST(math_lcm), METH_FASTCALL, math_lcm_doc}, MATH_LDEXP_METHODDEF {"lgamma", math_lgamma, METH_O, math_lgamma_doc}, - MATH_LOG_METHODDEF + {"log", _PyCFunction_CAST(math_log), METH_FASTCALL, math_log_doc}, {"log1p", math_log1p, METH_O, math_log1p_doc}, MATH_LOG10_METHODDEF MATH_LOG2_METHODDEF From webhook-mailer at python.org Wed Mar 22 05:32:13 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 09:32:13 -0000 Subject: [Python-checkins] [3.11] gh-102595: Document `PyObject_Format` c-api function (GH-102596) (GH-102879) Message-ID: https://github.com/python/cpython/commit/a7a373e1c56bdc3df5b8b14bab068258c974ddba commit: a7a373e1c56bdc3df5b8b14bab068258c974ddba branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T02:32:02-07:00 summary: [3.11] gh-102595: Document `PyObject_Format` c-api function (GH-102596) (GH-102879) (cherry picked from commit 910a64e3013bce821bfac75377cbe88bedf265de) Co-authored-by: Nikita Sobolev Def: https://github.com/python/cpython/blame/5ffdaf748d98da6065158534720f1996a45a0072/Include/abstract.hGH-L389 Automerge-Triggered-By: GH:encukou files: M Doc/c-api/object.rst diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 84c72e7e108b..0a12bb9e8c54 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -179,6 +179,15 @@ Object Protocol If *o1* and *o2* are the same object, :c:func:`PyObject_RichCompareBool` will always return ``1`` for :const:`Py_EQ` and ``0`` for :const:`Py_NE`. +.. c:function:: PyObject* PyObject_Format(PyObject *obj, PyObject *format_spec) + + Format *obj* using *format_spec*. This is equivalent to the Python + expression ``format(obj, format_spec)``. + + *format_spec* may be ``NULL``. In this case the call is equivalent + to ``format(obj)``. + Returns the formatted string on success, ``NULL`` on failure. + .. c:function:: PyObject* PyObject_Repr(PyObject *o) .. index:: builtin: repr From webhook-mailer at python.org Wed Mar 22 05:32:16 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 09:32:16 -0000 Subject: [Python-checkins] gh-102595: Document `PyObject_Format` c-api function (GH-102596) Message-ID: https://github.com/python/cpython/commit/eaafea86a0f49428092d359391d0a184d9ef8531 commit: eaafea86a0f49428092d359391d0a184d9ef8531 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T02:32:08-07:00 summary: gh-102595: Document `PyObject_Format` c-api function (GH-102596) (cherry picked from commit 910a64e3013bce821bfac75377cbe88bedf265de) Co-authored-by: Nikita Sobolev Def: https://github.com/python/cpython/blame/5ffdaf748d98da6065158534720f1996a45a0072/Include/abstract.hGH-L389 files: M Doc/c-api/object.rst diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index feadf503205e..29920d24742f 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -161,6 +161,15 @@ Object Protocol If *o1* and *o2* are the same object, :c:func:`PyObject_RichCompareBool` will always return ``1`` for :const:`Py_EQ` and ``0`` for :const:`Py_NE`. +.. c:function:: PyObject* PyObject_Format(PyObject *obj, PyObject *format_spec) + + Format *obj* using *format_spec*. This is equivalent to the Python + expression ``format(obj, format_spec)``. + + *format_spec* may be ``NULL``. In this case the call is equivalent + to ``format(obj)``. + Returns the formatted string on success, ``NULL`` on failure. + .. c:function:: PyObject* PyObject_Repr(PyObject *o) .. index:: builtin: repr From webhook-mailer at python.org Wed Mar 22 07:35:08 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 22 Mar 2023 11:35:08 -0000 Subject: [Python-checkins] Docs: improve accuracy of pdb alias example (#102892) Message-ID: https://github.com/python/cpython/commit/e0c63b72671bf816d3073f1a6a9107f6c171cae7 commit: e0c63b72671bf816d3073f1a6a9107f6c171cae7 branch: main author: gaogaotiantian committer: erlend-aasland date: 2023-03-22T12:34:52+01:00 summary: Docs: improve accuracy of pdb alias example (#102892) files: M Doc/library/pdb.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 21c6ca8622dc..5988477af03a 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -513,7 +513,7 @@ can be overridden by the local file. :file:`.pdbrc` file):: # Print instance variables (usage "pi classInst") - alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k]) + alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") # Print instance variables in self alias ps pi self From webhook-mailer at python.org Wed Mar 22 07:35:35 2023 From: webhook-mailer at python.org (corona10) Date: Wed, 22 Mar 2023 11:35:35 -0000 Subject: [Python-checkins] GH-94808: Cover `PyOS_mystrnicmp` and `PyOS_mystricmp` (gh-102469) Message-ID: https://github.com/python/cpython/commit/0a60deaeaf1d129cb061f50995a8b6d9d18fa3ec commit: 0a60deaeaf1d129cb061f50995a8b6d9d18fa3ec branch: main author: Artem Mukhin committer: corona10 date: 2023-03-22T20:35:27+09:00 summary: GH-94808: Cover `PyOS_mystrnicmp` and `PyOS_mystricmp` (gh-102469) files: A Modules/_testcapi/pyos.c M Modules/Setup.stdlib.in M Modules/_testcapi/parts.h M Modules/_testcapimodule.c M PCbuild/_testcapi.vcxproj M PCbuild/_testcapi.vcxproj.filters diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index b12290d436cb..fe1b9f8f5380 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -169,7 +169,7 @@ @MODULE__XXTESTFUZZ_TRUE at _xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE at _testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE at _testinternalcapi _testinternalcapi.c - at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c + at MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/pyos.c @MODULE__TESTCLINIC_TRUE at _testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index c8f31dc8e39f..60ec81dad2ba 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -38,6 +38,7 @@ int _PyTestCapi_Init_Float(PyObject *module); int _PyTestCapi_Init_Structmember(PyObject *module); int _PyTestCapi_Init_Exceptions(PyObject *module); int _PyTestCapi_Init_Code(PyObject *module); +int _PyTestCapi_Init_PyOS(PyObject *module); #ifdef LIMITED_API_AVAILABLE int _PyTestCapi_Init_VectorcallLimited(PyObject *module); diff --git a/Modules/_testcapi/pyos.c b/Modules/_testcapi/pyos.c new file mode 100644 index 000000000000..63140e914875 --- /dev/null +++ b/Modules/_testcapi/pyos.c @@ -0,0 +1,60 @@ +#include "parts.h" + + +static PyObject * +test_PyOS_mystrnicmp(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + assert(PyOS_mystrnicmp("", "", 0) == 0); + assert(PyOS_mystrnicmp("", "", 1) == 0); + + assert(PyOS_mystrnicmp("insert", "ins", 3) == 0); + assert(PyOS_mystrnicmp("ins", "insert", 3) == 0); + assert(PyOS_mystrnicmp("insect", "insert", 3) == 0); + + assert(PyOS_mystrnicmp("insert", "insert", 6) == 0); + assert(PyOS_mystrnicmp("Insert", "insert", 6) == 0); + assert(PyOS_mystrnicmp("INSERT", "insert", 6) == 0); + assert(PyOS_mystrnicmp("insert", "insert", 10) == 0); + + assert(PyOS_mystrnicmp("invert", "insert", 6) == ('v' - 's')); + assert(PyOS_mystrnicmp("insert", "invert", 6) == ('s' - 'v')); + assert(PyOS_mystrnicmp("insert", "ins\0rt", 6) == 'e'); + + // GH-21845 + assert(PyOS_mystrnicmp("insert\0a", "insert\0b", 8) == 0); + + Py_RETURN_NONE; +} + +static PyObject * +test_PyOS_mystricmp(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + assert(PyOS_mystricmp("", "") == 0); + assert(PyOS_mystricmp("insert", "insert") == 0); + assert(PyOS_mystricmp("Insert", "insert") == 0); + assert(PyOS_mystricmp("INSERT", "insert") == 0); + assert(PyOS_mystricmp("insert", "ins") == 'e'); + assert(PyOS_mystricmp("ins", "insert") == -'e'); + + // GH-21845 + assert(PyOS_mystricmp("insert", "ins\0rt") == 'e'); + assert(PyOS_mystricmp("invert", "insert") == ('v' - 's')); + + Py_RETURN_NONE; +} + +static PyMethodDef test_methods[] = { + {"test_PyOS_mystrnicmp", test_PyOS_mystrnicmp, METH_NOARGS, NULL}, + {"test_PyOS_mystricmp", test_PyOS_mystricmp, METH_NOARGS, NULL}, + {NULL}, +}; + +int +_PyTestCapi_Init_PyOS(PyObject *mod) +{ + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index e2ebab5c5b48..3d9a2aeeb7cf 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4154,6 +4154,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Code(m) < 0) { return NULL; } + if (_PyTestCapi_Init_PyOS(m) < 0) { + return NULL; + } #ifndef LIMITED_API_AVAILABLE PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False); diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 4cc184bfc1ac..439cd687fda6 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -109,6 +109,7 @@ + diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index fbdaf04ce37c..0e42e4982c21 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -57,6 +57,9 @@ Source Files + + Source Files + From webhook-mailer at python.org Wed Mar 22 07:37:20 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 22 Mar 2023 11:37:20 -0000 Subject: [Python-checkins] Docs: improve the accuracy of the sqlite3.connect() timeout param (#102900) Message-ID: https://github.com/python/cpython/commit/c24f1f1e874c283bb11d8b9fbd661536ade19fe9 commit: c24f1f1e874c283bb11d8b9fbd661536ade19fe9 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-03-22T12:37:13+01:00 summary: Docs: improve the accuracy of the sqlite3.connect() timeout param (#102900) Co-authored-by: C.A.M. Gerlach files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index ff036ad56acb..a78f3eb72217 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -272,9 +272,9 @@ Module functions :param float timeout: How many seconds the connection should wait before raising - an exception, if the database is locked by another connection. - If another connection opens a transaction to modify the database, - it will be locked until that transaction is committed. + an :exc:`OperationalError` when a table is locked. + If another connection opens a transaction to modify a table, + that table will be locked until the transaction is committed. Default five seconds. :param int detect_types: From webhook-mailer at python.org Wed Mar 22 07:42:02 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 11:42:02 -0000 Subject: [Python-checkins] Docs: improve accuracy of pdb alias example (GH-102892) Message-ID: https://github.com/python/cpython/commit/00b50606c0b323cbdcb007fe0785cded98f9519a commit: 00b50606c0b323cbdcb007fe0785cded98f9519a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T04:41:54-07:00 summary: Docs: improve accuracy of pdb alias example (GH-102892) (cherry picked from commit e0c63b72671bf816d3073f1a6a9107f6c171cae7) Co-authored-by: gaogaotiantian files: M Doc/library/pdb.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 3b4a57d86fe7..8df518c912a3 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -509,7 +509,7 @@ by the local file. :file:`.pdbrc` file):: # Print instance variables (usage "pi classInst") - alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k]) + alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") # Print instance variables in self alias ps pi self From webhook-mailer at python.org Wed Mar 22 07:44:29 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 11:44:29 -0000 Subject: [Python-checkins] Docs: improve accuracy of pdb alias example (GH-102892) Message-ID: https://github.com/python/cpython/commit/44782d3d34fc72387713c0b2665d1288d54f9778 commit: 44782d3d34fc72387713c0b2665d1288d54f9778 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T04:44:21-07:00 summary: Docs: improve accuracy of pdb alias example (GH-102892) (cherry picked from commit e0c63b72671bf816d3073f1a6a9107f6c171cae7) Co-authored-by: gaogaotiantian files: M Doc/library/pdb.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 21c6ca8622dc..5988477af03a 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -513,7 +513,7 @@ can be overridden by the local file. :file:`.pdbrc` file):: # Print instance variables (usage "pi classInst") - alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k]) + alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") # Print instance variables in self alias ps pi self From webhook-mailer at python.org Wed Mar 22 07:47:07 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 22 Mar 2023 11:47:07 -0000 Subject: [Python-checkins] gh-100989: Improve the accuracy of collections.deque docstrings (#100990) Message-ID: https://github.com/python/cpython/commit/c74073657e32b8872f91b3bbe1efa9af20adbea9 commit: c74073657e32b8872f91b3bbe1efa9af20adbea9 branch: main author: Timo Ludwig committer: erlend-aasland date: 2023-03-22T12:46:58+01:00 summary: gh-100989: Improve the accuracy of collections.deque docstrings (#100990) Co-authored-by: C.A.M. Gerlach files: M Modules/_collectionsmodule.c diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 68131f3b54d2..ba4a9760f7b9 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -910,7 +910,9 @@ deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(rotate_doc, -"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); +"rotate(n)\n\n" +"Rotate the deque *n* steps to the right (default ``n=1``). " +"If *n* is negative, rotates left."); static PyObject * deque_reverse(dequeobject *deque, PyObject *unused) @@ -951,7 +953,8 @@ deque_reverse(dequeobject *deque, PyObject *unused) } PyDoc_STRVAR(reverse_doc, -"D.reverse() -- reverse *IN PLACE*"); +"reverse()\n\n" +"Reverse the elements of the deque *IN PLACE*."); static PyObject * deque_count(dequeobject *deque, PyObject *v) @@ -990,7 +993,8 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"D.count(value) -> integer -- return number of occurrences of value"); +"count(x) -> int\n\n" +"Count the number of deque elements equal to *x*."); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1098,8 +1102,10 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" -"Raises ValueError if the value is not present."); +"index(x, [start, [stop]]) -> int\n\n" +"Return the position of *x* in the deque " +"(at or after index *start* and before index *stop*). " +"Returns the first match or raises a ValueError if not found."); /* insert(), remove(), and delitem() are implemented in terms of rotate() for simplicity and reasonable performance near the end @@ -1144,10 +1150,13 @@ deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(insert_doc, -"D.insert(index, object) -- insert object before index"); +"insert(i, x)\n\n" +"Insert *x* into the deque at position *i*."); PyDoc_STRVAR(remove_doc, -"D.remove(value) -- remove first occurrence of value."); +"remove(x)\n\n" +"Remove the first occurrence of *x*." +"If not found, raises a ValueError."); static int valid_index(Py_ssize_t i, Py_ssize_t limit) @@ -1518,7 +1527,8 @@ deque_sizeof(dequeobject *deque, void *unused) } PyDoc_STRVAR(sizeof_doc, -"D.__sizeof__() -- size of D in memory, in bytes"); +"__sizeof__() -> int\n\n" +"Size of the deque in memory, in bytes."); static PyObject * deque_get_maxlen(dequeobject *deque, void *Py_UNUSED(ignored)) @@ -1553,7 +1563,8 @@ static PySequenceMethods deque_as_sequence = { static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, - "D.__reversed__() -- return a reverse iterator over the deque"); +"__reversed__()\n\n" +"Return a reverse iterator over the deque."); static PyMethodDef deque_methods[] = { {"append", (PyCFunction)deque_append, @@ -1598,9 +1609,8 @@ static PyMethodDef deque_methods[] = { }; PyDoc_STRVAR(deque_doc, -"deque([iterable[, maxlen]]) --> deque object\n\ -\n\ -A list-like sequence optimized for data accesses near its endpoints."); +"deque([iterable[, maxlen]]) -> collections.deque\n\n" +"A list-like sequence optimized for data accesses near its endpoints."); static PyTypeObject deque_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -1979,7 +1989,8 @@ new_defdict(defdictobject *dd, PyObject *arg) dd->default_factory ? dd->default_factory : Py_None, arg, NULL); } -PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); +PyDoc_STRVAR(defdict_copy_doc, "copy() -> collections.deque\n\n" +"A shallow copy of the deque."); static PyObject * defdict_copy(defdictobject *dd, PyObject *Py_UNUSED(ignored)) From webhook-mailer at python.org Wed Mar 22 07:49:39 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 11:49:39 -0000 Subject: [Python-checkins] Docs: improve the accuracy of the sqlite3.connect() timeout param (GH-102900) Message-ID: https://github.com/python/cpython/commit/2e0505a1d93b62b6bca046e4b4b920a75f27bd5b commit: 2e0505a1d93b62b6bca046e4b4b920a75f27bd5b branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T04:49:32-07:00 summary: Docs: improve the accuracy of the sqlite3.connect() timeout param (GH-102900) (cherry picked from commit c24f1f1e874c283bb11d8b9fbd661536ade19fe9) Co-authored-by: Erlend E. Aasland Co-authored-by: C.A.M. Gerlach files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 509c4a8277eb..ba2ae83642a5 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -271,9 +271,9 @@ Module functions :param float timeout: How many seconds the connection should wait before raising - an exception, if the database is locked by another connection. - If another connection opens a transaction to modify the database, - it will be locked until that transaction is committed. + an :exc:`OperationalError` when a table is locked. + If another connection opens a transaction to modify a table, + that table will be locked until the transaction is committed. Default five seconds. :param int detect_types: From webhook-mailer at python.org Wed Mar 22 07:49:53 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 11:49:53 -0000 Subject: [Python-checkins] Docs: improve the accuracy of the sqlite3.connect() timeout param (GH-102900) Message-ID: https://github.com/python/cpython/commit/9a1453b6511f8d9ac0f03d8923b269a1fad01885 commit: 9a1453b6511f8d9ac0f03d8923b269a1fad01885 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T04:49:46-07:00 summary: Docs: improve the accuracy of the sqlite3.connect() timeout param (GH-102900) (cherry picked from commit c24f1f1e874c283bb11d8b9fbd661536ade19fe9) Co-authored-by: Erlend E. Aasland Co-authored-by: C.A.M. Gerlach files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index b5351a8feae8..cdb6f9d0e179 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -271,9 +271,9 @@ Module functions :param float timeout: How many seconds the connection should wait before raising - an exception, if the database is locked by another connection. - If another connection opens a transaction to modify the database, - it will be locked until that transaction is committed. + an :exc:`OperationalError` when a table is locked. + If another connection opens a transaction to modify a table, + that table will be locked until the transaction is committed. Default five seconds. :param int detect_types: From webhook-mailer at python.org Wed Mar 22 07:50:07 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 22 Mar 2023 11:50:07 -0000 Subject: [Python-checkins] Docs: improve accuracy of sqlite3.Connection.interrupt() (#102904) Message-ID: https://github.com/python/cpython/commit/7b2d53daccf5a6479e179535068fd9a841db44fc commit: 7b2d53daccf5a6479e179535068fd9a841db44fc branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-03-22T12:50:00+01:00 summary: Docs: improve accuracy of sqlite3.Connection.interrupt() (#102904) Co-authored-by: C.A.M. Gerlach files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index a78f3eb72217..4b2d13ab3a8f 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -911,7 +911,7 @@ Connection objects Call this method from a different thread to abort any queries that might be executing on the connection. - Aborted queries will raise an exception. + Aborted queries will raise an :exc:`OperationalError`. .. method:: set_authorizer(authorizer_callback) From webhook-mailer at python.org Wed Mar 22 08:00:05 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 12:00:05 -0000 Subject: [Python-checkins] Docs: improve accuracy of sqlite3.Connection.interrupt() (GH-102904) Message-ID: https://github.com/python/cpython/commit/3c2a7bb6b5226196f50baead9a554f900409eac4 commit: 3c2a7bb6b5226196f50baead9a554f900409eac4 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T04:59:56-07:00 summary: Docs: improve accuracy of sqlite3.Connection.interrupt() (GH-102904) (cherry picked from commit 7b2d53daccf5a6479e179535068fd9a841db44fc) Co-authored-by: Erlend E. Aasland Co-authored-by: C.A.M. Gerlach files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index ba2ae83642a5..051e76c440ca 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -700,7 +700,7 @@ Connection objects Call this method from a different thread to abort any queries that might be executing on the connection. - Aborted queries will raise an exception. + Aborted queries will raise an :exc:`OperationalError`. .. method:: set_authorizer(authorizer_callback) From webhook-mailer at python.org Wed Mar 22 08:00:32 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 12:00:32 -0000 Subject: [Python-checkins] Docs: improve accuracy of sqlite3.Connection.interrupt() (GH-102904) Message-ID: https://github.com/python/cpython/commit/592c34469bad3ba068fd1e72d747a1a01e52a242 commit: 592c34469bad3ba068fd1e72d747a1a01e52a242 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T05:00:25-07:00 summary: Docs: improve accuracy of sqlite3.Connection.interrupt() (GH-102904) (cherry picked from commit 7b2d53daccf5a6479e179535068fd9a841db44fc) Co-authored-by: Erlend E. Aasland Co-authored-by: C.A.M. Gerlach files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index cdb6f9d0e179..a87e8429e6df 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -867,7 +867,7 @@ Connection objects Call this method from a different thread to abort any queries that might be executing on the connection. - Aborted queries will raise an exception. + Aborted queries will raise an :exc:`OperationalError`. .. method:: set_authorizer(authorizer_callback) From webhook-mailer at python.org Wed Mar 22 08:16:33 2023 From: webhook-mailer at python.org (Yhg1s) Date: Wed, 22 Mar 2023 12:16:33 -0000 Subject: [Python-checkins] GH-95494: Fix transport EOF handling in OpenSSL 3.0 (GH-95495) Message-ID: https://github.com/python/cpython/commit/420bbb783b43216cc897dc8914851899db37a31d commit: 420bbb783b43216cc897dc8914851899db37a31d branch: main author: David Benjamin committer: Yhg1s date: 2023-03-22T13:16:26+01:00 summary: GH-95494: Fix transport EOF handling in OpenSSL 3.0 (GH-95495) GH-25309 enabled SSL_OP_IGNORE_UNEXPECTED_EOF by default, with a comment that it restores OpenSSL 1.1.1 behavior, but this wasn't quite right. That option causes OpenSSL to treat transport EOF as the same as close_notify (i.e. SSL_ERROR_ZERO_RETURN), whereas Python actually has distinct SSLEOFError and SSLZeroReturnError exceptions. (The latter is usually mapped to a zero return from read.) In OpenSSL 1.1.1, the ssl module would raise them for transport EOF and close_notify, respectively. In OpenSSL 3.0, both act like close_notify. Fix this by, instead, just detecting SSL_R_UNEXPECTED_EOF_WHILE_READING and mapping that to the other exception type. There doesn't seem to have been any unit test of this error, so fill in the missing one. This had to be done with the BIO path because it's actually slightly tricky to simulate a transport EOF with Python's fd based APIs. (If you instruct the server to close the socket, it gets confused, probably because the server's SSL object is still referencing the now dead fd?) files: A Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst M Lib/test/test_ssl.py M Modules/_ssl.c diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index d4eb2d2e81fe..76669bdac72f 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -151,7 +151,6 @@ def data_file(*name): OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0) OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0) -OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0) # Ubuntu has patched OpenSSL and changed behavior of security level 2 # see https://bugs.python.org/issue41561#msg389003 @@ -958,8 +957,7 @@ def test_options(self): # SSLContext also enables these by default default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE | OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE | - OP_ENABLE_MIDDLEBOX_COMPAT | - OP_IGNORE_UNEXPECTED_EOF) + OP_ENABLE_MIDDLEBOX_COMPAT) self.assertEqual(default, ctx.options) with warnings_helper.check_warnings(): ctx.options |= ssl.OP_NO_TLSv1 @@ -2120,6 +2118,20 @@ def test_bio_read_write_data(self): self.assertEqual(buf, b'foo\n') self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap) + def test_transport_eof(self): + client_context, server_context, hostname = testing_context() + with socket.socket(socket.AF_INET) as sock: + sock.connect(self.server_addr) + incoming = ssl.MemoryBIO() + outgoing = ssl.MemoryBIO() + sslobj = client_context.wrap_bio(incoming, outgoing, + server_hostname=hostname) + self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) + + # Simulate EOF from the transport. + incoming.write_eof() + self.assertRaises(ssl.SSLEOFError, sslobj.read) + @support.requires_resource('network') class NetworkedTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst new file mode 100644 index 000000000000..d0f4ccbdd3e3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst @@ -0,0 +1,7 @@ +When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it +reported unauthenticated EOFs (i.e. without close_notify) as a clean TLS-level +EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior in previous +versions of OpenSSL. The :attr:`~ssl.SSLContext.options` attribute on +:class:`~ssl.SSLContext` also no longer includes +:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to +specify the previous OpenSSL 3.0 behavior. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 121d18884d0a..321b6ec52b77 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -660,6 +660,16 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) ERR_GET_REASON(e) == SSL_R_CERTIFICATE_VERIFY_FAILED) { type = state->PySSLCertVerificationErrorObject; } +#if defined(SSL_R_UNEXPECTED_EOF_WHILE_READING) + /* OpenSSL 3.0 changed transport EOF from SSL_ERROR_SYSCALL with + * zero return value to SSL_ERROR_SSL with a special error code. */ + if (ERR_GET_LIB(e) == ERR_LIB_SSL && + ERR_GET_REASON(e) == SSL_R_UNEXPECTED_EOF_WHILE_READING) { + p = PY_SSL_ERROR_EOF; + type = state->PySSLEOFErrorObject; + errstr = "EOF occurred in violation of protocol"; + } +#endif break; } default: @@ -3092,10 +3102,6 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) #endif #ifdef SSL_OP_SINGLE_ECDH_USE options |= SSL_OP_SINGLE_ECDH_USE; -#endif -#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF - /* Make OpenSSL 3.0.0 behave like 1.1.1 */ - options |= SSL_OP_IGNORE_UNEXPECTED_EOF; #endif SSL_CTX_set_options(self->ctx, options); From webhook-mailer at python.org Wed Mar 22 08:20:00 2023 From: webhook-mailer at python.org (corona10) Date: Wed, 22 Mar 2023 12:20:00 -0000 Subject: [Python-checkins] gh-101313: Add -h and --help arguments to the webbrowser module (gh-101374) Message-ID: https://github.com/python/cpython/commit/3d7eb66c963c0c86021738271483bef27c425b17 commit: 3d7eb66c963c0c86021738271483bef27c425b17 branch: main author: Icelain committer: corona10 date: 2023-03-22T21:19:52+09:00 summary: gh-101313: Add -h and --help arguments to the webbrowser module (gh-101374) files: A Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst M Lib/webbrowser.py diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index a56ff33dbbdc..4336597e68f6 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -713,11 +713,12 @@ def open(self, url, new=0, autoraise=True): def main(): import getopt - usage = """Usage: %s [-n | -t] url + usage = """Usage: %s [-n | -t | -h] url -n: open new window - -t: open new tab""" % sys.argv[0] + -t: open new tab + -h, --help: show help""" % sys.argv[0] try: - opts, args = getopt.getopt(sys.argv[1:], 'ntd') + opts, args = getopt.getopt(sys.argv[1:], 'ntdh',['help']) except getopt.error as msg: print(msg, file=sys.stderr) print(usage, file=sys.stderr) @@ -726,6 +727,9 @@ def main(): for o, a in opts: if o == '-n': new_win = 1 elif o == '-t': new_win = 2 + elif o == '-h' or o == '--help': + print(usage, file=sys.stderr) + sys.exit() if len(args) != 1: print(usage, file=sys.stderr) sys.exit(1) diff --git a/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst b/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst new file mode 100644 index 000000000000..63d0a7286920 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst @@ -0,0 +1 @@ +Added -h and --help arguments to the webbrowser CLI From webhook-mailer at python.org Wed Mar 22 08:25:11 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 12:25:11 -0000 Subject: [Python-checkins] gh-100989: Improve the accuracy of collections.deque docstrings (GH-100990) Message-ID: https://github.com/python/cpython/commit/f7dea0cb329ea15c6834a10c64d5d7b9db96c503 commit: f7dea0cb329ea15c6834a10c64d5d7b9db96c503 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T05:25:03-07:00 summary: gh-100989: Improve the accuracy of collections.deque docstrings (GH-100990) (cherry picked from commit c74073657e32b8872f91b3bbe1efa9af20adbea9) Co-authored-by: Timo Ludwig Co-authored-by: C.A.M. Gerlach files: M Modules/_collectionsmodule.c diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 741cfbe9dc61..b20e51e8b0eb 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -916,7 +916,9 @@ deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(rotate_doc, -"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); +"rotate(n)\n\n" +"Rotate the deque *n* steps to the right (default ``n=1``). " +"If *n* is negative, rotates left."); static PyObject * deque_reverse(dequeobject *deque, PyObject *unused) @@ -957,7 +959,8 @@ deque_reverse(dequeobject *deque, PyObject *unused) } PyDoc_STRVAR(reverse_doc, -"D.reverse() -- reverse *IN PLACE*"); +"reverse()\n\n" +"Reverse the elements of the deque *IN PLACE*."); static PyObject * deque_count(dequeobject *deque, PyObject *v) @@ -997,7 +1000,8 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"D.count(value) -> integer -- return number of occurrences of value"); +"count(x) -> int\n\n" +"Count the number of deque elements equal to *x*."); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1106,8 +1110,10 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" -"Raises ValueError if the value is not present."); +"index(x, [start, [stop]]) -> int\n\n" +"Return the position of *x* in the deque " +"(at or after index *start* and before index *stop*). " +"Returns the first match or raises a ValueError if not found."); /* insert(), remove(), and delitem() are implemented in terms of rotate() for simplicity and reasonable performance near the end @@ -1152,10 +1158,13 @@ deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(insert_doc, -"D.insert(index, object) -- insert object before index"); +"insert(i, x)\n\n" +"Insert *x* into the deque at position *i*."); PyDoc_STRVAR(remove_doc, -"D.remove(value) -- remove first occurrence of value."); +"remove(x)\n\n" +"Remove the first occurrence of *x*." +"If not found, raises a ValueError."); static int valid_index(Py_ssize_t i, Py_ssize_t limit) @@ -1534,7 +1543,8 @@ deque_sizeof(dequeobject *deque, void *unused) } PyDoc_STRVAR(sizeof_doc, -"D.__sizeof__() -- size of D in memory, in bytes"); +"__sizeof__() -> int\n\n" +"Size of the deque in memory, in bytes."); static PyObject * deque_get_maxlen(dequeobject *deque, void *Py_UNUSED(ignored)) @@ -1569,7 +1579,8 @@ static PySequenceMethods deque_as_sequence = { static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, - "D.__reversed__() -- return a reverse iterator over the deque"); +"__reversed__()\n\n" +"Return a reverse iterator over the deque."); static PyMethodDef deque_methods[] = { {"append", (PyCFunction)deque_append, @@ -1614,9 +1625,8 @@ static PyMethodDef deque_methods[] = { }; PyDoc_STRVAR(deque_doc, -"deque([iterable[, maxlen]]) --> deque object\n\ -\n\ -A list-like sequence optimized for data accesses near its endpoints."); +"deque([iterable[, maxlen]]) -> collections.deque\n\n" +"A list-like sequence optimized for data accesses near its endpoints."); static PyTypeObject deque_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -1999,7 +2009,8 @@ new_defdict(defdictobject *dd, PyObject *arg) dd->default_factory ? dd->default_factory : Py_None, arg, NULL); } -PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); +PyDoc_STRVAR(defdict_copy_doc, "copy() -> collections.deque\n\n" +"A shallow copy of the deque."); static PyObject * defdict_copy(defdictobject *dd, PyObject *Py_UNUSED(ignored)) From webhook-mailer at python.org Wed Mar 22 08:39:54 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 12:39:54 -0000 Subject: [Python-checkins] gh-100989: Improve the accuracy of collections.deque docstrings (GH-100990) Message-ID: https://github.com/python/cpython/commit/100da7c31aeb3888962bf33c8cc3594272964815 commit: 100da7c31aeb3888962bf33c8cc3594272964815 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T05:39:45-07:00 summary: gh-100989: Improve the accuracy of collections.deque docstrings (GH-100990) (cherry picked from commit c74073657e32b8872f91b3bbe1efa9af20adbea9) Co-authored-by: Timo Ludwig Co-authored-by: C.A.M. Gerlach files: M Modules/_collectionsmodule.c diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index eff03c789ede..84bc2c2d087f 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -920,7 +920,9 @@ deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(rotate_doc, -"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); +"rotate(n)\n\n" +"Rotate the deque *n* steps to the right (default ``n=1``). " +"If *n* is negative, rotates left."); static PyObject * deque_reverse(dequeobject *deque, PyObject *unused) @@ -961,7 +963,8 @@ deque_reverse(dequeobject *deque, PyObject *unused) } PyDoc_STRVAR(reverse_doc, -"D.reverse() -- reverse *IN PLACE*"); +"reverse()\n\n" +"Reverse the elements of the deque *IN PLACE*."); static PyObject * deque_count(dequeobject *deque, PyObject *v) @@ -1001,7 +1004,8 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"D.count(value) -> integer -- return number of occurrences of value"); +"count(x) -> int\n\n" +"Count the number of deque elements equal to *x*."); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1110,8 +1114,10 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" -"Raises ValueError if the value is not present."); +"index(x, [start, [stop]]) -> int\n\n" +"Return the position of *x* in the deque " +"(at or after index *start* and before index *stop*). " +"Returns the first match or raises a ValueError if not found."); /* insert(), remove(), and delitem() are implemented in terms of rotate() for simplicity and reasonable performance near the end @@ -1156,10 +1162,13 @@ deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(insert_doc, -"D.insert(index, object) -- insert object before index"); +"insert(i, x)\n\n" +"Insert *x* into the deque at position *i*."); PyDoc_STRVAR(remove_doc, -"D.remove(value) -- remove first occurrence of value."); +"remove(x)\n\n" +"Remove the first occurrence of *x*." +"If not found, raises a ValueError."); static int valid_index(Py_ssize_t i, Py_ssize_t limit) @@ -1537,7 +1546,8 @@ deque_sizeof(dequeobject *deque, void *unused) } PyDoc_STRVAR(sizeof_doc, -"D.__sizeof__() -- size of D in memory, in bytes"); +"__sizeof__() -> int\n\n" +"Size of the deque in memory, in bytes."); static int deque_bool(dequeobject *deque) @@ -1592,7 +1602,8 @@ static PyNumberMethods deque_as_number = { static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, - "D.__reversed__() -- return a reverse iterator over the deque"); +"__reversed__()\n\n" +"Return a reverse iterator over the deque."); static PyMethodDef deque_methods[] = { {"append", (PyCFunction)deque_append, @@ -1637,9 +1648,8 @@ static PyMethodDef deque_methods[] = { }; PyDoc_STRVAR(deque_doc, -"deque([iterable[, maxlen]]) --> deque object\n\ -\n\ -A list-like sequence optimized for data accesses near its endpoints."); +"deque([iterable[, maxlen]]) -> collections.deque\n\n" +"A list-like sequence optimized for data accesses near its endpoints."); static PyTypeObject deque_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -2022,7 +2032,8 @@ new_defdict(defdictobject *dd, PyObject *arg) dd->default_factory ? dd->default_factory : Py_None, arg, NULL); } -PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); +PyDoc_STRVAR(defdict_copy_doc, "copy() -> collections.deque\n\n" +"A shallow copy of the deque."); static PyObject * defdict_copy(defdictobject *dd, PyObject *Py_UNUSED(ignored)) From webhook-mailer at python.org Wed Mar 22 09:05:17 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Wed, 22 Mar 2023 13:05:17 -0000 Subject: [Python-checkins] gh-101947: Remove size check from sqlite3 serialize test (#102914) Message-ID: https://github.com/python/cpython/commit/61405da9a5689f554aa53929a2a9c168cab6056b commit: 61405da9a5689f554aa53929a2a9c168cab6056b branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-03-22T14:05:08+01:00 summary: gh-101947: Remove size check from sqlite3 serialize test (#102914) The size of the returned data is too implementation specific. files: M Lib/test/test_sqlite3/test_dbapi.py diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 695e213cdc7b..3013abfa730e 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -606,7 +606,6 @@ def test_serialize_deserialize(self): with cx: cx.execute("create table t(t)") data = cx.serialize() - self.assertEqual(len(data), 8192) # Remove test table, verify that it was removed. with cx: From webhook-mailer at python.org Wed Mar 22 09:45:11 2023 From: webhook-mailer at python.org (Yhg1s) Date: Wed, 22 Mar 2023 13:45:11 -0000 Subject: [Python-checkins] gh-102027: Fix macro name (#102124) Message-ID: https://github.com/python/cpython/commit/ea93bde4ece139d4152a59f2c38aa6568559447c commit: ea93bde4ece139d4152a59f2c38aa6568559447c branch: main author: Max Bachmann committer: Yhg1s date: 2023-03-22T14:44:28+01:00 summary: gh-102027: Fix macro name (#102124) This fixes the ssse3 / sse2 detection when sse4 is available. Co-authored-by: Oleg Iarygin files: A Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst M Modules/_blake2/impl/blake2-config.h diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst new file mode 100644 index 000000000000..42d96b54677e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst @@ -0,0 +1,2 @@ +Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max +Bachmann. diff --git a/Modules/_blake2/impl/blake2-config.h b/Modules/_blake2/impl/blake2-config.h index f5dd6faa9e68..c09cb4bcf067 100644 --- a/Modules/_blake2/impl/blake2-config.h +++ b/Modules/_blake2/impl/blake2-config.h @@ -53,7 +53,7 @@ #endif #endif -#ifdef HAVE_SSE41 +#ifdef HAVE_SSE4_1 #ifndef HAVE_SSSE3 #define HAVE_SSSE3 #endif From webhook-mailer at python.org Wed Mar 22 09:45:36 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 13:45:36 -0000 Subject: [Python-checkins] gh-101947: Remove size check from sqlite3 serialize test (GH-102914) Message-ID: https://github.com/python/cpython/commit/b9304beda0ca0ce25d4f2aace73e7f926aaebcf4 commit: b9304beda0ca0ce25d4f2aace73e7f926aaebcf4 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T06:45:28-07:00 summary: gh-101947: Remove size check from sqlite3 serialize test (GH-102914) The size of the returned data is too implementation specific. (cherry picked from commit 61405da9a5689f554aa53929a2a9c168cab6056b) Co-authored-by: Erlend E. Aasland files: M Lib/test/test_sqlite3/test_dbapi.py diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 2aea1105a251..9d94ddda95bd 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -604,7 +604,6 @@ def test_serialize_deserialize(self): with cx: cx.execute("create table t(t)") data = cx.serialize() - self.assertEqual(len(data), 8192) # Remove test table, verify that it was removed. with cx: From webhook-mailer at python.org Wed Mar 22 09:53:31 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 13:53:31 -0000 Subject: [Python-checkins] gh-95913: Consolidate build requirements changes in 3.11 WhatsNew (GH-98781) Message-ID: https://github.com/python/cpython/commit/4c1b4eccbac6bf8ecd614717e10db75f75714c78 commit: 4c1b4eccbac6bf8ecd614717e10db75f75714c78 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T06:53:22-07:00 summary: gh-95913: Consolidate build requirements changes in 3.11 WhatsNew (GH-98781) Apply suggestion to combine build requirements changes in 3.11 WhatsNew (cherry picked from commit 4a3ea1fdd890e5e2ec26540dc3c958a52fba6556) Co-authored-by: C.A.M. Gerlach Co-authored-by: Petr Viktorin files: M Doc/whatsnew/3.11.rst diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 40a998c765c9..a38a80a5015a 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -2116,30 +2116,22 @@ Build Changes and WASI contributed by Christian Heimes in :gh:`90473`; platforms promoted in :gh:`95085`) -* Building Python now requires: +* Building CPython now requires: - * A `C11 `_ compiler. + * A `C11 `_ compiler and standard library. `Optional C11 features `_ are not required. - (Contributed by Victor Stinner in :issue:`46656`.) + (Contributed by Victor Stinner in :issue:`46656`, + :issue:`45440` and :issue:`46640`.) * Support for `IEEE 754 `_ floating point numbers. (Contributed by Victor Stinner in :issue:`46917`.) - * Support for `floating point Not-a-Number (NaN) - `_, - as the :c:macro:`!Py_NO_NAN` macro has been removed. - (Contributed by Victor Stinner in :issue:`46656`.) - - * A `C99 `_ - ```` header file providing the - :c:func:`!copysign`, :c:func:`!hypot`, :c:func:`!isfinite`, - :c:func:`!isinf`, :c:func:`!isnan`, and :c:func:`!round` functions - (contributed by Victor Stinner in :issue:`45440`); - and a :c:data:`!NAN` constant or the :c:func:`!__builtin_nan` function - (Contributed by Victor Stinner in :issue:`46640`). +* The :c:macro:`!Py_NO_NAN` macro has been removed. + Since CPython now requires IEEE 754 floats, NaN values are always available. + (Contributed by Victor Stinner in :issue:`46656`.) * The :mod:`tkinter` package now requires `Tcl/Tk `_ version 8.5.12 or newer. From webhook-mailer at python.org Wed Mar 22 10:08:49 2023 From: webhook-mailer at python.org (Yhg1s) Date: Wed, 22 Mar 2023 14:08:49 -0000 Subject: [Python-checkins] gh-96931: Fix incorrect results in ssl.SSLSocket.shared_ciphers (#96932) Message-ID: https://github.com/python/cpython/commit/af9c34f6ef8dceb21871206eb3e4d350f6e3d3dc commit: af9c34f6ef8dceb21871206eb3e4d350f6e3d3dc branch: main author: Benjamin Fogle committer: Yhg1s date: 2023-03-22T15:08:41+01:00 summary: gh-96931: Fix incorrect results in ssl.SSLSocket.shared_ciphers (#96932) files: A Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst M Doc/library/ssl.rst M Lib/test/test_ssl.py M Modules/_ssl.c diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 30f2a0765cc9..4b60b7c643b6 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1218,7 +1218,7 @@ SSL sockets also have the following additional methods and attributes: .. method:: SSLSocket.shared_ciphers() - Return the list of ciphers shared by the client during the handshake. Each + Return the list of ciphers available in both the client and server. Each entry of the returned list is a three-value tuple containing the name of the cipher, the version of the SSL protocol that defines its use, and the number of secret bits the cipher uses. :meth:`~SSLSocket.shared_ciphers` returns diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 76669bdac72f..1317efb33c23 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2082,13 +2082,13 @@ def test_bio_handshake(self): self.assertIs(sslobj._sslobj.owner, sslobj) self.assertIsNone(sslobj.cipher()) self.assertIsNone(sslobj.version()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertRaises(ValueError, sslobj.getpeercert) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: self.assertIsNone(sslobj.get_channel_binding('tls-unique')) self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) self.assertTrue(sslobj.cipher()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertIsNotNone(sslobj.version()) self.assertTrue(sslobj.getpeercert()) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: @@ -4051,7 +4051,7 @@ def cb_wrong_return_type(ssl_sock, server_name, initial_context): def test_shared_ciphers(self): client_context, server_context, hostname = testing_context() client_context.set_ciphers("AES128:AES256") - server_context.set_ciphers("AES256") + server_context.set_ciphers("AES256:eNULL") expected_algs = [ "AES256", "AES-256", # TLS 1.3 ciphers are always enabled diff --git a/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst new file mode 100644 index 000000000000..766b1d4d477b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst @@ -0,0 +1 @@ +Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 321b6ec52b77..36b66cdb5310 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1998,24 +1998,44 @@ static PyObject * _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self) /*[clinic end generated code: output=3d174ead2e42c4fd input=0bfe149da8fe6306]*/ { - STACK_OF(SSL_CIPHER) *ciphers; - int i; + STACK_OF(SSL_CIPHER) *server_ciphers; + STACK_OF(SSL_CIPHER) *client_ciphers; + int i, len; PyObject *res; + const SSL_CIPHER* cipher; + + /* Rather than use SSL_get_shared_ciphers, we use an equivalent algorithm because: + + 1) It returns a colon seperated list of strings, in an undefined + order, that we would have to post process back into tuples. + 2) It will return a truncated string with no indication that it has + done so, if the buffer is too small. + */ - ciphers = SSL_get_ciphers(self->ssl); - if (!ciphers) + server_ciphers = SSL_get_ciphers(self->ssl); + if (!server_ciphers) Py_RETURN_NONE; - res = PyList_New(sk_SSL_CIPHER_num(ciphers)); + client_ciphers = SSL_get_client_ciphers(self->ssl); + if (!client_ciphers) + Py_RETURN_NONE; + + res = PyList_New(sk_SSL_CIPHER_num(server_ciphers)); if (!res) return NULL; - for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { - PyObject *tup = cipher_to_tuple(sk_SSL_CIPHER_value(ciphers, i)); + len = 0; + for (i = 0; i < sk_SSL_CIPHER_num(server_ciphers); i++) { + cipher = sk_SSL_CIPHER_value(server_ciphers, i); + if (sk_SSL_CIPHER_find(client_ciphers, cipher) < 0) + continue; + + PyObject *tup = cipher_to_tuple(cipher); if (!tup) { Py_DECREF(res); return NULL; } - PyList_SET_ITEM(res, i, tup); + PyList_SET_ITEM(res, len++, tup); } + Py_SET_SIZE(res, len); return res; } From webhook-mailer at python.org Wed Mar 22 10:45:35 2023 From: webhook-mailer at python.org (barneygale) Date: Wed, 22 Mar 2023 14:45:35 -0000 Subject: [Python-checkins] GH-89727: Fix pathlib.Path.walk RecursionError on deep trees (GH-100282) Message-ID: https://github.com/python/cpython/commit/713df2c53489ce8012d0ede10b70950e6b0d8372 commit: 713df2c53489ce8012d0ede10b70950e6b0d8372 branch: main author: Stanislav Zmiev committer: barneygale date: 2023-03-22T14:45:25Z summary: GH-89727: Fix pathlib.Path.walk RecursionError on deep trees (GH-100282) Use a stack to implement `pathlib.Path.walk()` iteratively instead of recursively to avoid hitting recursion limits on deeply nested trees. Co-authored-by: Barney Gale Co-authored-by: Brett Cannon files: A Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst M Lib/pathlib.py M Lib/test/test_pathlib.py diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 55c44f12e5a2..a126bf2fe557 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -1197,45 +1197,47 @@ def expanduser(self): def walk(self, top_down=True, on_error=None, follow_symlinks=False): """Walk the directory tree from this directory, similar to os.walk().""" sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks) - return self._walk(top_down, on_error, follow_symlinks) - - def _walk(self, top_down, on_error, follow_symlinks): - # We may not have read permission for self, in which case we can't - # get a list of the files the directory contains. os.walk - # always suppressed the exception then, rather than blow up for a - # minor reason when (say) a thousand readable directories are still - # left to visit. That logic is copied here. - try: - scandir_it = self._scandir() - except OSError as error: - if on_error is not None: - on_error(error) - return - - with scandir_it: - dirnames = [] - filenames = [] - for entry in scandir_it: - try: - is_dir = entry.is_dir(follow_symlinks=follow_symlinks) - except OSError: - # Carried over from os.path.isdir(). - is_dir = False - - if is_dir: - dirnames.append(entry.name) - else: - filenames.append(entry.name) - - if top_down: - yield self, dirnames, filenames - - for dirname in dirnames: - dirpath = self._make_child_relpath(dirname) - yield from dirpath._walk(top_down, on_error, follow_symlinks) + paths = [self] + + while paths: + path = paths.pop() + if isinstance(path, tuple): + yield path + continue + + # We may not have read permission for self, in which case we can't + # get a list of the files the directory contains. os.walk() + # always suppressed the exception in that instance, rather than + # blow up for a minor reason when (say) a thousand readable + # directories are still left to visit. That logic is copied here. + try: + scandir_it = path._scandir() + except OSError as error: + if on_error is not None: + on_error(error) + continue + + with scandir_it: + dirnames = [] + filenames = [] + for entry in scandir_it: + try: + is_dir = entry.is_dir(follow_symlinks=follow_symlinks) + except OSError: + # Carried over from os.path.isdir(). + is_dir = False + + if is_dir: + dirnames.append(entry.name) + else: + filenames.append(entry.name) + + if top_down: + yield path, dirnames, filenames + else: + paths.append((path, dirnames, filenames)) - if not top_down: - yield self, dirnames, filenames + paths += [path._make_child_relpath(d) for d in reversed(dirnames)] class PosixPath(Path, PurePosixPath): diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index f05dead58867..3041630da678 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -13,6 +13,7 @@ from unittest import mock from test.support import import_helper +from test.support import set_recursion_limit from test.support import is_emscripten, is_wasi from test.support import os_helper from test.support.os_helper import TESTFN, FakePath @@ -2793,6 +2794,18 @@ def test_walk_many_open_files(self): self.assertEqual(next(it), expected) path = path / 'd' + def test_walk_above_recursion_limit(self): + recursion_limit = 40 + # directory_depth > recursion_limit + directory_depth = recursion_limit + 10 + base = pathlib.Path(os_helper.TESTFN, 'deep') + path = pathlib.Path(base, *(['d'] * directory_depth)) + path.mkdir(parents=True) + + with set_recursion_limit(recursion_limit): + list(base.walk()) + list(base.walk(top_down=False)) + class PathTest(_BasePathTest, unittest.TestCase): cls = pathlib.Path diff --git a/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst b/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst new file mode 100644 index 000000000000..f9ac1475dceb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst @@ -0,0 +1 @@ +Fix pathlib.Path.walk RecursionError on deep directory trees by rewriting it using iteration instead of recursion. From webhook-mailer at python.org Wed Mar 22 10:50:01 2023 From: webhook-mailer at python.org (markshannon) Date: Wed, 22 Mar 2023 14:50:01 -0000 Subject: [Python-checkins] GH-101291: Rearrange the size bits in PyLongObject (GH-102464) Message-ID: https://github.com/python/cpython/commit/7559f5fda94ab568a1a910b17683ed81dc3426fb commit: 7559f5fda94ab568a1a910b17683ed81dc3426fb branch: main author: Mark Shannon committer: markshannon date: 2023-03-22T14:49:51Z summary: GH-101291: Rearrange the size bits in PyLongObject (GH-102464) * Eliminate all remaining uses of Py_SIZE and Py_SET_SIZE on PyLongObject, adding asserts. * Change layout of size/sign bits in longobject to support future addition of immortal ints and tagged medium ints. * Add functions to hide some internals of long object, and for setting sign and digit count. * Replace uses of IS_MEDIUM_VALUE macro with _PyLong_IsCompact(). files: A Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst M Include/cpython/longintrepr.h M Include/internal/pycore_long.h M Include/internal/pycore_object.h M Include/internal/pycore_runtime_init.h M Include/object.h M Modules/_decimal/_decimal.c M Modules/_testcapi/mem.c M Modules/_tkinter.c M Modules/mathmodule.c M Objects/abstract.c M Objects/boolobject.c M Objects/listobject.c M Objects/longobject.c M Objects/rangeobject.c M Objects/sliceobject.c M Objects/typeobject.c M Python/ast_opt.c M Python/bltinmodule.c M Python/bytecodes.c M Python/generated_cases.c.h M Python/marshal.c M Python/specialize.c M Tools/build/deepfreeze.py M Tools/gdb/libpython.py diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 810daa83165e..c4cf820da5e4 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -80,7 +80,7 @@ typedef long stwodigits; /* signed variant of twodigits */ */ typedef struct _PyLongValue { - Py_ssize_t ob_size; /* Number of items in variable part */ + uintptr_t lv_tag; /* Number of digits, sign and flags */ digit ob_digit[1]; } _PyLongValue; @@ -94,6 +94,10 @@ PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); /* Return a copy of src. */ PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); +PyAPI_FUNC(PyLongObject *) +_PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits); + + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 8c1d017bb95e..137a0465d5ec 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -82,8 +82,6 @@ PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Subtract(PyLongObject *left, PyLongObject *right); -int _PyLong_AssignValue(PyObject **target, Py_ssize_t value); - /* Used by Python/mystrtoul.c, _PyBytes_FromHex(), _PyBytes_DecodeEscape(), etc. */ PyAPI_DATA(unsigned char) _PyLong_DigitValue[256]; @@ -110,25 +108,155 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( int base, int alternate); -/* Return 1 if the argument is positive single digit int */ +/* Long value tag bits: + * 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1. + * 2: Reserved for immortality bit + * 3+ Unsigned digit count + */ +#define SIGN_MASK 3 +#define SIGN_ZERO 1 +#define SIGN_NEGATIVE 2 +#define NON_SIZE_BITS 3 + +/* All *compact" values are guaranteed to fit into + * a Py_ssize_t with at least one bit to spare. + * In other words, for 64 bit machines, compact + * will be signed 63 (or fewer) bit values + */ + +/* Return 1 if the argument is compact int */ +static inline int +_PyLong_IsNonNegativeCompact(const PyLongObject* op) { + assert(PyLong_Check(op)); + return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); +} + +static inline int +_PyLong_IsCompact(const PyLongObject* op) { + assert(PyLong_Check(op)); + return op->long_value.lv_tag < (2 << NON_SIZE_BITS); +} + static inline int -_PyLong_IsPositiveSingleDigit(PyObject* sub) { - /* For a positive single digit int, the value of Py_SIZE(sub) is 0 or 1. - - We perform a fast check using a single comparison by casting from int - to uint which casts negative numbers to large positive numbers. - For details see Section 14.2 "Bounds Checking" in the Agner Fog - optimization manual found at: - https://www.agner.org/optimize/optimizing_cpp.pdf - - The function is not affected by -fwrapv, -fno-wrapv and -ftrapv - compiler options of GCC and clang - */ - assert(PyLong_CheckExact(sub)); - Py_ssize_t signed_size = Py_SIZE(sub); - return ((size_t)signed_size) <= 1; +_PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) { + assert(PyLong_Check(a)); + assert(PyLong_Check(b)); + return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS); +} + +/* Returns a *compact* value, iff `_PyLong_IsCompact` is true for `op`. + * + * "Compact" values have at least one bit to spare, + * so that addition and subtraction can be performed on the values + * without risk of overflow. + */ +static inline Py_ssize_t +_PyLong_CompactValue(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(_PyLong_IsCompact(op)); + Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); + return sign * (Py_ssize_t)op->long_value.ob_digit[0]; +} + +static inline bool +_PyLong_IsZero(const PyLongObject *op) +{ + return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO; +} + +static inline bool +_PyLong_IsNegative(const PyLongObject *op) +{ + return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE; +} + +static inline bool +_PyLong_IsPositive(const PyLongObject *op) +{ + return (op->long_value.lv_tag & SIGN_MASK) == 0; +} + +static inline Py_ssize_t +_PyLong_DigitCount(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + return op->long_value.lv_tag >> NON_SIZE_BITS; } +/* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonCompactSign(op) */ +static inline Py_ssize_t +_PyLong_SignedDigitCount(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); + return sign * (Py_ssize_t)(op->long_value.lv_tag >> NON_SIZE_BITS); +} + +static inline int +_PyLong_CompactSign(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(_PyLong_IsCompact(op)); + return 1 - (op->long_value.lv_tag & SIGN_MASK); +} + +static inline int +_PyLong_NonCompactSign(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(!_PyLong_IsCompact(op)); + return 1 - (op->long_value.lv_tag & SIGN_MASK); +} + +/* Do a and b have the same sign? */ +static inline int +_PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) +{ + return (a->long_value.lv_tag & SIGN_MASK) == (b->long_value.lv_tag & SIGN_MASK); +} + +#define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS)) + +static inline void +_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size) +{ + assert(size >= 0); + assert(-1 <= sign && sign <= 1); + assert(sign != 0 || size == 0); + op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, (size_t)size); +} + +static inline void +_PyLong_SetDigitCount(PyLongObject *op, Py_ssize_t size) +{ + assert(size >= 0); + op->long_value.lv_tag = (((size_t)size) << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK); +} + +#define NON_SIZE_MASK ~((1 << NON_SIZE_BITS) - 1) + +static inline void +_PyLong_FlipSign(PyLongObject *op) { + unsigned int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK); + op->long_value.lv_tag &= NON_SIZE_MASK; + op->long_value.lv_tag |= flipped_sign; +} + +#define _PyLong_DIGIT_INIT(val) \ + { \ + .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \ + .long_value = { \ + .lv_tag = TAG_FROM_SIGN_AND_SIZE( \ + (val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \ + (val) == 0 ? 0 : 1), \ + { ((val) >= 0 ? (val) : -(val)) }, \ + } \ + } + +#define _PyLong_FALSE_TAG TAG_FROM_SIGN_AND_SIZE(0, 0) +#define _PyLong_TRUE_TAG TAG_FROM_SIGN_AND_SIZE(1, 1) + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index d6bbafd4b6cc..e18e787449c2 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -137,8 +137,9 @@ static inline void _PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) { assert(op != NULL); - Py_SET_SIZE(op, size); + assert(typeobj != &PyLong_Type); _PyObject_Init((PyObject *)op, typeobj); + Py_SET_SIZE(op, size); } diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index bdecac944dfd..7cfa7c0c0249 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -8,6 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_long.h" #include "pycore_object.h" #include "pycore_parser.h" #include "pycore_pymem_init.h" @@ -130,15 +131,6 @@ extern PyTypeObject _PyExc_MemoryError; // global objects -#define _PyLong_DIGIT_INIT(val) \ - { \ - .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \ - .long_value = { \ - ((val) == 0 ? 0 : ((val) > 0 ? 1 : -1)), \ - { ((val) >= 0 ? (val) : -(val)) }, \ - } \ - } - #define _PyBytes_SIMPLE_INIT(CH, LEN) \ { \ _PyVarObject_IMMORTAL_INIT(&PyBytes_Type, (LEN)), \ diff --git a/Include/object.h b/Include/object.h index fc577353c1cc..2943a6066818 100644 --- a/Include/object.h +++ b/Include/object.h @@ -138,8 +138,13 @@ static inline PyTypeObject* Py_TYPE(PyObject *ob) { # define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob)) #endif +PyAPI_DATA(PyTypeObject) PyLong_Type; +PyAPI_DATA(PyTypeObject) PyBool_Type; + // bpo-39573: The Py_SET_SIZE() function must be used to set an object size. static inline Py_ssize_t Py_SIZE(PyObject *ob) { + assert(ob->ob_type != &PyLong_Type); + assert(ob->ob_type != &PyBool_Type); PyVarObject *var_ob = _PyVarObject_CAST(ob); return var_ob->ob_size; } @@ -171,8 +176,9 @@ static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { # define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) #endif - static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { + assert(ob->ob_base.ob_type != &PyLong_Type); + assert(ob->ob_base.ob_type != &PyBool_Type); ob->ob_size = size; } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst new file mode 100644 index 000000000000..46f0f325f916 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst @@ -0,0 +1,7 @@ +Rearrage bits in first field (after header) of PyLongObject. +* Bits 0 and 1: 1 - sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative numbers. +* Bit 2 reserved (probably for the immortal bit) +* Bits 3+ the unsigned size. + +This makes a few operations slightly more efficient, and will enable a more +compact and faster 2s-complement representation of most ints in future. diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 5936fbaaf35e..0e11c879732a 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -30,6 +30,7 @@ #endif #include +#include "pycore_long.h" // _PyLong_IsZero() #include "pycore_pystate.h" // _PyThreadState_GET() #include "complexobject.h" #include "mpdecimal.h" @@ -2146,35 +2147,25 @@ dec_from_long(PyTypeObject *type, PyObject *v, { PyObject *dec; PyLongObject *l = (PyLongObject *)v; - Py_ssize_t ob_size; - size_t len; - uint8_t sign; dec = PyDecType_New(type); if (dec == NULL) { return NULL; } - ob_size = Py_SIZE(l); - if (ob_size == 0) { + if (_PyLong_IsZero(l)) { _dec_settriple(dec, MPD_POS, 0, 0); return dec; } - if (ob_size < 0) { - len = -ob_size; - sign = MPD_NEG; - } - else { - len = ob_size; - sign = MPD_POS; - } + uint8_t sign = _PyLong_IsNegative(l) ? MPD_NEG : MPD_POS; - if (len == 1) { - _dec_settriple(dec, sign, *l->long_value.ob_digit, 0); + if (_PyLong_IsCompact(l)) { + _dec_settriple(dec, sign, l->long_value.ob_digit[0], 0); mpd_qfinalize(MPD(dec), ctx, status); return dec; } + size_t len = _PyLong_DigitCount(l); #if PYLONG_BITS_IN_DIGIT == 30 mpd_qimport_u32(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE, @@ -3482,7 +3473,6 @@ dec_as_long(PyObject *dec, PyObject *context, int round) PyLongObject *pylong; digit *ob_digit; size_t n; - Py_ssize_t i; mpd_t *x; mpd_context_t workctx; uint32_t status = 0; @@ -3536,26 +3526,9 @@ dec_as_long(PyObject *dec, PyObject *context, int round) } assert(n > 0); - pylong = _PyLong_New(n); - if (pylong == NULL) { - mpd_free(ob_digit); - mpd_del(x); - return NULL; - } - - memcpy(pylong->long_value.ob_digit, ob_digit, n * sizeof(digit)); + assert(!mpd_iszero(x)); + pylong = _PyLong_FromDigits(mpd_isnegative(x), n, ob_digit); mpd_free(ob_digit); - - i = n; - while ((i > 0) && (pylong->long_value.ob_digit[i-1] == 0)) { - i--; - } - - Py_SET_SIZE(pylong, i); - if (mpd_isnegative(x) && !mpd_iszero(x)) { - Py_SET_SIZE(pylong, -i); - } - mpd_del(x); return (PyObject *) pylong; } diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index ae3f7a4372dc..af32e9668dda 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -347,7 +347,7 @@ test_pyobject_new(PyObject *self, PyObject *Py_UNUSED(ignored)) { PyObject *obj; PyTypeObject *type = &PyBaseObject_Type; - PyTypeObject *var_type = &PyLong_Type; + PyTypeObject *var_type = &PyBytes_Type; // PyObject_New() obj = PyObject_New(PyObject, type); diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 1608939766ff..606e578a1f31 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -32,6 +32,8 @@ Copyright (C) 1994 Steen Lumholt. # include "pycore_fileutils.h" // _Py_stat() #endif +#include "pycore_long.h" + #ifdef MS_WINDOWS #include #endif @@ -886,7 +888,8 @@ asBignumObj(PyObject *value) const char *hexchars; mp_int bigValue; - neg = Py_SIZE(value) < 0; + assert(PyLong_Check(value)); + neg = _PyLong_IsNegative((PyLongObject *)value); hexstr = _PyLong_Format(value, 16); if (hexstr == NULL) return NULL; @@ -1950,7 +1953,7 @@ _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg) int v; if (PyLong_Check(arg)) { /* int or bool */ - return PyBool_FromLong(Py_SIZE(arg) != 0); + return PyBool_FromLong(!_PyLong_IsZero((PyLongObject *)arg)); } if (PyTclObject_Check(arg)) { diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 473936edb3f5..eddc1a33a953 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -836,7 +836,7 @@ long_lcm(PyObject *a, PyObject *b) { PyObject *g, *m, *f, *ab; - if (Py_SIZE(a) == 0 || Py_SIZE(b) == 0) { + if (_PyLong_IsZero((PyLongObject *)a) || _PyLong_IsZero((PyLongObject *)b)) { return PyLong_FromLong(0); } g = _PyLong_GCD(a, b); @@ -1726,13 +1726,13 @@ math_isqrt(PyObject *module, PyObject *n) return NULL; } - if (_PyLong_Sign(n) < 0) { + if (_PyLong_IsNegative((PyLongObject *)n)) { PyErr_SetString( PyExc_ValueError, "isqrt() argument must be nonnegative"); goto error; } - if (_PyLong_Sign(n) == 0) { + if (_PyLong_IsZero((PyLongObject *)n)) { Py_DECREF(n); return PyLong_FromLong(0); } @@ -2254,7 +2254,7 @@ loghelper(PyObject* arg, double (*func)(double)) Py_ssize_t e; /* Negative or zero inputs give a ValueError. */ - if (Py_SIZE(arg) <= 0) { + if (!_PyLong_IsPositive((PyLongObject *)arg)) { PyErr_SetString(PyExc_ValueError, "math domain error"); return NULL; @@ -3716,12 +3716,12 @@ math_perm_impl(PyObject *module, PyObject *n, PyObject *k) } assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); - if (Py_SIZE(n) < 0) { + if (_PyLong_IsNegative((PyLongObject *)n)) { PyErr_SetString(PyExc_ValueError, "n must be a non-negative integer"); goto error; } - if (Py_SIZE(k) < 0) { + if (_PyLong_IsNegative((PyLongObject *)k)) { PyErr_SetString(PyExc_ValueError, "k must be a non-negative integer"); goto error; @@ -3808,12 +3808,12 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) } assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); - if (Py_SIZE(n) < 0) { + if (_PyLong_IsNegative((PyLongObject *)n)) { PyErr_SetString(PyExc_ValueError, "n must be a non-negative integer"); goto error; } - if (Py_SIZE(k) < 0) { + if (_PyLong_IsNegative((PyLongObject *)k)) { PyErr_SetString(PyExc_ValueError, "k must be a non-negative integer"); goto error; @@ -3845,7 +3845,8 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) if (temp == NULL) { goto error; } - if (Py_SIZE(temp) < 0) { + assert(PyLong_Check(temp)); + if (_PyLong_IsNegative((PyLongObject *)temp)) { Py_DECREF(temp); result = PyLong_FromLong(0); goto done; diff --git a/Objects/abstract.c b/Objects/abstract.c index 9dc74fb9c260..e95785900c9c 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -5,6 +5,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_object.h" // _Py_CheckSlotResult() +#include "pycore_long.h" // _Py_IsNegative #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_unionobject.h" // _PyUnion_Check() @@ -1483,7 +1484,7 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) /* Whether or not it is less than or equal to zero is determined by the sign of ob_size */ - if (_PyLong_Sign(value) < 0) + if (_PyLong_IsNegative((PyLongObject *)value)) result = PY_SSIZE_T_MIN; else result = PY_SSIZE_T_MAX; diff --git a/Objects/boolobject.c b/Objects/boolobject.c index a035f4633238..9d8e956e06f7 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_object.h" // _Py_FatalRefcountError() +#include "pycore_long.h" // FALSE_TAG TRUE_TAG #include "pycore_runtime.h" // _Py_ID() #include @@ -198,10 +199,14 @@ PyTypeObject PyBool_Type = { struct _longobject _Py_FalseStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { 0, { 0 } } + { .lv_tag = _PyLong_FALSE_TAG, + { 0 } + } }; struct _longobject _Py_TrueStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { 1, { 1 } } + { .lv_tag = _PyLong_TRUE_TAG, + { 1 } + } }; diff --git a/Objects/listobject.c b/Objects/listobject.c index 1a210e77d55c..f1edfb3a9a03 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -4,6 +4,7 @@ #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_interp.h" // PyInterpreterState.list #include "pycore_list.h" // struct _Py_list_state, _PyListIterObject +#include "pycore_long.h" // _PyLong_DigitCount #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_tuple.h" // _PyTuple_FromArray() #include @@ -2144,24 +2145,21 @@ unsafe_latin_compare(PyObject *v, PyObject *w, MergeState *ms) static int unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms) { - PyLongObject *vl, *wl; sdigit v0, w0; int res; + PyLongObject *vl, *wl; + intptr_t v0, w0; + int res; /* Modified from Objects/longobject.c:long_compare, assuming: */ assert(Py_IS_TYPE(v, &PyLong_Type)); assert(Py_IS_TYPE(w, &PyLong_Type)); - assert(Py_ABS(Py_SIZE(v)) <= 1); - assert(Py_ABS(Py_SIZE(w)) <= 1); + assert(_PyLong_IsCompact((PyLongObject *)v)); + assert(_PyLong_IsCompact((PyLongObject *)w)); vl = (PyLongObject*)v; wl = (PyLongObject*)w; - v0 = Py_SIZE(vl) == 0 ? 0 : (sdigit)vl->long_value.ob_digit[0]; - w0 = Py_SIZE(wl) == 0 ? 0 : (sdigit)wl->long_value.ob_digit[0]; - - if (Py_SIZE(vl) < 0) - v0 = -v0; - if (Py_SIZE(wl) < 0) - w0 = -w0; + v0 = _PyLong_CompactValue(vl); + w0 = _PyLong_CompactValue(wl); res = v0 < w0; assert(res == PyObject_RichCompareBool(v, w, Py_LT)); @@ -2359,7 +2357,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse) if (keys_are_all_same_type) { if (key_type == &PyLong_Type && ints_are_bounded && - Py_ABS(Py_SIZE(key)) > 1) { + !_PyLong_IsCompact((PyLongObject *)key)) { ints_are_bounded = 0; } diff --git a/Objects/longobject.c b/Objects/longobject.c index 51655cd0bad9..bb4eac0d932b 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6,7 +6,7 @@ #include "pycore_bitutils.h" // _Py_popcount32() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_long.h" // _Py_SmallInts -#include "pycore_object.h" // _PyObject_InitVar() +#include "pycore_object.h" // _PyObject_Init() #include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "pycore_runtime.h" // _PY_NSMALLPOSINTS #include "pycore_structseq.h" // _PyStructSequence_FiniType() @@ -22,16 +22,7 @@ class int "PyObject *" "&PyLong_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/ -/* Is this PyLong of size 1, 0 or -1? */ -#define IS_MEDIUM_VALUE(x) (((size_t)Py_SIZE(x)) + 1U < 3U) - -/* convert a PyLong of size 1, 0 or -1 to a C integer */ -static inline stwodigits -medium_value(PyLongObject *x) -{ - assert(IS_MEDIUM_VALUE(x)); - return ((stwodigits)Py_SIZE(x)) * x->long_value.ob_digit[0]; -} +#define medium_value(x) ((stwodigits)_PyLong_CompactValue(x)) #define IS_SMALL_INT(ival) (-_PY_NSMALLNEGINTS <= (ival) && (ival) < _PY_NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < _PY_NSMALLPOSINTS) @@ -68,7 +59,7 @@ get_small_int(sdigit ival) static PyLongObject * maybe_small_long(PyLongObject *v) { - if (v && IS_MEDIUM_VALUE(v)) { + if (v && _PyLong_IsCompact(v)) { stwodigits ival = medium_value(v); if (IS_SMALL_INT(ival)) { _Py_DECREF_INT(v); @@ -126,13 +117,18 @@ maybe_small_long(PyLongObject *v) static PyLongObject * long_normalize(PyLongObject *v) { - Py_ssize_t j = Py_ABS(Py_SIZE(v)); + Py_ssize_t j = _PyLong_DigitCount(v); Py_ssize_t i = j; while (i > 0 && v->long_value.ob_digit[i-1] == 0) --i; if (i != j) { - Py_SET_SIZE(v, (Py_SIZE(v) < 0) ? -(i) : i); + if (i == 0) { + _PyLong_SetSignAndDigitCount(v, 0, 0); + } + else { + _PyLong_SetDigitCount(v, i); + } } return v; } @@ -146,6 +142,7 @@ long_normalize(PyLongObject *v) PyLongObject * _PyLong_New(Py_ssize_t size) { + assert(size >= 0); PyLongObject *result; if (size > (Py_ssize_t)MAX_LONG_DIGITS) { PyErr_SetString(PyExc_OverflowError, @@ -157,8 +154,8 @@ _PyLong_New(Py_ssize_t size) Py_ssize_t ndigits = size ? size : 1; /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + sizeof(digit)*size. Previous incarnations of this code used - sizeof(PyVarObject) instead of the offsetof, but this risks being - incorrect in the presence of padding between the PyVarObject header + sizeof() instead of the offsetof, but this risks being + incorrect in the presence of padding between the header and the digits. */ result = PyObject_Malloc(offsetof(PyLongObject, long_value.ob_digit) + ndigits*sizeof(digit)); @@ -166,34 +163,41 @@ _PyLong_New(Py_ssize_t size) PyErr_NoMemory(); return NULL; } - _PyObject_InitVar((PyVarObject*)result, &PyLong_Type, size); + _PyLong_SetSignAndDigitCount(result, size != 0, size); + _PyObject_Init((PyObject*)result, &PyLong_Type); + return result; +} + +PyLongObject * +_PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) +{ + assert(digit_count >= 0); + if (digit_count == 0) { + return (PyLongObject *)Py_NewRef(_PyLong_GetZero()); + } + PyLongObject *result = _PyLong_New(digit_count); + if (result == NULL) { + PyErr_NoMemory(); + return NULL; + } + _PyLong_SetSignAndDigitCount(result, negative?-1:1, digit_count); + memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit)); return result; } PyObject * _PyLong_Copy(PyLongObject *src) { - PyLongObject *result; - Py_ssize_t i; - assert(src != NULL); - i = Py_SIZE(src); - if (i < 0) - i = -(i); - if (i < 2) { + + if (_PyLong_IsCompact(src)) { stwodigits ival = medium_value(src); if (IS_SMALL_INT(ival)) { return get_small_int((sdigit)ival); } } - result = _PyLong_New(i); - if (result != NULL) { - Py_SET_SIZE(result, Py_SIZE(src)); - while (--i >= 0) { - result->long_value.ob_digit[i] = src->long_value.ob_digit[i]; - } - } - return (PyObject *)result; + Py_ssize_t size = _PyLong_DigitCount(src); + return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, src->long_value.ob_digit); } static PyObject * @@ -207,9 +211,9 @@ _PyLong_FromMedium(sdigit x) PyErr_NoMemory(); return NULL; } - Py_ssize_t sign = x < 0 ? -1: 1; digit abs_x = x < 0 ? -x : x; - _PyObject_InitVar((PyVarObject*)v, &PyLong_Type, sign); + _PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1); + _PyObject_Init((PyObject*)v, &PyLong_Type); v->long_value.ob_digit[0] = abs_x; return (PyObject*)v; } @@ -242,7 +246,7 @@ _PyLong_FromLarge(stwodigits ival) PyLongObject *v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, ndigits * sign); + _PyLong_SetSignAndDigitCount(v, sign, ndigits); t = abs_ival; while (t) { *p++ = Py_SAFE_DOWNCAST( @@ -267,38 +271,6 @@ _PyLong_FromSTwoDigits(stwodigits x) return _PyLong_FromLarge(x); } -int -_PyLong_AssignValue(PyObject **target, Py_ssize_t value) -{ - PyObject *old = *target; - if (IS_SMALL_INT(value)) { - *target = get_small_int(Py_SAFE_DOWNCAST(value, Py_ssize_t, sdigit)); - Py_XDECREF(old); - return 0; - } - else if (old != NULL && PyLong_CheckExact(old) && - Py_REFCNT(old) == 1 && Py_SIZE(old) == 1 && - (size_t)value <= PyLong_MASK) - { - // Mutate in place if there are no other references the old - // object. This avoids an allocation in a common case. - // Since the primary use-case is iterating over ranges, which - // are typically positive, only do this optimization - // for positive integers (for now). - ((PyLongObject *)old)->long_value.ob_digit[0] = - Py_SAFE_DOWNCAST(value, Py_ssize_t, digit); - return 0; - } - else { - *target = PyLong_FromSsize_t(value); - Py_XDECREF(old); - if (*target == NULL) { - return -1; - } - return 0; - } -} - /* If a freshly-allocated int is already shared, it must be a small integer, so negating it must go to PyLong_FromLong */ Py_LOCAL_INLINE(void) @@ -308,7 +280,7 @@ _PyLong_Negate(PyLongObject **x_p) x = (PyLongObject *)*x_p; if (Py_REFCNT(x) == 1) { - Py_SET_SIZE(x, -Py_SIZE(x)); + _PyLong_FlipSign(x); return; } @@ -347,7 +319,7 @@ PyLong_FromLong(long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits); + _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -457,7 +429,7 @@ PyLong_FromDouble(double dval) frac = ldexp(frac, PyLong_SHIFT); } if (neg) { - Py_SET_SIZE(v, -(Py_SIZE(v))); + _PyLong_FlipSign(v); } return (PyObject *)v; } @@ -510,27 +482,22 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) return -1; do_decref = 1; } - - res = -1; - i = Py_SIZE(v); - - switch (i) { - case -1: - res = -(sdigit)v->long_value.ob_digit[0]; - break; - case 0: - res = 0; - break; - case 1: - res = v->long_value.ob_digit[0]; - break; - default: - sign = 1; - x = 0; - if (i < 0) { - sign = -1; - i = -(i); + if (_PyLong_IsCompact(v)) { +#if SIZEOF_LONG < SIZEOF_VOID_P + intptr_t tmp = _PyLong_CompactValue(v); + res = (long)tmp; + if (res != tmp) { + *overflow = tmp < 0 ? -1 : 1; } +#else + res = _PyLong_CompactValue(v); +#endif + } + else { + res = -1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); + x = 0; while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -540,8 +507,8 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) } } /* Haven't lost any bits, but casting to long requires extra - * care (see comment above). - */ + * care (see comment above). + */ if (x <= (unsigned long)LONG_MAX) { res = (long)x * sign; } @@ -615,18 +582,12 @@ PyLong_AsSsize_t(PyObject *vv) { } v = (PyLongObject *)vv; - i = Py_SIZE(v); - switch (i) { - case -1: return -(sdigit)v->long_value.ob_digit[0]; - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsCompact(v)) { + return _PyLong_CompactValue(v); } - sign = 1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -670,28 +631,37 @@ PyLong_AsUnsignedLong(PyObject *vv) } v = (PyLongObject *)vv; - i = Py_SIZE(v); - x = 0; - if (i < 0) { + if (_PyLong_IsNonNegativeCompact(v)) { +#if SIZEOF_LONG < SIZEOF_VOID_P + intptr_t tmp = _PyLong_CompactValue(v); + unsigned long res = (unsigned long)tmp; + if (res != tmp) { + goto overflow; + } +#else + return _PyLong_CompactValue(v); +#endif + } + if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned int"); return (unsigned long) -1; } - switch (i) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; - } + i = _PyLong_DigitCount(v); + x = 0; while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; if ((x >> PyLong_SHIFT) != prev) { - PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert " - "to C unsigned long"); - return (unsigned long) -1; + goto overflow; } } return x; +overflow: + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert " + "to C unsigned long"); + return (unsigned long) -1; } /* Get a C size_t from an int object. Returns (size_t)-1 and sets @@ -714,17 +684,16 @@ PyLong_AsSize_t(PyObject *vv) } v = (PyLongObject *)vv; - i = Py_SIZE(v); - x = 0; - if (i < 0) { + if (_PyLong_IsNonNegativeCompact(v)) { + return _PyLong_CompactValue(v); + } + if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to size_t"); return (size_t) -1; } - switch (i) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; - } + i = _PyLong_DigitCount(v); + x = 0; while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -746,24 +715,18 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) PyLongObject *v; unsigned long x; Py_ssize_t i; - int sign; if (vv == NULL || !PyLong_Check(vv)) { PyErr_BadInternalCall(); return (unsigned long) -1; } v = (PyLongObject *)vv; - i = Py_SIZE(v); - switch (i) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsCompact(v)) { + return (unsigned long)_PyLong_CompactValue(v); } - sign = 1; + i = _PyLong_DigitCount(v); + int sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -i; - } while (--i >= 0) { x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; } @@ -801,8 +764,10 @@ _PyLong_Sign(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); - - return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1); + if (_PyLong_IsCompact(v)) { + return _PyLong_CompactSign(v); + } + return _PyLong_NonCompactSign(v); } static int @@ -825,7 +790,7 @@ _PyLong_NumBits(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); - ndigits = Py_ABS(Py_SIZE(v)); + ndigits = _PyLong_DigitCount(v); assert(ndigits == 0 || v->long_value.ob_digit[ndigits - 1] != 0); if (ndigits > 0) { digit msd = v->long_value.ob_digit[ndigits - 1]; @@ -952,7 +917,11 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n, } } - Py_SET_SIZE(v, is_signed ? -idigit : idigit); + int sign = is_signed ? -1: 1; + if (idigit == 0) { + sign = 0; + } + _PyLong_SetSignAndDigitCount(v, sign, idigit); return (PyObject *)maybe_small_long(long_normalize(v)); } @@ -962,7 +931,7 @@ _PyLong_AsByteArray(PyLongObject* v, int little_endian, int is_signed) { Py_ssize_t i; /* index into v->long_value.ob_digit */ - Py_ssize_t ndigits; /* |v->ob_size| */ + Py_ssize_t ndigits; /* number of digits */ twodigits accum; /* sliding register */ unsigned int accumbits; /* # bits in accum */ int do_twos_comp; /* store 2's-comp? is_signed and v < 0 */ @@ -973,8 +942,8 @@ _PyLong_AsByteArray(PyLongObject* v, assert(v != NULL && PyLong_Check(v)); - if (Py_SIZE(v) < 0) { - ndigits = -(Py_SIZE(v)); + ndigits = _PyLong_DigitCount(v); + if (_PyLong_IsNegative(v)) { if (!is_signed) { PyErr_SetString(PyExc_OverflowError, "can't convert negative int to unsigned"); @@ -983,7 +952,6 @@ _PyLong_AsByteArray(PyLongObject* v, do_twos_comp = 1; } else { - ndigits = Py_SIZE(v); do_twos_comp = 0; } @@ -1114,10 +1082,12 @@ PyLong_AsVoidPtr(PyObject *vv) #if SIZEOF_VOID_P <= SIZEOF_LONG long x; - if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) + if (PyLong_Check(vv) && _PyLong_IsNegative((PyLongObject *)vv)) { x = PyLong_AsLong(vv); - else + } + else { x = PyLong_AsUnsignedLong(vv); + } #else #if SIZEOF_LONG_LONG < SIZEOF_VOID_P @@ -1125,10 +1095,12 @@ PyLong_AsVoidPtr(PyObject *vv) #endif long long x; - if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) + if (PyLong_Check(vv) && _PyLong_IsNegative((PyLongObject *)vv)) { x = PyLong_AsLongLong(vv); - else + } + else { x = PyLong_AsUnsignedLongLong(vv); + } #endif /* SIZEOF_VOID_P <= SIZEOF_LONG */ @@ -1174,7 +1146,7 @@ PyLong_FromLongLong(long long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits); + _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -1217,7 +1189,7 @@ PyLong_FromSsize_t(Py_ssize_t ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, negative ? -ndigits : ndigits); + _PyLong_SetSignAndDigitCount(v, negative ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -1253,18 +1225,11 @@ PyLong_AsLongLong(PyObject *vv) do_decref = 1; } - res = 0; - switch(Py_SIZE(v)) { - case -1: - bytes = -(sdigit)v->long_value.ob_digit[0]; - break; - case 0: - bytes = 0; - break; - case 1: - bytes = v->long_value.ob_digit[0]; - break; - default: + if (_PyLong_IsCompact(v)) { + res = 0; + bytes = _PyLong_CompactValue(v); + } + else { res = _PyLong_AsByteArray((PyLongObject *)v, (unsigned char *)&bytes, SIZEOF_LONG_LONG, PY_LITTLE_ENDIAN, 1); } @@ -1299,13 +1264,14 @@ PyLong_AsUnsignedLongLong(PyObject *vv) } v = (PyLongObject*)vv; - switch(Py_SIZE(v)) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsNonNegativeCompact(v)) { + res = 0; + bytes = _PyLong_CompactValue(v); } - - res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, + else { + res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, SIZEOF_LONG_LONG, PY_LITTLE_ENDIAN, 0); + } /* Plan 9 can't handle long long in ? : expressions */ if (res < 0) @@ -1330,17 +1296,12 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) return (unsigned long long) -1; } v = (PyLongObject *)vv; - switch(Py_SIZE(v)) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsCompact(v)) { + return (unsigned long long)(signed long long)_PyLong_CompactValue(v); } - i = Py_SIZE(v); - sign = 1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -i; - } while (--i >= 0) { x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; } @@ -1407,32 +1368,19 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) return -1; do_decref = 1; } - - res = -1; - i = Py_SIZE(v); - - switch (i) { - case -1: - res = -(sdigit)v->long_value.ob_digit[0]; - break; - case 0: - res = 0; - break; - case 1: - res = v->long_value.ob_digit[0]; - break; - default: - sign = 1; + if (_PyLong_IsCompact(v)) { + res = _PyLong_CompactValue(v); + } + else { + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) + v->long_value.ob_digit[i]; if ((x >> PyLong_SHIFT) != prev) { *overflow = sign; + res = -1; goto exit; } } @@ -1447,7 +1395,7 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) } else { *overflow = sign; - /* res is already set to -1 */ + res = -1; } } exit: @@ -1462,7 +1410,7 @@ _PyLong_UnsignedShort_Converter(PyObject *obj, void *ptr) { unsigned long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1484,7 +1432,7 @@ _PyLong_UnsignedInt_Converter(PyObject *obj, void *ptr) { unsigned long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1506,7 +1454,7 @@ _PyLong_UnsignedLong_Converter(PyObject *obj, void *ptr) { unsigned long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1523,7 +1471,7 @@ _PyLong_UnsignedLongLong_Converter(PyObject *obj, void *ptr) { unsigned long long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1540,7 +1488,7 @@ _PyLong_Size_t_Converter(PyObject *obj, void *ptr) { size_t uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1694,7 +1642,7 @@ inplace_divrem1(digit *pout, digit *pin, Py_ssize_t size, digit n) static PyLongObject * divrem1(PyLongObject *a, digit n, digit *prem) { - const Py_ssize_t size = Py_ABS(Py_SIZE(a)); + const Py_ssize_t size = _PyLong_DigitCount(a); PyLongObject *z; assert(n > 0 && n <= PyLong_MASK); @@ -1726,7 +1674,7 @@ inplace_rem1(digit *pin, Py_ssize_t size, digit n) static PyLongObject * rem1(PyLongObject *a, digit n) { - const Py_ssize_t size = Py_ABS(Py_SIZE(a)); + const Py_ssize_t size = _PyLong_DigitCount(a); assert(n > 0 && n <= PyLong_MASK); return (PyLongObject *)PyLong_FromLong( @@ -1824,8 +1772,8 @@ long_to_decimal_string_internal(PyObject *aa, PyErr_BadInternalCall(); return -1; } - size_a = Py_ABS(Py_SIZE(a)); - negative = Py_SIZE(a) < 0; + size_a = _PyLong_DigitCount(a); + negative = _PyLong_IsNegative(a); /* quick and dirty pre-check for overflowing the decimal digit limit, based on the inequality 10/3 >= log2(10) @@ -2055,8 +2003,8 @@ long_format_binary(PyObject *aa, int base, int alternate, PyErr_BadInternalCall(); return -1; } - size_a = Py_ABS(Py_SIZE(a)); - negative = Py_SIZE(a) < 0; + size_a = _PyLong_DigitCount(a); + negative = _PyLong_IsNegative(a); /* Compute a rough upper bound for the length of the string */ switch (base) { @@ -2532,7 +2480,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, *res = NULL; return 0; } - Py_SET_SIZE(z, 0); + _PyLong_SetSignAndDigitCount(z, 0, 0); /* `convwidth` consecutive input digits are treated as a single * digit in base `convmultmax`. @@ -2572,7 +2520,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, /* Multiply z by convmult, and add c. */ pz = z->long_value.ob_digit; - pzstop = pz + Py_SIZE(z); + pzstop = pz + _PyLong_DigitCount(z); for (; pz < pzstop; ++pz) { c += (twodigits)*pz * convmult; *pz = (digit)(c & PyLong_MASK); @@ -2581,14 +2529,15 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, /* carry off the current end? */ if (c) { assert(c < PyLong_BASE); - if (Py_SIZE(z) < size_z) { + if (_PyLong_DigitCount(z) < size_z) { *pz = (digit)c; - Py_SET_SIZE(z, Py_SIZE(z) + 1); + assert(!_PyLong_IsNegative(z)); + _PyLong_SetSignAndDigitCount(z, 1, _PyLong_DigitCount(z) + 1); } else { PyLongObject *tmp; /* Extremely rare. Get more space. */ - assert(Py_SIZE(z) == size_z); + assert(_PyLong_DigitCount(z) == size_z); tmp = _PyLong_New(size_z + 1); if (tmp == NULL) { Py_DECREF(z); @@ -2790,7 +2739,7 @@ PyLong_FromString(const char *str, char **pend, int base) /* reset the base to 0, else the exception message doesn't make too much sense */ base = 0; - if (Py_SIZE(z) != 0) { + if (!_PyLong_IsZero(z)) { goto onError; } /* there might still be other problems, therefore base @@ -2799,7 +2748,7 @@ PyLong_FromString(const char *str, char **pend, int base) /* Set sign and normalize */ if (sign < 0) { - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); } long_normalize(z); z = maybe_small_long(z); @@ -2891,7 +2840,7 @@ static int long_divrem(PyLongObject *a, PyLongObject *b, PyLongObject **pdiv, PyLongObject **prem) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); PyLongObject *z; if (size_b == 0) { @@ -2932,14 +2881,14 @@ long_divrem(PyLongObject *a, PyLongObject *b, The quotient z has the sign of a*b; the remainder r has the sign of a, so a = b*z + r. */ - if ((Py_SIZE(a) < 0) != (Py_SIZE(b) < 0)) { + if ((_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b))) { _PyLong_Negate(&z); if (z == NULL) { Py_CLEAR(*prem); return -1; } } - if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) { + if (_PyLong_IsNegative(a) && !_PyLong_IsZero(*prem)) { _PyLong_Negate(prem); if (*prem == NULL) { Py_DECREF(z); @@ -2956,7 +2905,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, static int long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); if (size_b == 0) { PyErr_SetString(PyExc_ZeroDivisionError, @@ -2983,7 +2932,7 @@ long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) return -1; } /* Set the sign. */ - if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) { + if (_PyLong_IsNegative(a) && !_PyLong_IsZero(*prem)) { _PyLong_Negate(prem); if (*prem == NULL) { Py_CLEAR(*prem); @@ -2994,7 +2943,7 @@ long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) } /* Unsigned int division with remainder -- the algorithm. The arguments v1 - and w1 should satisfy 2 <= Py_ABS(Py_SIZE(w1)) <= Py_ABS(Py_SIZE(v1)). */ + and w1 should satisfy 2 <= _PyLong_DigitCount(w1) <= _PyLong_DigitCount(v1). */ static PyLongObject * x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) @@ -3014,8 +2963,8 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) that won't overflow a digit. */ /* allocate space; w will also be used to hold the final remainder */ - size_v = Py_ABS(Py_SIZE(v1)); - size_w = Py_ABS(Py_SIZE(w1)); + size_v = _PyLong_DigitCount(v1); + size_w = _PyLong_DigitCount(w1); assert(size_v >= size_w && size_w >= 2); /* Assert checks by div() */ v = _PyLong_New(size_v+1); if (v == NULL) { @@ -3154,7 +3103,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) multiple of 4, rounding ties to a multiple of 8. */ static const int half_even_correction[8] = {0, -1, -2, 1, 0, -1, 2, 1}; - a_size = Py_ABS(Py_SIZE(a)); + a_size = _PyLong_DigitCount(a); if (a_size == 0) { /* Special case for 0: significand 0.0, exponent 0. */ *e = 0; @@ -3240,7 +3189,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) } *e = a_bits; - return Py_SIZE(a) < 0 ? -dx : dx; + return _PyLong_IsNegative(a) ? -dx : dx; overflow: /* exponent > PY_SSIZE_T_MAX */ @@ -3267,7 +3216,7 @@ PyLong_AsDouble(PyObject *v) PyErr_SetString(PyExc_TypeError, "an integer is required"); return -1.0; } - if (IS_MEDIUM_VALUE(v)) { + if (_PyLong_IsCompact((PyLongObject *)v)) { /* Fast path; single digit long (31 bits) will cast safely to double. This improves performance of FP/long operations by 20%. @@ -3292,9 +3241,12 @@ PyLong_AsDouble(PyObject *v) static Py_ssize_t long_compare(PyLongObject *a, PyLongObject *b) { - Py_ssize_t sign = Py_SIZE(a) - Py_SIZE(b); + if (_PyLong_BothAreCompact(a, b)) { + return _PyLong_CompactValue(a) - _PyLong_CompactValue(b); + } + Py_ssize_t sign = _PyLong_SignedDigitCount(a) - _PyLong_SignedDigitCount(b); if (sign == 0) { - Py_ssize_t i = Py_ABS(Py_SIZE(a)); + Py_ssize_t i = _PyLong_DigitCount(a); sdigit diff = 0; while (--i >= 0) { diff = (sdigit) a->long_value.ob_digit[i] - (sdigit) b->long_value.ob_digit[i]; @@ -3302,7 +3254,7 @@ long_compare(PyLongObject *a, PyLongObject *b) break; } } - sign = Py_SIZE(a) < 0 ? -diff : diff; + sign = _PyLong_IsNegative(a) ? -diff : diff; } return sign; } @@ -3326,18 +3278,16 @@ long_hash(PyLongObject *v) Py_ssize_t i; int sign; - i = Py_SIZE(v); - switch(i) { - case -1: return v->long_value.ob_digit[0]==1 ? -2 : -(sdigit)v->long_value.ob_digit[0]; - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsCompact(v)) { + x = _PyLong_CompactValue(v); + if (x == (Py_uhash_t)-1) { + x = (Py_uhash_t)-2; + } + return x; } - sign = 1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { /* Here x is a quantity in the range [0, _PyHASH_MODULUS); we want to compute x * 2**PyLong_SHIFT + v->long_value.ob_digit[i] modulo @@ -3382,7 +3332,7 @@ long_hash(PyLongObject *v) static PyLongObject * x_add(PyLongObject *a, PyLongObject *b) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); PyLongObject *z; Py_ssize_t i; digit carry = 0; @@ -3416,7 +3366,7 @@ x_add(PyLongObject *a, PyLongObject *b) static PyLongObject * x_sub(PyLongObject *a, PyLongObject *b) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); PyLongObject *z; Py_ssize_t i; int sign = 1; @@ -3462,7 +3412,7 @@ x_sub(PyLongObject *a, PyLongObject *b) } assert(borrow == 0); if (sign < 0) { - Py_SET_SIZE(z, -Py_SIZE(z)); + _PyLong_FlipSign(z); } return maybe_small_long(long_normalize(z)); } @@ -3470,13 +3420,13 @@ x_sub(PyLongObject *a, PyLongObject *b) PyObject * _PyLong_Add(PyLongObject *a, PyLongObject *b) { - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + if (_PyLong_BothAreCompact(a, b)) { return _PyLong_FromSTwoDigits(medium_value(a) + medium_value(b)); } PyLongObject *z; - if (Py_SIZE(a) < 0) { - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(a)) { + if (_PyLong_IsNegative(b)) { z = x_add(a, b); if (z != NULL) { /* x_add received at least one multiple-digit int, @@ -3484,14 +3434,14 @@ _PyLong_Add(PyLongObject *a, PyLongObject *b) That also means z is not an element of small_ints, so negating it in-place is safe. */ assert(Py_REFCNT(z) == 1); - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); } } else z = x_sub(b, a); } else { - if (Py_SIZE(b) < 0) + if (_PyLong_IsNegative(b)) z = x_sub(a, b); else z = x_add(a, b); @@ -3511,23 +3461,23 @@ _PyLong_Subtract(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + if (_PyLong_BothAreCompact(a, b)) { return _PyLong_FromSTwoDigits(medium_value(a) - medium_value(b)); } - if (Py_SIZE(a) < 0) { - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(a)) { + if (_PyLong_IsNegative(b)) { z = x_sub(b, a); } else { z = x_add(a, b); if (z != NULL) { - assert(Py_SIZE(z) == 0 || Py_REFCNT(z) == 1); - Py_SET_SIZE(z, -(Py_SIZE(z))); + assert(_PyLong_IsZero(z) || Py_REFCNT(z) == 1); + _PyLong_FlipSign(z); } } } else { - if (Py_SIZE(b) < 0) + if (_PyLong_IsNegative(b)) z = x_add(a, b); else z = x_sub(a, b); @@ -3549,15 +3499,15 @@ static PyLongObject * x_mul(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)); - Py_ssize_t size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a); + Py_ssize_t size_b = _PyLong_DigitCount(b); Py_ssize_t i; z = _PyLong_New(size_a + size_b); if (z == NULL) return NULL; - memset(z->long_value.ob_digit, 0, Py_SIZE(z) * sizeof(digit)); + memset(z->long_value.ob_digit, 0, _PyLong_DigitCount(z) * sizeof(digit)); if (a == b) { /* Efficient squaring per HAC, Algorithm 14.16: * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf @@ -3658,7 +3608,7 @@ kmul_split(PyLongObject *n, { PyLongObject *hi, *lo; Py_ssize_t size_lo, size_hi; - const Py_ssize_t size_n = Py_ABS(Py_SIZE(n)); + const Py_ssize_t size_n = _PyLong_DigitCount(n); size_lo = Py_MIN(size_n, size); size_hi = size_n - size_lo; @@ -3687,8 +3637,8 @@ static PyLongObject *k_lopsided_mul(PyLongObject *a, PyLongObject *b); static PyLongObject * k_mul(PyLongObject *a, PyLongObject *b) { - Py_ssize_t asize = Py_ABS(Py_SIZE(a)); - Py_ssize_t bsize = Py_ABS(Py_SIZE(b)); + Py_ssize_t asize = _PyLong_DigitCount(a); + Py_ssize_t bsize = _PyLong_DigitCount(b); PyLongObject *ah = NULL; PyLongObject *al = NULL; PyLongObject *bh = NULL; @@ -3731,7 +3681,7 @@ k_mul(PyLongObject *a, PyLongObject *b) /* If a is small compared to b, splitting on b gives a degenerate * case with ah==0, and Karatsuba may be (even much) less efficient * than "grade school" then. However, we can still win, by viewing - * b as a string of "big digits", each of width a->ob_size. That + * b as a string of "big digits", each of the same width as a. That * leads to a sequence of balanced calls to k_mul. */ if (2 * asize <= bsize) @@ -3740,7 +3690,7 @@ k_mul(PyLongObject *a, PyLongObject *b) /* Split a & b into hi & lo pieces. */ shift = bsize >> 1; if (kmul_split(a, shift, &ah, &al) < 0) goto fail; - assert(Py_SIZE(ah) > 0); /* the split isn't degenerate */ + assert(_PyLong_IsPositive(ah)); /* the split isn't degenerate */ if (a == b) { bh = (PyLongObject*)Py_NewRef(ah); @@ -3769,20 +3719,20 @@ k_mul(PyLongObject *a, PyLongObject *b) if (ret == NULL) goto fail; #ifdef Py_DEBUG /* Fill with trash, to catch reference to uninitialized digits. */ - memset(ret->long_value.ob_digit, 0xDF, Py_SIZE(ret) * sizeof(digit)); + memset(ret->long_value.ob_digit, 0xDF, _PyLong_DigitCount(ret) * sizeof(digit)); #endif /* 2. t1 <- ah*bh, and copy into high digits of result. */ if ((t1 = k_mul(ah, bh)) == NULL) goto fail; - assert(Py_SIZE(t1) >= 0); - assert(2*shift + Py_SIZE(t1) <= Py_SIZE(ret)); + assert(!_PyLong_IsNegative(t1)); + assert(2*shift + _PyLong_DigitCount(t1) <= _PyLong_DigitCount(ret)); memcpy(ret->long_value.ob_digit + 2*shift, t1->long_value.ob_digit, - Py_SIZE(t1) * sizeof(digit)); + _PyLong_DigitCount(t1) * sizeof(digit)); /* Zero-out the digits higher than the ah*bh copy. */ - i = Py_SIZE(ret) - 2*shift - Py_SIZE(t1); + i = _PyLong_DigitCount(ret) - 2*shift - _PyLong_DigitCount(t1); if (i) - memset(ret->long_value.ob_digit + 2*shift + Py_SIZE(t1), 0, + memset(ret->long_value.ob_digit + 2*shift + _PyLong_DigitCount(t1), 0, i * sizeof(digit)); /* 3. t2 <- al*bl, and copy into the low digits. */ @@ -3790,23 +3740,23 @@ k_mul(PyLongObject *a, PyLongObject *b) Py_DECREF(t1); goto fail; } - assert(Py_SIZE(t2) >= 0); - assert(Py_SIZE(t2) <= 2*shift); /* no overlap with high digits */ - memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, Py_SIZE(t2) * sizeof(digit)); + assert(!_PyLong_IsNegative(t2)); + assert(_PyLong_DigitCount(t2) <= 2*shift); /* no overlap with high digits */ + memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, _PyLong_DigitCount(t2) * sizeof(digit)); /* Zero out remaining digits. */ - i = 2*shift - Py_SIZE(t2); /* number of uninitialized digits */ + i = 2*shift - _PyLong_DigitCount(t2); /* number of uninitialized digits */ if (i) - memset(ret->long_value.ob_digit + Py_SIZE(t2), 0, i * sizeof(digit)); + memset(ret->long_value.ob_digit + _PyLong_DigitCount(t2), 0, i * sizeof(digit)); /* 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first * because it's fresher in cache. */ - i = Py_SIZE(ret) - shift; /* # digits after shift */ - (void)v_isub(ret->long_value.ob_digit + shift, i, t2->long_value.ob_digit, Py_SIZE(t2)); + i = _PyLong_DigitCount(ret) - shift; /* # digits after shift */ + (void)v_isub(ret->long_value.ob_digit + shift, i, t2->long_value.ob_digit, _PyLong_DigitCount(t2)); _Py_DECREF_INT(t2); - (void)v_isub(ret->long_value.ob_digit + shift, i, t1->long_value.ob_digit, Py_SIZE(t1)); + (void)v_isub(ret->long_value.ob_digit + shift, i, t1->long_value.ob_digit, _PyLong_DigitCount(t1)); _Py_DECREF_INT(t1); /* 6. t3 <- (ah+al)(bh+bl), and add into result. */ @@ -3830,12 +3780,12 @@ k_mul(PyLongObject *a, PyLongObject *b) _Py_DECREF_INT(t1); _Py_DECREF_INT(t2); if (t3 == NULL) goto fail; - assert(Py_SIZE(t3) >= 0); + assert(!_PyLong_IsNegative(t3)); /* Add t3. It's not obvious why we can't run out of room here. * See the (*) comment after this function. */ - (void)v_iadd(ret->long_value.ob_digit + shift, i, t3->long_value.ob_digit, Py_SIZE(t3)); + (void)v_iadd(ret->long_value.ob_digit + shift, i, t3->long_value.ob_digit, _PyLong_DigitCount(t3)); _Py_DECREF_INT(t3); return long_normalize(ret); @@ -3896,17 +3846,17 @@ ah*bh and al*bl too. /* b has at least twice the digits of a, and a is big enough that Karatsuba * would pay off *if* the inputs had balanced sizes. View b as a sequence - * of slices, each with a->ob_size digits, and multiply the slices by a, - * one at a time. This gives k_mul balanced inputs to work with, and is - * also cache-friendly (we compute one double-width slice of the result + * of slices, each with the same number of digits as a, and multiply the + * slices by a, one at a time. This gives k_mul balanced inputs to work with, + * and is also cache-friendly (we compute one double-width slice of the result * at a time, then move on, never backtracking except for the helpful * single-width slice overlap between successive partial sums). */ static PyLongObject * k_lopsided_mul(PyLongObject *a, PyLongObject *b) { - const Py_ssize_t asize = Py_ABS(Py_SIZE(a)); - Py_ssize_t bsize = Py_ABS(Py_SIZE(b)); + const Py_ssize_t asize = _PyLong_DigitCount(a); + Py_ssize_t bsize = _PyLong_DigitCount(b); Py_ssize_t nbdone; /* # of b digits already multiplied */ PyLongObject *ret; PyLongObject *bslice = NULL; @@ -3918,7 +3868,7 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) ret = _PyLong_New(asize + bsize); if (ret == NULL) return NULL; - memset(ret->long_value.ob_digit, 0, Py_SIZE(ret) * sizeof(digit)); + memset(ret->long_value.ob_digit, 0, _PyLong_DigitCount(ret) * sizeof(digit)); /* Successive slices of b are copied into bslice. */ bslice = _PyLong_New(asize); @@ -3933,14 +3883,15 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) /* Multiply the next slice of b by a. */ memcpy(bslice->long_value.ob_digit, b->long_value.ob_digit + nbdone, nbtouse * sizeof(digit)); - Py_SET_SIZE(bslice, nbtouse); + assert(nbtouse >= 0); + _PyLong_SetSignAndDigitCount(bslice, 1, nbtouse); product = k_mul(a, bslice); if (product == NULL) goto fail; /* Add into result. */ - (void)v_iadd(ret->long_value.ob_digit + nbdone, Py_SIZE(ret) - nbdone, - product->long_value.ob_digit, Py_SIZE(product)); + (void)v_iadd(ret->long_value.ob_digit + nbdone, _PyLong_DigitCount(ret) - nbdone, + product->long_value.ob_digit, _PyLong_DigitCount(product)); _Py_DECREF_INT(product); bsize -= nbtouse; @@ -3962,14 +3913,14 @@ _PyLong_Multiply(PyLongObject *a, PyLongObject *b) PyLongObject *z; /* fast path for single-digit multiplication */ - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + if (_PyLong_BothAreCompact(a, b)) { stwodigits v = medium_value(a) * medium_value(b); return _PyLong_FromSTwoDigits(v); } z = k_mul(a, b); /* Negate if exactly one of the inputs is negative. */ - if (((Py_SIZE(a) ^ Py_SIZE(b)) < 0) && z) { + if (!_PyLong_SameSign(a, b) && z) { _PyLong_Negate(&z); if (z == NULL) return NULL; @@ -3992,11 +3943,10 @@ fast_mod(PyLongObject *a, PyLongObject *b) sdigit right = b->long_value.ob_digit[0]; sdigit mod; - assert(Py_ABS(Py_SIZE(a)) == 1); - assert(Py_ABS(Py_SIZE(b)) == 1); - - if (Py_SIZE(a) == Py_SIZE(b)) { - /* 'a' and 'b' have the same sign. */ + assert(_PyLong_DigitCount(a) == 1); + assert(_PyLong_DigitCount(b) == 1); + sdigit sign = _PyLong_CompactSign(b); + if (_PyLong_SameSign(a, b)) { mod = left % right; } else { @@ -4004,7 +3954,7 @@ fast_mod(PyLongObject *a, PyLongObject *b) mod = right - 1 - (left - 1) % right; } - return PyLong_FromLong(mod * (sdigit)Py_SIZE(b)); + return PyLong_FromLong(mod * sign); } /* Fast floor division for single-digit longs. */ @@ -4015,11 +3965,10 @@ fast_floor_div(PyLongObject *a, PyLongObject *b) sdigit right = b->long_value.ob_digit[0]; sdigit div; - assert(Py_ABS(Py_SIZE(a)) == 1); - assert(Py_ABS(Py_SIZE(b)) == 1); + assert(_PyLong_DigitCount(a) == 1); + assert(_PyLong_DigitCount(b) == 1); - if (Py_SIZE(a) == Py_SIZE(b)) { - /* 'a' and 'b' have the same sign. */ + if (_PyLong_SameSign(a, b)) { div = left / right; } else { @@ -4097,7 +4046,7 @@ l_divmod(PyLongObject *v, PyLongObject *w, { PyLongObject *div, *mod; - if (Py_ABS(Py_SIZE(v)) == 1 && Py_ABS(Py_SIZE(w)) == 1) { + if (_PyLong_DigitCount(v) == 1 && _PyLong_DigitCount(w) == 1) { /* Fast path for single-digit longs */ div = NULL; if (pdiv != NULL) { @@ -4122,8 +4071,8 @@ l_divmod(PyLongObject *v, PyLongObject *w, return 0; } #if WITH_PYLONG_MODULE - Py_ssize_t size_v = Py_ABS(Py_SIZE(v)); /* digits in numerator */ - Py_ssize_t size_w = Py_ABS(Py_SIZE(w)); /* digits in denominator */ + Py_ssize_t size_v = _PyLong_DigitCount(v); /* digits in numerator */ + Py_ssize_t size_w = _PyLong_DigitCount(w); /* digits in denominator */ if (size_w > 300 && (size_v - size_w) > 150) { /* Switch to _pylong.int_divmod(). If the quotient is small then "schoolbook" division is linear-time so don't use in that case. @@ -4135,8 +4084,8 @@ l_divmod(PyLongObject *v, PyLongObject *w, #endif if (long_divrem(v, w, &div, &mod) < 0) return -1; - if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) || - (Py_SIZE(mod) > 0 && Py_SIZE(w) < 0)) { + if ((_PyLong_IsNegative(mod) && _PyLong_IsPositive(w)) || + (_PyLong_IsPositive(mod) && _PyLong_IsNegative(w))) { PyLongObject *temp; temp = (PyLongObject *) long_add(mod, w); Py_SETREF(mod, temp); @@ -4175,15 +4124,15 @@ l_mod(PyLongObject *v, PyLongObject *w, PyLongObject **pmod) PyLongObject *mod; assert(pmod); - if (Py_ABS(Py_SIZE(v)) == 1 && Py_ABS(Py_SIZE(w)) == 1) { + if (_PyLong_DigitCount(v) == 1 && _PyLong_DigitCount(w) == 1) { /* Fast path for single-digit longs */ *pmod = (PyLongObject *)fast_mod(v, w); return -(*pmod == NULL); } if (long_rem(v, w, &mod) < 0) return -1; - if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) || - (Py_SIZE(mod) > 0 && Py_SIZE(w) < 0)) { + if ((_PyLong_IsNegative(mod) && _PyLong_IsPositive(w)) || + (_PyLong_IsPositive(mod) && _PyLong_IsNegative(w))) { PyLongObject *temp; temp = (PyLongObject *) long_add(mod, w); Py_SETREF(mod, temp); @@ -4202,7 +4151,7 @@ long_div(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (Py_ABS(Py_SIZE(a)) == 1 && Py_ABS(Py_SIZE(b)) == 1) { + if (_PyLong_DigitCount((PyLongObject*)a) == 1 && _PyLong_DigitCount((PyLongObject*)b) == 1) { return fast_floor_div((PyLongObject*)a, (PyLongObject*)b); } @@ -4317,9 +4266,9 @@ long_true_divide(PyObject *v, PyObject *w) */ /* Reduce to case where a and b are both positive. */ - a_size = Py_ABS(Py_SIZE(a)); - b_size = Py_ABS(Py_SIZE(b)); - negate = (Py_SIZE(a) < 0) ^ (Py_SIZE(b) < 0); + a_size = _PyLong_DigitCount(a); + b_size = _PyLong_DigitCount(b); + negate = (_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b)); if (b_size == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "division by zero"); @@ -4412,7 +4361,7 @@ long_true_divide(PyObject *v, PyObject *w) inexact = 1; } long_normalize(x); - x_size = Py_SIZE(x); + x_size = _PyLong_SignedDigitCount(x); /* x //= b. If the remainder is nonzero, set inexact. We own the only reference to x, so it's safe to modify it in-place. */ @@ -4429,11 +4378,11 @@ long_true_divide(PyObject *v, PyObject *w) Py_SETREF(x, div); if (x == NULL) goto error; - if (Py_SIZE(rem)) + if (!_PyLong_IsZero(rem)) inexact = 1; Py_DECREF(rem); } - x_size = Py_ABS(Py_SIZE(x)); + x_size = _PyLong_DigitCount(x); assert(x_size > 0); /* result of division is never zero */ x_bits = (x_size-1)*PyLong_SHIFT+bit_length_digit(x->long_value.ob_digit[x_size-1]); @@ -4535,7 +4484,7 @@ long_invmod(PyLongObject *a, PyLongObject *n) PyLongObject *b, *c; /* Should only ever be called for positive n */ - assert(Py_SIZE(n) > 0); + assert(_PyLong_IsPositive(n)); b = (PyLongObject *)PyLong_FromLong(1L); if (b == NULL) { @@ -4550,7 +4499,7 @@ long_invmod(PyLongObject *a, PyLongObject *n) Py_INCREF(n); /* references now owned: a, b, c, n */ - while (Py_SIZE(n) != 0) { + while (!_PyLong_IsZero(n)) { PyLongObject *q, *r, *s, *t; if (l_divmod(a, n, &q, &r) == -1) { @@ -4636,7 +4585,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) Py_RETURN_NOTIMPLEMENTED; } - if (Py_SIZE(b) < 0 && c == NULL) { + if (_PyLong_IsNegative(b) && c == NULL) { /* if exponent is negative and there's no modulus: return a float. This works because we know that this calls float_pow() which converts its @@ -4649,7 +4598,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) if (c) { /* if modulus == 0: raise ValueError() */ - if (Py_SIZE(c) == 0) { + if (_PyLong_IsZero(c)) { PyErr_SetString(PyExc_ValueError, "pow() 3rd argument cannot be 0"); goto Error; @@ -4658,7 +4607,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus < 0: negativeOutput = True modulus = -modulus */ - if (Py_SIZE(c) < 0) { + if (_PyLong_IsNegative(c)) { negativeOutput = 1; temp = (PyLongObject *)_PyLong_Copy(c); if (temp == NULL) @@ -4672,14 +4621,14 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus == 1: return 0 */ - if ((Py_SIZE(c) == 1) && (c->long_value.ob_digit[0] == 1)) { + if (_PyLong_IsNonNegativeCompact(c) && (c->long_value.ob_digit[0] == 1)) { z = (PyLongObject *)PyLong_FromLong(0L); goto Done; } /* if exponent is negative, negate the exponent and replace the base with a modular inverse */ - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(b)) { temp = (PyLongObject *)_PyLong_Copy(b); if (temp == NULL) goto Error; @@ -4705,7 +4654,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) base % modulus instead. We could _always_ do this reduction, but l_mod() isn't cheap, so we only do it when it buys something. */ - if (Py_SIZE(a) < 0 || Py_SIZE(a) > Py_SIZE(c)) { + if (_PyLong_IsNegative(a) || _PyLong_DigitCount(a) > _PyLong_DigitCount(c)) { if (l_mod(a, c, &temp) < 0) goto Error; Py_SETREF(a, temp); @@ -4747,7 +4696,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) REDUCE(result); \ } while(0) - i = Py_SIZE(b); + i = _PyLong_SignedDigitCount(b); digit bi = i ? b->long_value.ob_digit[i-1] : 0; digit bit; if (i <= 1 && bi <= 3) { @@ -4839,7 +4788,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) pending = 0; \ } while(0) - for (i = Py_SIZE(b) - 1; i >= 0; --i) { + for (i = _PyLong_SignedDigitCount(b) - 1; i >= 0; --i) { const digit bi = b->long_value.ob_digit[i]; for (j = PyLong_SHIFT - 1; j >= 0; --j) { const int bit = (bi >> j) & 1; @@ -4857,7 +4806,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) ABSORB_PENDING; } - if (negativeOutput && (Py_SIZE(z) != 0)) { + if (negativeOutput && !_PyLong_IsZero(z)) { temp = (PyLongObject *)long_sub(z, c); if (temp == NULL) goto Error; @@ -4885,14 +4834,14 @@ long_invert(PyLongObject *v) { /* Implement ~x as -(x+1) */ PyLongObject *x; - if (IS_MEDIUM_VALUE(v)) + if (_PyLong_IsCompact(v)) return _PyLong_FromSTwoDigits(~medium_value(v)); x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_GetOne()); if (x == NULL) return NULL; _PyLong_Negate(&x); - /* No need for maybe_small_long here, since any small - longs will have been caught in the Py_SIZE <= 1 fast path. */ + /* No need for maybe_small_long here, since any small longs + will have been caught in the _PyLong_IsCompact() fast path. */ return (PyObject *)x; } @@ -4900,18 +4849,18 @@ static PyObject * long_neg(PyLongObject *v) { PyLongObject *z; - if (IS_MEDIUM_VALUE(v)) + if (_PyLong_IsCompact(v)) return _PyLong_FromSTwoDigits(-medium_value(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) - Py_SET_SIZE(z, -(Py_SIZE(v))); + _PyLong_FlipSign(z); return (PyObject *)z; } static PyObject * long_abs(PyLongObject *v) { - if (Py_SIZE(v) < 0) + if (_PyLong_IsNegative(v)) return long_neg(v); else return long_long((PyObject *)v); @@ -4920,7 +4869,7 @@ long_abs(PyLongObject *v) static int long_bool(PyLongObject *v) { - return Py_SIZE(v) != 0; + return !_PyLong_IsZero(v); } /* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */ @@ -4928,14 +4877,14 @@ static int divmod_shift(PyObject *shiftby, Py_ssize_t *wordshift, digit *remshift) { assert(PyLong_Check(shiftby)); - assert(Py_SIZE(shiftby) >= 0); + assert(!_PyLong_IsNegative((PyLongObject *)shiftby)); Py_ssize_t lshiftby = PyLong_AsSsize_t((PyObject *)shiftby); if (lshiftby >= 0) { *wordshift = lshiftby / PyLong_SHIFT; *remshift = lshiftby % PyLong_SHIFT; return 0; } - /* PyLong_Check(shiftby) is true and Py_SIZE(shiftby) >= 0, so it must + /* PyLong_Check(shiftby) is true and shiftby is not negative, so it must be that PyLong_AsSsize_t raised an OverflowError. */ assert(PyErr_ExceptionMatches(PyExc_OverflowError)); PyErr_Clear(); @@ -4973,7 +4922,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) assert(remshift < PyLong_SHIFT); /* Fast path for small a. */ - if (IS_MEDIUM_VALUE(a)) { + if (_PyLong_IsCompact(a)) { stwodigits m, x; digit shift; m = medium_value(a); @@ -4982,8 +4931,8 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) return _PyLong_FromSTwoDigits(x); } - a_negative = Py_SIZE(a) < 0; - size_a = Py_ABS(Py_SIZE(a)); + a_negative = _PyLong_IsNegative(a); + size_a = _PyLong_DigitCount(a); if (a_negative) { /* For negative 'a', adjust so that 0 < remshift <= PyLong_SHIFT, @@ -5024,7 +4973,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) significant `wordshift` digits of `a` is nonzero. Digit `wordshift` of `2**shift - 1` has value `PyLong_MASK >> hishift`. */ - Py_SET_SIZE(z, -newsize); + _PyLong_SetSignAndDigitCount(z, -1, newsize); digit sticky = 0; for (Py_ssize_t j = 0; j < wordshift; j++) { @@ -5054,11 +5003,11 @@ long_rshift(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative((PyLongObject *)b)) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } if (divmod_shift(b, &wordshift, &remshift) < 0) @@ -5074,7 +5023,7 @@ _PyLong_Rshift(PyObject *a, size_t shiftby) digit remshift; assert(PyLong_Check(a)); - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } wordshift = shiftby / PyLong_SHIFT; @@ -5089,23 +5038,23 @@ long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) Py_ssize_t oldsize, newsize, i, j; twodigits accum; - if (wordshift == 0 && IS_MEDIUM_VALUE(a)) { + if (wordshift == 0 && _PyLong_IsCompact(a)) { stwodigits m = medium_value(a); // bypass undefined shift operator behavior stwodigits x = m < 0 ? -(-m << remshift) : m << remshift; return _PyLong_FromSTwoDigits(x); } - oldsize = Py_ABS(Py_SIZE(a)); + oldsize = _PyLong_DigitCount(a); newsize = oldsize + wordshift; if (remshift) ++newsize; z = _PyLong_New(newsize); if (z == NULL) return NULL; - if (Py_SIZE(a) < 0) { + if (_PyLong_IsNegative(a)) { assert(Py_REFCNT(z) == 1); - Py_SET_SIZE(z, -Py_SIZE(z)); + _PyLong_FlipSign(z); } for (i = 0; i < wordshift; i++) z->long_value.ob_digit[i] = 0; @@ -5131,11 +5080,11 @@ long_lshift(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative((PyLongObject *)b)) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } if (divmod_shift(b, &wordshift, &remshift) < 0) @@ -5151,7 +5100,7 @@ _PyLong_Lshift(PyObject *a, size_t shiftby) digit remshift; assert(PyLong_Check(a)); - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } wordshift = shiftby / PyLong_SHIFT; @@ -5193,8 +5142,8 @@ long_bitwise(PyLongObject *a, result back to sign-magnitude at the end. */ /* If a is negative, replace it by its two's complement. */ - size_a = Py_ABS(Py_SIZE(a)); - nega = Py_SIZE(a) < 0; + size_a = _PyLong_DigitCount(a); + nega = _PyLong_IsNegative(a); if (nega) { z = _PyLong_New(size_a); if (z == NULL) @@ -5207,8 +5156,8 @@ long_bitwise(PyLongObject *a, Py_INCREF(a); /* Same for b. */ - size_b = Py_ABS(Py_SIZE(b)); - negb = Py_SIZE(b) < 0; + size_b = _PyLong_DigitCount(b); + negb = _PyLong_IsNegative(b); if (negb) { z = _PyLong_New(size_b); if (z == NULL) { @@ -5289,7 +5238,7 @@ long_bitwise(PyLongObject *a, /* Complement result if negative. */ if (negz) { - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); z->long_value.ob_digit[size_z] = PyLong_MASK; v_complement(z->long_value.ob_digit, z->long_value.ob_digit, size_z+1); } @@ -5305,7 +5254,7 @@ long_and(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) & medium_value(y)); } return long_bitwise(x, '&', y); @@ -5317,7 +5266,7 @@ long_xor(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) ^ medium_value(y)); } return long_bitwise(x, '^', y); @@ -5329,7 +5278,7 @@ long_or(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) | medium_value(y)); } return long_bitwise(x, '|', y); @@ -5353,14 +5302,11 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) stwodigits x, y, q, s, t, c_carry, d_carry; stwodigits A, B, C, D, T; int nbits, k; - Py_ssize_t size_a, size_b, alloc_a, alloc_b; digit *a_digit, *b_digit, *c_digit, *d_digit, *a_end, *b_end; a = (PyLongObject *)aarg; b = (PyLongObject *)barg; - size_a = Py_SIZE(a); - size_b = Py_SIZE(b); - if (-2 <= size_a && size_a <= 2 && -2 <= size_b && size_b <= 2) { + if (_PyLong_DigitCount(a) <= 2 && _PyLong_DigitCount(b) <= 2) { Py_INCREF(a); Py_INCREF(b); goto simple; @@ -5382,14 +5328,15 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) } /* We now own references to a and b */ - alloc_a = Py_SIZE(a); - alloc_b = Py_SIZE(b); + Py_ssize_t size_a, size_b, alloc_a, alloc_b; + alloc_a = _PyLong_DigitCount(a); + alloc_b = _PyLong_DigitCount(b); /* reduce until a fits into 2 digits */ - while ((size_a = Py_SIZE(a)) > 2) { + while ((size_a = _PyLong_DigitCount(a)) > 2) { nbits = bit_length_digit(a->long_value.ob_digit[size_a-1]); /* extract top 2*PyLong_SHIFT bits of a into x, along with corresponding bits of b into y */ - size_b = Py_SIZE(b); + size_b = _PyLong_DigitCount(b); assert(size_b <= size_a); if (size_b == 0) { if (size_a < alloc_a) { @@ -5433,7 +5380,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) Py_SETREF(a, b); b = r; alloc_a = alloc_b; - alloc_b = Py_SIZE(b); + alloc_b = _PyLong_DigitCount(b); continue; } @@ -5446,7 +5393,8 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) T = -C; C = -D; D = T; } if (c != NULL) { - Py_SET_SIZE(c, size_a); + assert(size_a >= 0); + _PyLong_SetSignAndDigitCount(c, 1, size_a); } else if (Py_REFCNT(a) == 1) { c = (PyLongObject*)Py_NewRef(a); @@ -5459,11 +5407,13 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) } if (d != NULL) { - Py_SET_SIZE(d, size_a); + assert(size_a >= 0); + _PyLong_SetSignAndDigitCount(d, 1, size_a); } else if (Py_REFCNT(b) == 1 && size_a <= alloc_b) { d = (PyLongObject*)Py_NewRef(b); - Py_SET_SIZE(d, size_a); + assert(size_a >= 0); + _PyLong_SetSignAndDigitCount(d, 1, size_a); } else { alloc_b = size_a; @@ -5635,9 +5585,7 @@ long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) if (tmp == NULL) return NULL; assert(PyLong_Check(tmp)); - n = Py_SIZE(tmp); - if (n < 0) - n = -n; + n = _PyLong_DigitCount(tmp); /* Fast operations for single digit integers (including zero) * assume that there is always at least one digit present. */ if (n == 0) { @@ -5649,7 +5597,7 @@ long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) return NULL; } assert(PyLong_Check(newobj)); - Py_SET_SIZE(newobj, Py_SIZE(tmp)); + newobj->long_value.lv_tag = tmp->long_value.lv_tag; for (i = 0; i < n; i++) { newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i]; } @@ -5743,7 +5691,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) } /* Do a and b have different signs? If so, quotient is negative. */ - quo_is_neg = (Py_SIZE(a) < 0) != (Py_SIZE(b) < 0); + quo_is_neg = (_PyLong_IsNegative((PyLongObject *)a)) != (_PyLong_IsNegative((PyLongObject *)b)); if (long_divrem((PyLongObject*)a, (PyLongObject*)b, &quo, &rem) < 0) goto error; @@ -5763,8 +5711,8 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) cmp = long_compare((PyLongObject *)twice_rem, (PyLongObject *)b); Py_DECREF(twice_rem); - quo_is_odd = Py_SIZE(quo) != 0 && ((quo->long_value.ob_digit[0] & 1) != 0); - if ((Py_SIZE(b) < 0 ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { + quo_is_odd = (quo->long_value.ob_digit[0] & 1) != 0; + if ((_PyLong_IsNegative((PyLongObject *)b) ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { /* fix up quotient */ if (quo_is_neg) temp = long_sub(quo, (PyLongObject *)one); @@ -5837,7 +5785,7 @@ int___round___impl(PyObject *self, PyObject *o_ndigits) return NULL; /* if ndigits >= 0 then no rounding is necessary; return self unchanged */ - if (Py_SIZE(ndigits) >= 0) { + if (!_PyLong_IsNegative((PyLongObject *)ndigits)) { Py_DECREF(ndigits); return long_long(self); } @@ -5883,8 +5831,8 @@ int___sizeof___impl(PyObject *self) /*[clinic end generated code: output=3303f008eaa6a0a5 input=9b51620c76fc4507]*/ { /* using Py_MAX(..., 1) because we always allocate space for at least - one digit, even though the integer zero has a Py_SIZE of 0 */ - Py_ssize_t ndigits = Py_MAX(Py_ABS(Py_SIZE(self)), 1); + one digit, even though the integer zero has a digit count of 0 */ + Py_ssize_t ndigits = Py_MAX(_PyLong_DigitCount((PyLongObject *)self), 1); return Py_TYPE(self)->tp_basicsize + Py_TYPE(self)->tp_itemsize * ndigits; } @@ -5911,7 +5859,7 @@ int_bit_length_impl(PyObject *self) assert(self != NULL); assert(PyLong_Check(self)); - ndigits = Py_ABS(Py_SIZE(self)); + ndigits = _PyLong_DigitCount((PyLongObject *)self); if (ndigits == 0) return PyLong_FromLong(0); @@ -5980,7 +5928,7 @@ int_bit_count_impl(PyObject *self) assert(PyLong_Check(self)); PyLongObject *z = (PyLongObject *)self; - Py_ssize_t ndigits = Py_ABS(Py_SIZE(z)); + Py_ssize_t ndigits = _PyLong_DigitCount(z); Py_ssize_t bit_count = 0; /* Each digit has up to PyLong_SHIFT ones, so the accumulated bit count diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index b4d0bbf32c84..beb86b9623bd 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -33,7 +33,7 @@ validate_step(PyObject *step) return PyLong_FromLong(1); step = PyNumber_Index(step); - if (step && _PyLong_Sign(step) == 0) { + if (step && _PyLong_IsZero((PyLongObject *)step)) { PyErr_SetString(PyExc_ValueError, "range() arg 3 must not be zero"); Py_CLEAR(step); diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 5d2e6ad522bc..584ebce721fa 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -445,7 +445,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, if (start == NULL) goto error; - if (_PyLong_Sign(start) < 0) { + if (_PyLong_IsNegative((PyLongObject *)start)) { /* start += length */ PyObject *tmp = PyNumber_Add(start, length); Py_SETREF(start, tmp); @@ -478,7 +478,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, if (stop == NULL) goto error; - if (_PyLong_Sign(stop) < 0) { + if (_PyLong_IsNegative((PyLongObject *)stop)) { /* stop += length */ PyObject *tmp = PyNumber_Add(stop, length); Py_SETREF(stop, tmp); @@ -533,7 +533,7 @@ slice_indices(PySliceObject* self, PyObject* len) if (length == NULL) return NULL; - if (_PyLong_Sign(length) < 0) { + if (_PyLong_IsNegative((PyLongObject *)length)) { PyErr_SetString(PyExc_ValueError, "length should not be negative"); Py_DECREF(length); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a37f97c71ec7..69e84743f13a 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8,6 +8,7 @@ #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_object.h" // _PyType_HasFeature() +#include "pycore_long.h" // _PyLong_IsNegative() #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_typeobject.h" // struct type_cache @@ -7865,7 +7866,7 @@ slot_sq_length(PyObject *self) return -1; assert(PyLong_Check(res)); - if (Py_SIZE(res) < 0) { + if (_PyLong_IsNegative((PyLongObject *)res)) { Py_DECREF(res); PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0"); diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 1a0b2a05b1c7..8270fa8e372d 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_ast.h" // _PyAST_GetDocString() #include "pycore_compile.h" // _PyASTOptimizeState +#include "pycore_long.h" // _PyLong #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_format.h" // F_LJUST @@ -152,7 +153,9 @@ check_complexity(PyObject *obj, Py_ssize_t limit) static PyObject * safe_multiply(PyObject *v, PyObject *w) { - if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) { + if (PyLong_Check(v) && PyLong_Check(w) && + !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) + ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = _PyLong_NumBits(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { @@ -198,7 +201,9 @@ safe_multiply(PyObject *v, PyObject *w) static PyObject * safe_power(PyObject *v, PyObject *w) { - if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) { + if (PyLong_Check(v) && PyLong_Check(w) && + !_PyLong_IsZero((PyLongObject *)v) && _PyLong_IsPositive((PyLongObject *)w) + ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { @@ -215,7 +220,9 @@ safe_power(PyObject *v, PyObject *w) static PyObject * safe_lshift(PyObject *v, PyObject *w) { - if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) { + if (PyLong_Check(v) && PyLong_Check(w) && + !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) + ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 12ca0ba6c487..55fd364d0079 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -5,6 +5,7 @@ #include "pycore_ast.h" // _PyAST_Validate() #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_compile.h" // _PyAST_Compile() +#include "pycore_long.h" // _PyLong_CompactValue #include "pycore_object.h" // _Py_AddToAllObjects() #include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pystate.h" // _PyThreadState_GET() @@ -2491,7 +2492,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) */ if (PyLong_CheckExact(result)) { int overflow; - long i_result = PyLong_AsLongAndOverflow(result, &overflow); + Py_ssize_t i_result = PyLong_AsLongAndOverflow(result, &overflow); /* If this already overflowed, don't even enter the loop. */ if (overflow == 0) { Py_SETREF(result, NULL); @@ -2505,15 +2506,14 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) return PyLong_FromLong(i_result); } if (PyLong_CheckExact(item) || PyBool_Check(item)) { - long b; + Py_ssize_t b; overflow = 0; /* Single digits are common, fast, and cannot overflow on unpacking. */ - switch (Py_SIZE(item)) { - case -1: b = -(sdigit) ((PyLongObject*)item)->long_value.ob_digit[0]; break; - // Note: the continue goes to the top of the "while" loop that iterates over the elements - case 0: Py_DECREF(item); continue; - case 1: b = ((PyLongObject*)item)->long_value.ob_digit[0]; break; - default: b = PyLong_AsLongAndOverflow(item, &overflow); break; + if (_PyLong_IsCompact((PyLongObject *)item)) { + b = _PyLong_CompactValue((PyLongObject *)item); + } + else { + b = PyLong_AsLongAndOverflow(item, &overflow); } if (overflow == 0 && (i_result >= 0 ? (b <= LONG_MAX - i_result) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index ce2a58b6e304..f1fec0be343c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -345,8 +345,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -363,8 +362,7 @@ dummy_func( DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -456,7 +454,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); @@ -1755,12 +1753,13 @@ dummy_func( assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); - assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); - Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0]; - Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0]; + assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && + _PyLong_DigitCount((PyLongObject *)right) <= 1); + Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); + Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 34b608fced04..e9f28b0abff4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -547,8 +547,7 @@ DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -557,7 +556,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 561 "Python/generated_cases.c.h" + #line 560 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 4; @@ -568,14 +567,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 361 "Python/bytecodes.c" + #line 360 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -584,7 +582,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 588 "Python/generated_cases.c.h" + #line 586 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 4; @@ -595,7 +593,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 379 "Python/bytecodes.c" + #line 377 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -604,14 +602,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 608 "Python/generated_cases.c.h" + #line 606 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 388 "Python/bytecodes.c" + #line 386 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 615 "Python/generated_cases.c.h" + #line 613 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -625,7 +623,7 @@ PyObject *container = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t func_version = read_u16(&next_instr[3].cache); - #line 395 "Python/bytecodes.c" + #line 393 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(tp->tp_version_tag != type_version, BINARY_SUBSCR); assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); @@ -644,15 +642,15 @@ new_frame->localsplus[1] = sub; JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); DISPATCH_INLINED(new_frame); - #line 648 "Python/generated_cases.c.h" + #line 646 "Python/generated_cases.c.h" } TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 416 "Python/bytecodes.c" + #line 414 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 656 "Python/generated_cases.c.h" + #line 654 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -661,13 +659,13 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 421 "Python/bytecodes.c" + #line 419 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 667 "Python/generated_cases.c.h" + #line 665 "Python/generated_cases.c.h" Py_DECREF(v); - #line 423 "Python/bytecodes.c" + #line 421 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 671 "Python/generated_cases.c.h" + #line 669 "Python/generated_cases.c.h" STACK_SHRINK(1); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -680,7 +678,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 434 "Python/bytecodes.c" + #line 432 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -696,13 +694,13 @@ #endif /* ENABLE_SPECIALIZATION */ /* container[sub] = v */ int err = PyObject_SetItem(container, sub, v); - #line 700 "Python/generated_cases.c.h" + #line 698 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 450 "Python/bytecodes.c" + #line 448 "Python/bytecodes.c" if (err) goto pop_3_error; - #line 706 "Python/generated_cases.c.h" + #line 704 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -712,13 +710,13 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 454 "Python/bytecodes.c" + #line 452 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); @@ -730,7 +728,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 734 "Python/generated_cases.c.h" + #line 732 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -740,14 +738,14 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 474 "Python/bytecodes.c" + #line 472 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 751 "Python/generated_cases.c.h" + #line 749 "Python/generated_cases.c.h" STACK_SHRINK(3); next_instr += 1; DISPATCH(); @@ -756,15 +754,15 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 483 "Python/bytecodes.c" + #line 481 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 763 "Python/generated_cases.c.h" + #line 761 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 486 "Python/bytecodes.c" + #line 484 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 768 "Python/generated_cases.c.h" + #line 766 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -772,14 +770,14 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 490 "Python/bytecodes.c" + #line 488 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 779 "Python/generated_cases.c.h" + #line 777 "Python/generated_cases.c.h" Py_DECREF(value); - #line 493 "Python/bytecodes.c" + #line 491 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 783 "Python/generated_cases.c.h" + #line 781 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -788,15 +786,15 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 497 "Python/bytecodes.c" + #line 495 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 795 "Python/generated_cases.c.h" + #line 793 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 500 "Python/bytecodes.c" + #line 498 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 800 "Python/generated_cases.c.h" + #line 798 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -804,7 +802,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 504 "Python/bytecodes.c" + #line 502 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -822,12 +820,12 @@ break; } if (true) { STACK_SHRINK(oparg); goto error; } - #line 826 "Python/generated_cases.c.h" + #line 824 "Python/generated_cases.c.h" } TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 524 "Python/bytecodes.c" + #line 522 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -839,12 +837,12 @@ assert(!_PyErr_Occurred(tstate)); _Py_LeaveRecursiveCallTstate(tstate); return retval; - #line 843 "Python/generated_cases.c.h" + #line 841 "Python/generated_cases.c.h" } TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 538 "Python/bytecodes.c" + #line 536 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -858,11 +856,11 @@ _PyEvalFrameClearAndPop(tstate, dying); _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 862 "Python/generated_cases.c.h" + #line 860 "Python/generated_cases.c.h" } TARGET(RETURN_CONST) { - #line 554 "Python/bytecodes.c" + #line 552 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -877,13 +875,13 @@ _PyEvalFrameClearAndPop(tstate, dying); _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 881 "Python/generated_cases.c.h" + #line 879 "Python/generated_cases.c.h" } TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 571 "Python/bytecodes.c" + #line 569 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -896,16 +894,16 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 900 "Python/generated_cases.c.h" + #line 898 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 584 "Python/bytecodes.c" + #line 582 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 907 "Python/generated_cases.c.h" + #line 905 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 589 "Python/bytecodes.c" + #line 587 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -918,7 +916,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 922 "Python/generated_cases.c.h" + #line 920 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -926,7 +924,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 604 "Python/bytecodes.c" + #line 602 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -970,7 +968,7 @@ } } - #line 974 "Python/generated_cases.c.h" + #line 972 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; PREDICT(LOAD_CONST); @@ -981,16 +979,16 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 651 "Python/bytecodes.c" + #line 649 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 992 "Python/generated_cases.c.h" + #line 990 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 658 "Python/bytecodes.c" + #line 656 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1008,7 +1006,7 @@ if (iter == NULL) goto pop_1_error; - #line 1012 "Python/generated_cases.c.h" + #line 1010 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -1019,7 +1017,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 684 "Python/bytecodes.c" + #line 682 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1055,7 +1053,7 @@ assert(retval != NULL); } Py_DECREF(v); - #line 1059 "Python/generated_cases.c.h" + #line 1057 "Python/generated_cases.c.h" stack_pointer[-1] = retval; next_instr += 1; DISPATCH(); @@ -1064,7 +1062,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 722 "Python/bytecodes.c" + #line 720 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1080,12 +1078,12 @@ tstate->exc_info = &gen->gi_exc_state; JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg); DISPATCH_INLINED(gen_frame); - #line 1084 "Python/generated_cases.c.h" + #line 1082 "Python/generated_cases.c.h" } TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 740 "Python/bytecodes.c" + #line 738 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1104,15 +1102,15 @@ frame->prev_instr -= frame->yield_offset; _PyFrame_StackPush(frame, retval); goto resume_frame; - #line 1108 "Python/generated_cases.c.h" + #line 1106 "Python/generated_cases.c.h" } TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 761 "Python/bytecodes.c" + #line 759 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 1116 "Python/generated_cases.c.h" + #line 1114 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1120,7 +1118,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 766 "Python/bytecodes.c" + #line 764 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1138,26 +1136,26 @@ Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; - #line 1142 "Python/generated_cases.c.h" + #line 1140 "Python/generated_cases.c.h" } TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 786 "Python/bytecodes.c" + #line 784 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { - #line 1151 "Python/generated_cases.c.h" + #line 1149 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 789 "Python/bytecodes.c" + #line 787 "Python/bytecodes.c" } else { Py_INCREF(exc); _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } - #line 1161 "Python/generated_cases.c.h" + #line 1159 "Python/generated_cases.c.h" STACK_SHRINK(2); DISPATCH(); } @@ -1168,23 +1166,23 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 798 "Python/bytecodes.c" + #line 796 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { value = Py_NewRef(((PyStopIterationObject *)exc_value)->value); - #line 1177 "Python/generated_cases.c.h" + #line 1175 "Python/generated_cases.c.h" Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 803 "Python/bytecodes.c" + #line 801 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); goto exception_unwind; } - #line 1188 "Python/generated_cases.c.h" + #line 1186 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = value; stack_pointer[-2] = none; @@ -1193,9 +1191,9 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 812 "Python/bytecodes.c" + #line 810 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 1199 "Python/generated_cases.c.h" + #line 1197 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1203,7 +1201,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 816 "Python/bytecodes.c" + #line 814 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1225,7 +1223,7 @@ if (true) goto error; } } - #line 1229 "Python/generated_cases.c.h" + #line 1227 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; DISPATCH(); @@ -1233,33 +1231,33 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 840 "Python/bytecodes.c" + #line 838 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 1244 "Python/generated_cases.c.h" + #line 1242 "Python/generated_cases.c.h" Py_DECREF(v); - #line 847 "Python/bytecodes.c" + #line 845 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 1253 "Python/generated_cases.c.h" + #line 1251 "Python/generated_cases.c.h" Py_DECREF(v); - #line 854 "Python/bytecodes.c" + #line 852 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1257 "Python/generated_cases.c.h" + #line 1255 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_NAME) { - #line 858 "Python/bytecodes.c" + #line 856 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1276,7 +1274,7 @@ name); goto error; } - #line 1280 "Python/generated_cases.c.h" + #line 1278 "Python/generated_cases.c.h" DISPATCH(); } @@ -1284,7 +1282,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 884 "Python/bytecodes.c" + #line 882 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1298,11 +1296,11 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - #line 1302 "Python/generated_cases.c.h" + #line 1300 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 898 "Python/bytecodes.c" + #line 896 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1306 "Python/generated_cases.c.h" + #line 1304 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW(oparg); next_instr += 1; @@ -1312,14 +1310,14 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 902 "Python/bytecodes.c" + #line 900 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 1323 "Python/generated_cases.c.h" + #line 1321 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1330,7 +1328,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 912 "Python/bytecodes.c" + #line 910 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1338,7 +1336,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1342 "Python/generated_cases.c.h" + #line 1340 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1349,7 +1347,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 923 "Python/bytecodes.c" + #line 921 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1357,7 +1355,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 1361 "Python/generated_cases.c.h" + #line 1359 "Python/generated_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -1367,15 +1365,15 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 934 "Python/bytecodes.c" + #line 932 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 1375 "Python/generated_cases.c.h" + #line 1373 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 938 "Python/bytecodes.c" + #line 936 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 1379 "Python/generated_cases.c.h" + #line 1377 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -1386,7 +1384,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 949 "Python/bytecodes.c" + #line 947 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -1403,12 +1401,12 @@ #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - #line 1407 "Python/generated_cases.c.h" + #line 1405 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 966 "Python/bytecodes.c" + #line 964 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 1412 "Python/generated_cases.c.h" + #line 1410 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -1416,34 +1414,34 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 970 "Python/bytecodes.c" + #line 968 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 1423 "Python/generated_cases.c.h" + #line 1421 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 973 "Python/bytecodes.c" + #line 971 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1427 "Python/generated_cases.c.h" + #line 1425 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 977 "Python/bytecodes.c" + #line 975 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 1437 "Python/generated_cases.c.h" + #line 1435 "Python/generated_cases.c.h" Py_DECREF(v); - #line 980 "Python/bytecodes.c" + #line 978 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 1441 "Python/generated_cases.c.h" + #line 1439 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(DELETE_GLOBAL) { - #line 984 "Python/bytecodes.c" + #line 982 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1455,13 +1453,13 @@ } goto error; } - #line 1459 "Python/generated_cases.c.h" + #line 1457 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_NAME) { PyObject *v; - #line 998 "Python/bytecodes.c" + #line 996 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1520,7 +1518,7 @@ } } } - #line 1524 "Python/generated_cases.c.h" + #line 1522 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = v; DISPATCH(); @@ -1531,7 +1529,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1065 "Python/bytecodes.c" + #line 1063 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1584,7 +1582,7 @@ } } null = NULL; - #line 1588 "Python/generated_cases.c.h" + #line 1586 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = v; @@ -1598,7 +1596,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1120 "Python/bytecodes.c" + #line 1118 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -1610,7 +1608,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1614 "Python/generated_cases.c.h" + #line 1612 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1625,7 +1623,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1134 "Python/bytecodes.c" + #line 1132 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); @@ -1640,7 +1638,7 @@ Py_INCREF(res); STAT_INC(LOAD_GLOBAL, hit); null = NULL; - #line 1644 "Python/generated_cases.c.h" + #line 1642 "Python/generated_cases.c.h" STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1650,16 +1648,16 @@ } TARGET(DELETE_FAST) { - #line 1151 "Python/bytecodes.c" + #line 1149 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1658 "Python/generated_cases.c.h" + #line 1656 "Python/generated_cases.c.h" DISPATCH(); } TARGET(MAKE_CELL) { - #line 1157 "Python/bytecodes.c" + #line 1155 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1668,12 +1666,12 @@ goto resume_with_error; } SETLOCAL(oparg, cell); - #line 1672 "Python/generated_cases.c.h" + #line 1670 "Python/generated_cases.c.h" DISPATCH(); } TARGET(DELETE_DEREF) { - #line 1168 "Python/bytecodes.c" + #line 1166 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1684,13 +1682,13 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1688 "Python/generated_cases.c.h" + #line 1686 "Python/generated_cases.c.h" DISPATCH(); } TARGET(LOAD_CLASSDEREF) { PyObject *value; - #line 1181 "Python/bytecodes.c" + #line 1179 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1722,7 +1720,7 @@ } Py_INCREF(value); } - #line 1726 "Python/generated_cases.c.h" + #line 1724 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1730,7 +1728,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1215 "Python/bytecodes.c" + #line 1213 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1738,7 +1736,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1742 "Python/generated_cases.c.h" + #line 1740 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; DISPATCH(); @@ -1746,18 +1744,18 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1225 "Python/bytecodes.c" + #line 1223 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1755 "Python/generated_cases.c.h" + #line 1753 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(COPY_FREE_VARS) { - #line 1232 "Python/bytecodes.c" + #line 1230 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1768,22 +1766,22 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1772 "Python/generated_cases.c.h" + #line 1770 "Python/generated_cases.c.h" DISPATCH(); } TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1245 "Python/bytecodes.c" + #line 1243 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1781 "Python/generated_cases.c.h" + #line 1779 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1247 "Python/bytecodes.c" + #line 1245 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1787 "Python/generated_cases.c.h" + #line 1785 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1793,10 +1791,10 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1251 "Python/bytecodes.c" + #line 1249 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1800 "Python/generated_cases.c.h" + #line 1798 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1806,10 +1804,10 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1256 "Python/bytecodes.c" + #line 1254 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1813 "Python/generated_cases.c.h" + #line 1811 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1819,7 +1817,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1261 "Python/bytecodes.c" + #line 1259 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1830,13 +1828,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1834 "Python/generated_cases.c.h" + #line 1832 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1272 "Python/bytecodes.c" + #line 1270 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); - #line 1840 "Python/generated_cases.c.h" + #line 1838 "Python/generated_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); DISPATCH(); @@ -1845,13 +1843,13 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1279 "Python/bytecodes.c" + #line 1277 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1851 "Python/generated_cases.c.h" + #line 1849 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1281 "Python/bytecodes.c" + #line 1279 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1855 "Python/generated_cases.c.h" + #line 1853 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -1859,7 +1857,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1285 "Python/bytecodes.c" + #line 1283 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1874,7 +1872,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1878 "Python/generated_cases.c.h" + #line 1876 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1884,7 +1882,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1302 "Python/bytecodes.c" + #line 1300 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1892,13 +1890,13 @@ if (map == NULL) goto error; - #line 1896 "Python/generated_cases.c.h" + #line 1894 "Python/generated_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1310 "Python/bytecodes.c" + #line 1308 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1902 "Python/generated_cases.c.h" + #line 1900 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1906,7 +1904,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1314 "Python/bytecodes.c" + #line 1312 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1946,7 +1944,7 @@ Py_DECREF(ann_dict); } } - #line 1950 "Python/generated_cases.c.h" + #line 1948 "Python/generated_cases.c.h" DISPATCH(); } @@ -1954,7 +1952,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1356 "Python/bytecodes.c" + #line 1354 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1964,14 +1962,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1968 "Python/generated_cases.c.h" + #line 1966 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1366 "Python/bytecodes.c" + #line 1364 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1975 "Python/generated_cases.c.h" + #line 1973 "Python/generated_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; DISPATCH(); @@ -1979,7 +1977,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1370 "Python/bytecodes.c" + #line 1368 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1987,12 +1985,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1991 "Python/generated_cases.c.h" + #line 1989 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1378 "Python/bytecodes.c" + #line 1376 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1996 "Python/generated_cases.c.h" + #line 1994 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); DISPATCH(); @@ -2000,17 +1998,17 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1384 "Python/bytecodes.c" + #line 1382 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 2009 "Python/generated_cases.c.h" + #line 2007 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1389 "Python/bytecodes.c" + #line 1387 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 2014 "Python/generated_cases.c.h" + #line 2012 "Python/generated_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); PREDICT(CALL_FUNCTION_EX); @@ -2020,13 +2018,13 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1396 "Python/bytecodes.c" + #line 1394 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ // Do not DECREF INPUTS because the function steals the references if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - #line 2030 "Python/generated_cases.c.h" + #line 2028 "Python/generated_cases.c.h" STACK_SHRINK(2); PREDICT(JUMP_BACKWARD); DISPATCH(); @@ -2038,7 +2036,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1419 "Python/bytecodes.c" + #line 1417 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2073,9 +2071,9 @@ NULL | meth | arg1 | ... | argN */ - #line 2077 "Python/generated_cases.c.h" + #line 2075 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1454 "Python/bytecodes.c" + #line 1452 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2084,12 +2082,12 @@ else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - #line 2088 "Python/generated_cases.c.h" + #line 2086 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1463 "Python/bytecodes.c" + #line 1461 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } - #line 2093 "Python/generated_cases.c.h" + #line 2091 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -2103,7 +2101,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1468 "Python/bytecodes.c" + #line 1466 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2117,7 +2115,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2121 "Python/generated_cases.c.h" + #line 2119 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2132,7 +2130,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1485 "Python/bytecodes.c" + #line 1483 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; @@ -2146,7 +2144,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2150 "Python/generated_cases.c.h" + #line 2148 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2161,7 +2159,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1502 "Python/bytecodes.c" + #line 1500 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2189,7 +2187,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2193 "Python/generated_cases.c.h" + #line 2191 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2204,7 +2202,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1533 "Python/bytecodes.c" + #line 1531 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2215,7 +2213,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2219 "Python/generated_cases.c.h" + #line 2217 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2230,7 +2228,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1547 "Python/bytecodes.c" + #line 1545 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); @@ -2243,7 +2241,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2247 "Python/generated_cases.c.h" + #line 2245 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2257,7 +2255,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1563 "Python/bytecodes.c" + #line 1561 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); @@ -2281,7 +2279,7 @@ new_frame->localsplus[0] = owner; JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); - #line 2285 "Python/generated_cases.c.h" + #line 2283 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2289,7 +2287,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1589 "Python/bytecodes.c" + #line 1587 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2315,7 +2313,7 @@ new_frame->localsplus[1] = Py_NewRef(name); JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); DISPATCH_INLINED(new_frame); - #line 2319 "Python/generated_cases.c.h" + #line 2317 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2323,7 +2321,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1617 "Python/bytecodes.c" + #line 1615 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2342,7 +2340,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2346 "Python/generated_cases.c.h" + #line 2344 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2353,7 +2351,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1638 "Python/bytecodes.c" + #line 1636 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2393,7 +2391,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2397 "Python/generated_cases.c.h" + #line 2395 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2404,7 +2402,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1680 "Python/bytecodes.c" + #line 1678 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2415,7 +2413,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2419 "Python/generated_cases.c.h" + #line 2417 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2425,16 +2423,16 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1693 "Python/bytecodes.c" + #line 1691 "Python/bytecodes.c" STAT_INC(COMPARE_OP, deferred); assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2433 "Python/generated_cases.c.h" + #line 2431 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1697 "Python/bytecodes.c" + #line 1695 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2438 "Python/generated_cases.c.h" + #line 2436 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2445,7 +2443,7 @@ PREDICTED(COMPARE_AND_BRANCH); PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1709 "Python/bytecodes.c" + #line 1707 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2459,10 +2457,10 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); - #line 2463 "Python/generated_cases.c.h" + #line 2461 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1723 "Python/bytecodes.c" + #line 1721 "Python/bytecodes.c" if (cond == NULL) goto pop_2_error; assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || next_instr[1].op.code == POP_JUMP_IF_TRUE); @@ -2474,7 +2472,7 @@ if (jump_on_true == (err != 0)) { JUMPBY(offset); } - #line 2478 "Python/generated_cases.c.h" + #line 2476 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2483,7 +2481,7 @@ TARGET(COMPARE_AND_BRANCH_FLOAT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1737 "Python/bytecodes.c" + #line 1735 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); @@ -2498,7 +2496,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } - #line 2502 "Python/generated_cases.c.h" + #line 2500 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2507,16 +2505,17 @@ TARGET(COMPARE_AND_BRANCH_INT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1755 "Python/bytecodes.c" + #line 1753 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); - assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); - Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0]; - Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0]; + assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && + _PyLong_DigitCount((PyLongObject *)right) <= 1); + Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); + Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); @@ -2525,7 +2524,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } - #line 2529 "Python/generated_cases.c.h" + #line 2528 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2534,7 +2533,7 @@ TARGET(COMPARE_AND_BRANCH_STR) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1776 "Python/bytecodes.c" + #line 1775 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); @@ -2550,7 +2549,7 @@ int offset = next_instr[1].op.arg; JUMPBY(offset); } - #line 2554 "Python/generated_cases.c.h" + #line 2553 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 2; DISPATCH(); @@ -2560,14 +2559,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1794 "Python/bytecodes.c" + #line 1793 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2566 "Python/generated_cases.c.h" + #line 2565 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1796 "Python/bytecodes.c" + #line 1795 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2571 "Python/generated_cases.c.h" + #line 2570 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2577,15 +2576,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1800 "Python/bytecodes.c" + #line 1799 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2583 "Python/generated_cases.c.h" + #line 2582 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1802 "Python/bytecodes.c" + #line 1801 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2589 "Python/generated_cases.c.h" + #line 2588 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2596,12 +2595,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1807 "Python/bytecodes.c" + #line 1806 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2602 "Python/generated_cases.c.h" + #line 2601 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1809 "Python/bytecodes.c" + #line 1808 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2609,10 +2608,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2613 "Python/generated_cases.c.h" + #line 2612 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1817 "Python/bytecodes.c" + #line 1816 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2621,7 +2620,7 @@ if (!Py_IsNone(match)) { PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); } - #line 2625 "Python/generated_cases.c.h" + #line 2624 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2631,21 +2630,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1828 "Python/bytecodes.c" + #line 1827 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2638 "Python/generated_cases.c.h" + #line 2637 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1831 "Python/bytecodes.c" + #line 1830 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2645 "Python/generated_cases.c.h" + #line 2644 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1836 "Python/bytecodes.c" + #line 1835 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2649 "Python/generated_cases.c.h" + #line 2648 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2654,15 +2653,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 1840 "Python/bytecodes.c" + #line 1839 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2661 "Python/generated_cases.c.h" + #line 2660 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 1843 "Python/bytecodes.c" + #line 1842 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2666 "Python/generated_cases.c.h" + #line 2665 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2671,29 +2670,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 1847 "Python/bytecodes.c" + #line 1846 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2679 "Python/generated_cases.c.h" + #line 2678 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 1853 "Python/bytecodes.c" + #line 1852 "Python/bytecodes.c" JUMPBY(oparg); - #line 2688 "Python/generated_cases.c.h" + #line 2687 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 1857 "Python/bytecodes.c" + #line 1856 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2697 "Python/generated_cases.c.h" + #line 2696 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2701,7 +2700,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 1863 "Python/bytecodes.c" + #line 1862 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2711,9 +2710,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2715 "Python/generated_cases.c.h" + #line 2714 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1873 "Python/bytecodes.c" + #line 1872 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2721,14 +2720,14 @@ if (err < 0) goto pop_1_error; } } - #line 2725 "Python/generated_cases.c.h" + #line 2724 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 1883 "Python/bytecodes.c" + #line 1882 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2738,9 +2737,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2742 "Python/generated_cases.c.h" + #line 2741 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1893 "Python/bytecodes.c" + #line 1892 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2748,48 +2747,48 @@ if (err < 0) goto pop_1_error; } } - #line 2752 "Python/generated_cases.c.h" + #line 2751 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 1903 "Python/bytecodes.c" + #line 1902 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2761 "Python/generated_cases.c.h" + #line 2760 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1905 "Python/bytecodes.c" + #line 1904 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2769 "Python/generated_cases.c.h" + #line 2768 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 1913 "Python/bytecodes.c" + #line 1912 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 2782 "Python/generated_cases.c.h" + #line 2781 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1919 "Python/bytecodes.c" + #line 1918 "Python/bytecodes.c" } - #line 2786 "Python/generated_cases.c.h" + #line 2785 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_IF_FALSE_OR_POP) { PyObject *cond = stack_pointer[-1]; - #line 1923 "Python/bytecodes.c" + #line 1922 "Python/bytecodes.c" bool jump = false; int err; if (Py_IsTrue(cond)) { @@ -2812,7 +2811,7 @@ goto error; } } - #line 2816 "Python/generated_cases.c.h" + #line 2815 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); @@ -2820,7 +2819,7 @@ TARGET(JUMP_IF_TRUE_OR_POP) { PyObject *cond = stack_pointer[-1]; - #line 1948 "Python/bytecodes.c" + #line 1947 "Python/bytecodes.c" bool jump = false; int err; if (Py_IsFalse(cond)) { @@ -2843,34 +2842,34 @@ goto error; } } - #line 2847 "Python/generated_cases.c.h" + #line 2846 "Python/generated_cases.c.h" STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 1973 "Python/bytecodes.c" + #line 1972 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 2861 "Python/generated_cases.c.h" + #line 2860 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 1982 "Python/bytecodes.c" + #line 1981 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 2874 "Python/generated_cases.c.h" + #line 2873 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2881,16 +2880,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 1990 "Python/bytecodes.c" + #line 1989 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 2890 "Python/generated_cases.c.h" + #line 2889 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 1995 "Python/bytecodes.c" + #line 1994 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2898,7 +2897,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 2902 "Python/generated_cases.c.h" + #line 2901 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -2907,10 +2906,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2005 "Python/bytecodes.c" + #line 2004 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 2914 "Python/generated_cases.c.h" + #line 2913 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2920,10 +2919,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2011 "Python/bytecodes.c" + #line 2010 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 2927 "Python/generated_cases.c.h" + #line 2926 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2934,11 +2933,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2017 "Python/bytecodes.c" + #line 2016 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 2942 "Python/generated_cases.c.h" + #line 2941 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -2947,14 +2946,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2023 "Python/bytecodes.c" + #line 2022 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 2954 "Python/generated_cases.c.h" + #line 2953 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2026 "Python/bytecodes.c" + #line 2025 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 2958 "Python/generated_cases.c.h" + #line 2957 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -2962,7 +2961,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2030 "Python/bytecodes.c" + #line 2029 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2985,11 +2984,11 @@ if (iter == NULL) { goto error; } - #line 2989 "Python/generated_cases.c.h" + #line 2988 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2053 "Python/bytecodes.c" + #line 2052 "Python/bytecodes.c" } - #line 2993 "Python/generated_cases.c.h" + #line 2992 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -3000,7 +2999,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2072 "Python/bytecodes.c" + #line 2071 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3033,7 +3032,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3037 "Python/generated_cases.c.h" + #line 3036 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3043,7 +3042,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2107 "Python/bytecodes.c" + #line 2106 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -3064,7 +3063,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3068 "Python/generated_cases.c.h" + #line 3067 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3074,7 +3073,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2130 "Python/bytecodes.c" + #line 2129 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -3095,7 +3094,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3099 "Python/generated_cases.c.h" + #line 3098 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3105,7 +3104,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2153 "Python/bytecodes.c" + #line 2152 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -3124,7 +3123,7 @@ if (next == NULL) { goto error; } - #line 3128 "Python/generated_cases.c.h" + #line 3127 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3133,7 +3132,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2174 "Python/bytecodes.c" + #line 2173 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3148,14 +3147,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); assert(next_instr->op.code == END_FOR); DISPATCH_INLINED(gen_frame); - #line 3152 "Python/generated_cases.c.h" + #line 3151 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2191 "Python/bytecodes.c" + #line 2190 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3178,16 +3177,16 @@ Py_DECREF(enter); goto error; } - #line 3182 "Python/generated_cases.c.h" + #line 3181 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2214 "Python/bytecodes.c" + #line 2213 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3191 "Python/generated_cases.c.h" + #line 3190 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3199,7 +3198,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2224 "Python/bytecodes.c" + #line 2223 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3225,16 +3224,16 @@ Py_DECREF(enter); goto error; } - #line 3229 "Python/generated_cases.c.h" + #line 3228 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2250 "Python/bytecodes.c" + #line 2249 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3238 "Python/generated_cases.c.h" + #line 3237 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3246,7 +3245,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2259 "Python/bytecodes.c" + #line 2258 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3267,7 +3266,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3271 "Python/generated_cases.c.h" + #line 3270 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3276,7 +3275,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2282 "Python/bytecodes.c" + #line 2281 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3286,7 +3285,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3290 "Python/generated_cases.c.h" + #line 3289 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3300,7 +3299,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2294 "Python/bytecodes.c" + #line 2293 "Python/bytecodes.c" /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -3318,7 +3317,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3322 "Python/generated_cases.c.h" + #line 3321 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3332,7 +3331,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2314 "Python/bytecodes.c" + #line 2313 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3343,7 +3342,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3347 "Python/generated_cases.c.h" + #line 3346 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3357,7 +3356,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2327 "Python/bytecodes.c" + #line 2326 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3372,7 +3371,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3376 "Python/generated_cases.c.h" + #line 3375 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3381,11 +3380,11 @@ } TARGET(KW_NAMES) { - #line 2344 "Python/bytecodes.c" + #line 2343 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3389 "Python/generated_cases.c.h" + #line 3388 "Python/generated_cases.c.h" DISPATCH(); } @@ -3396,7 +3395,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2380 "Python/bytecodes.c" + #line 2379 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3468,7 +3467,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3472 "Python/generated_cases.c.h" + #line 3471 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3480,7 +3479,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2458 "Python/bytecodes.c" + #line 2457 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3490,7 +3489,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3494 "Python/generated_cases.c.h" + #line 3493 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3499,7 +3498,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2470 "Python/bytecodes.c" + #line 2469 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3524,7 +3523,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3528 "Python/generated_cases.c.h" + #line 3527 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3533,7 +3532,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); uint16_t min_args = read_u16(&next_instr[3].cache); - #line 2497 "Python/bytecodes.c" + #line 2496 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3563,7 +3562,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3567 "Python/generated_cases.c.h" + #line 3566 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3571,7 +3570,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2529 "Python/bytecodes.c" + #line 2528 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3582,7 +3581,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3586 "Python/generated_cases.c.h" + #line 3585 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3595,7 +3594,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2542 "Python/bytecodes.c" + #line 2541 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3607,7 +3606,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3611 "Python/generated_cases.c.h" + #line 3610 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3621,7 +3620,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2557 "Python/bytecodes.c" + #line 2556 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3632,7 +3631,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3636 "Python/generated_cases.c.h" + #line 3635 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3646,7 +3645,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2571 "Python/bytecodes.c" + #line 2570 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3668,7 +3667,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3672 "Python/generated_cases.c.h" + #line 3671 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3682,7 +3681,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2596 "Python/bytecodes.c" + #line 2595 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3711,7 +3710,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3715 "Python/generated_cases.c.h" + #line 3714 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3725,7 +3724,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2628 "Python/bytecodes.c" + #line 2627 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3758,7 +3757,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3762 "Python/generated_cases.c.h" + #line 3761 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3772,7 +3771,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2664 "Python/bytecodes.c" + #line 2663 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3805,7 +3804,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3809 "Python/generated_cases.c.h" + #line 3808 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3819,7 +3818,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2700 "Python/bytecodes.c" + #line 2699 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3845,7 +3844,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3849 "Python/generated_cases.c.h" + #line 3848 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3858,7 +3857,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2728 "Python/bytecodes.c" + #line 2727 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3886,7 +3885,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3890 "Python/generated_cases.c.h" + #line 3889 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3898,7 +3897,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2759 "Python/bytecodes.c" + #line 2758 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3917,14 +3916,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 3921 "Python/generated_cases.c.h" + #line 3920 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2780 "Python/bytecodes.c" + #line 2779 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3955,7 +3954,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3959 "Python/generated_cases.c.h" + #line 3958 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3968,7 +3967,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2814 "Python/bytecodes.c" + #line 2813 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3997,7 +3996,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4001 "Python/generated_cases.c.h" + #line 4000 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4010,7 +4009,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2846 "Python/bytecodes.c" + #line 2845 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4039,7 +4038,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4043 "Python/generated_cases.c.h" + #line 4042 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4052,7 +4051,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2878 "Python/bytecodes.c" + #line 2877 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4080,7 +4079,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4084 "Python/generated_cases.c.h" + #line 4083 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4095,7 +4094,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 2909 "Python/bytecodes.c" + #line 2908 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -4114,15 +4113,15 @@ assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - #line 4118 "Python/generated_cases.c.h" + #line 4117 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 2928 "Python/bytecodes.c" + #line 2927 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4126 "Python/generated_cases.c.h" + #line 4125 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4137,7 +4136,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 2939 "Python/bytecodes.c" + #line 2938 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4166,14 +4165,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4170 "Python/generated_cases.c.h" + #line 4169 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 2970 "Python/bytecodes.c" + #line 2969 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4194,7 +4193,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4198 "Python/generated_cases.c.h" + #line 4197 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4202,15 +4201,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 2993 "Python/bytecodes.c" + #line 2992 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4208 "Python/generated_cases.c.h" + #line 4207 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 2995 "Python/bytecodes.c" + #line 2994 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4214 "Python/generated_cases.c.h" + #line 4213 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4221,7 +4220,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 2999 "Python/bytecodes.c" + #line 2998 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4256,7 +4255,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4260 "Python/generated_cases.c.h" + #line 4259 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4265,10 +4264,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3036 "Python/bytecodes.c" + #line 3035 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4272 "Python/generated_cases.c.h" + #line 4271 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4280,7 +4279,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3041 "Python/bytecodes.c" + #line 3040 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4296,12 +4295,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4300 "Python/generated_cases.c.h" + #line 4299 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3057 "Python/bytecodes.c" + #line 3056 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4305 "Python/generated_cases.c.h" + #line 4304 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4311,27 +4310,27 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3062 "Python/bytecodes.c" + #line 3061 "Python/bytecodes.c" assert(oparg >= 2); - #line 4317 "Python/generated_cases.c.h" + #line 4316 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3066 "Python/bytecodes.c" + #line 3065 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4331 "Python/generated_cases.c.h" + #line 4330 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3075 "Python/bytecodes.c" + #line 3074 "Python/bytecodes.c" Py_UNREACHABLE(); - #line 4337 "Python/generated_cases.c.h" + #line 4336 "Python/generated_cases.c.h" } diff --git a/Python/marshal.c b/Python/marshal.c index 94e79d4392ae..2966139cec9a 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -11,6 +11,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_code.h" // _PyCode_New() +#include "pycore_long.h" // _PyLong_DigitCount #include "pycore_hashtable.h" // _Py_hashtable_t #include "marshal.h" // Py_MARSHAL_VERSION @@ -232,13 +233,13 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) digit d; W_TYPE(TYPE_LONG, p); - if (Py_SIZE(ob) == 0) { + if (_PyLong_IsZero(ob)) { w_long((long)0, p); return; } /* set l to number of base PyLong_MARSHAL_BASE digits */ - n = Py_ABS(Py_SIZE(ob)); + n = _PyLong_DigitCount(ob); l = (n-1) * PyLong_MARSHAL_RATIO; d = ob->long_value.ob_digit[n-1]; assert(d != 0); /* a PyLong is always normalized */ @@ -251,7 +252,7 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) p->error = WFERR_UNMARSHALLABLE; return; } - w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p); + w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p); for (i=0; i < n-1; i++) { d = ob->long_value.ob_digit[i]; @@ -839,7 +840,7 @@ r_PyLong(RFILE *p) if (ob == NULL) return NULL; - Py_SET_SIZE(ob, n > 0 ? size : -size); + _PyLong_SetSignAndDigitCount(ob, n < 0 ? -1 : 1, size); for (i = 0; i < size-1; i++) { d = 0; diff --git a/Python/specialize.c b/Python/specialize.c index 719bd5bda329..2e93ab193990 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1308,7 +1308,7 @@ _Py_Specialize_BinarySubscr( PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) { + if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_LIST_INT; goto success; } @@ -1321,7 +1321,7 @@ _Py_Specialize_BinarySubscr( } if (container_type == &PyTuple_Type) { if (PyLong_CheckExact(sub)) { - if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) { + if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_TUPLE_INT; goto success; } @@ -1389,7 +1389,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) + if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub) && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container)) { instr->op.code = STORE_SUBSCR_LIST_INT; @@ -2007,7 +2007,7 @@ _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *inst goto success; } if (PyLong_CheckExact(lhs)) { - if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) { + if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) { instr->op.code = COMPARE_AND_BRANCH_INT; goto success; } diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 511b26a5ce3d..ec808526b7bb 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -309,7 +309,7 @@ def generate_tuple(self, name: str, t: Tuple[object, ...]) -> str: return f"& {name}._object.ob_base.ob_base" def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: - sign = -1 if i < 0 else 0 if i == 0 else +1 + sign = (i > 0) - (i < 0) i = abs(i) digits: list[int] = [] while i: @@ -318,10 +318,12 @@ def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: self.write("static") with self.indent(): with self.block("struct"): - self.write("PyObject_VAR_HEAD") + self.write("PyObject ob_base;") + self.write("uintptr_t lv_tag;") self.write(f"digit ob_digit[{max(1, len(digits))}];") with self.block(f"{name} =", ";"): - self.object_var_head("PyLong_Type", sign*len(digits)) + self.object_head("PyLong_Type") + self.write(f".lv_tag = TAG_FROM_SIGN_AND_SIZE({sign}, {len(digits)}),") if digits: ds = ", ".join(map(str, digits)) self.write(f".ob_digit = {{ {ds} }},") @@ -345,7 +347,7 @@ def generate_int(self, name: str, i: int) -> str: self.write('#error "PYLONG_BITS_IN_DIGIT should be 15 or 30"') self.write("#endif") # If neither clause applies, it won't compile - return f"& {name}.ob_base.ob_base" + return f"& {name}.ob_base" def generate_float(self, name: str, x: float) -> str: with self.block(f"static PyFloatObject {name} =", ";"): diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 56d6970b2924..e38bd59e20a3 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -882,10 +882,16 @@ class PyLongObjectPtr(PyObjectPtr): def proxyval(self, visited): ''' Python's Include/longobjrep.h has this declaration: - struct _longobject { - PyObject_VAR_HEAD - digit ob_digit[1]; - }; + + typedef struct _PyLongValue { + uintptr_t lv_tag; /* Number of digits, sign and flags */ + digit ob_digit[1]; + } _PyLongValue; + + struct _longobject { + PyObject_HEAD + _PyLongValue long_value; + }; with this description: The absolute value of a number is equal to @@ -897,11 +903,13 @@ def proxyval(self, visited): #define PyLong_SHIFT 30 #define PyLong_SHIFT 15 ''' - ob_size = int(self.field('ob_size')) - if ob_size == 0: + long_value = self.field('long_value') + lv_tag = int(long_value['lv_tag']) + size = lv_tag >> 3 + if size == 0: return 0 - ob_digit = self.field('long_value')['ob_digit'] + ob_digit = long_value['ob_digit'] if gdb.lookup_type('digit').sizeof == 2: SHIFT = 15 @@ -909,9 +917,9 @@ def proxyval(self, visited): SHIFT = 30 digits = [int(ob_digit[i]) * 2**(SHIFT*i) - for i in safe_range(abs(ob_size))] + for i in safe_range(size)] result = sum(digits) - if ob_size < 0: + if (lv_tag & 3) == 2: result = -result return result From webhook-mailer at python.org Wed Mar 22 10:59:45 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 14:59:45 -0000 Subject: [Python-checkins] gh-102033: Fix syntax error in `Tools/c-analyzer` (GH-102066) Message-ID: https://github.com/python/cpython/commit/1ca315538f2f9da6c7b86c4c46e76d454c1ec4b9 commit: 1ca315538f2f9da6c7b86c4c46e76d454c1ec4b9 branch: main author: Nikita Sobolev committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T07:59:32-07:00 summary: gh-102033: Fix syntax error in `Tools/c-analyzer` (GH-102066) The easiest way to format strings with `{}` meaningful chars is via `%`. files: D Tools/c-analyzer/c_common/info.py D Tools/c-analyzer/c_common/show.py D Tools/c-analyzer/c_parser/_state_machine.py D Tools/c-analyzer/c_parser/parser/_alt.py D Tools/c-analyzer/c_parser/parser/_delim.py M Tools/c-analyzer/c_analyzer/__main__.py M Tools/c-analyzer/c_analyzer/info.py M Tools/c-analyzer/c_common/iterutil.py M Tools/c-analyzer/c_parser/__main__.py M Tools/c-analyzer/c_parser/info.py M Tools/c-analyzer/c_parser/parser/_global.py M Tools/c-analyzer/cpython/__main__.py M Tools/c-analyzer/cpython/_analyzer.py M Tools/c-analyzer/cpython/_capi.py diff --git a/Tools/c-analyzer/c_analyzer/__main__.py b/Tools/c-analyzer/c_analyzer/__main__.py index 5d89b29adf89..cde39bc4e649 100644 --- a/Tools/c-analyzer/c_analyzer/__main__.py +++ b/Tools/c-analyzer/c_analyzer/__main__.py @@ -18,10 +18,8 @@ configure_logger, get_prog, filter_filenames, - iter_marks, ) from c_parser.info import KIND -from c_parser.match import is_type_decl from .match import filter_forward from . import ( analyze as _analyze, diff --git a/Tools/c-analyzer/c_analyzer/info.py b/Tools/c-analyzer/c_analyzer/info.py index 27c3a5a4ee76..d231e07a60dd 100644 --- a/Tools/c-analyzer/c_analyzer/info.py +++ b/Tools/c-analyzer/c_analyzer/info.py @@ -1,4 +1,3 @@ -from collections import namedtuple import os.path from c_common import fsutil @@ -13,9 +12,6 @@ from c_parser.match import ( is_type_decl, ) -from .match import ( - is_process_global, -) IGNORED = _misc.Labeled('IGNORED') diff --git a/Tools/c-analyzer/c_common/info.py b/Tools/c-analyzer/c_common/info.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/Tools/c-analyzer/c_common/iterutil.py b/Tools/c-analyzer/c_common/iterutil.py index 6ded105304e4..dda3dd57c1cf 100644 --- a/Tools/c-analyzer/c_common/iterutil.py +++ b/Tools/c-analyzer/c_common/iterutil.py @@ -1,7 +1,3 @@ - -_NOT_SET = object() - - def peek_and_iter(items): if not items: return None, None diff --git a/Tools/c-analyzer/c_common/show.py b/Tools/c-analyzer/c_common/show.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/Tools/c-analyzer/c_parser/__main__.py b/Tools/c-analyzer/c_parser/__main__.py index 78f47a1808f5..2454fcba8142 100644 --- a/Tools/c-analyzer/c_parser/__main__.py +++ b/Tools/c-analyzer/c_parser/__main__.py @@ -1,10 +1,7 @@ import logging -import os.path import sys -from c_common import fsutil from c_common.scriptutil import ( - CLIArgSpec as Arg, add_verbosity_cli, add_traceback_cli, add_kind_filtering_cli, @@ -15,7 +12,6 @@ get_prog, main_for_filenames, ) -from .preprocessor import get_preprocessor from .preprocessor.__main__ import ( add_common_cli as add_preprocessor_cli, ) diff --git a/Tools/c-analyzer/c_parser/_state_machine.py b/Tools/c-analyzer/c_parser/_state_machine.py deleted file mode 100644 index 875323188aad..000000000000 --- a/Tools/c-analyzer/c_parser/_state_machine.py +++ /dev/null @@ -1,244 +0,0 @@ - -f''' - struct {ANON_IDENTIFIER}; - struct {{ ... }} - struct {IDENTIFIER} {{ ... }} - - union {ANON_IDENTIFIER}; - union {{ ... }} - union {IDENTIFIER} {{ ... }} - - enum {ANON_IDENTIFIER}; - enum {{ ... }} - enum {IDENTIFIER} {{ ... }} - - typedef {VARTYPE} {IDENTIFIER}; - typedef {IDENTIFIER}; - typedef {IDENTIFIER}; - typedef {IDENTIFIER}; -''' - - -def parse(srclines): - if isinstance(srclines, str): # a filename - raise NotImplementedError - - - -# This only handles at most 10 nested levels. -#MATCHED_PARENS = textwrap.dedent(rf''' -# # matched parens -# (?: -# [(] # level 0 -# (?: -# [^()]* -# [(] # level 1 -# (?: -# [^()]* -# [(] # level 2 -# (?: -# [^()]* -# [(] # level 3 -# (?: -# [^()]* -# [(] # level 4 -# (?: -# [^()]* -# [(] # level 5 -# (?: -# [^()]* -# [(] # level 6 -# (?: -# [^()]* -# [(] # level 7 -# (?: -# [^()]* -# [(] # level 8 -# (?: -# [^()]* -# [(] # level 9 -# (?: -# [^()]* -# [(] # level 10 -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# ) -# # end matched parens -# ''') - -r''' - # for loop - (?: - \s* \b for - \s* [(] - ( - [^;]* ; - [^;]* ; - .*? - ) #
- [)] - \s* - (?: - (?: - ( - {_ind(SIMPLE_STMT, 6)} - ) # - ; - ) - | - ( {{ ) # - ) - ) - | - - - - ( - (?: - (?: - (?: - {_ind(SIMPLE_STMT, 6)} - )? - return \b \s* - {_ind(INITIALIZER, 5)} - ) - | - (?: - (?: - {IDENTIFIER} \s* - (?: . | -> ) \s* - )* - {IDENTIFIER} - \s* = \s* - {_ind(INITIALIZER, 5)} - ) - | - (?: - {_ind(SIMPLE_STMT, 5)} - ) - ) - | - # cast compound literal - (?: - (?: - [^'"{{}};]* - {_ind(STRING_LITERAL, 5)} - )* - [^'"{{}};]*? - [^'"{{}};=] - = - \s* [(] [^)]* [)] - \s* {{ [^;]* }} - ) - ) # - - - - # compound statement - (?: - ( - (?: - - # "for" statements are handled separately above. - (?: (?: else \s+ )? if | switch | while ) \s* - {_ind(COMPOUND_HEAD, 5)} - ) - | - (?: else | do ) - # We do not worry about compound statements for labels, - # "case", or "default". - )? #
- \s* - ( {{ ) # - ) - - - - ( - (?: - [^'"{{}};]* - {_ind(STRING_LITERAL, 5)} - )* - [^'"{{}};]* - # Presumably we will not see "== {{". - [^\s='"{{}};] - )? #
- - - - ( - \b - (?: - # We don't worry about labels with a compound statement. - (?: - switch \s* [(] [^{{]* [)] - ) - | - (?: - case \b \s* [^:]+ [:] - ) - | - (?: - default \s* [:] - ) - | - (?: - do - ) - | - (?: - while \s* [(] [^{{]* [)] - ) - | - #(?: - # for \s* [(] [^{{]* [)] - # ) - #| - (?: - if \s* [(] - (?: [^{{]* [^)] \s* {{ )* [^{{]* - [)] - ) - | - (?: - else - (?: - \s* - if \s* [(] - (?: [^{{]* [^)] \s* {{ )* [^{{]* - [)] - )? - ) - ) - )? #
-''' diff --git a/Tools/c-analyzer/c_parser/info.py b/Tools/c-analyzer/c_parser/info.py index 3fa9fefbd5ec..799f92378774 100644 --- a/Tools/c-analyzer/c_parser/info.py +++ b/Tools/c-analyzer/c_parser/info.py @@ -1,6 +1,5 @@ from collections import namedtuple import enum -import os.path import re from c_common import fsutil @@ -8,7 +7,7 @@ import c_common.misc as _misc import c_common.strutil as _strutil import c_common.tables as _tables -from .parser._regexes import SIMPLE_TYPE, _STORAGE +from .parser._regexes import _STORAGE FIXED_TYPE = _misc.Labeled('FIXED_TYPE') diff --git a/Tools/c-analyzer/c_parser/parser/_alt.py b/Tools/c-analyzer/c_parser/parser/_alt.py deleted file mode 100644 index 05a9101b4f52..000000000000 --- a/Tools/c-analyzer/c_parser/parser/_alt.py +++ /dev/null @@ -1,6 +0,0 @@ - -def _parse(srclines, anon_name): - text = ' '.join(l for _, l in srclines) - - from ._delim import parse - yield from parse(text, anon_name) diff --git a/Tools/c-analyzer/c_parser/parser/_delim.py b/Tools/c-analyzer/c_parser/parser/_delim.py deleted file mode 100644 index 51433a629d3a..000000000000 --- a/Tools/c-analyzer/c_parser/parser/_delim.py +++ /dev/null @@ -1,54 +0,0 @@ -import re -import textwrap - -from ._regexes import _ind, STRING_LITERAL - - -def parse(text, anon_name): - context = None - data = None - for m in DELIMITER_RE.find_iter(text): - before, opened, closed = m.groups() - delim = opened or closed - - handle_segment = HANDLERS[context][delim] - result, context, data = handle_segment(before, delim, data) - if result: - yield result - - -DELIMITER = textwrap.dedent(rf''' - ( - (?: - [^'"()\[\]{};]* - {_ind(STRING_LITERAL, 3)} - }* - [^'"()\[\]{};]+ - )? # - (?: - ( - [(\[{] - ) # - | - ( - [)\]};] - ) # - )? - ''') -DELIMITER_RE = re.compile(DELIMITER, re.VERBOSE) - -_HANDLERS = { - None: { # global - # opened - '{': ..., - '[': None, - '(': None, - # closed - '}': None, - ']': None, - ')': None, - ';': ..., - }, - '': { - }, -} diff --git a/Tools/c-analyzer/c_parser/parser/_global.py b/Tools/c-analyzer/c_parser/parser/_global.py index 35947c129981..b1ac9f5db034 100644 --- a/Tools/c-analyzer/c_parser/parser/_global.py +++ b/Tools/c-analyzer/c_parser/parser/_global.py @@ -9,7 +9,6 @@ set_capture_groups, ) from ._compound_decl_body import DECL_BODY_PARSERS -#from ._func_body import parse_function_body from ._func_body import parse_function_statics as parse_function_body diff --git a/Tools/c-analyzer/cpython/__main__.py b/Tools/c-analyzer/cpython/__main__.py index fe7a16726f45..ec026c6932f1 100644 --- a/Tools/c-analyzer/cpython/__main__.py +++ b/Tools/c-analyzer/cpython/__main__.py @@ -2,7 +2,6 @@ import sys import textwrap -from c_common.fsutil import expand_filenames, iter_files_by_suffix from c_common.scriptutil import ( VERBOSITY, add_verbosity_cli, @@ -11,7 +10,6 @@ add_kind_filtering_cli, add_files_cli, add_progress_cli, - main_for_filenames, process_args_by_key, configure_logger, get_prog, diff --git a/Tools/c-analyzer/cpython/_analyzer.py b/Tools/c-analyzer/cpython/_analyzer.py index cfe5e75f2f4d..68d6b31cf2b6 100644 --- a/Tools/c-analyzer/cpython/_analyzer.py +++ b/Tools/c-analyzer/cpython/_analyzer.py @@ -4,16 +4,12 @@ from c_common.clsutil import classonly from c_parser.info import ( KIND, - DeclID, Declaration, TypeDeclaration, - TypeDef, - Struct, Member, FIXED_TYPE, ) from c_parser.match import ( - is_type_decl, is_pots, is_funcptr, ) diff --git a/Tools/c-analyzer/cpython/_capi.py b/Tools/c-analyzer/cpython/_capi.py index df8159a8cc16..4552f71479bd 100644 --- a/Tools/c-analyzer/cpython/_capi.py +++ b/Tools/c-analyzer/cpython/_capi.py @@ -7,7 +7,7 @@ from c_common.tables import build_table, resolve_columns from c_parser.parser._regexes import _ind -from ._files import iter_header_files, resolve_filename +from ._files import iter_header_files from . import REPO_ROOT @@ -610,8 +610,7 @@ def _render_item_full(item, groupby, verbose): yield item.name yield f' {"filename:":10} {item.relfile}' for extra in ('kind', 'level'): - #if groupby != extra: - yield f' {extra+":":10} {getattr(item, extra)}' + yield f' {extra+":":10} {getattr(item, extra)}' if verbose: print(' ---------------------------------------') for lno, line in enumerate(item.text, item.lno): @@ -636,7 +635,6 @@ def render_summary(items, *, subtotals = summary['totals']['subs'] bygroup = summary['totals']['bygroup'] - lastempty = False for outer, subtotal in subtotals.items(): if bygroup: subtotal = f'({subtotal})' @@ -646,10 +644,6 @@ def render_summary(items, *, if outer in bygroup: for inner, count in bygroup[outer].items(): yield f' {inner + ":":9} {count}' - lastempty = False - else: - lastempty = True - total = f'*{summary["totals"]["all"]}*' label = '*total*:' if bygroup: From webhook-mailer at python.org Wed Mar 22 13:52:19 2023 From: webhook-mailer at python.org (gvanrossum) Date: Wed, 22 Mar 2023 17:52:19 -0000 Subject: [Python-checkins] gh-102780: Fix uncancel() call in asyncio timeouts (#102815) Message-ID: https://github.com/python/cpython/commit/04adf2df395ded81922c71360a5d66b597471e49 commit: 04adf2df395ded81922c71360a5d66b597471e49 branch: main author: Kristj?n Valur J?nsson committer: gvanrossum date: 2023-03-22T10:52:10-07:00 summary: gh-102780: Fix uncancel() call in asyncio timeouts (#102815) Also use `raise TimeOut from ` so that the CancelledError is set in the `__cause__` field rather than in the `__context__` field. Co-authored-by: Guido van Rossum Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst M Doc/library/asyncio-task.rst M Lib/asyncio/timeouts.py M Lib/test/test_asyncio/test_timeouts.py diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index a0900cd25a77..d908e45b3c8d 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -300,13 +300,17 @@ in the task at the next opportunity. It is recommended that coroutines use ``try/finally`` blocks to robustly perform clean-up logic. In case :exc:`asyncio.CancelledError` is explicitly caught, it should generally be propagated when -clean-up is complete. Most code can safely ignore :exc:`asyncio.CancelledError`. +clean-up is complete. :exc:`asyncio.CancelledError` directly subclasses +:exc:`BaseException` so most code will not need to be aware of it. The asyncio components that enable structured concurrency, like :class:`asyncio.TaskGroup` and :func:`asyncio.timeout`, are implemented using cancellation internally and might misbehave if a coroutine swallows :exc:`asyncio.CancelledError`. Similarly, user code -should not call :meth:`uncancel `. +should not generally call :meth:`uncancel `. +However, in cases when suppressing :exc:`asyncio.CancelledError` is +truly desired, it is necessary to also call ``uncancel()`` to completely +remove the cancellation state. .. _taskgroups: @@ -1148,7 +1152,9 @@ Task Object Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does not guarantee that the Task will be cancelled, although suppressing cancellation completely is not common and is actively - discouraged. + discouraged. Should the coroutine nevertheless decide to suppress + the cancellation, it needs to call :meth:`Task.uncancel` in addition + to catching the exception. .. versionchanged:: 3.9 Added the *msg* parameter. @@ -1238,6 +1244,10 @@ Task Object with :meth:`uncancel`. :class:`TaskGroup` context managers use :func:`uncancel` in a similar fashion. + If end-user code is, for some reason, suppresing cancellation by + catching :exc:`CancelledError`, it needs to call this method to remove + the cancellation state. + .. method:: cancelling() Return the number of pending cancellation requests to this Task, i.e., diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py index d07b291005e8..029c468739bf 100644 --- a/Lib/asyncio/timeouts.py +++ b/Lib/asyncio/timeouts.py @@ -84,6 +84,7 @@ def __repr__(self) -> str: async def __aenter__(self) -> "Timeout": self._state = _State.ENTERED self._task = tasks.current_task() + self._cancelling = self._task.cancelling() if self._task is None: raise RuntimeError("Timeout should be used inside a task") self.reschedule(self._when) @@ -104,10 +105,10 @@ async def __aexit__( if self._state is _State.EXPIRING: self._state = _State.EXPIRED - if self._task.uncancel() == 0 and exc_type is exceptions.CancelledError: - # Since there are no outstanding cancel requests, we're + if self._task.uncancel() <= self._cancelling and exc_type is exceptions.CancelledError: + # Since there are no new cancel requests, we're # handling this. - raise TimeoutError + raise TimeoutError from exc_val elif self._state is _State.ENTERED: self._state = _State.EXITED diff --git a/Lib/test/test_asyncio/test_timeouts.py b/Lib/test/test_asyncio/test_timeouts.py index b9bac6f78377..8b6b9a1fea0b 100644 --- a/Lib/test/test_asyncio/test_timeouts.py +++ b/Lib/test/test_asyncio/test_timeouts.py @@ -247,6 +247,36 @@ async def test_nested_timeout_in_finally(self): async with asyncio.timeout(0.01): await asyncio.sleep(10) + async def test_timeout_after_cancellation(self): + try: + asyncio.current_task().cancel() + await asyncio.sleep(1) # work which will be cancelled + except asyncio.CancelledError: + pass + finally: + with self.assertRaises(TimeoutError): + async with asyncio.timeout(0.0): + await asyncio.sleep(1) # some cleanup + + async def test_cancel_in_timeout_after_cancellation(self): + try: + asyncio.current_task().cancel() + await asyncio.sleep(1) # work which will be cancelled + except asyncio.CancelledError: + pass + finally: + with self.assertRaises(asyncio.CancelledError): + async with asyncio.timeout(1.0): + asyncio.current_task().cancel() + await asyncio.sleep(2) # some cleanup + + async def test_timeout_exception_cause (self): + with self.assertRaises(asyncio.TimeoutError) as exc: + async with asyncio.timeout(0): + await asyncio.sleep(1) + cause = exc.exception.__cause__ + assert isinstance(cause, asyncio.CancelledError) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst b/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst new file mode 100644 index 000000000000..2aaffe34b864 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst @@ -0,0 +1,3 @@ +The :class:`asyncio.Timeout` context manager now works reliably even when performing cleanup due +to task cancellation. Previously it could raise a +:exc:`~asyncio.CancelledError` instead of an :exc:`~asyncio.TimeoutError` in such cases. From webhook-mailer at python.org Wed Mar 22 14:10:57 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 22 Mar 2023 18:10:57 -0000 Subject: [Python-checkins] gh-102859: Remove JUMP_IF_FALSE_OR_POP and JUMP_IF_TRUE_OR_POP (#102870) Message-ID: https://github.com/python/cpython/commit/3468c768ce5e467799758ec70b840da08c3c1da9 commit: 3468c768ce5e467799758ec70b840da08c3c1da9 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-22T18:10:48Z summary: gh-102859: Remove JUMP_IF_FALSE_OR_POP and JUMP_IF_TRUE_OR_POP (#102870) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst M Doc/library/dis.rst M Doc/whatsnew/3.12.rst M Include/internal/pycore_opcode.h M Include/opcode.h M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Lib/test/test__opcode.py M Lib/test/test_peepholer.py M Objects/frameobject.c M Python/bytecodes.c M Python/compile.c M Python/generated_cases.c.h M Python/opcode_metadata.h M Python/opcode_targets.h diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index f4f47b3bf484..b06fe67a983a 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1152,30 +1152,6 @@ iterations of the loop. .. versionchanged:: 3.12 This is no longer a pseudo-instruction. - -.. opcode:: JUMP_IF_TRUE_OR_POP (delta) - - If ``STACK[-1]`` is true, increments the bytecode counter by *delta* and leaves - ``STACK[-1]`` on the stack. Otherwise (``STACK[-1]`` is false), ``STACK[-1]`` - is popped. - - .. versionadded:: 3.1 - - .. versionchanged:: 3.11 - The oparg is now a relative delta rather than an absolute target. - -.. opcode:: JUMP_IF_FALSE_OR_POP (delta) - - If ``STACK[-1]`` is false, increments the bytecode counter by *delta* and leaves - ``STACK[-1]`` on the stack. Otherwise (``STACK[-1]`` is true), ``STACK[-1]`` is - popped. - - .. versionadded:: 3.1 - - .. versionchanged:: 3.11 - The oparg is now a relative delta rather than an absolute target. - - .. opcode:: FOR_ITER (delta) ``STACK[-1]`` is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b7c956d7f784..06ea416d7513 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -435,6 +435,9 @@ CPython bytecode changes :opcode:`LOAD_METHOD` instruction if the low bit of its oparg is set. (Contributed by Ken Jin in :gh:`93429`.) +* Removed the :opcode:`JUMP_IF_FALSE_OR_POP` and :opcode:`JUMP_IF_TRUE_OR_POP` + instructions. (Contributed by Irit Katriel in :gh:`102859`.) + Demos and Tools =============== diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index da94fc81dcbe..edcf4476ff3e 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -21,7 +21,7 @@ static const uint32_t _PyOpcode_RelativeJump[9] = { 0U, 0U, 536870912U, - 135118848U, + 135020544U, 4163U, 0U, 0U, @@ -32,7 +32,7 @@ static const uint32_t _PyOpcode_Jump[9] = { 0U, 0U, 536870912U, - 135118848U, + 135020544U, 4163U, 0U, 0U, @@ -143,8 +143,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [JUMP_BACKWARD] = JUMP_BACKWARD, [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, [JUMP_FORWARD] = JUMP_FORWARD, - [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, - [JUMP_IF_TRUE_OR_POP] = JUMP_IF_TRUE_OR_POP, [KW_NAMES] = KW_NAMES, [LIST_APPEND] = LIST_APPEND, [LIST_EXTEND] = LIST_EXTEND, @@ -342,9 +340,9 @@ static const char *const _PyOpcode_OpName[263] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", - [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", - [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -374,7 +372,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_BACKWARD] = "JUMP_BACKWARD", [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -384,15 +382,15 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [SEND_GEN] = "SEND_GEN", + [160] = "<160>", + [161] = "<161>", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", @@ -498,6 +496,8 @@ static const char *const _PyOpcode_OpName[263] = { #endif #define EXTRA_CASES \ + case 160: \ + case 161: \ case 166: \ case 167: \ case 168: \ diff --git a/Include/opcode.h b/Include/opcode.h index 760ff945f31f..8ec10742fb77 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -66,8 +66,6 @@ extern "C" { #define IMPORT_NAME 108 #define IMPORT_FROM 109 #define JUMP_FORWARD 110 -#define JUMP_IF_FALSE_OR_POP 111 -#define JUMP_IF_TRUE_OR_POP 112 #define POP_JUMP_IF_FALSE 114 #define POP_JUMP_IF_TRUE 115 #define LOAD_GLOBAL 116 @@ -180,14 +178,14 @@ extern "C" { #define STORE_ATTR_INSTANCE_VALUE 86 #define STORE_ATTR_SLOT 87 #define STORE_ATTR_WITH_HINT 88 -#define STORE_FAST__LOAD_FAST 113 -#define STORE_FAST__STORE_FAST 143 -#define STORE_SUBSCR_DICT 153 -#define STORE_SUBSCR_LIST_INT 154 -#define UNPACK_SEQUENCE_LIST 158 -#define UNPACK_SEQUENCE_TUPLE 159 -#define UNPACK_SEQUENCE_TWO_TUPLE 160 -#define SEND_GEN 161 +#define STORE_FAST__LOAD_FAST 111 +#define STORE_FAST__STORE_FAST 112 +#define STORE_SUBSCR_DICT 113 +#define STORE_SUBSCR_LIST_INT 143 +#define UNPACK_SEQUENCE_LIST 153 +#define UNPACK_SEQUENCE_TUPLE 154 +#define UNPACK_SEQUENCE_TWO_TUPLE 158 +#define SEND_GEN 159 #define DO_TRACING 255 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index a01a0955182d..3f78300c2263 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -435,6 +435,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a6 3519 (Modify SEND instruction) # Python 3.12a6 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) # Python 3.12a7 3521 (Shrink the LOAD_GLOBAL caches) +# Python 3.12a7 3522 (Removed JUMP_IF_FALSE_OR_POP/JUMP_IF_TRUE_OR_POP) # Python 3.13 will start with 3550 @@ -451,7 +452,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3521).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3522).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index d4a2d554cf67..f37d00e5014a 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -154,8 +154,6 @@ def pseudo_op(name, op, real_ops): name_op('IMPORT_NAME', 108) # Index in name list name_op('IMPORT_FROM', 109) # Index in name list jrel_op('JUMP_FORWARD', 110) # Number of words to skip -jrel_op('JUMP_IF_FALSE_OR_POP', 111) # Number of words to skip -jrel_op('JUMP_IF_TRUE_OR_POP', 112) # "" jrel_op('POP_JUMP_IF_FALSE', 114) jrel_op('POP_JUMP_IF_TRUE', 115) name_op('LOAD_GLOBAL', 116) # Index in name list diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index fb4ab15f7041..31f3c53992db 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -34,10 +34,6 @@ def test_stack_effect(self): self.assertRaises(ValueError, stack_effect, code, 0) def test_stack_effect_jump(self): - JUMP_IF_TRUE_OR_POP = dis.opmap['JUMP_IF_TRUE_OR_POP'] - self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0), 0) - self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=True), 0) - self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=False), -1) FOR_ITER = dis.opmap['FOR_ITER'] self.assertEqual(stack_effect(FOR_ITER, 0), 1) self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), 1) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 9ff017da53c2..01eb04b53060 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -52,10 +52,6 @@ def check_jump_targets(self, code): tgt.opname == 'RETURN_VALUE'): self.fail(f'{instr.opname} at {instr.offset} ' f'jumps to {tgt.opname} at {tgt.offset}') - # JUMP_IF_*_OR_POP jump to conditional jump - if '_OR_POP' in instr.opname and 'JUMP_IF_' in tgt.opname: - self.fail(f'{instr.opname} at {instr.offset} ' - f'jumps to {tgt.opname} at {tgt.offset}') def check_lnotab(self, code): "Check that the lnotab byte offsets are sensible." @@ -384,38 +380,36 @@ def f(): def test_elim_jump_to_uncond_jump3(self): # Intentionally use two-line expressions to test issue37213. - # JUMP_IF_FALSE_OR_POP to JUMP_IF_FALSE_OR_POP --> JUMP_IF_FALSE_OR_POP to non-jump + # POP_JUMP_IF_FALSE to POP_JUMP_IF_FALSE --> POP_JUMP_IF_FALSE to non-jump def f(a, b, c): return ((a and b) and c) self.check_jump_targets(f) self.check_lnotab(f) - self.assertEqual(count_instr_recursively(f, 'JUMP_IF_FALSE_OR_POP'), 2) - # JUMP_IF_TRUE_OR_POP to JUMP_IF_TRUE_OR_POP --> JUMP_IF_TRUE_OR_POP to non-jump + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_FALSE'), 2) + # POP_JUMP_IF_TRUE to POP_JUMP_IF_TRUE --> POP_JUMP_IF_TRUE to non-jump def f(a, b, c): return ((a or b) or c) self.check_jump_targets(f) self.check_lnotab(f) - self.assertEqual(count_instr_recursively(f, 'JUMP_IF_TRUE_OR_POP'), 2) + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_TRUE'), 2) # JUMP_IF_FALSE_OR_POP to JUMP_IF_TRUE_OR_POP --> POP_JUMP_IF_FALSE to non-jump def f(a, b, c): return ((a and b) or c) self.check_jump_targets(f) self.check_lnotab(f) - self.assertNotInBytecode(f, 'JUMP_IF_FALSE_OR_POP') - self.assertInBytecode(f, 'JUMP_IF_TRUE_OR_POP') - self.assertInBytecode(f, 'POP_JUMP_IF_FALSE') - # JUMP_IF_TRUE_OR_POP to JUMP_IF_FALSE_OR_POP --> POP_JUMP_IF_TRUE to non-jump + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_FALSE'), 1) + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_TRUE'), 1) + # POP_JUMP_IF_TRUE to POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE to non-jump def f(a, b, c): return ((a or b) and c) self.check_jump_targets(f) self.check_lnotab(f) - self.assertNotInBytecode(f, 'JUMP_IF_TRUE_OR_POP') - self.assertInBytecode(f, 'JUMP_IF_FALSE_OR_POP') - self.assertInBytecode(f, 'POP_JUMP_IF_TRUE') + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_FALSE'), 1) + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_TRUE'), 1) def test_elim_jump_to_uncond_jump4(self): def f(): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst new file mode 100644 index 000000000000..d2e2232c33cc --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst @@ -0,0 +1,2 @@ +Removed :opcode:`JUMP_IF_FALSE_OR_POP` and :opcode:`JUMP_IF_TRUE_OR_POP` +instructions. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 133c991bf701..19bd4b10780b 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -306,8 +306,6 @@ mark_stacks(PyCodeObject *code_obj, int len) } opcode = code[i].op.code; switch (opcode) { - case JUMP_IF_FALSE_OR_POP: - case JUMP_IF_TRUE_OR_POP: case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: { @@ -318,16 +316,8 @@ mark_stacks(PyCodeObject *code_obj, int len) if (stacks[j] == UNINITIALIZED && j < i) { todo = 1; } - if (opcode == JUMP_IF_FALSE_OR_POP || - opcode == JUMP_IF_TRUE_OR_POP) - { - target_stack = next_stack; - next_stack = pop_value(next_stack); - } - else { - next_stack = pop_value(next_stack); - target_stack = next_stack; - } + next_stack = pop_value(next_stack); + target_stack = next_stack; assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack); stacks[j] = target_stack; stacks[i+1] = next_stack; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f1fec0be343c..b5ead16d3f1b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1918,56 +1918,6 @@ dummy_func( } } - inst(JUMP_IF_FALSE_OR_POP, (cond -- cond if (jump))) { - bool jump = false; - int err; - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsFalse(cond)) { - JUMPBY(oparg); - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - Py_DECREF(cond); - } - else if (err == 0) { - JUMPBY(oparg); - jump = true; - } - else { - goto error; - } - } - } - - inst(JUMP_IF_TRUE_OR_POP, (cond -- cond if (jump))) { - bool jump = false; - int err; - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsTrue(cond)) { - JUMPBY(oparg); - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - JUMPBY(oparg); - jump = true; - } - else if (err == 0) { - Py_DECREF(cond); - } - else { - goto error; - } - } - } - inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost diff --git a/Python/compile.c b/Python/compile.c index 99296050445f..33cd6ca07d3b 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4241,19 +4241,18 @@ compiler_boolop(struct compiler *c, expr_ty e) location loc = LOC(e); assert(e->kind == BoolOp_kind); if (e->v.BoolOp.op == And) - jumpi = JUMP_IF_FALSE_OR_POP; + jumpi = POP_JUMP_IF_FALSE; else - jumpi = JUMP_IF_TRUE_OR_POP; + jumpi = POP_JUMP_IF_TRUE; NEW_JUMP_TARGET_LABEL(c, end); s = e->v.BoolOp.values; n = asdl_seq_LEN(s) - 1; assert(n >= 0); for (i = 0; i < n; ++i) { VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); + ADDOP_I(c, loc, COPY, 1); ADDOP_JUMP(c, loc, jumpi, end); - NEW_JUMP_TARGET_LABEL(c, next); - - USE_LABEL(c, next); + ADDOP(c, loc, POP_TOP); } VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n)); @@ -4558,7 +4557,9 @@ compiler_compare(struct compiler *c, expr_ty e) ADDOP_I(c, loc, SWAP, 2); ADDOP_I(c, loc, COPY, 2); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, i)); - ADDOP_JUMP(c, loc, JUMP_IF_FALSE_OR_POP, cleanup); + ADDOP_I(c, loc, COPY, 1); + ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, cleanup); + ADDOP(c, loc, POP_TOP); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, n)); @@ -7836,21 +7837,6 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) { case POP_JUMP_IF_TRUE: reversed_opcode = POP_JUMP_IF_FALSE; break; - case JUMP_IF_TRUE_OR_POP: - case JUMP_IF_FALSE_OR_POP: - if (!is_forward) { - /* As far as we can tell, the compiler never emits - * these jumps with a backwards target. If/when this - * exception is raised, we have found a use case for - * a backwards version of this jump (or to replace - * it with the sequence (COPY 1, POP_JUMP_IF_T/F, POP) - */ - PyErr_Format(PyExc_SystemError, - "unexpected %s jumping backwards", - last->i_opcode == JUMP_IF_TRUE_OR_POP ? - "JUMP_IF_TRUE_OR_POP" : "JUMP_IF_FALSE_OR_POP"); - } - return SUCCESS; } if (is_forward) { return SUCCESS; @@ -9143,21 +9129,30 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) assert(PyList_CheckExact(consts)); struct cfg_instr nop; INSTR_SET_OP0(&nop, NOP); - struct cfg_instr *target; + struct cfg_instr *target = &nop; + int opcode = 0; + int oparg = 0; + int nextop = 0; for (int i = 0; i < bb->b_iused; i++) { struct cfg_instr *inst = &bb->b_instr[i]; - int oparg = inst->i_oparg; - int nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0; - if (HAS_TARGET(inst->i_opcode)) { - assert(inst->i_target->b_iused > 0); - target = &inst->i_target->b_instr[0]; - assert(!IS_ASSEMBLER_OPCODE(target->i_opcode)); - } - else { - target = &nop; + bool is_copy_of_load_const = (opcode == LOAD_CONST && + inst->i_opcode == COPY && + inst->i_oparg == 1); + if (! is_copy_of_load_const) { + opcode = inst->i_opcode; + oparg = inst->i_oparg; + if (HAS_TARGET(opcode)) { + assert(inst->i_target->b_iused > 0); + target = &inst->i_target->b_instr[0]; + assert(!IS_ASSEMBLER_OPCODE(target->i_opcode)); + } + else { + target = &nop; + } } - assert(!IS_ASSEMBLER_OPCODE(inst->i_opcode)); - switch (inst->i_opcode) { + nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0; + assert(!IS_ASSEMBLER_OPCODE(opcode)); + switch (opcode) { /* Remove LOAD_CONST const; conditional jump */ case LOAD_CONST: { @@ -9167,7 +9162,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) switch(nextop) { case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: - cnt = get_const_value(inst->i_opcode, oparg, consts); + cnt = get_const_value(opcode, oparg, consts); if (cnt == NULL) { goto error; } @@ -9185,28 +9180,8 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); } break; - case JUMP_IF_FALSE_OR_POP: - case JUMP_IF_TRUE_OR_POP: - cnt = get_const_value(inst->i_opcode, oparg, consts); - if (cnt == NULL) { - goto error; - } - is_true = PyObject_IsTrue(cnt); - Py_DECREF(cnt); - if (is_true == -1) { - goto error; - } - jump_if_true = nextop == JUMP_IF_TRUE_OR_POP; - if (is_true == jump_if_true) { - bb->b_instr[i+1].i_opcode = JUMP; - } - else { - INSTR_SET_OP0(inst, NOP); - INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); - } - break; case IS_OP: - cnt = get_const_value(inst->i_opcode, oparg, consts); + cnt = get_const_value(opcode, oparg, consts); if (cnt == NULL) { goto error; } @@ -9252,65 +9227,6 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) } } break; - - /* Simplify conditional jump to conditional jump where the - result of the first test implies the success of a similar - test or the failure of the opposite test. - Arises in code like: - "a and b or c" - "(a and b) and c" - "(a or b) or c" - "(a or b) and c" - x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z - --> x:JUMP_IF_FALSE_OR_POP z - x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z - --> x:POP_JUMP_IF_FALSE y+1 - where y+1 is the instruction following the second test. - */ - case JUMP_IF_FALSE_OR_POP: - switch (target->i_opcode) { - case POP_JUMP_IF_FALSE: - i -= jump_thread(inst, target, POP_JUMP_IF_FALSE); - break; - case JUMP: - case JUMP_IF_FALSE_OR_POP: - i -= jump_thread(inst, target, JUMP_IF_FALSE_OR_POP); - break; - case JUMP_IF_TRUE_OR_POP: - case POP_JUMP_IF_TRUE: - if (inst->i_loc.lineno == target->i_loc.lineno) { - // We don't need to bother checking for loops here, - // since a block's b_next cannot point to itself: - assert(inst->i_target != inst->i_target->b_next); - inst->i_opcode = POP_JUMP_IF_FALSE; - inst->i_target = inst->i_target->b_next; - --i; - } - break; - } - break; - case JUMP_IF_TRUE_OR_POP: - switch (target->i_opcode) { - case POP_JUMP_IF_TRUE: - i -= jump_thread(inst, target, POP_JUMP_IF_TRUE); - break; - case JUMP: - case JUMP_IF_TRUE_OR_POP: - i -= jump_thread(inst, target, JUMP_IF_TRUE_OR_POP); - break; - case JUMP_IF_FALSE_OR_POP: - case POP_JUMP_IF_FALSE: - if (inst->i_loc.lineno == target->i_loc.lineno) { - // We don't need to bother checking for loops here, - // since a block's b_next cannot point to itself: - assert(inst->i_target != inst->i_target->b_next); - inst->i_opcode = POP_JUMP_IF_TRUE; - inst->i_target = inst->i_target->b_next; - --i; - } - break; - } - break; case POP_JUMP_IF_NOT_NONE: case POP_JUMP_IF_NONE: switch (target->i_opcode) { @@ -9398,6 +9314,52 @@ inline_small_exit_blocks(basicblock *bb) { return 0; } + +static int +remove_redundant_nops_and_pairs(basicblock *entryblock) +{ + bool done = false; + + while (! done) { + done = true; + struct cfg_instr *prev_instr = NULL; + struct cfg_instr *instr = NULL; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + remove_redundant_nops(b); + if (IS_LABEL(b->b_label)) { + /* this block is a jump target, forget instr */ + instr = NULL; + } + for (int i = 0; i < b->b_iused; i++) { + prev_instr = instr; + instr = &b->b_instr[i]; + int prev_opcode = prev_instr ? prev_instr->i_opcode : 0; + int prev_oparg = prev_instr ? prev_instr->i_oparg : 0; + int opcode = instr->i_opcode; + bool is_redundant_pair = false; + if (opcode == POP_TOP) { + if (prev_opcode == LOAD_CONST) { + is_redundant_pair = true; + } + else if (prev_opcode == COPY && prev_oparg == 1) { + is_redundant_pair = true; + } + } + if (is_redundant_pair) { + INSTR_SET_OP0(prev_instr, NOP); + INSTR_SET_OP0(instr, NOP); + done = false; + } + } + if ((instr && is_jump(instr)) || !BB_HAS_FALLTHROUGH(b)) { + instr = NULL; + } + } + } + return SUCCESS; +} + + static int remove_redundant_nops(basicblock *bb) { /* Remove NOPs when legal to do so. */ @@ -9636,9 +9598,9 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache) assert(no_empty_basic_blocks(g)); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts)); - remove_redundant_nops(b); assert(b->b_predecessors == 0); } + RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock)); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { RETURN_IF_ERROR(inline_small_exit_blocks(b)); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e9f28b0abff4..c59042dad66c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2786,90 +2786,28 @@ DISPATCH(); } - TARGET(JUMP_IF_FALSE_OR_POP) { - PyObject *cond = stack_pointer[-1]; - #line 1922 "Python/bytecodes.c" - bool jump = false; - int err; - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsFalse(cond)) { - JUMPBY(oparg); - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - Py_DECREF(cond); - } - else if (err == 0) { - JUMPBY(oparg); - jump = true; - } - else { - goto error; - } - } - #line 2815 "Python/generated_cases.c.h" - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); - DISPATCH(); - } - - TARGET(JUMP_IF_TRUE_OR_POP) { - PyObject *cond = stack_pointer[-1]; - #line 1947 "Python/bytecodes.c" - bool jump = false; - int err; - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsTrue(cond)) { - JUMPBY(oparg); - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - JUMPBY(oparg); - jump = true; - } - else if (err == 0) { - Py_DECREF(cond); - } - else { - goto error; - } - } - #line 2846 "Python/generated_cases.c.h" - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); - DISPATCH(); - } - TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 1972 "Python/bytecodes.c" + #line 1922 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 2860 "Python/generated_cases.c.h" + #line 2798 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 1981 "Python/bytecodes.c" + #line 1931 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 2873 "Python/generated_cases.c.h" + #line 2811 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2880,16 +2818,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 1989 "Python/bytecodes.c" + #line 1939 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 2889 "Python/generated_cases.c.h" + #line 2827 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 1994 "Python/bytecodes.c" + #line 1944 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2897,7 +2835,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 2901 "Python/generated_cases.c.h" + #line 2839 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -2906,10 +2844,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2004 "Python/bytecodes.c" + #line 1954 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 2913 "Python/generated_cases.c.h" + #line 2851 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2919,10 +2857,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2010 "Python/bytecodes.c" + #line 1960 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 2926 "Python/generated_cases.c.h" + #line 2864 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2933,11 +2871,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2016 "Python/bytecodes.c" + #line 1966 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 2941 "Python/generated_cases.c.h" + #line 2879 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -2946,14 +2884,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2022 "Python/bytecodes.c" + #line 1972 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 2953 "Python/generated_cases.c.h" + #line 2891 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2025 "Python/bytecodes.c" + #line 1975 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 2957 "Python/generated_cases.c.h" + #line 2895 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -2961,7 +2899,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2029 "Python/bytecodes.c" + #line 1979 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2984,11 +2922,11 @@ if (iter == NULL) { goto error; } - #line 2988 "Python/generated_cases.c.h" + #line 2926 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2052 "Python/bytecodes.c" + #line 2002 "Python/bytecodes.c" } - #line 2992 "Python/generated_cases.c.h" + #line 2930 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -2999,7 +2937,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2071 "Python/bytecodes.c" + #line 2021 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3032,7 +2970,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3036 "Python/generated_cases.c.h" + #line 2974 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3042,7 +2980,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2106 "Python/bytecodes.c" + #line 2056 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -3063,7 +3001,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3067 "Python/generated_cases.c.h" + #line 3005 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3073,7 +3011,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2129 "Python/bytecodes.c" + #line 2079 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -3094,7 +3032,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3098 "Python/generated_cases.c.h" + #line 3036 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3104,7 +3042,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2152 "Python/bytecodes.c" + #line 2102 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -3123,7 +3061,7 @@ if (next == NULL) { goto error; } - #line 3127 "Python/generated_cases.c.h" + #line 3065 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3132,7 +3070,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2173 "Python/bytecodes.c" + #line 2123 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3147,14 +3085,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); assert(next_instr->op.code == END_FOR); DISPATCH_INLINED(gen_frame); - #line 3151 "Python/generated_cases.c.h" + #line 3089 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2190 "Python/bytecodes.c" + #line 2140 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3177,16 +3115,16 @@ Py_DECREF(enter); goto error; } - #line 3181 "Python/generated_cases.c.h" + #line 3119 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2213 "Python/bytecodes.c" + #line 2163 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3190 "Python/generated_cases.c.h" + #line 3128 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3198,7 +3136,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2223 "Python/bytecodes.c" + #line 2173 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3224,16 +3162,16 @@ Py_DECREF(enter); goto error; } - #line 3228 "Python/generated_cases.c.h" + #line 3166 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2249 "Python/bytecodes.c" + #line 2199 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3237 "Python/generated_cases.c.h" + #line 3175 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3245,7 +3183,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2258 "Python/bytecodes.c" + #line 2208 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3266,7 +3204,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3270 "Python/generated_cases.c.h" + #line 3208 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3275,7 +3213,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2281 "Python/bytecodes.c" + #line 2231 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3285,7 +3223,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3289 "Python/generated_cases.c.h" + #line 3227 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3299,7 +3237,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2293 "Python/bytecodes.c" + #line 2243 "Python/bytecodes.c" /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -3317,7 +3255,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3321 "Python/generated_cases.c.h" + #line 3259 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3331,7 +3269,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2313 "Python/bytecodes.c" + #line 2263 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3342,7 +3280,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3346 "Python/generated_cases.c.h" + #line 3284 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3356,7 +3294,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2326 "Python/bytecodes.c" + #line 2276 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3371,7 +3309,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3375 "Python/generated_cases.c.h" + #line 3313 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3380,11 +3318,11 @@ } TARGET(KW_NAMES) { - #line 2343 "Python/bytecodes.c" + #line 2293 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3388 "Python/generated_cases.c.h" + #line 3326 "Python/generated_cases.c.h" DISPATCH(); } @@ -3395,7 +3333,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2379 "Python/bytecodes.c" + #line 2329 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3467,7 +3405,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3471 "Python/generated_cases.c.h" + #line 3409 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3479,7 +3417,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2457 "Python/bytecodes.c" + #line 2407 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3489,7 +3427,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3493 "Python/generated_cases.c.h" + #line 3431 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3498,7 +3436,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2469 "Python/bytecodes.c" + #line 2419 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3523,7 +3461,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3527 "Python/generated_cases.c.h" + #line 3465 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3532,7 +3470,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); uint16_t min_args = read_u16(&next_instr[3].cache); - #line 2496 "Python/bytecodes.c" + #line 2446 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3562,7 +3500,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3566 "Python/generated_cases.c.h" + #line 3504 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3570,7 +3508,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2528 "Python/bytecodes.c" + #line 2478 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3581,7 +3519,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3585 "Python/generated_cases.c.h" + #line 3523 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3594,7 +3532,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2541 "Python/bytecodes.c" + #line 2491 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3606,7 +3544,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3610 "Python/generated_cases.c.h" + #line 3548 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3620,7 +3558,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2556 "Python/bytecodes.c" + #line 2506 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3631,7 +3569,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3635 "Python/generated_cases.c.h" + #line 3573 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3645,7 +3583,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2570 "Python/bytecodes.c" + #line 2520 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3667,7 +3605,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3671 "Python/generated_cases.c.h" + #line 3609 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3681,7 +3619,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2595 "Python/bytecodes.c" + #line 2545 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3710,7 +3648,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3714 "Python/generated_cases.c.h" + #line 3652 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3724,7 +3662,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2627 "Python/bytecodes.c" + #line 2577 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3757,7 +3695,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3761 "Python/generated_cases.c.h" + #line 3699 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3771,7 +3709,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2663 "Python/bytecodes.c" + #line 2613 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3804,7 +3742,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3808 "Python/generated_cases.c.h" + #line 3746 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3818,7 +3756,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2699 "Python/bytecodes.c" + #line 2649 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3844,7 +3782,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3848 "Python/generated_cases.c.h" + #line 3786 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3857,7 +3795,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2727 "Python/bytecodes.c" + #line 2677 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3885,7 +3823,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3889 "Python/generated_cases.c.h" + #line 3827 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3897,7 +3835,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2758 "Python/bytecodes.c" + #line 2708 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3916,14 +3854,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 3920 "Python/generated_cases.c.h" + #line 3858 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2779 "Python/bytecodes.c" + #line 2729 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3954,7 +3892,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3958 "Python/generated_cases.c.h" + #line 3896 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3967,7 +3905,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2813 "Python/bytecodes.c" + #line 2763 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3996,7 +3934,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4000 "Python/generated_cases.c.h" + #line 3938 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4009,7 +3947,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2845 "Python/bytecodes.c" + #line 2795 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4038,7 +3976,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4042 "Python/generated_cases.c.h" + #line 3980 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4051,7 +3989,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2877 "Python/bytecodes.c" + #line 2827 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4079,7 +4017,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4083 "Python/generated_cases.c.h" + #line 4021 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4094,7 +4032,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 2908 "Python/bytecodes.c" + #line 2858 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -4113,15 +4051,15 @@ assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - #line 4117 "Python/generated_cases.c.h" + #line 4055 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 2927 "Python/bytecodes.c" + #line 2877 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4125 "Python/generated_cases.c.h" + #line 4063 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4136,7 +4074,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 2938 "Python/bytecodes.c" + #line 2888 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4165,14 +4103,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4169 "Python/generated_cases.c.h" + #line 4107 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 2969 "Python/bytecodes.c" + #line 2919 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4193,7 +4131,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4197 "Python/generated_cases.c.h" + #line 4135 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4201,15 +4139,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 2992 "Python/bytecodes.c" + #line 2942 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4207 "Python/generated_cases.c.h" + #line 4145 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 2994 "Python/bytecodes.c" + #line 2944 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4213 "Python/generated_cases.c.h" + #line 4151 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4220,7 +4158,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 2998 "Python/bytecodes.c" + #line 2948 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4255,7 +4193,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4259 "Python/generated_cases.c.h" + #line 4197 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4264,10 +4202,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3035 "Python/bytecodes.c" + #line 2985 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4271 "Python/generated_cases.c.h" + #line 4209 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4279,7 +4217,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3040 "Python/bytecodes.c" + #line 2990 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4295,12 +4233,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4299 "Python/generated_cases.c.h" + #line 4237 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3056 "Python/bytecodes.c" + #line 3006 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4304 "Python/generated_cases.c.h" + #line 4242 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4310,27 +4248,27 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3061 "Python/bytecodes.c" + #line 3011 "Python/bytecodes.c" assert(oparg >= 2); - #line 4316 "Python/generated_cases.c.h" + #line 4254 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3065 "Python/bytecodes.c" + #line 3015 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4330 "Python/generated_cases.c.h" + #line 4268 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3074 "Python/bytecodes.c" + #line 3024 "Python/bytecodes.c" Py_UNREACHABLE(); - #line 4336 "Python/generated_cases.c.h" + #line 4274 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index ee760ab78af2..920b7595484d 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -247,10 +247,6 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case POP_JUMP_IF_NONE: return 1; - case JUMP_IF_FALSE_OR_POP: - return 1; - case JUMP_IF_TRUE_OR_POP: - return 1; case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -599,10 +595,6 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case POP_JUMP_IF_NONE: return 0; - case JUMP_IF_FALSE_OR_POP: - return (jump ? 1 : 0); - case JUMP_IF_TRUE_OR_POP: - return (jump ? 1 : 0); case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -836,8 +828,6 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB }, [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, - [JUMP_IF_FALSE_OR_POP] = { true, INSTR_FMT_IB }, - [JUMP_IF_TRUE_OR_POP] = { true, INSTR_FMT_IB }, [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB }, [GET_LEN] = { true, INSTR_FMT_IX }, [MATCH_CLASS] = { true, INSTR_FMT_IB }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index bc64bd582fd5..52f23ce7752e 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, - &&TARGET_JUMP_IF_FALSE_OR_POP, - &&TARGET_JUMP_IF_TRUE_OR_POP, &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_STORE_SUBSCR_DICT, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -142,7 +142,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_COMPARE_AND_BRANCH, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,15 +152,15 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_SUBSCR_DICT, - &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_UNPACK_SEQUENCE_LIST, - &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, + &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, From webhook-mailer at python.org Wed Mar 22 14:14:13 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 22 Mar 2023 18:14:13 -0000 Subject: [Python-checkins] gh-102921: [doc] Clarify `exc` argument name in `BaseExceptionGroup` is plural (#102922) Message-ID: https://github.com/python/cpython/commit/9b19d3936d7cabef67698636d2faf6fa23a95059 commit: 9b19d3936d7cabef67698636d2faf6fa23a95059 branch: main author: Kevin Kirsche committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-22T18:14:05Z summary: gh-102921: [doc] Clarify `exc` argument name in `BaseExceptionGroup` is plural (#102922) files: M Doc/library/exceptions.rst diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 4a57e9c87993..18c3f47dddc0 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -948,8 +948,8 @@ their subgroups based on the types of the contained exceptions. these fields do not need to be updated by :meth:`derive`. :: >>> class MyGroup(ExceptionGroup): - ... def derive(self, exc): - ... return MyGroup(self.message, exc) + ... def derive(self, excs): + ... return MyGroup(self.message, excs) ... >>> e = MyGroup("eg", [ValueError(1), TypeError(2)]) >>> e.add_note("a note") From webhook-mailer at python.org Wed Mar 22 14:22:08 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 18:22:08 -0000 Subject: [Python-checkins] gh-102921: [doc] Clarify `exc` argument name in `BaseExceptionGroup` is plural (GH-102922) Message-ID: https://github.com/python/cpython/commit/f1b96737a4e42c96141927b2ea3976eb84557ed6 commit: f1b96737a4e42c96141927b2ea3976eb84557ed6 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T11:21:59-07:00 summary: gh-102921: [doc] Clarify `exc` argument name in `BaseExceptionGroup` is plural (GH-102922) (cherry picked from commit 9b19d3936d7cabef67698636d2faf6fa23a95059) Co-authored-by: Kevin Kirsche files: M Doc/library/exceptions.rst diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 4a57e9c87993..18c3f47dddc0 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -948,8 +948,8 @@ their subgroups based on the types of the contained exceptions. these fields do not need to be updated by :meth:`derive`. :: >>> class MyGroup(ExceptionGroup): - ... def derive(self, exc): - ... return MyGroup(self.message, exc) + ... def derive(self, excs): + ... return MyGroup(self.message, excs) ... >>> e = MyGroup("eg", [ValueError(1), TypeError(2)]) >>> e.add_note("a note") From webhook-mailer at python.org Wed Mar 22 14:23:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 18:23:56 -0000 Subject: [Python-checkins] gh-102780: Fix uncancel() call in asyncio timeouts (GH-102815) Message-ID: https://github.com/python/cpython/commit/a9ece4a8392768b4ab35253101f628ec61956646 commit: a9ece4a8392768b4ab35253101f628ec61956646 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T11:23:47-07:00 summary: gh-102780: Fix uncancel() call in asyncio timeouts (GH-102815) Also use `raise TimeOut from ` so that the CancelledError is set in the `__cause__` field rather than in the `__context__` field. (cherry picked from commit 04adf2df395ded81922c71360a5d66b597471e49) Co-authored-by: Kristj?n Valur J?nsson Co-authored-by: Guido van Rossum Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst M Doc/library/asyncio-task.rst M Lib/asyncio/timeouts.py M Lib/test/test_asyncio/test_timeouts.py diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index c15d719ff332..5fb8776c3db3 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -300,13 +300,17 @@ in the task at the next opportunity. It is recommended that coroutines use ``try/finally`` blocks to robustly perform clean-up logic. In case :exc:`asyncio.CancelledError` is explicitly caught, it should generally be propagated when -clean-up is complete. Most code can safely ignore :exc:`asyncio.CancelledError`. +clean-up is complete. :exc:`asyncio.CancelledError` directly subclasses +:exc:`BaseException` so most code will not need to be aware of it. The asyncio components that enable structured concurrency, like :class:`asyncio.TaskGroup` and :func:`asyncio.timeout`, are implemented using cancellation internally and might misbehave if a coroutine swallows :exc:`asyncio.CancelledError`. Similarly, user code -should not call :meth:`uncancel `. +should not generally call :meth:`uncancel `. +However, in cases when suppressing :exc:`asyncio.CancelledError` is +truly desired, it is necessary to also call ``uncancel()`` to completely +remove the cancellation state. .. _taskgroups: @@ -1137,7 +1141,9 @@ Task Object Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does not guarantee that the Task will be cancelled, although suppressing cancellation completely is not common and is actively - discouraged. + discouraged. Should the coroutine nevertheless decide to suppress + the cancellation, it needs to call :meth:`Task.uncancel` in addition + to catching the exception. .. versionchanged:: 3.9 Added the *msg* parameter. @@ -1227,6 +1233,10 @@ Task Object with :meth:`uncancel`. :class:`TaskGroup` context managers use :func:`uncancel` in a similar fashion. + If end-user code is, for some reason, suppresing cancellation by + catching :exc:`CancelledError`, it needs to call this method to remove + the cancellation state. + .. method:: cancelling() Return the number of pending cancellation requests to this Task, i.e., diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py index d07b291005e8..029c468739bf 100644 --- a/Lib/asyncio/timeouts.py +++ b/Lib/asyncio/timeouts.py @@ -84,6 +84,7 @@ def __repr__(self) -> str: async def __aenter__(self) -> "Timeout": self._state = _State.ENTERED self._task = tasks.current_task() + self._cancelling = self._task.cancelling() if self._task is None: raise RuntimeError("Timeout should be used inside a task") self.reschedule(self._when) @@ -104,10 +105,10 @@ async def __aexit__( if self._state is _State.EXPIRING: self._state = _State.EXPIRED - if self._task.uncancel() == 0 and exc_type is exceptions.CancelledError: - # Since there are no outstanding cancel requests, we're + if self._task.uncancel() <= self._cancelling and exc_type is exceptions.CancelledError: + # Since there are no new cancel requests, we're # handling this. - raise TimeoutError + raise TimeoutError from exc_val elif self._state is _State.ENTERED: self._state = _State.EXITED diff --git a/Lib/test/test_asyncio/test_timeouts.py b/Lib/test/test_asyncio/test_timeouts.py index 3a54297050f1..cc8feb8d0c1a 100644 --- a/Lib/test/test_asyncio/test_timeouts.py +++ b/Lib/test/test_asyncio/test_timeouts.py @@ -248,6 +248,36 @@ async def test_nested_timeout_in_finally(self): async with asyncio.timeout(0.01): await asyncio.sleep(10) + async def test_timeout_after_cancellation(self): + try: + asyncio.current_task().cancel() + await asyncio.sleep(1) # work which will be cancelled + except asyncio.CancelledError: + pass + finally: + with self.assertRaises(TimeoutError): + async with asyncio.timeout(0.0): + await asyncio.sleep(1) # some cleanup + + async def test_cancel_in_timeout_after_cancellation(self): + try: + asyncio.current_task().cancel() + await asyncio.sleep(1) # work which will be cancelled + except asyncio.CancelledError: + pass + finally: + with self.assertRaises(asyncio.CancelledError): + async with asyncio.timeout(1.0): + asyncio.current_task().cancel() + await asyncio.sleep(2) # some cleanup + + async def test_timeout_exception_cause (self): + with self.assertRaises(asyncio.TimeoutError) as exc: + async with asyncio.timeout(0): + await asyncio.sleep(1) + cause = exc.exception.__cause__ + assert isinstance(cause, asyncio.CancelledError) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst b/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst new file mode 100644 index 000000000000..2aaffe34b864 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst @@ -0,0 +1,3 @@ +The :class:`asyncio.Timeout` context manager now works reliably even when performing cleanup due +to task cancellation. Previously it could raise a +:exc:`~asyncio.CancelledError` instead of an :exc:`~asyncio.TimeoutError` in such cases. From webhook-mailer at python.org Wed Mar 22 14:43:49 2023 From: webhook-mailer at python.org (iritkatriel) Date: Wed, 22 Mar 2023 18:43:49 -0000 Subject: [Python-checkins] [doc] Fix error in tutorial example: type(exc) is the type rather than the instance (#102751) Message-ID: https://github.com/python/cpython/commit/8709697292c67254ba836d7e88d1eba08c4a351a commit: 8709697292c67254ba836d7e88d1eba08c4a351a branch: main author: Jens-Hilmar Bradt <17177271+jenshb at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-22T18:43:41Z summary: [doc] Fix error in tutorial example: type(exc) is the type rather than the instance (#102751) files: M Doc/tutorial/errors.rst diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index e09c829b8e97..ca5dc3314c63 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -160,7 +160,7 @@ accessing ``.args``. :: >>> try: ... raise Exception('spam', 'eggs') ... except Exception as inst: - ... print(type(inst)) # the exception instance + ... print(type(inst)) # the exception type ... print(inst.args) # arguments stored in .args ... print(inst) # __str__ allows args to be printed directly, ... # but may be overridden in exception subclasses From webhook-mailer at python.org Wed Mar 22 14:51:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 22 Mar 2023 18:51:56 -0000 Subject: [Python-checkins] [doc] Fix error in tutorial example: type(exc) is the type rather than the instance (GH-102751) Message-ID: https://github.com/python/cpython/commit/f79cfb662589a0c1a5fdb35a5ed429c07c93ebd6 commit: f79cfb662589a0c1a5fdb35a5ed429c07c93ebd6 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-22T11:51:48-07:00 summary: [doc] Fix error in tutorial example: type(exc) is the type rather than the instance (GH-102751) (cherry picked from commit 8709697292c67254ba836d7e88d1eba08c4a351a) Co-authored-by: Jens-Hilmar Bradt <17177271+jenshb at users.noreply.github.com> files: M Doc/tutorial/errors.rst diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index e09c829b8e97..ca5dc3314c63 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -160,7 +160,7 @@ accessing ``.args``. :: >>> try: ... raise Exception('spam', 'eggs') ... except Exception as inst: - ... print(type(inst)) # the exception instance + ... print(type(inst)) # the exception type ... print(inst.args) # arguments stored in .args ... print(inst) # __str__ allows args to be printed directly, ... # but may be overridden in exception subclasses From webhook-mailer at python.org Wed Mar 22 20:30:12 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Thu, 23 Mar 2023 00:30:12 -0000 Subject: [Python-checkins] gh-100227: Make the Global Interned Dict Safe for Isolated Interpreters (gh-102925) Message-ID: https://github.com/python/cpython/commit/87be8d95228ee95de9045cf2952311d20dc5de45 commit: 87be8d95228ee95de9045cf2952311d20dc5de45 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-22T18:30:04-06:00 summary: gh-100227: Make the Global Interned Dict Safe for Isolated Interpreters (gh-102925) This is effectively two changes. The first (the bulk of the change) is where we add _Py_AddToGlobalDict() (and _PyRuntime.cached_objects.main_tstate, etc.). The second (much smaller) change is where we update PyUnicode_InternInPlace() to use _Py_AddToGlobalDict() instead of calling PyDict_SetDefault() directly. Basically, _Py_AddToGlobalDict() is a wrapper around PyDict_SetDefault() that should be used whenever we need to add a value to a runtime-global dict object (in the few cases where we are leaving the container global rather than moving it to PyInterpreterState, e.g. the interned strings dict). _Py_AddToGlobalDict() does all the necessary work to make sure the target global dict is shared safely between isolated interpreters. This is especially important as we move the obmalloc state to each interpreter (gh-101660), as well as, potentially, the GIL (PEP 684). https://github.com/python/cpython/issues/100227 files: M Include/internal/pycore_global_objects.h M Include/internal/pycore_pystate.h M Include/internal/pycore_runtime_init.h M Include/internal/pycore_unicodeobject.h M Objects/unicodeobject.c M Python/pylifecycle.c M Python/pystate.c diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 9957da1fc5f2..858321d67df4 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -28,6 +28,10 @@ extern "C" { struct _Py_cached_objects { PyObject *interned_strings; + /* A thread state tied to the main interpreter, + used exclusively for when a global object (e.g. interned strings) + is resized (i.e. deallocated + allocated) from an arbitrary thread. */ + PyThreadState main_tstate; }; #define _Py_GLOBAL_OBJECT(NAME) \ diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 7046ec8d9ada..f159b516e66b 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -127,6 +127,11 @@ PyAPI_FUNC(void) _PyThreadState_Init( PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); +extern void _PyThreadState_InitDetached(PyThreadState *, PyInterpreterState *); +extern void _PyThreadState_ClearDetached(PyThreadState *); + +extern PyObject * _Py_AddToGlobalDict(PyObject *, PyObject *, PyObject *); + static inline void _PyThreadState_UpdateTracingState(PyThreadState *tstate) diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 7cfa7c0c0249..fd358b2da6cc 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -59,6 +59,9 @@ extern PyTypeObject _PyExc_MemoryError; .types = { \ .next_version_tag = 1, \ }, \ + .cached_objects = { \ + .main_tstate = _PyThreadState_INIT, \ + }, \ .static_objects = { \ .singletons = { \ .small_ints = _Py_small_ints_INIT, \ diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 19faceebf1d8..ed4feb603d6f 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -34,6 +34,7 @@ struct _Py_unicode_runtime_ids { struct _Py_unicode_runtime_state { struct _Py_unicode_runtime_ids ids; + /* The interned dict is at _PyRuntime.cached_objects.interned_strings. */ }; /* fs_codec.encoding is initialized to NULL. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index b9fb53147b9b..891a65576ee2 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14609,16 +14609,11 @@ PyUnicode_InternInPlace(PyObject **p) } PyObject *interned = get_interned_dict(); - assert(interned != NULL); - - PyObject *t = PyDict_SetDefault(interned, s, s); - if (t == NULL) { - PyErr_Clear(); - return; - } - + PyObject *t = _Py_AddToGlobalDict(interned, s, s); if (t != s) { - Py_SETREF(*p, Py_NewRef(t)); + if (t != NULL) { + Py_SETREF(*p, Py_NewRef(t)); + } return; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 8110d94ba175..5d7f86218330 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -636,6 +636,8 @@ pycore_create_interpreter(_PyRuntimeState *runtime, return status; } + _PyThreadState_InitDetached(&runtime->cached_objects.main_tstate, interp); + *tstate_p = tstate; return _PyStatus_OK(); } @@ -1932,6 +1934,8 @@ Py_FinalizeEx(void) // XXX Do this sooner during finalization. // XXX Ensure finalizer errors are handled properly. + _PyThreadState_ClearDetached(&runtime->cached_objects.main_tstate); + finalize_interp_clear(tstate); finalize_interp_delete(tstate->interp); diff --git a/Python/pystate.c b/Python/pystate.c index b17efdbefd12..394b12d24065 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -565,6 +565,124 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) #endif +//--------------- +// global objects +//--------------- + +/* The global objects thread state is meant to be used in a very limited + way and should not be used to actually run any Python code. */ + +static PyThreadState * +bind_global_objects_state(_PyRuntimeState *runtime) +{ + PyThreadState *main_tstate = &runtime->cached_objects.main_tstate; + + bind_tstate(main_tstate); + /* Unlike _PyThreadState_Bind(), we do not modify gilstate TSS. */ + + return main_tstate; +} + +static void +unbind_global_objects_state(_PyRuntimeState *runtime) +{ + PyThreadState *main_tstate = &runtime->cached_objects.main_tstate; + assert(tstate_is_alive(main_tstate)); + assert(!main_tstate->_status.active); + assert(gilstate_tss_get(runtime) != main_tstate); + + unbind_tstate(main_tstate); + + /* This thread state may be bound/unbound repeatedly, + so we must erase evidence that it was ever bound (or unbound). */ + main_tstate->_status.bound = 0; + main_tstate->_status.unbound = 0; + + /* We must fully unlink the thread state from any OS thread, + to allow it to be bound more than once. */ + main_tstate->thread_id = 0; +#ifdef PY_HAVE_THREAD_NATIVE_ID + main_tstate->native_thread_id = 0; +#endif +} + +static inline void +acquire_global_objects_lock(_PyRuntimeState *runtime) +{ + /* For now we can rely on the GIL, so we don't actually + acquire a global lock here. */ + assert(current_fast_get(runtime) != NULL); +} + +static inline void +release_global_objects_lock(_PyRuntimeState *runtime) +{ + /* For now we can rely on the GIL, so we don't actually + release a global lock here. */ + assert(current_fast_get(runtime) != NULL); +} + +PyObject * +_Py_AddToGlobalDict(PyObject *dict, PyObject *key, PyObject *value) +{ + assert(dict != NULL); + assert(PyDict_CheckExact(dict)); + + /* All global objects are stored in _PyRuntime + and owned by the main interpreter. */ + _PyRuntimeState *runtime = &_PyRuntime; + PyThreadState *curts = current_fast_get(runtime); + PyInterpreterState *interp = curts->interp; + assert(interp != NULL); // The GIL must be held. + + /* Due to interpreter isolation we must hold a global lock, + starting at this point and ending before we return. + Note that the operations in this function are very fucused + and we should not expect any reentrancy. */ + acquire_global_objects_lock(runtime); + + /* Swap to the main interpreter, if necessary. */ + PyThreadState *oldts = NULL; + if (!_Py_IsMainInterpreter(interp)) { + PyThreadState *main_tstate = bind_global_objects_state(runtime); + + oldts = _PyThreadState_Swap(runtime, main_tstate); + assert(oldts != NULL); + assert(!_Py_IsMainInterpreter(oldts->interp)); + + /* The limitations of the global objects thread state apply + from this point to the point we swap back to oldts. */ + } + + /* This might trigger a resize, which is why we must "acquire" + the global object state. Also note that PyDict_SetDefault() + must be compatible with our reentrancy and global objects state + constraints. */ + PyObject *actual = PyDict_SetDefault(dict, key, value); + if (actual == NULL) { + /* Raising an exception from one interpreter in another + is problematic, so we clear it and let the caller deal + with the returned NULL. */ + assert(PyErr_ExceptionMatches(PyExc_MemoryError)); + PyErr_Clear(); + } + + /* Swap back, it it wasn't in the main interpreter already. */ + if (oldts != NULL) { + // The returned tstate should be _PyRuntime.cached_objects.main_tstate. + _PyThreadState_Swap(runtime, oldts); + + unbind_global_objects_state(runtime); + } + + release_global_objects_lock(runtime); + + // XXX Immortalize the key and value. + + return actual; +} + + /*************************************/ /* the per-interpreter runtime state */ /*************************************/ @@ -1217,8 +1335,7 @@ free_threadstate(PyThreadState *tstate) static void init_threadstate(PyThreadState *tstate, - PyInterpreterState *interp, uint64_t id, - PyThreadState *next) + PyInterpreterState *interp, uint64_t id) { if (tstate->_status.initialized) { Py_FatalError("thread state already initialized"); @@ -1227,18 +1344,13 @@ init_threadstate(PyThreadState *tstate, assert(interp != NULL); tstate->interp = interp; + // next/prev are set in add_threadstate(). + assert(tstate->next == NULL); + assert(tstate->prev == NULL); + assert(id > 0); tstate->id = id; - assert(interp->threads.head == tstate); - assert((next != NULL && id != 1) || (next == NULL && id == 1)); - if (next != NULL) { - assert(next->prev == NULL || next->prev == tstate); - next->prev = tstate; - } - tstate->next = next; - assert(tstate->prev == NULL); - // thread_id and native_thread_id are set in bind_tstate(). tstate->py_recursion_limit = interp->ceval.recursion_limit, @@ -1259,6 +1371,22 @@ init_threadstate(PyThreadState *tstate, tstate->_status.initialized = 1; } +static void +add_threadstate(PyInterpreterState *interp, PyThreadState *tstate, + PyThreadState *next) +{ + assert(interp->threads.head != tstate); + assert((next != NULL && tstate->id != 1) || + (next == NULL && tstate->id == 1)); + if (next != NULL) { + assert(next->prev == NULL || next->prev == tstate); + next->prev = tstate; + } + tstate->next = next; + assert(tstate->prev == NULL); + interp->threads.head = tstate; +} + static PyThreadState * new_threadstate(PyInterpreterState *interp) { @@ -1298,9 +1426,9 @@ new_threadstate(PyInterpreterState *interp) &initial._main_interpreter._initial_thread, sizeof(*tstate)); } - interp->threads.head = tstate; - init_threadstate(tstate, interp, id, old_head); + init_threadstate(tstate, interp, id); + add_threadstate(interp, tstate, old_head); HEAD_UNLOCK(runtime); if (!used_newtstate) { @@ -1347,6 +1475,33 @@ _PyThreadState_Init(PyThreadState *tstate) Py_FatalError("_PyThreadState_Init() is for internal use only"); } +void +_PyThreadState_InitDetached(PyThreadState *tstate, PyInterpreterState *interp) +{ + _PyRuntimeState *runtime = interp->runtime; + + HEAD_LOCK(runtime); + interp->threads.next_unique_id += 1; + uint64_t id = interp->threads.next_unique_id; + HEAD_UNLOCK(runtime); + + init_threadstate(tstate, interp, id); + // We do not call add_threadstate(). +} + + +static void +clear_datastack(PyThreadState *tstate) +{ + _PyStackChunk *chunk = tstate->datastack_chunk; + tstate->datastack_chunk = NULL; + while (chunk != NULL) { + _PyStackChunk *prev = chunk->previous; + _PyObject_VirtualFree(chunk, chunk->size); + chunk = prev; + } +} + void PyThreadState_Clear(PyThreadState *tstate) { @@ -1421,7 +1576,6 @@ PyThreadState_Clear(PyThreadState *tstate) // XXX Do it as early in the function as possible. } - /* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */ static void tstate_delete_common(PyThreadState *tstate) @@ -1454,17 +1608,25 @@ tstate_delete_common(PyThreadState *tstate) unbind_tstate(tstate); // XXX Move to PyThreadState_Clear()? - _PyStackChunk *chunk = tstate->datastack_chunk; - tstate->datastack_chunk = NULL; - while (chunk != NULL) { - _PyStackChunk *prev = chunk->previous; - _PyObject_VirtualFree(chunk, chunk->size); - chunk = prev; - } + clear_datastack(tstate); tstate->_status.finalized = 1; } +void +_PyThreadState_ClearDetached(PyThreadState *tstate) +{ + assert(!tstate->_status.bound); + assert(!tstate->_status.bound_gilstate); + assert(tstate->datastack_chunk == NULL); + assert(tstate->thread_id == 0); + assert(tstate->native_thread_id == 0); + assert(tstate->next == NULL); + assert(tstate->prev == NULL); + + PyThreadState_Clear(tstate); + clear_datastack(tstate); +} static void zapthreads(PyInterpreterState *interp) From webhook-mailer at python.org Thu Mar 23 06:37:29 2023 From: webhook-mailer at python.org (markshannon) Date: Thu, 23 Mar 2023 10:37:29 -0000 Subject: [Python-checkins] gh-102939: Fix "conversion from Py_ssize_t to long" warning in builtins (GH-102940) Message-ID: https://github.com/python/cpython/commit/0f2ba6580565c3b51396c840406211ad81297735 commit: 0f2ba6580565c3b51396c840406211ad81297735 branch: main author: Nikita Sobolev committer: markshannon date: 2023-03-23T10:37:04Z summary: gh-102939: Fix "conversion from Py_ssize_t to long" warning in builtins (GH-102940) files: M Python/bltinmodule.c diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 55fd364d0079..fcb4d7a9a975 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2503,7 +2503,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) Py_DECREF(iter); if (PyErr_Occurred()) return NULL; - return PyLong_FromLong(i_result); + return PyLong_FromSsize_t(i_result); } if (PyLong_CheckExact(item) || PyBool_Check(item)) { Py_ssize_t b; @@ -2525,7 +2525,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) } } /* Either overflowed or is not an int. Restore real objects and process normally */ - result = PyLong_FromLong(i_result); + result = PyLong_FromSsize_t(i_result); if (result == NULL) { Py_DECREF(item); Py_DECREF(iter); From webhook-mailer at python.org Thu Mar 23 09:22:15 2023 From: webhook-mailer at python.org (erlend-aasland) Date: Thu, 23 Mar 2023 13:22:15 -0000 Subject: [Python-checkins] Docs: fixup incorrect escape char in sqlite3 docs (#102945) Message-ID: https://github.com/python/cpython/commit/08254be6c5324416081cc28a047b377e1f4ed644 commit: 08254be6c5324416081cc28a047b377e1f4ed644 branch: main author: Erlend E. Aasland committer: erlend-aasland date: 2023-03-23T14:21:32+01:00 summary: Docs: fixup incorrect escape char in sqlite3 docs (#102945) files: M Doc/library/sqlite3.rst diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 4b2d13ab3a8f..51146e009996 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -259,7 +259,7 @@ Module functions .. function:: connect(database, timeout=5.0, detect_types=0, \ isolation_level="DEFERRED", check_same_thread=True, \ factory=sqlite3.Connection, cached_statements=128, \ - uri=False, \*, \ + uri=False, *, \ autocommit=sqlite3.LEGACY_TRANSACTION_CONTROL) Open a connection to an SQLite database. From webhook-mailer at python.org Thu Mar 23 10:18:04 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 23 Mar 2023 14:18:04 -0000 Subject: [Python-checkins] gh-102947: Improve traceback when calling `fields()` on a non-dataclass (#102948) Message-ID: https://github.com/python/cpython/commit/baf4eb083c09b323cc12b8636c28c14089b87de8 commit: baf4eb083c09b323cc12b8636c28c14089b87de8 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-03-23T14:17:54Z summary: gh-102947: Improve traceback when calling `fields()` on a non-dataclass (#102948) files: A Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 82b08fc01788..e3fd0b3e380d 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1248,7 +1248,7 @@ def fields(class_or_instance): try: fields = getattr(class_or_instance, _FIELDS) except AttributeError: - raise TypeError('must be called with a dataclass type or instance') + raise TypeError('must be called with a dataclass type or instance') from None # Exclude pseudo-fields. Note that fields is sorted by insertion # order, so the order of the tuple is as the fields were defined. diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 46f33043c270..affd9cede19c 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -5,11 +5,13 @@ from dataclasses import * import abc +import io import pickle import inspect import builtins import types import weakref +import traceback import unittest from unittest.mock import Mock from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol, DefaultDict @@ -1526,6 +1528,16 @@ class C: pass with self.assertRaisesRegex(TypeError, 'dataclass type or instance'): fields(C()) + def test_clean_traceback_from_fields_exception(self): + stdout = io.StringIO() + try: + fields(object) + except TypeError as exc: + traceback.print_exception(exc, file=stdout) + printed_traceback = stdout.getvalue() + self.assertNotIn("AttributeError", printed_traceback) + self.assertNotIn("__dataclass_fields__", printed_traceback) + def test_helper_asdict(self): # Basic tests for asdict(), it should return a new dictionary. @dataclass diff --git a/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst new file mode 100644 index 000000000000..b59c98203566 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst @@ -0,0 +1,2 @@ +Improve traceback when :func:`dataclasses.fields` is called on a +non-dataclass. Patch by Alex Waygood From webhook-mailer at python.org Thu Mar 23 10:46:08 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 23 Mar 2023 14:46:08 -0000 Subject: [Python-checkins] gh-102947: Improve traceback when calling `fields()` on a non-dataclass (GH-102948) Message-ID: https://github.com/python/cpython/commit/6ffeeb2199176b8433c1b7b46e669132e44d394d commit: 6ffeeb2199176b8433c1b7b46e669132e44d394d branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T07:45:59-07:00 summary: gh-102947: Improve traceback when calling `fields()` on a non-dataclass (GH-102948) (cherry picked from commit baf4eb083c09b323cc12b8636c28c14089b87de8) Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index d2af451efed5..221ea2ba3e77 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1234,7 +1234,7 @@ def fields(class_or_instance): try: fields = getattr(class_or_instance, _FIELDS) except AttributeError: - raise TypeError('must be called with a dataclass type or instance') + raise TypeError('must be called with a dataclass type or instance') from None # Exclude pseudo-fields. Note that fields is sorted by insertion # order, so the order of the tuple is as the fields were defined. diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 3a247776e5f4..abe02e3b1ab6 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -5,11 +5,13 @@ from dataclasses import * import abc +import io import pickle import inspect import builtins import types import weakref +import traceback import unittest from unittest.mock import Mock from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol @@ -1500,6 +1502,16 @@ class C: pass with self.assertRaisesRegex(TypeError, 'dataclass type or instance'): fields(C()) + def test_clean_traceback_from_fields_exception(self): + stdout = io.StringIO() + try: + fields(object) + except TypeError as exc: + traceback.print_exception(exc, file=stdout) + printed_traceback = stdout.getvalue() + self.assertNotIn("AttributeError", printed_traceback) + self.assertNotIn("__dataclass_fields__", printed_traceback) + def test_helper_asdict(self): # Basic tests for asdict(), it should return a new dictionary. @dataclass diff --git a/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst new file mode 100644 index 000000000000..b59c98203566 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst @@ -0,0 +1,2 @@ +Improve traceback when :func:`dataclasses.fields` is called on a +non-dataclass. Patch by Alex Waygood From webhook-mailer at python.org Thu Mar 23 11:13:14 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 23 Mar 2023 15:13:14 -0000 Subject: [Python-checkins] [3.10] gh-102947: Improve traceback when calling `fields()` on a non-dataclass (#102948) (#102954) Message-ID: https://github.com/python/cpython/commit/4531fd0cea0d2d8a0c5b8109f92ff6be886f5692 commit: 4531fd0cea0d2d8a0c5b8109f92ff6be886f5692 branch: 3.10 author: Alex Waygood committer: AlexWaygood date: 2023-03-23T15:13:05Z summary: [3.10] gh-102947: Improve traceback when calling `fields()` on a non-dataclass (#102948) (#102954) files: A Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 9dc67fa47708..1742900e653a 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1195,7 +1195,7 @@ def fields(class_or_instance): try: fields = getattr(class_or_instance, _FIELDS) except AttributeError: - raise TypeError('must be called with a dataclass type or instance') + raise TypeError('must be called with a dataclass type or instance') from None # Exclude pseudo-fields. Note that fields is sorted by insertion # order, so the order of the tuple is as the fields were defined. diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index a642ed96c7ff..d6170eba4176 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -5,10 +5,12 @@ from dataclasses import * import abc +import io import pickle import inspect import builtins import types +import traceback import unittest from unittest.mock import Mock from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol @@ -1414,6 +1416,16 @@ class C: pass with self.assertRaisesRegex(TypeError, 'dataclass type or instance'): fields(C()) + def test_clean_traceback_from_fields_exception(self): + stdout = io.StringIO() + try: + fields(object) + except TypeError as exc: + traceback.print_exception(exc, file=stdout) + printed_traceback = stdout.getvalue() + self.assertNotIn("AttributeError", printed_traceback) + self.assertNotIn("__dataclass_fields__", printed_traceback) + def test_helper_asdict(self): # Basic tests for asdict(), it should return a new dictionary. @dataclass diff --git a/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst new file mode 100644 index 000000000000..b59c98203566 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst @@ -0,0 +1,2 @@ +Improve traceback when :func:`dataclasses.fields` is called on a +non-dataclass. Patch by Alex Waygood From webhook-mailer at python.org Thu Mar 23 12:26:32 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 23 Mar 2023 16:26:32 -0000 Subject: [Python-checkins] gh-88965: typing: fix type substitution of a list of types after initial `ParamSpec` substitution (#102808) Message-ID: https://github.com/python/cpython/commit/adb0621652f489033b9db8d3949564c9fe545c1d commit: adb0621652f489033b9db8d3949564c9fe545c1d branch: main author: Nikita Sobolev committer: AlexWaygood date: 2023-03-23T16:26:11Z summary: gh-88965: typing: fix type substitution of a list of types after initial `ParamSpec` substitution (#102808) Previously, this used to fail: ```py from typing import * T = TypeVar("T") P = ParamSpec("P") class X(Generic[P]): f: Callable[P, int] Y = X[[int, T]] Z = Y[str] ``` Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c9f55de95c54..f448b0ee60a9 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7679,6 +7679,127 @@ def test_bad_var_substitution(self): with self.assertRaises(TypeError): collections.abc.Callable[P, T][arg, str] + def test_type_var_subst_for_other_type_vars(self): + T = TypeVar('T') + T2 = TypeVar('T2') + P = ParamSpec('P') + P2 = ParamSpec('P2') + Ts = TypeVarTuple('Ts') + + class Base(Generic[P]): + pass + + A1 = Base[T] + self.assertEqual(A1.__parameters__, (T,)) + self.assertEqual(A1.__args__, ((T,),)) + self.assertEqual(A1[int], Base[int]) + + A2 = Base[[T]] + self.assertEqual(A2.__parameters__, (T,)) + self.assertEqual(A2.__args__, ((T,),)) + self.assertEqual(A2[int], Base[int]) + + A3 = Base[[int, T]] + self.assertEqual(A3.__parameters__, (T,)) + self.assertEqual(A3.__args__, ((int, T),)) + self.assertEqual(A3[str], Base[[int, str]]) + + A4 = Base[[T, int, T2]] + self.assertEqual(A4.__parameters__, (T, T2)) + self.assertEqual(A4.__args__, ((T, int, T2),)) + self.assertEqual(A4[str, bool], Base[[str, int, bool]]) + + A5 = Base[[*Ts, int]] + self.assertEqual(A5.__parameters__, (Ts,)) + self.assertEqual(A5.__args__, ((*Ts, int),)) + self.assertEqual(A5[str, bool], Base[[str, bool, int]]) + + A5_2 = Base[[int, *Ts]] + self.assertEqual(A5_2.__parameters__, (Ts,)) + self.assertEqual(A5_2.__args__, ((int, *Ts),)) + self.assertEqual(A5_2[str, bool], Base[[int, str, bool]]) + + A6 = Base[[T, *Ts]] + self.assertEqual(A6.__parameters__, (T, Ts)) + self.assertEqual(A6.__args__, ((T, *Ts),)) + self.assertEqual(A6[int, str, bool], Base[[int, str, bool]]) + + A7 = Base[[T, T]] + self.assertEqual(A7.__parameters__, (T,)) + self.assertEqual(A7.__args__, ((T, T),)) + self.assertEqual(A7[int], Base[[int, int]]) + + A8 = Base[[T, list[T]]] + self.assertEqual(A8.__parameters__, (T,)) + self.assertEqual(A8.__args__, ((T, list[T]),)) + self.assertEqual(A8[int], Base[[int, list[int]]]) + + A9 = Base[[Tuple[*Ts], *Ts]] + self.assertEqual(A9.__parameters__, (Ts,)) + self.assertEqual(A9.__args__, ((Tuple[*Ts], *Ts),)) + self.assertEqual(A9[int, str], Base[Tuple[int, str], int, str]) + + A10 = Base[P2] + self.assertEqual(A10.__parameters__, (P2,)) + self.assertEqual(A10.__args__, (P2,)) + self.assertEqual(A10[[int, str]], Base[[int, str]]) + + class DoubleP(Generic[P, P2]): + pass + + B1 = DoubleP[P, P2] + self.assertEqual(B1.__parameters__, (P, P2)) + self.assertEqual(B1.__args__, (P, P2)) + self.assertEqual(B1[[int, str], [bool]], DoubleP[[int, str], [bool]]) + self.assertEqual(B1[[], []], DoubleP[[], []]) + + B2 = DoubleP[[int, str], P2] + self.assertEqual(B2.__parameters__, (P2,)) + self.assertEqual(B2.__args__, ((int, str), P2)) + self.assertEqual(B2[[bool, bool]], DoubleP[[int, str], [bool, bool]]) + self.assertEqual(B2[[]], DoubleP[[int, str], []]) + + B3 = DoubleP[P, [bool, bool]] + self.assertEqual(B3.__parameters__, (P,)) + self.assertEqual(B3.__args__, (P, (bool, bool))) + self.assertEqual(B3[[int, str]], DoubleP[[int, str], [bool, bool]]) + self.assertEqual(B3[[]], DoubleP[[], [bool, bool]]) + + B4 = DoubleP[[T, int], [bool, T2]] + self.assertEqual(B4.__parameters__, (T, T2)) + self.assertEqual(B4.__args__, ((T, int), (bool, T2))) + self.assertEqual(B4[str, float], DoubleP[[str, int], [bool, float]]) + + B5 = DoubleP[[*Ts, int], [bool, T2]] + self.assertEqual(B5.__parameters__, (Ts, T2)) + self.assertEqual(B5.__args__, ((*Ts, int), (bool, T2))) + self.assertEqual(B5[str, bytes, float], + DoubleP[[str, bytes, int], [bool, float]]) + + B6 = DoubleP[[T, int], [bool, *Ts]] + self.assertEqual(B6.__parameters__, (T, Ts)) + self.assertEqual(B6.__args__, ((T, int), (bool, *Ts))) + self.assertEqual(B6[str, bytes, float], + DoubleP[[str, int], [bool, bytes, float]]) + + class PandT(Generic[P, T]): + pass + + C1 = PandT[P, T] + self.assertEqual(C1.__parameters__, (P, T)) + self.assertEqual(C1.__args__, (P, T)) + self.assertEqual(C1[[int, str], bool], PandT[[int, str], bool]) + + C2 = PandT[[int, T], T] + self.assertEqual(C2.__parameters__, (T,)) + self.assertEqual(C2.__args__, ((int, T), T)) + self.assertEqual(C2[str], PandT[[int, str], str]) + + C3 = PandT[[int, *Ts], T] + self.assertEqual(C3.__parameters__, (Ts, T)) + self.assertEqual(C3.__args__, ((int, *Ts), T)) + self.assertEqual(C3[str, bool, bytes], PandT[[int, str, bool], bytes]) + def test_paramspec_in_nested_generics(self): # Although ParamSpec should not be found in __parameters__ of most # generics, they probably should be found when nested in diff --git a/Lib/typing.py b/Lib/typing.py index 3ee9679e50c0..157a563bbece 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -255,10 +255,17 @@ def _collect_parameters(args): """ parameters = [] for t in args: - # We don't want __parameters__ descriptor of a bare Python class. if isinstance(t, type): - continue - if hasattr(t, '__typing_subst__'): + # We don't want __parameters__ descriptor of a bare Python class. + pass + elif isinstance(t, tuple): + # `t` might be a tuple, when `ParamSpec` is substituted with + # `[T, int]`, or `[int, *Ts]`, etc. + for x in t: + for collected in _collect_parameters([x]): + if collected not in parameters: + parameters.append(collected) + elif hasattr(t, '__typing_subst__'): if t not in parameters: parameters.append(t) else: @@ -1441,10 +1448,12 @@ def _determine_new_args(self, args): raise TypeError(f"Too {'many' if alen > plen else 'few'} arguments for {self};" f" actual {alen}, expected {plen}") new_arg_by_param = dict(zip(params, args)) + return tuple(self._make_substitution(self.__args__, new_arg_by_param)) + def _make_substitution(self, args, new_arg_by_param): + """Create a list of new type arguments.""" new_args = [] - for old_arg in self.__args__: - + for old_arg in args: if isinstance(old_arg, type): new_args.append(old_arg) continue @@ -1488,10 +1497,20 @@ def _determine_new_args(self, args): # should join all these types together in a flat list # `(float, int, str)` - so again, we should `extend`. new_args.extend(new_arg) + elif isinstance(old_arg, tuple): + # Corner case: + # P = ParamSpec('P') + # T = TypeVar('T') + # class Base(Generic[P]): ... + # Can be substituted like this: + # X = Base[[int, T]] + # In this case, `old_arg` will be a tuple: + new_args.append( + tuple(self._make_substitution(old_arg, new_arg_by_param)), + ) else: new_args.append(new_arg) - - return tuple(new_args) + return new_args def copy_with(self, args): return self.__class__(self.__origin__, args, name=self._name, inst=self._inst, diff --git a/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst b/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst new file mode 100644 index 000000000000..6e9642100cd8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst @@ -0,0 +1,7 @@ +typing: Fix a bug relating to substitution in custom classes generic over a +:class:`~typing.ParamSpec`. Previously, if the ``ParamSpec`` was substituted +with a parameters list that itself contained a :class:`~typing.TypeVar`, the +``TypeVar`` in the parameters list could not be subsequently substituted. This +is now fixed. + +Patch by Nikita Sobolev. From webhook-mailer at python.org Thu Mar 23 12:34:56 2023 From: webhook-mailer at python.org (zooba) Date: Thu, 23 Mar 2023 16:34:56 -0000 Subject: [Python-checkins] gh-102943: Stop checking localized error text in socket tests on Windows (GH-102944) Message-ID: https://github.com/python/cpython/commit/bf42eb8722befddf099a7bc26ea4a258179c32bf commit: bf42eb8722befddf099a7bc26ea4a258179c32bf branch: main author: AN Long committer: zooba date: 2023-03-23T16:34:48Z summary: gh-102943: Stop checking localized error text in socket tests on Windows (GH-102944) files: M Lib/test/test_socket.py diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 60f106f2d1a1..32252f7b741f 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -2562,8 +2562,7 @@ def testHyperVConstants(self): socket.HV_GUID_LOOPBACK def testCreateHyperVSocketWithUnknownProtoFailure(self): - expected = "A protocol was specified in the socket function call " \ - "that does not support the semantics of the socket type requested" + expected = r"\[WinError 10041\]" with self.assertRaisesRegex(OSError, expected): socket.socket(socket.AF_HYPERV, socket.SOCK_STREAM) From webhook-mailer at python.org Thu Mar 23 12:43:22 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 23 Mar 2023 16:43:22 -0000 Subject: [Python-checkins] gh-102810 Improve the sphinx docs for `asyncio.Timeout` (#102934) Message-ID: https://github.com/python/cpython/commit/f13fdacadfca87c71130057b6f03c89ae640c9b2 commit: f13fdacadfca87c71130057b6f03c89ae640c9b2 branch: main author: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> committer: AlexWaygood date: 2023-03-23T16:43:13Z summary: gh-102810 Improve the sphinx docs for `asyncio.Timeout` (#102934) Co-authored-by: Alex Waygood files: M Doc/library/asyncio-task.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index d908e45b3c8d..c5a480ba2019 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -624,32 +624,26 @@ Timeouts The context manager produced by :func:`asyncio.timeout` can be rescheduled to a different deadline and inspected. - .. class:: Timeout() + .. class:: Timeout(when) An :ref:`asynchronous context manager ` - that limits time spent inside of it. + for cancelling overdue coroutines. - .. versionadded:: 3.11 + ``when`` should be an absolute time at which the context should time out, + as measured by the event loop's clock: + + - If ``when`` is ``None``, the timeout will never trigger. + - If ``when < loop.time()``, the timeout will trigger on the next + iteration of the event loop. .. method:: when() -> float | None Return the current deadline, or ``None`` if the current deadline is not set. - The deadline is a float, consistent with the time returned by - :meth:`loop.time`. - .. method:: reschedule(when: float | None) - Change the time the timeout will trigger. - - If *when* is ``None``, any current deadline will be removed, and the - context manager will wait indefinitely. - - If *when* is a float, it is set as the new deadline. - - if *when* is in the past, the timeout will trigger on the next - iteration of the event loop. + Reschedule the timeout. .. method:: expired() -> bool From webhook-mailer at python.org Thu Mar 23 12:52:54 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 23 Mar 2023 16:52:54 -0000 Subject: [Python-checkins] gh-102810 Improve the sphinx docs for `asyncio.Timeout` (GH-102934) Message-ID: https://github.com/python/cpython/commit/84ae50c9146e98be28cf3af4606f0ebad07807aa commit: 84ae50c9146e98be28cf3af4606f0ebad07807aa branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T09:52:43-07:00 summary: gh-102810 Improve the sphinx docs for `asyncio.Timeout` (GH-102934) (cherry picked from commit f13fdacadfca87c71130057b6f03c89ae640c9b2) Co-authored-by: JosephSBoyle <48555120+JosephSBoyle at users.noreply.github.com> Co-authored-by: Alex Waygood files: M Doc/library/asyncio-task.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 5fb8776c3db3..1e0a69c75e25 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -624,32 +624,26 @@ Timeouts The context manager produced by :func:`asyncio.timeout` can be rescheduled to a different deadline and inspected. - .. class:: Timeout() + .. class:: Timeout(when) An :ref:`asynchronous context manager ` - that limits time spent inside of it. + for cancelling overdue coroutines. - .. versionadded:: 3.11 + ``when`` should be an absolute time at which the context should time out, + as measured by the event loop's clock: + + - If ``when`` is ``None``, the timeout will never trigger. + - If ``when < loop.time()``, the timeout will trigger on the next + iteration of the event loop. .. method:: when() -> float | None Return the current deadline, or ``None`` if the current deadline is not set. - The deadline is a float, consistent with the time returned by - :meth:`loop.time`. - .. method:: reschedule(when: float | None) - Change the time the timeout will trigger. - - If *when* is ``None``, any current deadline will be removed, and the - context manager will wait indefinitely. - - If *when* is a float, it is set as the new deadline. - - if *when* is in the past, the timeout will trigger on the next - iteration of the event loop. + Reschedule the timeout. .. method:: expired() -> bool From webhook-mailer at python.org Thu Mar 23 12:54:15 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 23 Mar 2023 16:54:15 -0000 Subject: [Python-checkins] gh-88965: typing: fix type substitution of a list of types after initial `ParamSpec` substitution (GH-102808) Message-ID: https://github.com/python/cpython/commit/1645a40b5eb59e7021c93fd6593d1a316d3e26e8 commit: 1645a40b5eb59e7021c93fd6593d1a316d3e26e8 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T09:54:07-07:00 summary: gh-88965: typing: fix type substitution of a list of types after initial `ParamSpec` substitution (GH-102808) Previously, this used to fail: ```py from typing import * T = TypeVar("T") P = ParamSpec("P") class X(Generic[P]): f: Callable[P, int] Y = X[[int, T]] Z = Y[str] ``` (cherry picked from commit adb0621652f489033b9db8d3949564c9fe545c1d) Co-authored-by: Nikita Sobolev Co-authored-by: Alex Waygood files: A Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst M Lib/test/test_typing.py M Lib/typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 4aa5faf9b3c9..558d928167ac 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7454,6 +7454,127 @@ def test_bad_var_substitution(self): with self.assertRaises(TypeError): collections.abc.Callable[P, T][arg, str] + def test_type_var_subst_for_other_type_vars(self): + T = TypeVar('T') + T2 = TypeVar('T2') + P = ParamSpec('P') + P2 = ParamSpec('P2') + Ts = TypeVarTuple('Ts') + + class Base(Generic[P]): + pass + + A1 = Base[T] + self.assertEqual(A1.__parameters__, (T,)) + self.assertEqual(A1.__args__, ((T,),)) + self.assertEqual(A1[int], Base[int]) + + A2 = Base[[T]] + self.assertEqual(A2.__parameters__, (T,)) + self.assertEqual(A2.__args__, ((T,),)) + self.assertEqual(A2[int], Base[int]) + + A3 = Base[[int, T]] + self.assertEqual(A3.__parameters__, (T,)) + self.assertEqual(A3.__args__, ((int, T),)) + self.assertEqual(A3[str], Base[[int, str]]) + + A4 = Base[[T, int, T2]] + self.assertEqual(A4.__parameters__, (T, T2)) + self.assertEqual(A4.__args__, ((T, int, T2),)) + self.assertEqual(A4[str, bool], Base[[str, int, bool]]) + + A5 = Base[[*Ts, int]] + self.assertEqual(A5.__parameters__, (Ts,)) + self.assertEqual(A5.__args__, ((*Ts, int),)) + self.assertEqual(A5[str, bool], Base[[str, bool, int]]) + + A5_2 = Base[[int, *Ts]] + self.assertEqual(A5_2.__parameters__, (Ts,)) + self.assertEqual(A5_2.__args__, ((int, *Ts),)) + self.assertEqual(A5_2[str, bool], Base[[int, str, bool]]) + + A6 = Base[[T, *Ts]] + self.assertEqual(A6.__parameters__, (T, Ts)) + self.assertEqual(A6.__args__, ((T, *Ts),)) + self.assertEqual(A6[int, str, bool], Base[[int, str, bool]]) + + A7 = Base[[T, T]] + self.assertEqual(A7.__parameters__, (T,)) + self.assertEqual(A7.__args__, ((T, T),)) + self.assertEqual(A7[int], Base[[int, int]]) + + A8 = Base[[T, list[T]]] + self.assertEqual(A8.__parameters__, (T,)) + self.assertEqual(A8.__args__, ((T, list[T]),)) + self.assertEqual(A8[int], Base[[int, list[int]]]) + + A9 = Base[[Tuple[*Ts], *Ts]] + self.assertEqual(A9.__parameters__, (Ts,)) + self.assertEqual(A9.__args__, ((Tuple[*Ts], *Ts),)) + self.assertEqual(A9[int, str], Base[Tuple[int, str], int, str]) + + A10 = Base[P2] + self.assertEqual(A10.__parameters__, (P2,)) + self.assertEqual(A10.__args__, (P2,)) + self.assertEqual(A10[[int, str]], Base[[int, str]]) + + class DoubleP(Generic[P, P2]): + pass + + B1 = DoubleP[P, P2] + self.assertEqual(B1.__parameters__, (P, P2)) + self.assertEqual(B1.__args__, (P, P2)) + self.assertEqual(B1[[int, str], [bool]], DoubleP[[int, str], [bool]]) + self.assertEqual(B1[[], []], DoubleP[[], []]) + + B2 = DoubleP[[int, str], P2] + self.assertEqual(B2.__parameters__, (P2,)) + self.assertEqual(B2.__args__, ((int, str), P2)) + self.assertEqual(B2[[bool, bool]], DoubleP[[int, str], [bool, bool]]) + self.assertEqual(B2[[]], DoubleP[[int, str], []]) + + B3 = DoubleP[P, [bool, bool]] + self.assertEqual(B3.__parameters__, (P,)) + self.assertEqual(B3.__args__, (P, (bool, bool))) + self.assertEqual(B3[[int, str]], DoubleP[[int, str], [bool, bool]]) + self.assertEqual(B3[[]], DoubleP[[], [bool, bool]]) + + B4 = DoubleP[[T, int], [bool, T2]] + self.assertEqual(B4.__parameters__, (T, T2)) + self.assertEqual(B4.__args__, ((T, int), (bool, T2))) + self.assertEqual(B4[str, float], DoubleP[[str, int], [bool, float]]) + + B5 = DoubleP[[*Ts, int], [bool, T2]] + self.assertEqual(B5.__parameters__, (Ts, T2)) + self.assertEqual(B5.__args__, ((*Ts, int), (bool, T2))) + self.assertEqual(B5[str, bytes, float], + DoubleP[[str, bytes, int], [bool, float]]) + + B6 = DoubleP[[T, int], [bool, *Ts]] + self.assertEqual(B6.__parameters__, (T, Ts)) + self.assertEqual(B6.__args__, ((T, int), (bool, *Ts))) + self.assertEqual(B6[str, bytes, float], + DoubleP[[str, int], [bool, bytes, float]]) + + class PandT(Generic[P, T]): + pass + + C1 = PandT[P, T] + self.assertEqual(C1.__parameters__, (P, T)) + self.assertEqual(C1.__args__, (P, T)) + self.assertEqual(C1[[int, str], bool], PandT[[int, str], bool]) + + C2 = PandT[[int, T], T] + self.assertEqual(C2.__parameters__, (T,)) + self.assertEqual(C2.__args__, ((int, T), T)) + self.assertEqual(C2[str], PandT[[int, str], str]) + + C3 = PandT[[int, *Ts], T] + self.assertEqual(C3.__parameters__, (Ts, T)) + self.assertEqual(C3.__args__, ((int, *Ts), T)) + self.assertEqual(C3[str, bool, bytes], PandT[[int, str, bool], bytes]) + def test_paramspec_in_nested_generics(self): # Although ParamSpec should not be found in __parameters__ of most # generics, they probably should be found when nested in diff --git a/Lib/typing.py b/Lib/typing.py index 9f5db1a1faab..8995564f8994 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -250,10 +250,17 @@ def _collect_parameters(args): """ parameters = [] for t in args: - # We don't want __parameters__ descriptor of a bare Python class. if isinstance(t, type): - continue - if hasattr(t, '__typing_subst__'): + # We don't want __parameters__ descriptor of a bare Python class. + pass + elif isinstance(t, tuple): + # `t` might be a tuple, when `ParamSpec` is substituted with + # `[T, int]`, or `[int, *Ts]`, etc. + for x in t: + for collected in _collect_parameters([x]): + if collected not in parameters: + parameters.append(collected) + elif hasattr(t, '__typing_subst__'): if t not in parameters: parameters.append(t) else: @@ -1416,10 +1423,12 @@ def _determine_new_args(self, args): raise TypeError(f"Too {'many' if alen > plen else 'few'} arguments for {self};" f" actual {alen}, expected {plen}") new_arg_by_param = dict(zip(params, args)) + return tuple(self._make_substitution(self.__args__, new_arg_by_param)) + def _make_substitution(self, args, new_arg_by_param): + """Create a list of new type arguments.""" new_args = [] - for old_arg in self.__args__: - + for old_arg in args: if isinstance(old_arg, type): new_args.append(old_arg) continue @@ -1463,10 +1472,20 @@ def _determine_new_args(self, args): # should join all these types together in a flat list # `(float, int, str)` - so again, we should `extend`. new_args.extend(new_arg) + elif isinstance(old_arg, tuple): + # Corner case: + # P = ParamSpec('P') + # T = TypeVar('T') + # class Base(Generic[P]): ... + # Can be substituted like this: + # X = Base[[int, T]] + # In this case, `old_arg` will be a tuple: + new_args.append( + tuple(self._make_substitution(old_arg, new_arg_by_param)), + ) else: new_args.append(new_arg) - - return tuple(new_args) + return new_args def copy_with(self, args): return self.__class__(self.__origin__, args, name=self._name, inst=self._inst, diff --git a/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst b/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst new file mode 100644 index 000000000000..6e9642100cd8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst @@ -0,0 +1,7 @@ +typing: Fix a bug relating to substitution in custom classes generic over a +:class:`~typing.ParamSpec`. Previously, if the ``ParamSpec`` was substituted +with a parameters list that itself contained a :class:`~typing.TypeVar`, the +``TypeVar`` in the parameters list could not be subsequently substituted. This +is now fixed. + +Patch by Nikita Sobolev. From webhook-mailer at python.org Thu Mar 23 13:10:20 2023 From: webhook-mailer at python.org (rhettinger) Date: Thu, 23 Mar 2023 17:10:20 -0000 Subject: [Python-checkins] Move binomialvariate() to a section for discrete distributions (GH-102955) Message-ID: https://github.com/python/cpython/commit/46957091433bfa097d7ea19b177bf42a52412f2d commit: 46957091433bfa097d7ea19b177bf42a52412f2d branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-23T12:10:12-05:00 summary: Move binomialvariate() to a section for discrete distributions (GH-102955) files: M Doc/library/random.rst M Lib/random.py diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 098684d7270f..c192919ac62e 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -404,8 +404,8 @@ Alternative Generator Class that implements the default pseudo-random number generator used by the :mod:`random` module. - .. deprecated:: 3.9 - In the future, the *seed* must be one of the following types: + .. deprecated-removed:: 3.9 3.11 + Formerly the *seed* could be any hashable object. Now it is limited to: :class:`NoneType`, :class:`int`, :class:`float`, :class:`str`, :class:`bytes`, or :class:`bytearray`. @@ -423,7 +423,7 @@ Notes on Reproducibility ------------------------ Sometimes it is useful to be able to reproduce the sequences given by a -pseudo-random number generator. By re-using a seed value, the same sequence should be +pseudo-random number generator. By reusing a seed value, the same sequence should be reproducible from run to run as long as multiple threads are not running. Most of the random module's algorithms and seeding functions are subject to diff --git a/Lib/random.py b/Lib/random.py index 3c4291f6a652..586c3f7f9da9 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -24,7 +24,6 @@ negative exponential gamma beta - binomial pareto Weibull @@ -33,6 +32,11 @@ circular uniform von Mises + discrete distributions + ---------------------- + binomial + + General notes on the underlying Mersenne Twister core generator: * The period is 2**19937-1. @@ -731,6 +735,26 @@ def betavariate(self, alpha, beta): return y / (y + self.gammavariate(beta, 1.0)) return 0.0 + def paretovariate(self, alpha): + """Pareto distribution. alpha is the shape parameter.""" + # Jain, pg. 495 + + u = 1.0 - self.random() + return u ** (-1.0 / alpha) + + def weibullvariate(self, alpha, beta): + """Weibull distribution. + + alpha is the scale parameter and beta is the shape parameter. + + """ + # Jain, pg. 499; bug fix courtesy Bill Arms + + u = 1.0 - self.random() + return alpha * (-_log(u)) ** (1.0 / beta) + + + ## -------------------- discrete distributions --------------------- def binomialvariate(self, n=1, p=0.5): """Binomial random variable. @@ -816,25 +840,6 @@ def binomialvariate(self, n=1, p=0.5): return k - def paretovariate(self, alpha): - """Pareto distribution. alpha is the shape parameter.""" - # Jain, pg. 495 - - u = 1.0 - self.random() - return u ** (-1.0 / alpha) - - def weibullvariate(self, alpha, beta): - """Weibull distribution. - - alpha is the scale parameter and beta is the shape parameter. - - """ - # Jain, pg. 499; bug fix courtesy Bill Arms - - u = 1.0 - self.random() - return alpha * (-_log(u)) ** (1.0 / beta) - - ## ------------------------------------------------------------------ ## --------------- Operating System Random Source ------------------ From webhook-mailer at python.org Thu Mar 23 14:19:01 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 23 Mar 2023 18:19:01 -0000 Subject: [Python-checkins] gh-102936: typing: document performance pitfalls of protocols decorated with `@runtime_checkable` (#102937) Message-ID: https://github.com/python/cpython/commit/58d2b30c012c3a9fe5ab747ae47c96af09e0fd15 commit: 58d2b30c012c3a9fe5ab747ae47c96af09e0fd15 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-03-23T18:18:53Z summary: gh-102936: typing: document performance pitfalls of protocols decorated with `@runtime_checkable` (#102937) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 80a969e6335a..08ffa0310f0f 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1584,16 +1584,32 @@ These are not used in annotations. They are building blocks for creating generic assert isinstance(open('/some/file'), Closable) + @runtime_checkable + class Named(Protocol): + name: str + + import threading + assert isinstance(threading.Thread(name='Bob'), Named) + .. note:: - :func:`runtime_checkable` will check only the presence of the required - methods, not their type signatures. For example, :class:`ssl.SSLObject` + :func:`!runtime_checkable` will check only the presence of the required + methods or attributes, not their type signatures or types. + For example, :class:`ssl.SSLObject` is a class, therefore it passes an :func:`issubclass` check against :data:`Callable`. However, the ``ssl.SSLObject.__init__`` method exists only to raise a :exc:`TypeError` with a more informative message, therefore making it impossible to call (instantiate) :class:`ssl.SSLObject`. + .. note:: + + An :func:`isinstance` check against a runtime-checkable protocol can be + surprisingly slow compared to an ``isinstance()`` check against + a non-protocol class. Consider using alternative idioms such as + :func:`hasattr` calls for structural checks in performance-sensitive + code. + .. versionadded:: 3.8 Other special directives From webhook-mailer at python.org Thu Mar 23 14:27:36 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 23 Mar 2023 18:27:36 -0000 Subject: [Python-checkins] gh-102936: typing: document performance pitfalls of protocols decorated with `@runtime_checkable` (GH-102937) Message-ID: https://github.com/python/cpython/commit/e2924c0ee55ce257851b9e847fe7e4f210af1270 commit: e2924c0ee55ce257851b9e847fe7e4f210af1270 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T11:27:28-07:00 summary: gh-102936: typing: document performance pitfalls of protocols decorated with `@runtime_checkable` (GH-102937) (cherry picked from commit 58d2b30c012c3a9fe5ab747ae47c96af09e0fd15) Co-authored-by: Alex Waygood files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 8db9a3f2c609..df6ddb6726cf 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1582,16 +1582,32 @@ These are not used in annotations. They are building blocks for creating generic assert isinstance(open('/some/file'), Closable) + @runtime_checkable + class Named(Protocol): + name: str + + import threading + assert isinstance(threading.Thread(name='Bob'), Named) + .. note:: - :func:`runtime_checkable` will check only the presence of the required - methods, not their type signatures. For example, :class:`ssl.SSLObject` + :func:`!runtime_checkable` will check only the presence of the required + methods or attributes, not their type signatures or types. + For example, :class:`ssl.SSLObject` is a class, therefore it passes an :func:`issubclass` check against :data:`Callable`. However, the ``ssl.SSLObject.__init__`` method exists only to raise a :exc:`TypeError` with a more informative message, therefore making it impossible to call (instantiate) :class:`ssl.SSLObject`. + .. note:: + + An :func:`isinstance` check against a runtime-checkable protocol can be + surprisingly slow compared to an ``isinstance()`` check against + a non-protocol class. Consider using alternative idioms such as + :func:`hasattr` calls for structural checks in performance-sensitive + code. + .. versionadded:: 3.8 Other special directives From webhook-mailer at python.org Thu Mar 23 14:28:18 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 23 Mar 2023 18:28:18 -0000 Subject: [Python-checkins] gh-102936: typing: document performance pitfalls of protocols decorated with `@runtime_checkable` (GH-102937) Message-ID: https://github.com/python/cpython/commit/6c667d025a1bea6d897006d556878f59f651243f commit: 6c667d025a1bea6d897006d556878f59f651243f branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T11:28:11-07:00 summary: gh-102936: typing: document performance pitfalls of protocols decorated with `@runtime_checkable` (GH-102937) (cherry picked from commit 58d2b30c012c3a9fe5ab747ae47c96af09e0fd15) Co-authored-by: Alex Waygood files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 5deaa7adbe1e..00f779647e0b 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1350,16 +1350,32 @@ These are not used in annotations. They are building blocks for creating generic assert isinstance(open('/some/file'), Closable) + @runtime_checkable + class Named(Protocol): + name: str + + import threading + assert isinstance(threading.Thread(name='Bob'), Named) + .. note:: - :func:`runtime_checkable` will check only the presence of the required - methods, not their type signatures. For example, :class:`ssl.SSLObject` + :func:`!runtime_checkable` will check only the presence of the required + methods or attributes, not their type signatures or types. + For example, :class:`ssl.SSLObject` is a class, therefore it passes an :func:`issubclass` check against :data:`Callable`. However, the ``ssl.SSLObject.__init__`` method exists only to raise a :exc:`TypeError` with a more informative message, therefore making it impossible to call (instantiate) :class:`ssl.SSLObject`. + .. note:: + + An :func:`isinstance` check against a runtime-checkable protocol can be + surprisingly slow compared to an ``isinstance()`` check against + a non-protocol class. Consider using alternative idioms such as + :func:`hasattr` calls for structural checks in performance-sensitive + code. + .. versionadded:: 3.8 Other special directives From webhook-mailer at python.org Thu Mar 23 15:35:10 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Thu, 23 Mar 2023 19:35:10 -0000 Subject: [Python-checkins] gh-98239: Document that `inspect.getsource()` can raise `TypeError` (#101689) Message-ID: https://github.com/python/cpython/commit/b6132085ca5418f714eff6e31d1d03369d3fd1d9 commit: b6132085ca5418f714eff6e31d1d03369d3fd1d9 branch: main author: Nikita Sobolev committer: AlexWaygood date: 2023-03-23T19:35:02Z summary: gh-98239: Document that `inspect.getsource()` can raise `TypeError` (#101689) files: M Doc/library/inspect.rst diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index ccf240193d36..88f843c03b1d 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -574,6 +574,8 @@ Retrieving source code object and the line number indicates where in the original source file the first line of code was found. An :exc:`OSError` is raised if the source code cannot be retrieved. + A :exc:`TypeError` is raised if the object is a built-in module, class, or + function. .. versionchanged:: 3.3 :exc:`OSError` is raised instead of :exc:`IOError`, now an alias of the @@ -586,6 +588,8 @@ Retrieving source code class, method, function, traceback, frame, or code object. The source code is returned as a single string. An :exc:`OSError` is raised if the source code cannot be retrieved. + A :exc:`TypeError` is raised if the object is a built-in module, class, or + function. .. versionchanged:: 3.3 :exc:`OSError` is raised instead of :exc:`IOError`, now an alias of the From webhook-mailer at python.org Thu Mar 23 15:41:58 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 23 Mar 2023 19:41:58 -0000 Subject: [Python-checkins] gh-98239: Document that `inspect.getsource()` can raise `TypeError` (GH-101689) Message-ID: https://github.com/python/cpython/commit/77e54fe98a52a70e7d692d4765821e66e9c40b4a commit: 77e54fe98a52a70e7d692d4765821e66e9c40b4a branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T12:41:50-07:00 summary: gh-98239: Document that `inspect.getsource()` can raise `TypeError` (GH-101689) (cherry picked from commit b6132085ca5418f714eff6e31d1d03369d3fd1d9) Co-authored-by: Nikita Sobolev files: M Doc/library/inspect.rst diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 35aa99464ed0..0fe4fb6275af 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -526,6 +526,8 @@ Retrieving source code object and the line number indicates where in the original source file the first line of code was found. An :exc:`OSError` is raised if the source code cannot be retrieved. + A :exc:`TypeError` is raised if the object is a built-in module, class, or + function. .. versionchanged:: 3.3 :exc:`OSError` is raised instead of :exc:`IOError`, now an alias of the @@ -538,6 +540,8 @@ Retrieving source code class, method, function, traceback, frame, or code object. The source code is returned as a single string. An :exc:`OSError` is raised if the source code cannot be retrieved. + A :exc:`TypeError` is raised if the object is a built-in module, class, or + function. .. versionchanged:: 3.3 :exc:`OSError` is raised instead of :exc:`IOError`, now an alias of the From webhook-mailer at python.org Thu Mar 23 15:43:02 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 23 Mar 2023 19:43:02 -0000 Subject: [Python-checkins] gh-98239: Document that `inspect.getsource()` can raise `TypeError` (GH-101689) Message-ID: https://github.com/python/cpython/commit/202e16ea050eaa34a328f281d24f8a0e662be463 commit: 202e16ea050eaa34a328f281d24f8a0e662be463 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T12:42:54-07:00 summary: gh-98239: Document that `inspect.getsource()` can raise `TypeError` (GH-101689) (cherry picked from commit b6132085ca5418f714eff6e31d1d03369d3fd1d9) Co-authored-by: Nikita Sobolev files: M Doc/library/inspect.rst diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index caca1050d7bf..932e52816413 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -553,6 +553,8 @@ Retrieving source code object and the line number indicates where in the original source file the first line of code was found. An :exc:`OSError` is raised if the source code cannot be retrieved. + A :exc:`TypeError` is raised if the object is a built-in module, class, or + function. .. versionchanged:: 3.3 :exc:`OSError` is raised instead of :exc:`IOError`, now an alias of the @@ -565,6 +567,8 @@ Retrieving source code class, method, function, traceback, frame, or code object. The source code is returned as a single string. An :exc:`OSError` is raised if the source code cannot be retrieved. + A :exc:`TypeError` is raised if the object is a built-in module, class, or + function. .. versionchanged:: 3.3 :exc:`OSError` is raised instead of :exc:`IOError`, now an alias of the From webhook-mailer at python.org Thu Mar 23 15:46:22 2023 From: webhook-mailer at python.org (rhettinger) Date: Thu, 23 Mar 2023 19:46:22 -0000 Subject: [Python-checkins] Minor readability improvement to the factor() recipe (GH-102971) Message-ID: https://github.com/python/cpython/commit/16f6165b71e81b5e4d0be660ac64a9fce7dfd86c commit: 16f6165b71e81b5e4d0be660ac64a9fce7dfd86c branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-23T14:46:15-05:00 summary: Minor readability improvement to the factor() recipe (GH-102971) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 5daadfd3759f..70e5b7905f20 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -936,7 +936,7 @@ which incur interpreter overhead. n = quotient if n == 1: return - if n >= 2: + if n > 1: yield n def flatten(list_of_lists): From webhook-mailer at python.org Thu Mar 23 15:56:43 2023 From: webhook-mailer at python.org (rhettinger) Date: Thu, 23 Mar 2023 19:56:43 -0000 Subject: [Python-checkins] [3.11] Minor readability improvement to the factor() recipe (GH-102971) (GH-102972) Message-ID: https://github.com/python/cpython/commit/60b2b58f87af178f8eb5e4b579f8a518c267373f commit: 60b2b58f87af178f8eb5e4b579f8a518c267373f branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: rhettinger date: 2023-03-23T14:56:35-05:00 summary: [3.11] Minor readability improvement to the factor() recipe (GH-102971) (GH-102972) files: M Doc/library/itertools.rst diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index e1ffd39b1bd8..2196e53502f5 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -925,7 +925,7 @@ which incur interpreter overhead. n = quotient if n == 1: return - if n >= 2: + if n > 1: yield n def flatten(list_of_lists): From webhook-mailer at python.org Thu Mar 23 16:30:26 2023 From: webhook-mailer at python.org (ethanfurman) Date: Thu, 23 Mar 2023 20:30:26 -0000 Subject: [Python-checkins] gh-102558: [Enum] fix AttributeError during member repr() (GH-102601) Message-ID: https://github.com/python/cpython/commit/bd063756b34003c1bc7cacf5b1bd90a409180fb6 commit: bd063756b34003c1bc7cacf5b1bd90a409180fb6 branch: main author: Dong-hee Na committer: ethanfurman date: 2023-03-23T13:30:18-07:00 summary: gh-102558: [Enum] fix AttributeError during member repr() (GH-102601) files: M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index d14e91a9b017..ba927662a43b 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1186,6 +1186,8 @@ def _missing_(cls, value): return None def __repr__(self): + if not isinstance(self, Enum): + return repr(self) v_repr = self.__class__._value_repr_ or repr return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_)) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index a11bb441f06e..bb163c46481a 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -11,7 +11,7 @@ import builtins as bltns from collections import OrderedDict from datetime import date -from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto +from enum import Enum, EnumMeta, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum from enum import member, nonmember, _iter_bits_lsb @@ -644,6 +644,13 @@ class MySubEnum(MyEnum): theother = auto() self.assertEqual(repr(MySubEnum.that), "My name is that.") + def test_multiple_superclasses_repr(self): + class _EnumSuperClass(metaclass=EnumMeta): + pass + class E(_EnumSuperClass, Enum): + A = 1 + self.assertEqual(repr(E.A), "") + def test_reversed_iteration_order(self): self.assertEqual( list(reversed(self.MainEnum)), From webhook-mailer at python.org Thu Mar 23 16:56:46 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 23 Mar 2023 20:56:46 -0000 Subject: [Python-checkins] gh-102558: [Enum] fix AttributeError during member repr() (GH-102601) Message-ID: https://github.com/python/cpython/commit/8132aefa0f23cb65b004e6f7b203f9f7b47fd997 commit: 8132aefa0f23cb65b004e6f7b203f9f7b47fd997 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T13:56:38-07:00 summary: gh-102558: [Enum] fix AttributeError during member repr() (GH-102601) (cherry picked from commit bd063756b34003c1bc7cacf5b1bd90a409180fb6) Co-authored-by: Dong-hee Na files: M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index 5cff41713ae5..ea55f7bbef86 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1187,6 +1187,8 @@ def _missing_(cls, value): return None def __repr__(self): + if not isinstance(self, Enum): + return repr(self) v_repr = self.__class__._value_repr_ or repr return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_)) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 72dfb9881779..2a305e415cd9 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -11,7 +11,7 @@ import builtins as bltns from collections import OrderedDict from datetime import date -from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto +from enum import Enum, EnumMeta, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum from enum import member, nonmember, _iter_bits_lsb @@ -632,6 +632,13 @@ class MySubEnum(MyEnum): theother = auto() self.assertEqual(repr(MySubEnum.that), "My name is that.") + def test_multiple_superclasses_repr(self): + class _EnumSuperClass(metaclass=EnumMeta): + pass + class E(_EnumSuperClass, Enum): + A = 1 + self.assertEqual(repr(E.A), "") + def test_reversed_iteration_order(self): self.assertEqual( list(reversed(self.MainEnum)), From webhook-mailer at python.org Thu Mar 23 18:25:42 2023 From: webhook-mailer at python.org (brandtbucher) Date: Thu, 23 Mar 2023 22:25:42 -0000 Subject: [Python-checkins] GH-100982: Break up COMPARE_AND_BRANCH (GH-102801) Message-ID: https://github.com/python/cpython/commit/0444ae24875489dc290d8efdb9ee6440ee60dac8 commit: 0444ae24875489dc290d8efdb9ee6440ee60dac8 branch: main author: Brandt Bucher committer: brandtbucher date: 2023-03-23T15:25:09-07:00 summary: GH-100982: Break up COMPARE_AND_BRANCH (GH-102801) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst M Doc/library/dis.rst M Include/internal/pycore_code.h M Include/internal/pycore_opcode.h M Include/opcode.h M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Lib/test/test_compile.py M Lib/test/test_dis.py M Objects/frameobject.c M Python/bytecodes.c M Python/compile.c M Python/generated_cases.c.h M Python/opcode_metadata.h M Python/opcode_targets.h M Python/specialize.c M Tools/c-analyzer/cpython/ignored.tsv M Tools/scripts/summarize_stats.py diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index b06fe67a983a..8703cddb3448 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1042,15 +1042,6 @@ iterations of the loop. ``cmp_op[opname]``. -.. opcode:: COMPARE_AND_BRANCH (opname) - - Compares the top two values on the stack, popping them, then branches. - The direction and offset of the jump is embedded as a ``POP_JUMP_IF_TRUE`` - or ``POP_JUMP_IF_FALSE`` instruction immediately following the cache. - - .. versionadded:: 3.12 - - .. opcode:: IS_OP (invert) Performs ``is`` comparison, or ``is not`` if ``invert`` is 1. diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 6bd212dd42c6..3359dfd8a499 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -234,7 +234,7 @@ extern void _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames); extern void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg, PyObject **locals); -extern void _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, +extern void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg); extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg); diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index edcf4476ff3e..4a0b27a13ae9 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -51,7 +51,6 @@ const uint8_t _PyOpcode_Caches[256] = { [LOAD_GLOBAL] = 4, [BINARY_OP] = 1, [SEND] = 1, - [COMPARE_AND_BRANCH] = 1, [CALL] = 4, }; @@ -105,11 +104,10 @@ const uint8_t _PyOpcode_Deopt[256] = { [CHECK_EG_MATCH] = CHECK_EG_MATCH, [CHECK_EXC_MATCH] = CHECK_EXC_MATCH, [CLEANUP_THROW] = CLEANUP_THROW, - [COMPARE_AND_BRANCH] = COMPARE_AND_BRANCH, - [COMPARE_AND_BRANCH_FLOAT] = COMPARE_AND_BRANCH, - [COMPARE_AND_BRANCH_INT] = COMPARE_AND_BRANCH, - [COMPARE_AND_BRANCH_STR] = COMPARE_AND_BRANCH, [COMPARE_OP] = COMPARE_OP, + [COMPARE_OP_FLOAT] = COMPARE_OP, + [COMPARE_OP_INT] = COMPARE_OP, + [COMPARE_OP_STR] = COMPARE_OP, [CONTAINS_OP] = CONTAINS_OP, [COPY] = COPY, [COPY_FREE_VARS] = COPY_FREE_VARS, @@ -277,7 +275,7 @@ static const char *const _PyOpcode_OpName[263] = { [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", - [COMPARE_AND_BRANCH_FLOAT] = "COMPARE_AND_BRANCH_FLOAT", + [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -285,8 +283,8 @@ static const char *const _PyOpcode_OpName[263] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", - [COMPARE_AND_BRANCH_INT] = "COMPARE_AND_BRANCH_INT", - [COMPARE_AND_BRANCH_STR] = "COMPARE_AND_BRANCH_STR", + [COMPARE_OP_INT] = "COMPARE_OP_INT", + [COMPARE_OP_STR] = "COMPARE_OP_STR", [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [STORE_SUBSCR] = "STORE_SUBSCR", @@ -370,9 +368,9 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", - [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -382,13 +380,13 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", - [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [SEND_GEN] = "SEND_GEN", + [159] = "<159>", [160] = "<160>", [161] = "<161>", [LIST_EXTEND] = "LIST_EXTEND", @@ -496,6 +494,7 @@ static const char *const _PyOpcode_OpName[263] = { #endif #define EXTRA_CASES \ + case 159: \ case 160: \ case 161: \ case 166: \ diff --git a/Include/opcode.h b/Include/opcode.h index 8ec10742fb77..0ff84dc5a551 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -93,7 +93,6 @@ extern "C" { #define STORE_DEREF 138 #define DELETE_DEREF 139 #define JUMP_BACKWARD 140 -#define COMPARE_AND_BRANCH 141 #define CALL_FUNCTION_EX 142 #define EXTENDED_ARG 144 #define LIST_APPEND 145 @@ -153,9 +152,9 @@ extern "C" { #define CALL_NO_KW_STR_1 45 #define CALL_NO_KW_TUPLE_1 46 #define CALL_NO_KW_TYPE_1 47 -#define COMPARE_AND_BRANCH_FLOAT 48 -#define COMPARE_AND_BRANCH_INT 56 -#define COMPARE_AND_BRANCH_STR 57 +#define COMPARE_OP_FLOAT 48 +#define COMPARE_OP_INT 56 +#define COMPARE_OP_STR 57 #define FOR_ITER_LIST 58 #define FOR_ITER_TUPLE 59 #define FOR_ITER_RANGE 62 @@ -181,11 +180,11 @@ extern "C" { #define STORE_FAST__LOAD_FAST 111 #define STORE_FAST__STORE_FAST 112 #define STORE_SUBSCR_DICT 113 -#define STORE_SUBSCR_LIST_INT 143 -#define UNPACK_SEQUENCE_LIST 153 -#define UNPACK_SEQUENCE_TUPLE 154 -#define UNPACK_SEQUENCE_TWO_TUPLE 158 -#define SEND_GEN 159 +#define STORE_SUBSCR_LIST_INT 141 +#define UNPACK_SEQUENCE_LIST 143 +#define UNPACK_SEQUENCE_TUPLE 153 +#define UNPACK_SEQUENCE_TWO_TUPLE 154 +#define SEND_GEN 158 #define DO_TRACING 255 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 3f78300c2263..28e55fdc8b7d 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -435,7 +435,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a6 3519 (Modify SEND instruction) # Python 3.12a6 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) # Python 3.12a7 3521 (Shrink the LOAD_GLOBAL caches) -# Python 3.12a7 3522 (Removed JUMP_IF_FALSE_OR_POP/JUMP_IF_TRUE_OR_POP) +# Python 3.12a7 3523 (Convert COMPARE_AND_BRANCH back to COMPARE_OP) # Python 3.13 will start with 3550 @@ -452,7 +452,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3522).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3523).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index f37d00e5014a..60670f571fdc 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -191,8 +191,6 @@ def pseudo_op(name, op, real_ops): def_op('DELETE_DEREF', 139) hasfree.append(139) jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards) -def_op('COMPARE_AND_BRANCH', 141) # Comparison and jump -hascompare.append(141) def_op('CALL_FUNCTION_EX', 142) # Flags @@ -314,10 +312,10 @@ def pseudo_op(name, op, real_ops): "CALL_NO_KW_TUPLE_1", "CALL_NO_KW_TYPE_1", ], - "COMPARE_AND_BRANCH": [ - "COMPARE_AND_BRANCH_FLOAT", - "COMPARE_AND_BRANCH_INT", - "COMPARE_AND_BRANCH_STR", + "COMPARE_OP": [ + "COMPARE_OP_FLOAT", + "COMPARE_OP_INT", + "COMPARE_OP_STR", ], "FOR_ITER": [ "FOR_ITER_LIST", @@ -392,9 +390,6 @@ def pseudo_op(name, op, real_ops): "COMPARE_OP": { "counter": 1, }, - "COMPARE_AND_BRANCH": { - "counter": 1, - }, "BINARY_SUBSCR": { "counter": 1, "type_version": 2, diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index fe775779c50f..dca38418935b 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1283,7 +1283,7 @@ def test_multiline_boolean_expression(self): self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_FALSE', line=2, end_line=2, column=15, end_column=16, occurrence=2) # compare d and 0 - self.assertOpcodeSourcePositionIs(compiled_code, 'COMPARE_AND_BRANCH', + self.assertOpcodeSourcePositionIs(compiled_code, 'COMPARE_OP', line=4, end_line=4, column=8, end_column=13, occurrence=1) # jump if comparison it True self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_TRUE', diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index fa1de1c7ded1..ed66b362b080 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -46,7 +46,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 32 (==) + COMPARE_OP 40 (==) LOAD_FAST 0 (self) STORE_ATTR 0 (x) RETURN_CONST 0 (None) @@ -56,7 +56,7 @@ def cm(cls, x): RESUME 0 LOAD_FAST 1 LOAD_CONST 1 - COMPARE_OP 32 (==) + COMPARE_OP 40 (==) LOAD_FAST 0 STORE_ATTR 0 RETURN_CONST 0 @@ -67,7 +67,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 32 (==) + COMPARE_OP 40 (==) LOAD_FAST 0 (cls) STORE_ATTR 0 (x) RETURN_CONST 0 (None) @@ -78,7 +78,7 @@ def cm(cls, x): %3d LOAD_FAST 0 (x) LOAD_CONST 1 (1) - COMPARE_OP 32 (==) + COMPARE_OP 40 (==) STORE_FAST 0 (x) RETURN_CONST 0 (None) """ % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,) @@ -1554,12 +1554,12 @@ def _prepare_test_cases(): Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=58, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=60, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=60, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=68, argrepr='to 68', offset=64, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=21, argval=26, argrepr='to 26', offset=66, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=68, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=70, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=68, argval='>', argrepr='>', offset=72, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=72, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=27, argval=26, argrepr='to 26', offset=78, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=80, starts_line=8, is_jump_target=True, positions=None), @@ -1581,12 +1581,12 @@ def _prepare_test_cases(): Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=146, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=148, starts_line=14, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=150, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=75, argval='>', argrepr='>', offset=152, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=152, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=160, argrepr='to 160', offset=156, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=25, argval=110, argrepr='to 110', offset=158, starts_line=15, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=160, starts_line=16, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=162, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=164, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=164, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=172, argrepr='to 172', offset=168, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=15, argval=202, argrepr='to 202', offset=170, starts_line=17, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=172, starts_line=11, is_jump_target=True, positions=None), diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst new file mode 100644 index 000000000000..31a8660836c7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst @@ -0,0 +1 @@ +Replace all occurrences of ``COMPARE_AND_BRANCH`` with :opcode:`COMPARE_OP`. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 19bd4b10780b..63590d58809e 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -347,14 +347,6 @@ mark_stacks(PyCodeObject *code_obj, int len) assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); stacks[j] = next_stack; break; - case COMPARE_AND_BRANCH: - next_stack = pop_value(pop_value(next_stack)); - i++; - j = get_arg(code, i) + i + 1; - assert(j < len); - assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); - stacks[j] = next_stack; - break; case GET_ITER: case GET_AITER: next_stack = push_value(pop_value(next_stack), Iterator); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b5ead16d3f1b..2fe85dfeedf4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1687,75 +1687,54 @@ dummy_func( Py_DECREF(owner); } - inst(COMPARE_OP, (unused/1, left, right -- res)) { - STAT_INC(COMPARE_OP, deferred); - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); - DECREF_INPUTS(); - ERROR_IF(res == NULL, error); - } - - // No cache size here, since this is a family of super-instructions. - family(compare_and_branch) = { - COMPARE_AND_BRANCH, - COMPARE_AND_BRANCH_FLOAT, - COMPARE_AND_BRANCH_INT, - COMPARE_AND_BRANCH_STR, + family(compare_op, INLINE_CACHE_ENTRIES_COMPARE_OP) = { + COMPARE_OP, + COMPARE_OP_FLOAT, + COMPARE_OP_INT, + COMPARE_OP_STR, }; - inst(COMPARE_AND_BRANCH, (unused/2, left, right -- )) { + inst(COMPARE_OP, (unused/1, left, right -- res)) { #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_CompareAndBranch(left, right, next_instr, oparg); + _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); } - STAT_INC(COMPARE_AND_BRANCH, deferred); + STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); - PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); + res = PyObject_RichCompare(left, right, oparg>>4); DECREF_INPUTS(); - ERROR_IF(cond == NULL, error); - assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || - next_instr[1].op.code == POP_JUMP_IF_TRUE); - bool jump_on_true = next_instr[1].op.code == POP_JUMP_IF_TRUE; - int offset = next_instr[1].op.arg; - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - ERROR_IF(err < 0, error); - if (jump_on_true == (err != 0)) { - JUMPBY(offset); - } + ERROR_IF(res == NULL, error); } - inst(COMPARE_AND_BRANCH_FLOAT, (unused/2, left, right -- )) { + inst(COMPARE_OP_FLOAT, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); double dleft = PyFloat_AS_DOUBLE(left); double dright = PyFloat_AS_DOUBLE(right); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - if (sign_ish & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } + res = (sign_ish & oparg) ? Py_True : Py_False; + Py_INCREF(res); } - // Similar to COMPARE_AND_BRANCH_FLOAT - inst(COMPARE_AND_BRANCH_INT, (unused/2, left, right -- )) { + // Similar to COMPARE_OP_FLOAT + inst(COMPARE_OP_INT, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); @@ -1764,29 +1743,25 @@ dummy_func( int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - if (sign_ish & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } + res = (sign_ish & oparg) ? Py_True : Py_False; + Py_INCREF(res); } - // Similar to COMPARE_AND_BRANCH_FLOAT, but for ==, != only - inst(COMPARE_AND_BRANCH_STR, (unused/2, left, right -- )) { + // Similar to COMPARE_OP_FLOAT, but for ==, != only + inst(COMPARE_OP_STR, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); - int res = _PyUnicode_Equal(left, right); + DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); + int eq = _PyUnicode_Equal(left, right); assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - assert(res == 0 || res == 1); + assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); - if ((res + COMPARISON_NOT_EQUALS) & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } + res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; + Py_INCREF(res); } inst(IS_OP, (left, right -- b)) { diff --git a/Python/compile.c b/Python/compile.c index 33cd6ca07d3b..192deaa4b35f 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2800,6 +2800,15 @@ check_compare(struct compiler *c, expr_ty e) return SUCCESS; } +static const int compare_masks[] = { + [Py_LT] = COMPARISON_LESS_THAN, + [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, + [Py_EQ] = COMPARISON_EQUALS, + [Py_NE] = COMPARISON_NOT_EQUALS, + [Py_GT] = COMPARISON_GREATER_THAN, + [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS, +}; + static int compiler_addcompare(struct compiler *c, location loc, cmpop_ty op) { @@ -2840,7 +2849,7 @@ static int compiler_addcompare(struct compiler *c, location loc, } /* cmp goes in top bits of the oparg, while the low bits are used by quickened * versions of this opcode to store the comparison mask. */ - ADDOP_I(c, loc, COMPARE_OP, cmp << 4); + ADDOP_I(c, loc, COMPARE_OP, (cmp << 4) | compare_masks[cmp]); return SUCCESS; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c59042dad66c..d793c1e23bc4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2420,98 +2420,72 @@ } TARGET(COMPARE_OP) { + PREDICTED(COMPARE_OP); + static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1691 "Python/bytecodes.c" - STAT_INC(COMPARE_OP, deferred); - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); - #line 2431 "Python/generated_cases.c.h" - Py_DECREF(left); - Py_DECREF(right); - #line 1695 "Python/bytecodes.c" - if (res == NULL) goto pop_2_error; - #line 2436 "Python/generated_cases.c.h" - STACK_SHRINK(1); - stack_pointer[-1] = res; - next_instr += 1; - DISPATCH(); - } - - TARGET(COMPARE_AND_BRANCH) { - PREDICTED(COMPARE_AND_BRANCH); - PyObject *right = stack_pointer[-1]; - PyObject *left = stack_pointer[-2]; - #line 1707 "Python/bytecodes.c" + #line 1698 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_CompareAndBranch(left, right, next_instr, oparg); + _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); } - STAT_INC(COMPARE_AND_BRANCH, deferred); + STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); - PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); - #line 2461 "Python/generated_cases.c.h" + res = PyObject_RichCompare(left, right, oparg>>4); + #line 2443 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1721 "Python/bytecodes.c" - if (cond == NULL) goto pop_2_error; - assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || - next_instr[1].op.code == POP_JUMP_IF_TRUE); - bool jump_on_true = next_instr[1].op.code == POP_JUMP_IF_TRUE; - int offset = next_instr[1].op.arg; - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err < 0) goto pop_2_error; - if (jump_on_true == (err != 0)) { - JUMPBY(offset); - } - #line 2476 "Python/generated_cases.c.h" - STACK_SHRINK(2); - next_instr += 2; + #line 1712 "Python/bytecodes.c" + if (res == NULL) goto pop_2_error; + #line 2448 "Python/generated_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + next_instr += 1; DISPATCH(); } - TARGET(COMPARE_AND_BRANCH_FLOAT) { + TARGET(COMPARE_OP_FLOAT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1735 "Python/bytecodes.c" + PyObject *res; + #line 1716 "Python/bytecodes.c" assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); double dleft = PyFloat_AS_DOUBLE(left); double dright = PyFloat_AS_DOUBLE(right); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - if (sign_ish & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } - #line 2500 "Python/generated_cases.c.h" - STACK_SHRINK(2); - next_instr += 2; + res = (sign_ish & oparg) ? Py_True : Py_False; + Py_INCREF(res); + #line 2472 "Python/generated_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + next_instr += 1; DISPATCH(); } - TARGET(COMPARE_AND_BRANCH_INT) { + TARGET(COMPARE_OP_INT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1753 "Python/bytecodes.c" + PyObject *res; + #line 1732 "Python/bytecodes.c" assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); @@ -2520,38 +2494,37 @@ int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - if (sign_ish & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } - #line 2528 "Python/generated_cases.c.h" - STACK_SHRINK(2); - next_instr += 2; + res = (sign_ish & oparg) ? Py_True : Py_False; + Py_INCREF(res); + #line 2500 "Python/generated_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + next_instr += 1; DISPATCH(); } - TARGET(COMPARE_AND_BRANCH_STR) { + TARGET(COMPARE_OP_STR) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 1775 "Python/bytecodes.c" + PyObject *res; + #line 1752 "Python/bytecodes.c" assert(cframe.use_tracing == 0); - DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); - int res = _PyUnicode_Equal(left, right); + DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); + int eq = _PyUnicode_Equal(left, right); assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - assert(res == 0 || res == 1); + assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); - if ((res + COMPARISON_NOT_EQUALS) & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } - #line 2553 "Python/generated_cases.c.h" - STACK_SHRINK(2); - next_instr += 2; + res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; + Py_INCREF(res); + #line 2525 "Python/generated_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + next_instr += 1; DISPATCH(); } @@ -2559,14 +2532,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1793 "Python/bytecodes.c" + #line 1768 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2565 "Python/generated_cases.c.h" + #line 2538 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1795 "Python/bytecodes.c" + #line 1770 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2570 "Python/generated_cases.c.h" + #line 2543 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2576,15 +2549,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1799 "Python/bytecodes.c" + #line 1774 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2582 "Python/generated_cases.c.h" + #line 2555 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1801 "Python/bytecodes.c" + #line 1776 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); - #line 2588 "Python/generated_cases.c.h" + #line 2561 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2595,12 +2568,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1806 "Python/bytecodes.c" + #line 1781 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2601 "Python/generated_cases.c.h" + #line 2574 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1808 "Python/bytecodes.c" + #line 1783 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2608,10 +2581,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2612 "Python/generated_cases.c.h" + #line 2585 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1816 "Python/bytecodes.c" + #line 1791 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2620,7 +2593,7 @@ if (!Py_IsNone(match)) { PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); } - #line 2624 "Python/generated_cases.c.h" + #line 2597 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -2630,21 +2603,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1827 "Python/bytecodes.c" + #line 1802 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 2637 "Python/generated_cases.c.h" + #line 2610 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1830 "Python/bytecodes.c" + #line 1805 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 2644 "Python/generated_cases.c.h" + #line 2617 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1835 "Python/bytecodes.c" + #line 1810 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); - #line 2648 "Python/generated_cases.c.h" + #line 2621 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -2653,15 +2626,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 1839 "Python/bytecodes.c" + #line 1814 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 2660 "Python/generated_cases.c.h" + #line 2633 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 1842 "Python/bytecodes.c" + #line 1817 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2665 "Python/generated_cases.c.h" + #line 2638 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -2670,29 +2643,29 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 1846 "Python/bytecodes.c" + #line 1821 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 2678 "Python/generated_cases.c.h" + #line 2651 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 1852 "Python/bytecodes.c" + #line 1827 "Python/bytecodes.c" JUMPBY(oparg); - #line 2687 "Python/generated_cases.c.h" + #line 2660 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 1856 "Python/bytecodes.c" + #line 1831 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); - #line 2696 "Python/generated_cases.c.h" + #line 2669 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -2700,7 +2673,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 1862 "Python/bytecodes.c" + #line 1837 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2710,9 +2683,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2714 "Python/generated_cases.c.h" + #line 2687 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1872 "Python/bytecodes.c" + #line 1847 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2720,14 +2693,14 @@ if (err < 0) goto pop_1_error; } } - #line 2724 "Python/generated_cases.c.h" + #line 2697 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 1882 "Python/bytecodes.c" + #line 1857 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2737,9 +2710,9 @@ } else { int err = PyObject_IsTrue(cond); - #line 2741 "Python/generated_cases.c.h" + #line 2714 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1892 "Python/bytecodes.c" + #line 1867 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2747,67 +2720,67 @@ if (err < 0) goto pop_1_error; } } - #line 2751 "Python/generated_cases.c.h" + #line 2724 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 1902 "Python/bytecodes.c" + #line 1877 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 2760 "Python/generated_cases.c.h" + #line 2733 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1904 "Python/bytecodes.c" + #line 1879 "Python/bytecodes.c" JUMPBY(oparg); } else { _Py_DECREF_NO_DEALLOC(value); } - #line 2768 "Python/generated_cases.c.h" + #line 2741 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 1912 "Python/bytecodes.c" + #line 1887 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); } else { - #line 2781 "Python/generated_cases.c.h" + #line 2754 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1918 "Python/bytecodes.c" + #line 1893 "Python/bytecodes.c" } - #line 2785 "Python/generated_cases.c.h" + #line 2758 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 1922 "Python/bytecodes.c" + #line 1897 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. * (see bpo-30039). */ JUMPBY(-oparg); - #line 2798 "Python/generated_cases.c.h" + #line 2771 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 1931 "Python/bytecodes.c" + #line 1906 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 2811 "Python/generated_cases.c.h" + #line 2784 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -2818,16 +2791,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 1939 "Python/bytecodes.c" + #line 1914 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 2827 "Python/generated_cases.c.h" + #line 2800 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 1944 "Python/bytecodes.c" + #line 1919 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2835,7 +2808,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_NewRef(Py_None); // Failure! } - #line 2839 "Python/generated_cases.c.h" + #line 2812 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -2844,10 +2817,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1954 "Python/bytecodes.c" + #line 1929 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); - #line 2851 "Python/generated_cases.c.h" + #line 2824 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2857,10 +2830,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1960 "Python/bytecodes.c" + #line 1935 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); - #line 2864 "Python/generated_cases.c.h" + #line 2837 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; PREDICT(POP_JUMP_IF_FALSE); @@ -2871,11 +2844,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 1966 "Python/bytecodes.c" + #line 1941 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 2879 "Python/generated_cases.c.h" + #line 2852 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -2884,14 +2857,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 1972 "Python/bytecodes.c" + #line 1947 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 2891 "Python/generated_cases.c.h" + #line 2864 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1975 "Python/bytecodes.c" + #line 1950 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 2895 "Python/generated_cases.c.h" + #line 2868 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -2899,7 +2872,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 1979 "Python/bytecodes.c" + #line 1954 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2922,11 +2895,11 @@ if (iter == NULL) { goto error; } - #line 2926 "Python/generated_cases.c.h" + #line 2899 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2002 "Python/bytecodes.c" + #line 1977 "Python/bytecodes.c" } - #line 2930 "Python/generated_cases.c.h" + #line 2903 "Python/generated_cases.c.h" stack_pointer[-1] = iter; PREDICT(LOAD_CONST); DISPATCH(); @@ -2937,7 +2910,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2021 "Python/bytecodes.c" + #line 1996 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2970,7 +2943,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 2974 "Python/generated_cases.c.h" + #line 2947 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -2980,7 +2953,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2056 "Python/bytecodes.c" + #line 2031 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -3001,7 +2974,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3005 "Python/generated_cases.c.h" + #line 2978 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3011,7 +2984,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2079 "Python/bytecodes.c" + #line 2054 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -3032,7 +3005,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3036 "Python/generated_cases.c.h" + #line 3009 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3042,7 +3015,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2102 "Python/bytecodes.c" + #line 2077 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -3061,7 +3034,7 @@ if (next == NULL) { goto error; } - #line 3065 "Python/generated_cases.c.h" + #line 3038 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3070,7 +3043,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2123 "Python/bytecodes.c" + #line 2098 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3085,14 +3058,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); assert(next_instr->op.code == END_FOR); DISPATCH_INLINED(gen_frame); - #line 3089 "Python/generated_cases.c.h" + #line 3062 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2140 "Python/bytecodes.c" + #line 2115 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3115,16 +3088,16 @@ Py_DECREF(enter); goto error; } - #line 3119 "Python/generated_cases.c.h" + #line 3092 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2163 "Python/bytecodes.c" + #line 2138 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3128 "Python/generated_cases.c.h" + #line 3101 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3136,7 +3109,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2173 "Python/bytecodes.c" + #line 2148 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3162,16 +3135,16 @@ Py_DECREF(enter); goto error; } - #line 3166 "Python/generated_cases.c.h" + #line 3139 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2199 "Python/bytecodes.c" + #line 2174 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3175 "Python/generated_cases.c.h" + #line 3148 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3183,7 +3156,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2208 "Python/bytecodes.c" + #line 2183 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3204,7 +3177,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3208 "Python/generated_cases.c.h" + #line 3181 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3213,7 +3186,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2231 "Python/bytecodes.c" + #line 2206 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3223,7 +3196,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3227 "Python/generated_cases.c.h" + #line 3200 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3237,7 +3210,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2243 "Python/bytecodes.c" + #line 2218 "Python/bytecodes.c" /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -3255,7 +3228,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3259 "Python/generated_cases.c.h" + #line 3232 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3269,7 +3242,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2263 "Python/bytecodes.c" + #line 2238 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3280,7 +3253,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3284 "Python/generated_cases.c.h" + #line 3257 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3294,7 +3267,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2276 "Python/bytecodes.c" + #line 2251 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3309,7 +3282,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3313 "Python/generated_cases.c.h" + #line 3286 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3318,11 +3291,11 @@ } TARGET(KW_NAMES) { - #line 2293 "Python/bytecodes.c" + #line 2268 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); - #line 3326 "Python/generated_cases.c.h" + #line 3299 "Python/generated_cases.c.h" DISPATCH(); } @@ -3333,7 +3306,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2329 "Python/bytecodes.c" + #line 2304 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3405,7 +3378,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3409 "Python/generated_cases.c.h" + #line 3382 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3417,7 +3390,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2407 "Python/bytecodes.c" + #line 2382 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3427,7 +3400,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3431 "Python/generated_cases.c.h" + #line 3404 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3436,7 +3409,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2419 "Python/bytecodes.c" + #line 2394 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3461,7 +3434,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3465 "Python/generated_cases.c.h" + #line 3438 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3470,7 +3443,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); uint16_t min_args = read_u16(&next_instr[3].cache); - #line 2446 "Python/bytecodes.c" + #line 2421 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3500,7 +3473,7 @@ STACK_SHRINK(oparg + 2); JUMPBY(INLINE_CACHE_ENTRIES_CALL); DISPATCH_INLINED(new_frame); - #line 3504 "Python/generated_cases.c.h" + #line 3477 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3508,7 +3481,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2478 "Python/bytecodes.c" + #line 2453 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3519,7 +3492,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3523 "Python/generated_cases.c.h" + #line 3496 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3532,7 +3505,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2491 "Python/bytecodes.c" + #line 2466 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3544,7 +3517,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3548 "Python/generated_cases.c.h" + #line 3521 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3558,7 +3531,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2506 "Python/bytecodes.c" + #line 2481 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3569,7 +3542,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3573 "Python/generated_cases.c.h" + #line 3546 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3583,7 +3556,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2520 "Python/bytecodes.c" + #line 2495 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3605,7 +3578,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3609 "Python/generated_cases.c.h" + #line 3582 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3619,7 +3592,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2545 "Python/bytecodes.c" + #line 2520 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3648,7 +3621,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3652 "Python/generated_cases.c.h" + #line 3625 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3662,7 +3635,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2577 "Python/bytecodes.c" + #line 2552 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3695,7 +3668,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 3699 "Python/generated_cases.c.h" + #line 3672 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3709,7 +3682,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2613 "Python/bytecodes.c" + #line 2588 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3742,7 +3715,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3746 "Python/generated_cases.c.h" + #line 3719 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3756,7 +3729,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2649 "Python/bytecodes.c" + #line 2624 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3782,7 +3755,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3786 "Python/generated_cases.c.h" + #line 3759 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3795,7 +3768,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2677 "Python/bytecodes.c" + #line 2652 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3823,7 +3796,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3827 "Python/generated_cases.c.h" + #line 3800 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3835,7 +3808,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2708 "Python/bytecodes.c" + #line 2683 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3854,14 +3827,14 @@ JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 3858 "Python/generated_cases.c.h" + #line 3831 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2729 "Python/bytecodes.c" + #line 2704 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3892,7 +3865,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3896 "Python/generated_cases.c.h" + #line 3869 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3905,7 +3878,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2763 "Python/bytecodes.c" + #line 2738 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3934,7 +3907,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3938 "Python/generated_cases.c.h" + #line 3911 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3947,7 +3920,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2795 "Python/bytecodes.c" + #line 2770 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -3976,7 +3949,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3980 "Python/generated_cases.c.h" + #line 3953 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3989,7 +3962,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2827 "Python/bytecodes.c" + #line 2802 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4017,7 +3990,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4021 "Python/generated_cases.c.h" + #line 3994 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4032,7 +4005,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 2858 "Python/bytecodes.c" + #line 2833 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -4051,15 +4024,15 @@ assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - #line 4055 "Python/generated_cases.c.h" + #line 4028 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 2877 "Python/bytecodes.c" + #line 2852 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4063 "Python/generated_cases.c.h" + #line 4036 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4074,7 +4047,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 2888 "Python/bytecodes.c" + #line 2863 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4103,14 +4076,14 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4107 "Python/generated_cases.c.h" + #line 4080 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 2919 "Python/bytecodes.c" + #line 2894 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4131,7 +4104,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4135 "Python/generated_cases.c.h" + #line 4108 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4139,15 +4112,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 2942 "Python/bytecodes.c" + #line 2917 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4145 "Python/generated_cases.c.h" + #line 4118 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 2944 "Python/bytecodes.c" + #line 2919 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4151 "Python/generated_cases.c.h" + #line 4124 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4158,7 +4131,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 2948 "Python/bytecodes.c" + #line 2923 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4193,7 +4166,7 @@ Py_DECREF(value); Py_XDECREF(fmt_spec); if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - #line 4197 "Python/generated_cases.c.h" + #line 4170 "Python/generated_cases.c.h" STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); @@ -4202,10 +4175,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 2985 "Python/bytecodes.c" + #line 2960 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4209 "Python/generated_cases.c.h" + #line 4182 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4217,7 +4190,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 2990 "Python/bytecodes.c" + #line 2965 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4233,12 +4206,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4237 "Python/generated_cases.c.h" + #line 4210 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3006 "Python/bytecodes.c" + #line 2981 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4242 "Python/generated_cases.c.h" + #line 4215 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4248,27 +4221,27 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3011 "Python/bytecodes.c" + #line 2986 "Python/bytecodes.c" assert(oparg >= 2); - #line 4254 "Python/generated_cases.c.h" + #line 4227 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3015 "Python/bytecodes.c" + #line 2990 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4268 "Python/generated_cases.c.h" + #line 4241 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3024 "Python/bytecodes.c" + #line 2999 "Python/bytecodes.c" Py_UNREACHABLE(); - #line 4274 "Python/generated_cases.c.h" + #line 4247 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 920b7595484d..347a84dad463 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -215,13 +215,11 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case COMPARE_OP: return 2; - case COMPARE_AND_BRANCH: + case COMPARE_OP_FLOAT: return 2; - case COMPARE_AND_BRANCH_FLOAT: + case COMPARE_OP_INT: return 2; - case COMPARE_AND_BRANCH_INT: - return 2; - case COMPARE_AND_BRANCH_STR: + case COMPARE_OP_STR: return 2; case IS_OP: return 2; @@ -563,14 +561,12 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case COMPARE_OP: return 1; - case COMPARE_AND_BRANCH: - return 0; - case COMPARE_AND_BRANCH_FLOAT: - return 0; - case COMPARE_AND_BRANCH_INT: - return 0; - case COMPARE_AND_BRANCH_STR: - return 0; + case COMPARE_OP_FLOAT: + return 1; + case COMPARE_OP_INT: + return 1; + case COMPARE_OP_STR: + return 1; case IS_OP: return 1; case CONTAINS_OP: @@ -699,7 +695,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; +enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; @@ -812,10 +808,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000 }, [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000 }, [COMPARE_OP] = { true, INSTR_FMT_IBC }, - [COMPARE_AND_BRANCH] = { true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_FLOAT] = { true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_INT] = { true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_STR] = { true, INSTR_FMT_IBC0 }, + [COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC }, + [COMPARE_OP_INT] = { true, INSTR_FMT_IBC }, + [COMPARE_OP_STR] = { true, INSTR_FMT_IBC }, [IS_OP] = { true, INSTR_FMT_IB }, [CONTAINS_OP] = { true, INSTR_FMT_IB }, [CHECK_EG_MATCH] = { true, INSTR_FMT_IX }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 52f23ce7752e..c502471bcd17 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -47,7 +47,7 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_STR_1, &&TARGET_CALL_NO_KW_TUPLE_1, &&TARGET_CALL_NO_KW_TYPE_1, - &&TARGET_COMPARE_AND_BRANCH_FLOAT, + &&TARGET_COMPARE_OP_FLOAT, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,8 +55,8 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, - &&TARGET_COMPARE_AND_BRANCH_INT, - &&TARGET_COMPARE_AND_BRANCH_STR, + &&TARGET_COMPARE_OP_INT, + &&TARGET_COMPARE_OP_STR, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_TUPLE, &&TARGET_STORE_SUBSCR, @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_COMPARE_AND_BRANCH, - &&TARGET_CALL_FUNCTION_EX, &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_CALL_FUNCTION_EX, + &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,15 +152,15 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, &&_unknown_opcode, &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, diff --git a/Python/specialize.c b/Python/specialize.c index 2e93ab193990..dd5b22dd2346 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -264,15 +264,6 @@ do { \ #define SPECIALIZATION_FAIL(opcode, kind) ((void)0) #endif -static int compare_masks[] = { - [Py_LT] = COMPARISON_LESS_THAN, - [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, - [Py_EQ] = COMPARISON_EQUALS, - [Py_NE] = COMPARISON_NOT_EQUALS, - [Py_GT] = COMPARISON_GREATER_THAN, - [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS, -}; - // Initialize warmup counters and insert superinstructions. This cannot fail. void _PyCode_Quicken(PyCodeObject *code) @@ -305,19 +296,6 @@ _PyCode_Quicken(PyCodeObject *code) case STORE_FAST << 8 | STORE_FAST: instructions[i - 1].op.code = STORE_FAST__STORE_FAST; break; - case COMPARE_OP << 8 | POP_JUMP_IF_TRUE: - case COMPARE_OP << 8 | POP_JUMP_IF_FALSE: - { - int oparg = instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].op.arg; - assert((oparg >> 4) <= Py_GE); - int mask = compare_masks[oparg >> 4]; - if (opcode == POP_JUMP_IF_FALSE) { - mask = mask ^ 0xf; - } - instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].op.code = COMPARE_AND_BRANCH; - instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].op.arg = (oparg & 0xf0) | mask; - break; - } } } #endif /* ENABLE_SPECIALIZATION */ @@ -436,19 +414,17 @@ _PyCode_Quicken(PyCodeObject *code) #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29 /* COMPARE_OP */ -#define SPEC_FAIL_COMPARE_DIFFERENT_TYPES 12 -#define SPEC_FAIL_COMPARE_STRING 13 -#define SPEC_FAIL_COMPARE_NOT_FOLLOWED_BY_COND_JUMP 14 -#define SPEC_FAIL_COMPARE_BIG_INT 15 -#define SPEC_FAIL_COMPARE_BYTES 16 -#define SPEC_FAIL_COMPARE_TUPLE 17 -#define SPEC_FAIL_COMPARE_LIST 18 -#define SPEC_FAIL_COMPARE_SET 19 -#define SPEC_FAIL_COMPARE_BOOL 20 -#define SPEC_FAIL_COMPARE_BASEOBJECT 21 -#define SPEC_FAIL_COMPARE_FLOAT_LONG 22 -#define SPEC_FAIL_COMPARE_LONG_FLOAT 23 -#define SPEC_FAIL_COMPARE_EXTENDED_ARG 24 +#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12 +#define SPEC_FAIL_COMPARE_OP_STRING 13 +#define SPEC_FAIL_COMPARE_OP_BIG_INT 14 +#define SPEC_FAIL_COMPARE_OP_BYTES 15 +#define SPEC_FAIL_COMPARE_OP_TUPLE 16 +#define SPEC_FAIL_COMPARE_OP_LIST 17 +#define SPEC_FAIL_COMPARE_OP_SET 18 +#define SPEC_FAIL_COMPARE_OP_BOOL 19 +#define SPEC_FAIL_COMPARE_OP_BASEOBJECT 20 +#define SPEC_FAIL_COMPARE_OP_FLOAT_LONG 21 +#define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 22 /* FOR_ITER */ #define SPEC_FAIL_FOR_ITER_GENERATOR 10 @@ -1958,83 +1934,79 @@ compare_op_fail_kind(PyObject *lhs, PyObject *rhs) { if (Py_TYPE(lhs) != Py_TYPE(rhs)) { if (PyFloat_CheckExact(lhs) && PyLong_CheckExact(rhs)) { - return SPEC_FAIL_COMPARE_FLOAT_LONG; + return SPEC_FAIL_COMPARE_OP_FLOAT_LONG; } if (PyLong_CheckExact(lhs) && PyFloat_CheckExact(rhs)) { - return SPEC_FAIL_COMPARE_LONG_FLOAT; + return SPEC_FAIL_COMPARE_OP_LONG_FLOAT; } - return SPEC_FAIL_COMPARE_DIFFERENT_TYPES; + return SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES; } if (PyBytes_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_BYTES; + return SPEC_FAIL_COMPARE_OP_BYTES; } if (PyTuple_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_TUPLE; + return SPEC_FAIL_COMPARE_OP_TUPLE; } if (PyList_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_LIST; + return SPEC_FAIL_COMPARE_OP_LIST; } if (PySet_CheckExact(lhs) || PyFrozenSet_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_SET; + return SPEC_FAIL_COMPARE_OP_SET; } if (PyBool_Check(lhs)) { - return SPEC_FAIL_COMPARE_BOOL; + return SPEC_FAIL_COMPARE_OP_BOOL; } if (Py_TYPE(lhs)->tp_richcompare == PyBaseObject_Type.tp_richcompare) { - return SPEC_FAIL_COMPARE_BASEOBJECT; + return SPEC_FAIL_COMPARE_OP_BASEOBJECT; } return SPEC_FAIL_OTHER; } #endif void -_Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, +_Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg) { assert(ENABLE_SPECIALIZATION); - assert(_PyOpcode_Caches[COMPARE_AND_BRANCH] == INLINE_CACHE_ENTRIES_COMPARE_OP); + assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1); -#ifndef NDEBUG - int next_opcode = instr[INLINE_CACHE_ENTRIES_COMPARE_OP + 1].op.code; - assert(next_opcode == POP_JUMP_IF_FALSE || next_opcode == POP_JUMP_IF_TRUE); -#endif if (Py_TYPE(lhs) != Py_TYPE(rhs)) { - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, compare_op_fail_kind(lhs, rhs)); + SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); goto failure; } if (PyFloat_CheckExact(lhs)) { - instr->op.code = COMPARE_AND_BRANCH_FLOAT; + instr->op.code = COMPARE_OP_FLOAT; goto success; } if (PyLong_CheckExact(lhs)) { if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) { - instr->op.code = COMPARE_AND_BRANCH_INT; + instr->op.code = COMPARE_OP_INT; goto success; } else { - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, SPEC_FAIL_COMPARE_BIG_INT); + SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_BIG_INT); goto failure; } } if (PyUnicode_CheckExact(lhs)) { int cmp = oparg >> 4; if (cmp != Py_EQ && cmp != Py_NE) { - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, SPEC_FAIL_COMPARE_STRING); + SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_STRING); goto failure; } else { - instr->op.code = COMPARE_AND_BRANCH_STR; + instr->op.code = COMPARE_OP_STR; goto success; } } - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, compare_op_fail_kind(lhs, rhs)); + SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); failure: - STAT_INC(COMPARE_AND_BRANCH, failure); - instr->op.code = COMPARE_AND_BRANCH; + STAT_INC(COMPARE_OP, failure); + instr->op.code = COMPARE_OP; cache->counter = adaptive_counter_backoff(cache->counter); return; success: - STAT_INC(COMPARE_AND_BRANCH, success); + STAT_INC(COMPARE_OP, success); cache->counter = adaptive_counter_cooldown(); } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 14fc32a07b43..9203c1888149 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -350,7 +350,6 @@ Python/pylifecycle.c - INTERPRETER_TRAMPOLINE_CODEDEF - Python/pystate.c - initial - Python/specialize.c - adaptive_opcodes - Python/specialize.c - cache_requirements - -Python/specialize.c - compare_masks - Python/stdlib_module_names.h - _Py_stdlib_module_names - Python/sysmodule.c - _PySys_ImplCacheTag - Python/sysmodule.c - _PySys_ImplName - diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index 7789c4d3a17d..ce25374f3a9a 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -228,8 +228,6 @@ def kind_to_text(kind, defines, opname): return pretty(defines[kind][0]) if opname.endswith("ATTR"): opname = "ATTR" - if opname in ("COMPARE_OP", "COMPARE_AND_BRANCH"): - opname = "COMPARE" if opname.endswith("SUBSCR"): opname = "SUBSCR" for name in defines[kind]: From webhook-mailer at python.org Thu Mar 23 19:27:53 2023 From: webhook-mailer at python.org (zooba) Date: Thu, 23 Mar 2023 23:27:53 -0000 Subject: [Python-checkins] gh-99726: Fix order of recently added fields for FILE_STAT_BASIC_INFORMATION (GH-102976) Message-ID: https://github.com/python/cpython/commit/f1e3eeebc01941f9c25bca4d2fa6313cf5041cc4 commit: f1e3eeebc01941f9c25bca4d2fa6313cf5041cc4 branch: main author: Steve Dower committer: zooba date: 2023-03-23T23:27:46Z summary: gh-99726: Fix order of recently added fields for FILE_STAT_BASIC_INFORMATION (GH-102976) files: M Include/internal/pycore_fileutils_windows.h diff --git a/Include/internal/pycore_fileutils_windows.h b/Include/internal/pycore_fileutils_windows.h index 44874903b092..9bc7feb8cecd 100644 --- a/Include/internal/pycore_fileutils_windows.h +++ b/Include/internal/pycore_fileutils_windows.h @@ -25,8 +25,8 @@ typedef struct _FILE_STAT_BASIC_INFORMATION { ULONG DeviceType; ULONG DeviceCharacteristics; ULONG Reserved; - FILE_ID_128 FileId128; LARGE_INTEGER VolumeSerialNumber; + FILE_ID_128 FileId128; } FILE_STAT_BASIC_INFORMATION; typedef enum _FILE_INFO_BY_NAME_CLASS { From webhook-mailer at python.org Thu Mar 23 19:42:50 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Thu, 23 Mar 2023 23:42:50 -0000 Subject: [Python-checkins] gh-94684: uuid: support bytes in the name argument to uuid3/5 (#94709) Message-ID: https://github.com/python/cpython/commit/413b7db8a480ea6e0d3e8c9729502282ca748a84 commit: 413b7db8a480ea6e0d3e8c9729502282ca748a84 branch: main author: MonadChains committer: JelleZijlstra date: 2023-03-23T17:42:43-06:00 summary: gh-94684: uuid: support bytes in the name argument to uuid3/5 (#94709) RFC 4122 does not specify that name should be a string, so for completness the functions should also support a name given as a raw byte sequence. files: A Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst M Doc/library/uuid.rst M Lib/test/test_uuid.py M Lib/uuid.py diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index 38b6434f467f..94b9a4323721 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -186,7 +186,8 @@ The :mod:`uuid` module defines the following functions: .. function:: uuid3(namespace, name) Generate a UUID based on the MD5 hash of a namespace identifier (which is a - UUID) and a name (which is a string). + UUID) and a name (which is a :class:`bytes` object or a string + that will be encoded using UTF-8). .. index:: single: uuid3 @@ -201,7 +202,8 @@ The :mod:`uuid` module defines the following functions: .. function:: uuid5(namespace, name) Generate a UUID based on the SHA-1 hash of a namespace identifier (which is a - UUID) and a name (which is a string). + UUID) and a name (which is a :class:`bytes` object or a string + that will be encoded using UTF-8). .. index:: single: uuid5 diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index b2c229cd634e..a178e942ecda 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -600,7 +600,22 @@ def test_uuid1_time(self): def test_uuid3(self): equal = self.assertEqual - # Test some known version-3 UUIDs. + # Test some known version-3 UUIDs with name passed as a byte object + for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, b'python.org'), + '6fa459ea-ee8a-3ca4-894e-db77e160355e'), + (self.uuid.uuid3(self.uuid.NAMESPACE_URL, b'http://python.org/'), + '9fe8e8c4-aaa8-32a9-a55c-4535a88b748d'), + (self.uuid.uuid3(self.uuid.NAMESPACE_OID, b'1.3.6.1'), + 'dd1a1cef-13d5-368a-ad82-eca71acd4cd1'), + (self.uuid.uuid3(self.uuid.NAMESPACE_X500, b'c=ca'), + '658d3002-db6b-3040-a1d1-8ddd7d189a4d'), + ]: + equal(u.variant, self.uuid.RFC_4122) + equal(u.version, 3) + equal(u, self.uuid.UUID(v)) + equal(str(u), v) + + # Test some known version-3 UUIDs with name passed as a string for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, 'python.org'), '6fa459ea-ee8a-3ca4-894e-db77e160355e'), (self.uuid.uuid3(self.uuid.NAMESPACE_URL, 'http://python.org/'), @@ -632,7 +647,22 @@ def test_uuid4(self): def test_uuid5(self): equal = self.assertEqual - # Test some known version-5 UUIDs. + # Test some known version-5 UUIDs with names given as byte objects + for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, b'python.org'), + '886313e1-3b8a-5372-9b90-0c9aee199e5d'), + (self.uuid.uuid5(self.uuid.NAMESPACE_URL, b'http://python.org/'), + '4c565f0d-3f5a-5890-b41b-20cf47701c5e'), + (self.uuid.uuid5(self.uuid.NAMESPACE_OID, b'1.3.6.1'), + '1447fa61-5277-5fef-a9b3-fbc6e44f4af3'), + (self.uuid.uuid5(self.uuid.NAMESPACE_X500, b'c=ca'), + 'cc957dd1-a972-5349-98cd-874190002798'), + ]: + equal(u.variant, self.uuid.RFC_4122) + equal(u.version, 5) + equal(u, self.uuid.UUID(v)) + equal(str(u), v) + + # Test some known version-5 UUIDs with names given as strings for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, 'python.org'), '886313e1-3b8a-5372-9b90-0c9aee199e5d'), (self.uuid.uuid5(self.uuid.NAMESPACE_URL, 'http://python.org/'), diff --git a/Lib/uuid.py b/Lib/uuid.py index 1c5578bf1f05..698be34873b9 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -711,9 +711,11 @@ def uuid1(node=None, clock_seq=None): def uuid3(namespace, name): """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" + if isinstance(name, str): + name = bytes(name, "utf-8") from hashlib import md5 digest = md5( - namespace.bytes + bytes(name, "utf-8"), + namespace.bytes + name, usedforsecurity=False ).digest() return UUID(bytes=digest[:16], version=3) @@ -724,8 +726,10 @@ def uuid4(): def uuid5(namespace, name): """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" + if isinstance(name, str): + name = bytes(name, "utf-8") from hashlib import sha1 - hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest() + hash = sha1(namespace.bytes + name).digest() return UUID(bytes=hash[:16], version=5) diff --git a/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst b/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst new file mode 100644 index 000000000000..1fa38c0044d3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst @@ -0,0 +1 @@ +Now :func:`uuid.uuid3` and :func:`uuid.uuid5` functions support :class:`bytes` objects as their *name* argument. From webhook-mailer at python.org Thu Mar 23 20:50:42 2023 From: webhook-mailer at python.org (rhettinger) Date: Fri, 24 Mar 2023 00:50:42 -0000 Subject: [Python-checkins] GH-100989: Revert Improve the accuracy of collections.deque docstrings (GH-102979) Message-ID: https://github.com/python/cpython/commit/7f01a11199864bcf230b243b99e8a51e9044675d commit: 7f01a11199864bcf230b243b99e8a51e9044675d branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-23T19:50:17-05:00 summary: GH-100989: Revert Improve the accuracy of collections.deque docstrings (GH-102979) files: M Modules/_collectionsmodule.c diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index ba4a9760f7b9..68131f3b54d2 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -910,9 +910,7 @@ deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(rotate_doc, -"rotate(n)\n\n" -"Rotate the deque *n* steps to the right (default ``n=1``). " -"If *n* is negative, rotates left."); +"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); static PyObject * deque_reverse(dequeobject *deque, PyObject *unused) @@ -953,8 +951,7 @@ deque_reverse(dequeobject *deque, PyObject *unused) } PyDoc_STRVAR(reverse_doc, -"reverse()\n\n" -"Reverse the elements of the deque *IN PLACE*."); +"D.reverse() -- reverse *IN PLACE*"); static PyObject * deque_count(dequeobject *deque, PyObject *v) @@ -993,8 +990,7 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"count(x) -> int\n\n" -"Count the number of deque elements equal to *x*."); +"D.count(value) -> integer -- return number of occurrences of value"); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1102,10 +1098,8 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"index(x, [start, [stop]]) -> int\n\n" -"Return the position of *x* in the deque " -"(at or after index *start* and before index *stop*). " -"Returns the first match or raises a ValueError if not found."); +"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" +"Raises ValueError if the value is not present."); /* insert(), remove(), and delitem() are implemented in terms of rotate() for simplicity and reasonable performance near the end @@ -1150,13 +1144,10 @@ deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(insert_doc, -"insert(i, x)\n\n" -"Insert *x* into the deque at position *i*."); +"D.insert(index, object) -- insert object before index"); PyDoc_STRVAR(remove_doc, -"remove(x)\n\n" -"Remove the first occurrence of *x*." -"If not found, raises a ValueError."); +"D.remove(value) -- remove first occurrence of value."); static int valid_index(Py_ssize_t i, Py_ssize_t limit) @@ -1527,8 +1518,7 @@ deque_sizeof(dequeobject *deque, void *unused) } PyDoc_STRVAR(sizeof_doc, -"__sizeof__() -> int\n\n" -"Size of the deque in memory, in bytes."); +"D.__sizeof__() -- size of D in memory, in bytes"); static PyObject * deque_get_maxlen(dequeobject *deque, void *Py_UNUSED(ignored)) @@ -1563,8 +1553,7 @@ static PySequenceMethods deque_as_sequence = { static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, -"__reversed__()\n\n" -"Return a reverse iterator over the deque."); + "D.__reversed__() -- return a reverse iterator over the deque"); static PyMethodDef deque_methods[] = { {"append", (PyCFunction)deque_append, @@ -1609,8 +1598,9 @@ static PyMethodDef deque_methods[] = { }; PyDoc_STRVAR(deque_doc, -"deque([iterable[, maxlen]]) -> collections.deque\n\n" -"A list-like sequence optimized for data accesses near its endpoints."); +"deque([iterable[, maxlen]]) --> deque object\n\ +\n\ +A list-like sequence optimized for data accesses near its endpoints."); static PyTypeObject deque_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -1989,8 +1979,7 @@ new_defdict(defdictobject *dd, PyObject *arg) dd->default_factory ? dd->default_factory : Py_None, arg, NULL); } -PyDoc_STRVAR(defdict_copy_doc, "copy() -> collections.deque\n\n" -"A shallow copy of the deque."); +PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); static PyObject * defdict_copy(defdictobject *dd, PyObject *Py_UNUSED(ignored)) From webhook-mailer at python.org Thu Mar 23 21:10:43 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 24 Mar 2023 01:10:43 -0000 Subject: [Python-checkins] GH-100989: Revert Improve the accuracy of collections.deque docstrings (GH-102979) Message-ID: https://github.com/python/cpython/commit/206c2b1b123f82a8edfe8619756b1f1b77d54feb commit: 206c2b1b123f82a8edfe8619756b1f1b77d54feb branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T18:10:34-07:00 summary: GH-100989: Revert Improve the accuracy of collections.deque docstrings (GH-102979) (cherry picked from commit 7f01a11199864bcf230b243b99e8a51e9044675d) Co-authored-by: Raymond Hettinger files: M Modules/_collectionsmodule.c diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 84bc2c2d087f..eff03c789ede 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -920,9 +920,7 @@ deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(rotate_doc, -"rotate(n)\n\n" -"Rotate the deque *n* steps to the right (default ``n=1``). " -"If *n* is negative, rotates left."); +"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); static PyObject * deque_reverse(dequeobject *deque, PyObject *unused) @@ -963,8 +961,7 @@ deque_reverse(dequeobject *deque, PyObject *unused) } PyDoc_STRVAR(reverse_doc, -"reverse()\n\n" -"Reverse the elements of the deque *IN PLACE*."); +"D.reverse() -- reverse *IN PLACE*"); static PyObject * deque_count(dequeobject *deque, PyObject *v) @@ -1004,8 +1001,7 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"count(x) -> int\n\n" -"Count the number of deque elements equal to *x*."); +"D.count(value) -> integer -- return number of occurrences of value"); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1114,10 +1110,8 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"index(x, [start, [stop]]) -> int\n\n" -"Return the position of *x* in the deque " -"(at or after index *start* and before index *stop*). " -"Returns the first match or raises a ValueError if not found."); +"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" +"Raises ValueError if the value is not present."); /* insert(), remove(), and delitem() are implemented in terms of rotate() for simplicity and reasonable performance near the end @@ -1162,13 +1156,10 @@ deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(insert_doc, -"insert(i, x)\n\n" -"Insert *x* into the deque at position *i*."); +"D.insert(index, object) -- insert object before index"); PyDoc_STRVAR(remove_doc, -"remove(x)\n\n" -"Remove the first occurrence of *x*." -"If not found, raises a ValueError."); +"D.remove(value) -- remove first occurrence of value."); static int valid_index(Py_ssize_t i, Py_ssize_t limit) @@ -1546,8 +1537,7 @@ deque_sizeof(dequeobject *deque, void *unused) } PyDoc_STRVAR(sizeof_doc, -"__sizeof__() -> int\n\n" -"Size of the deque in memory, in bytes."); +"D.__sizeof__() -- size of D in memory, in bytes"); static int deque_bool(dequeobject *deque) @@ -1602,8 +1592,7 @@ static PyNumberMethods deque_as_number = { static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, -"__reversed__()\n\n" -"Return a reverse iterator over the deque."); + "D.__reversed__() -- return a reverse iterator over the deque"); static PyMethodDef deque_methods[] = { {"append", (PyCFunction)deque_append, @@ -1648,8 +1637,9 @@ static PyMethodDef deque_methods[] = { }; PyDoc_STRVAR(deque_doc, -"deque([iterable[, maxlen]]) -> collections.deque\n\n" -"A list-like sequence optimized for data accesses near its endpoints."); +"deque([iterable[, maxlen]]) --> deque object\n\ +\n\ +A list-like sequence optimized for data accesses near its endpoints."); static PyTypeObject deque_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -2032,8 +2022,7 @@ new_defdict(defdictobject *dd, PyObject *arg) dd->default_factory ? dd->default_factory : Py_None, arg, NULL); } -PyDoc_STRVAR(defdict_copy_doc, "copy() -> collections.deque\n\n" -"A shallow copy of the deque."); +PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); static PyObject * defdict_copy(defdictobject *dd, PyObject *Py_UNUSED(ignored)) From webhook-mailer at python.org Thu Mar 23 21:17:50 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 24 Mar 2023 01:17:50 -0000 Subject: [Python-checkins] GH-100989: Revert Improve the accuracy of collections.deque docstrings (GH-102979) Message-ID: https://github.com/python/cpython/commit/a4a039c5465b5afe65f95db801477405886abcc9 commit: a4a039c5465b5afe65f95db801477405886abcc9 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T18:17:43-07:00 summary: GH-100989: Revert Improve the accuracy of collections.deque docstrings (GH-102979) (cherry picked from commit 7f01a11199864bcf230b243b99e8a51e9044675d) Co-authored-by: Raymond Hettinger files: M Modules/_collectionsmodule.c diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index b20e51e8b0eb..741cfbe9dc61 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -916,9 +916,7 @@ deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(rotate_doc, -"rotate(n)\n\n" -"Rotate the deque *n* steps to the right (default ``n=1``). " -"If *n* is negative, rotates left."); +"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); static PyObject * deque_reverse(dequeobject *deque, PyObject *unused) @@ -959,8 +957,7 @@ deque_reverse(dequeobject *deque, PyObject *unused) } PyDoc_STRVAR(reverse_doc, -"reverse()\n\n" -"Reverse the elements of the deque *IN PLACE*."); +"D.reverse() -- reverse *IN PLACE*"); static PyObject * deque_count(dequeobject *deque, PyObject *v) @@ -1000,8 +997,7 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"count(x) -> int\n\n" -"Count the number of deque elements equal to *x*."); +"D.count(value) -> integer -- return number of occurrences of value"); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1110,10 +1106,8 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"index(x, [start, [stop]]) -> int\n\n" -"Return the position of *x* in the deque " -"(at or after index *start* and before index *stop*). " -"Returns the first match or raises a ValueError if not found."); +"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" +"Raises ValueError if the value is not present."); /* insert(), remove(), and delitem() are implemented in terms of rotate() for simplicity and reasonable performance near the end @@ -1158,13 +1152,10 @@ deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(insert_doc, -"insert(i, x)\n\n" -"Insert *x* into the deque at position *i*."); +"D.insert(index, object) -- insert object before index"); PyDoc_STRVAR(remove_doc, -"remove(x)\n\n" -"Remove the first occurrence of *x*." -"If not found, raises a ValueError."); +"D.remove(value) -- remove first occurrence of value."); static int valid_index(Py_ssize_t i, Py_ssize_t limit) @@ -1543,8 +1534,7 @@ deque_sizeof(dequeobject *deque, void *unused) } PyDoc_STRVAR(sizeof_doc, -"__sizeof__() -> int\n\n" -"Size of the deque in memory, in bytes."); +"D.__sizeof__() -- size of D in memory, in bytes"); static PyObject * deque_get_maxlen(dequeobject *deque, void *Py_UNUSED(ignored)) @@ -1579,8 +1569,7 @@ static PySequenceMethods deque_as_sequence = { static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, -"__reversed__()\n\n" -"Return a reverse iterator over the deque."); + "D.__reversed__() -- return a reverse iterator over the deque"); static PyMethodDef deque_methods[] = { {"append", (PyCFunction)deque_append, @@ -1625,8 +1614,9 @@ static PyMethodDef deque_methods[] = { }; PyDoc_STRVAR(deque_doc, -"deque([iterable[, maxlen]]) -> collections.deque\n\n" -"A list-like sequence optimized for data accesses near its endpoints."); +"deque([iterable[, maxlen]]) --> deque object\n\ +\n\ +A list-like sequence optimized for data accesses near its endpoints."); static PyTypeObject deque_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -2009,8 +1999,7 @@ new_defdict(defdictobject *dd, PyObject *arg) dd->default_factory ? dd->default_factory : Py_None, arg, NULL); } -PyDoc_STRVAR(defdict_copy_doc, "copy() -> collections.deque\n\n" -"A shallow copy of the deque."); +PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); static PyObject * defdict_copy(defdictobject *dd, PyObject *Py_UNUSED(ignored)) From webhook-mailer at python.org Fri Mar 24 01:39:19 2023 From: webhook-mailer at python.org (rhettinger) Date: Fri, 24 Mar 2023 05:39:19 -0000 Subject: [Python-checkins] GH-100989: remove annotation from docstring (GH-102991) Message-ID: https://github.com/python/cpython/commit/d49409196e0c73c38e3f96cf860cbffda40607ec commit: d49409196e0c73c38e3f96cf860cbffda40607ec branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-24T00:39:12-05:00 summary: GH-100989: remove annotation from docstring (GH-102991) files: M Modules/_collectionsmodule.c diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 68131f3b54d2..9d8aef1e6771 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -990,7 +990,7 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"D.count(value) -> integer -- return number of occurrences of value"); +"D.count(value) -- return number of occurrences of value"); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1098,7 +1098,7 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" +"D.index(value, [start, [stop]]) -- return first index of value.\n" "Raises ValueError if the value is not present."); /* insert(), remove(), and delitem() are implemented in terms of From webhook-mailer at python.org Fri Mar 24 02:04:34 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 24 Mar 2023 06:04:34 -0000 Subject: [Python-checkins] GH-100989: remove annotation from docstring (GH-102991) Message-ID: https://github.com/python/cpython/commit/fd43fb69962361ce4ef8e1175fde0a32726cdf77 commit: fd43fb69962361ce4ef8e1175fde0a32726cdf77 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-23T23:04:06-07:00 summary: GH-100989: remove annotation from docstring (GH-102991) (cherry picked from commit d49409196e0c73c38e3f96cf860cbffda40607ec) Co-authored-by: Raymond Hettinger files: M Modules/_collectionsmodule.c diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 741cfbe9dc61..5f5c0886e2f6 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -997,7 +997,7 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"D.count(value) -> integer -- return number of occurrences of value"); +"D.count(value) -- return number of occurrences of value"); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1106,7 +1106,7 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" +"D.index(value, [start, [stop]]) -- return first index of value.\n" "Raises ValueError if the value is not present."); /* insert(), remove(), and delitem() are implemented in terms of From webhook-mailer at python.org Fri Mar 24 07:23:45 2023 From: webhook-mailer at python.org (hugovk) Date: Fri, 24 Mar 2023 11:23:45 -0000 Subject: [Python-checkins] gh-101100: Test docs in nit-picky mode (#102513) Message-ID: https://github.com/python/cpython/commit/6a1c49a7176f29435e71a326866d952b686bceb3 commit: 6a1c49a7176f29435e71a326866d952b686bceb3 branch: main author: Hugo van Kemenade committer: hugovk date: 2023-03-24T13:23:35+02:00 summary: gh-101100: Test docs in nit-picky mode (#102513) Co-authored-by: C.A.M. Gerlach Co-authored-by: Petr Viktorin files: A Doc/tools/warnings-to-gh-actions.py M .github/workflows/doc.yml M Doc/c-api/exceptions.rst M Doc/c-api/weakref.rst M Doc/library/asyncio-task.rst M Doc/library/gzip.rst M Doc/whatsnew/3.12.rst M Misc/NEWS.d/3.10.0a2.rst diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 465da12fa1be..9ec60c198eb3 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -53,6 +53,28 @@ jobs: - name: 'Build HTML documentation' run: make -C Doc/ SPHINXOPTS="-q" SPHINXERRORHANDLING="-W --keep-going" html + # Add pull request annotations for Sphinx nitpicks (missing references) + - name: 'Get list of changed files' + id: changed_files + uses: Ana06/get-changed-files at v2.2.0 + - name: 'Build changed files in nit-picky mode' + continue-on-error: true + run: | + # Mark files the pull request modified + touch ${{ steps.changed_files.outputs.added_modified }} + # Build docs with the '-n' (nit-picky) option; convert warnings to annotations + make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n --keep-going" html 2>&1 | + python Doc/tools/warnings-to-gh-actions.py + + # Ensure some files always pass Sphinx nit-picky mode (no missing references) + - name: 'Build known-good files in nit-picky mode' + run: | + # Mark files that must pass nit-picky + touch Doc/whatsnew/3.12.rst + touch Doc/library/sqlite3.rst + # Build docs with the '-n' (nit-picky) option, convert warnings to errors (-W) + make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n -W --keep-going" html 2>&1 + # Run "doctest" on HEAD as new syntax doesn't exist in the latest stable release doctest: name: 'Doctest' diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index ddf7dc780b27..49d2f18d4573 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -86,7 +86,7 @@ Printing and clearing An exception must be set when calling this function. -.. c:function: void PyErr_DisplayException(PyObject *exc) +.. c:function:: void PyErr_DisplayException(PyObject *exc) Print the standard traceback display of ``exc`` to ``sys.stderr``, including chained exceptions and notes. diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index ace743ba01c5..f27ec4411b4a 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -67,3 +67,13 @@ as much as it can. .. c:function:: PyObject* PyWeakref_GET_OBJECT(PyObject *ref) Similar to :c:func:`PyWeakref_GetObject`, but does no error checking. + + +.. c:function:: void PyObject_ClearWeakRefs(PyObject *object) + + This function is called by the :c:member:`~PyTypeObject.tp_dealloc` handler + to clear weak references. + + This iterates through the weak references for *object* and calls callbacks + for those references which have one. It returns when all callbacks have + been attempted. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index c5a480ba2019..41d09e1e7970 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -960,6 +960,13 @@ Introspection .. versionadded:: 3.7 +.. function:: iscoroutine(obj) + + Return ``True`` if *obj* is a coroutine object. + + .. versionadded:: 3.4 + + Task Object =========== diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 1a2582d6a904..06cbd2567a0b 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -143,6 +143,12 @@ The module defines the following items: :func:`time.time` and the :attr:`~os.stat_result.st_mtime` attribute of the object returned by :func:`os.stat`. + .. attribute:: name + + The path to the gzip file on disk, as a :class:`str` or :class:`bytes`. + Equivalent to the output of :func:`os.fspath` on the original input path, + with no other normalization, resolution or expansion. + .. versionchanged:: 3.1 Support for the :keyword:`with` statement was added, along with the *mtime* constructor argument and :attr:`mtime` attribute. diff --git a/Doc/tools/warnings-to-gh-actions.py b/Doc/tools/warnings-to-gh-actions.py new file mode 100644 index 000000000000..da33a4ede07a --- /dev/null +++ b/Doc/tools/warnings-to-gh-actions.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +""" +Convert Sphinx warning messages to GitHub Actions. + +Converts lines like: + .../Doc/library/cgi.rst:98: WARNING: reference target not found +to: + ::warning file=.../Doc/library/cgi.rst,line=98::reference target not found + +Non-matching lines are echoed unchanged. + +see: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message +""" + +import re +import sys + +pattern = re.compile(r'(?P[^:]+):(?P\d+): WARNING: (?P.+)') + +for line in sys.stdin: + if match := pattern.fullmatch(line.strip()): + print('::warning file={file},line={line}::{msg}'.format_map(match)) + else: + print(line) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 06ea416d7513..e5bcfdecd9a4 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -248,7 +248,7 @@ inspect ------- * Add :func:`inspect.markcoroutinefunction` to mark sync functions that return - a :term:`coroutine` for use with :func:`iscoroutinefunction`. + a :term:`coroutine` for use with :func:`inspect.iscoroutinefunction`. (Contributed Carlton Gibson in :gh:`99247`.) * Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals` @@ -277,7 +277,7 @@ dis * Pseudo instruction opcodes (which are used by the compiler but do not appear in executable bytecode) are now exposed in the :mod:`dis` module. - :data:`~dis.HAVE_ARGUMENT` is still relevant to real opcodes, + :opcode:`HAVE_ARGUMENT` is still relevant to real opcodes, but it is not useful for pseudo instructions. Use the new :data:`~dis.hasarg` collection instead. (Contributed by Irit Katriel in :gh:`94216`.) @@ -422,7 +422,7 @@ Optimizations (Contributed by Kevin Modzelewski in :gh:`90536`.) * Speed up the regular expression substitution (functions :func:`re.sub` and - :func:`re.subn` and corresponding :class:`re.Pattern` methods) for + :func:`re.subn` and corresponding :class:`!re.Pattern` methods) for replacement strings containing group references by 2--3 times. (Contributed by Serhiy Storchaka in :gh:`91524`.) @@ -435,7 +435,7 @@ CPython bytecode changes :opcode:`LOAD_METHOD` instruction if the low bit of its oparg is set. (Contributed by Ken Jin in :gh:`93429`.) -* Removed the :opcode:`JUMP_IF_FALSE_OR_POP` and :opcode:`JUMP_IF_TRUE_OR_POP` +* Removed the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` instructions. (Contributed by Irit Katriel in :gh:`102859`.) @@ -482,7 +482,7 @@ Deprecated :exc:`ImportWarning`). (Contributed by Brett Cannon in :gh:`65961`.) -* The :meth:`~asyncio.DefaultEventLoopPolicy.get_event_loop` method of the +* The :meth:`~asyncio.get_event_loop` method of the default event loop policy now emits a :exc:`DeprecationWarning` if there is no current event loop set and it decides to create one. (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.) @@ -541,13 +541,13 @@ Modules (see :pep:`594`): APIs: -* :class:`configparser.LegacyInterpolation` (:gh:`90765`) +* :class:`!configparser.LegacyInterpolation` (:gh:`90765`) * :func:`locale.getdefaultlocale` (:gh:`90817`) -* :meth:`turtle.RawTurtle.settiltangle` (:gh:`50096`) -* :func:`unittest.findTestCases` (:gh:`50096`) -* :func:`unittest.makeSuite` (:gh:`50096`) -* :func:`unittest.getTestCaseNames` (:gh:`50096`) -* :class:`webbrowser.MacOSX` (:gh:`86421`) +* :meth:`!turtle.RawTurtle.settiltangle` (:gh:`50096`) +* :func:`!unittest.findTestCases` (:gh:`50096`) +* :func:`!unittest.makeSuite` (:gh:`50096`) +* :func:`!unittest.getTestCaseNames` (:gh:`50096`) +* :class:`!webbrowser.MacOSX` (:gh:`86421`) Pending Removal in Python 3.14 ------------------------------ @@ -555,9 +555,9 @@ Pending Removal in Python 3.14 * Deprecated the following :mod:`importlib.abc` classes, scheduled for removal in Python 3.14: - * :class:`importlib.abc.ResourceReader` - * :class:`importlib.abc.Traversable` - * :class:`importlib.abc.TraversableResources` + * :class:`!importlib.abc.ResourceReader` + * :class:`!importlib.abc.Traversable` + * :class:`!importlib.abc.TraversableResources` Use :mod:`importlib.resources.abc` classes instead: @@ -566,7 +566,7 @@ Pending Removal in Python 3.14 (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.) -* Creating :c:data:`immutable types ` with mutable +* Creating immutable types (:data:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases using the C API. * Deprecated the *isdst* parameter in :func:`email.utils.localtime`. @@ -701,11 +701,11 @@ Removed * Remove ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, deprecated in Python 3.10: just use :func:`open` instead. The :func:`open` (:func:`io.open`) - function is a built-in function. Since Python 3.10, :func:`_pyio.open` is + function is a built-in function. Since Python 3.10, :func:`!_pyio.open` is also a static method. (Contributed by Victor Stinner in :gh:`94169`.) -* Remove the :func:`ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: +* Remove the :func:`!ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: use :func:`os.urandom` or :func:`ssl.RAND_bytes` instead. (Contributed by Victor Stinner in :gh:`94199`.) @@ -715,13 +715,13 @@ Removed extension if it was not present. (Contributed by Victor Stinner in :gh:`94196`.) -* Remove the :func:`ssl.match_hostname` function. The - :func:`ssl.match_hostname` was deprecated in Python 3.7. OpenSSL performs +* Remove the :func:`!ssl.match_hostname` function. + It was deprecated in Python 3.7. OpenSSL performs hostname matching since Python 3.7, Python no longer uses the - :func:`ssl.match_hostname` function. + :func:`!ssl.match_hostname` function. (Contributed by Victor Stinner in :gh:`94199`.) -* Remove the :func:`locale.format` function, deprecated in Python 3.7: +* Remove the :func:`!locale.format` function, deprecated in Python 3.7: use :func:`locale.format_string` instead. (Contributed by Victor Stinner in :gh:`94226`.) @@ -731,9 +731,9 @@ Removed a C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. (Contributed by Victor Stinner in :gh:`94199`.) -* :mod:`xml.etree`: Remove the ``ElementTree.Element.copy()`` method of the +* :mod:`xml.etree.ElementTree`: Remove the ``ElementTree.Element.copy()`` method of the pure Python implementation, deprecated in Python 3.10, use the - :func:`copy.copy` function instead. The C implementation of :mod:`xml.etree` + :func:`copy.copy` function instead. The C implementation of :mod:`xml.etree.ElementTree` has no ``copy()`` method, only a ``__copy__()`` method. (Contributed by Victor Stinner in :gh:`94383`.) @@ -742,10 +742,10 @@ Removed :pep:`451` for the rationale. (Contributed by Victor Stinner in :gh:`94379`.) -* Remove the :func:`ssl.wrap_socket` function, deprecated in Python 3.7: +* Remove the :func:`!ssl.wrap_socket` function, deprecated in Python 3.7: instead, create a :class:`ssl.SSLContext` object and call its :class:`ssl.SSLContext.wrap_socket` method. Any package that still uses - :func:`ssl.wrap_socket` is broken and insecure. The function neither sends a + :func:`!ssl.wrap_socket` is broken and insecure. The function neither sends a SNI TLS extension nor validates server hostname. Code is subject to `CWE-295 `_: Improper Certificate Validation. @@ -912,7 +912,7 @@ New Features The :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class when the class's :py:meth:`~object.__call__` method is reassigned. This makes vectorcall safe to use with mutable types (i.e. heap types - without the :const:`immutable ` flag). + without the immutable flag, :const:`Py_TPFLAGS_IMMUTABLETYPE`). Mutable types that do not override :c:member:`~PyTypeObject.tp_call` now inherit the ``Py_TPFLAGS_HAVE_VECTORCALL`` flag. (Contributed by Petr Viktorin in :gh:`93274`.) @@ -945,7 +945,7 @@ New Features (Contributed by Andrew Frost in :gh:`92257`.) * The C API now permits registering callbacks via :c:func:`PyDict_AddWatcher`, - :c:func:`PyDict_AddWatch` and related APIs to be called whenever a dictionary + :c:func:`PyDict_Watch` and related APIs to be called whenever a dictionary is modified. This is intended for use by optimizing interpreters, JIT compilers, or debuggers. (Contributed by Carl Meyer in :gh:`91052`.) @@ -977,7 +977,7 @@ New Features (Contributed by Mark Shannon in :gh:`101578`.) * Add :c:func:`PyErr_DisplayException`, which takes an exception instance, - to replace the legacy-api :c:func:`PyErr_Display`. (Contributed by + to replace the legacy-api :c:func:`!PyErr_Display`. (Contributed by Irit Katriel in :gh:`102755`). Porting to Python 3.12 @@ -1024,7 +1024,7 @@ Porting to Python 3.12 supported, but does not fully support multiple inheritance (:gh:`95589`), and performance may be worse. Classes declaring :const:`Py_TPFLAGS_MANAGED_DICT` should call - :c:func:`_PyObject_VisitManagedDict` and :c:func:`_PyObject_ClearManagedDict` + :c:func:`!_PyObject_VisitManagedDict` and :c:func:`!_PyObject_ClearManagedDict` to traverse and clear their instance's dictionaries. To clear weakrefs, call :c:func:`PyObject_ClearWeakRefs`, as before. @@ -1069,17 +1069,17 @@ Deprecated * :c:var:`Py_HashRandomizationFlag`: use :c:member:`PyConfig.use_hash_seed` and :c:member:`PyConfig.hash_seed` * :c:var:`Py_IsolatedFlag`: use :c:member:`PyConfig.isolated` - * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyConfig.legacy_windows_fs_encoding` + * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` - * :c:var:`Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` - * :c:var:`Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` - * :c:var:`Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) + * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` + * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) The :c:func:`Py_InitializeFromConfig` API should be used with :c:type:`PyConfig` instead. (Contributed by Victor Stinner in :gh:`77782`.) -* Creating :c:data:`immutable types ` with mutable +* Creating immutable types (:const:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases is deprecated and will be disabled in Python 3.14. * The ``structmember.h`` header is deprecated, though it continues to be @@ -1118,7 +1118,7 @@ Deprecated :c:func:`PyErr_SetRaisedException` instead. (Contributed by Mark Shannon in :gh:`101578`.) -* :c:func:`PyErr_Display` is deprecated. Use :c:func:`PyErr_DisplayException` +* :c:func:`!PyErr_Display` is deprecated. Use :c:func:`PyErr_DisplayException` instead. (Contributed by Irit Katriel in :gh:`102755`). @@ -1132,15 +1132,15 @@ Removed * Legacy Unicode APIs have been removed. See :pep:`623` for detail. - * :c:macro:`PyUnicode_WCHAR_KIND` - * :c:func:`PyUnicode_AS_UNICODE` - * :c:func:`PyUnicode_AsUnicode` - * :c:func:`PyUnicode_AsUnicodeAndSize` - * :c:func:`PyUnicode_AS_DATA` - * :c:func:`PyUnicode_FromUnicode` - * :c:func:`PyUnicode_GET_SIZE` - * :c:func:`PyUnicode_GetSize` - * :c:func:`PyUnicode_GET_DATA_SIZE` + * :c:macro:`!PyUnicode_WCHAR_KIND` + * :c:func:`!PyUnicode_AS_UNICODE` + * :c:func:`!PyUnicode_AsUnicode` + * :c:func:`!PyUnicode_AsUnicodeAndSize` + * :c:func:`!PyUnicode_AS_DATA` + * :c:func:`!PyUnicode_FromUnicode` + * :c:func:`!PyUnicode_GET_SIZE` + * :c:func:`!PyUnicode_GetSize` + * :c:func:`!PyUnicode_GET_DATA_SIZE` * Remove the ``PyUnicode_InternImmortal()`` function and the ``SSTATE_INTERNED_IMMORTAL`` macro. diff --git a/Misc/NEWS.d/3.10.0a2.rst b/Misc/NEWS.d/3.10.0a2.rst index 61a291914f93..061a82e90afd 100644 --- a/Misc/NEWS.d/3.10.0a2.rst +++ b/Misc/NEWS.d/3.10.0a2.rst @@ -888,7 +888,7 @@ file descriptors. .. nonce: JUPE59 .. section: C API -:c:data:`Py_FileSystemDefaultEncodeErrors` and :c:data:`Py_UTF8Mode` are +:c:data:`!Py_FileSystemDefaultEncodeErrors` and :c:data:`!Py_UTF8Mode` are available again in limited API. .. From webhook-mailer at python.org Fri Mar 24 08:33:39 2023 From: webhook-mailer at python.org (Yhg1s) Date: Fri, 24 Mar 2023 12:33:39 -0000 Subject: [Python-checkins] [3.11] gh-96931: Fix incorrect results in ssl.SSLSocket.shared_ciphers (GH-96932) (#102918) Message-ID: https://github.com/python/cpython/commit/e075631f672730067fe467fd6d058e6bfec9cbec commit: e075631f672730067fe467fd6d058e6bfec9cbec branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Yhg1s date: 2023-03-24T13:33:24+01:00 summary: [3.11] gh-96931: Fix incorrect results in ssl.SSLSocket.shared_ciphers (GH-96932) (#102918) gh-96931: Fix incorrect results in ssl.SSLSocket.shared_ciphers (GH-96932) (cherry picked from commit af9c34f6ef8dceb21871206eb3e4d350f6e3d3dc) Co-authored-by: Benjamin Fogle files: A Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst M Doc/library/ssl.rst M Lib/test/test_ssl.py M Modules/_ssl.c diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 372b1243dd75..6ac08fd6548e 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1309,7 +1309,7 @@ SSL sockets also have the following additional methods and attributes: .. method:: SSLSocket.shared_ciphers() - Return the list of ciphers shared by the client during the handshake. Each + Return the list of ciphers available in both the client and server. Each entry of the returned list is a three-value tuple containing the name of the cipher, the version of the SSL protocol that defines its use, and the number of secret bits the cipher uses. :meth:`~SSLSocket.shared_ciphers` returns diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 3b3b869bb53a..5c6ddf12ec35 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2326,13 +2326,13 @@ def test_bio_handshake(self): self.assertIs(sslobj._sslobj.owner, sslobj) self.assertIsNone(sslobj.cipher()) self.assertIsNone(sslobj.version()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertRaises(ValueError, sslobj.getpeercert) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: self.assertIsNone(sslobj.get_channel_binding('tls-unique')) self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) self.assertTrue(sslobj.cipher()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertIsNotNone(sslobj.version()) self.assertTrue(sslobj.getpeercert()) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: @@ -4302,7 +4302,7 @@ def cb_wrong_return_type(ssl_sock, server_name, initial_context): def test_shared_ciphers(self): client_context, server_context, hostname = testing_context() client_context.set_ciphers("AES128:AES256") - server_context.set_ciphers("AES256") + server_context.set_ciphers("AES256:eNULL") expected_algs = [ "AES256", "AES-256", # TLS 1.3 ciphers are always enabled diff --git a/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst new file mode 100644 index 000000000000..766b1d4d477b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst @@ -0,0 +1 @@ +Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 6071202104fa..79f78007b68d 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2000,24 +2000,44 @@ static PyObject * _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self) /*[clinic end generated code: output=3d174ead2e42c4fd input=0bfe149da8fe6306]*/ { - STACK_OF(SSL_CIPHER) *ciphers; - int i; + STACK_OF(SSL_CIPHER) *server_ciphers; + STACK_OF(SSL_CIPHER) *client_ciphers; + int i, len; PyObject *res; + const SSL_CIPHER* cipher; + + /* Rather than use SSL_get_shared_ciphers, we use an equivalent algorithm because: + + 1) It returns a colon seperated list of strings, in an undefined + order, that we would have to post process back into tuples. + 2) It will return a truncated string with no indication that it has + done so, if the buffer is too small. + */ - ciphers = SSL_get_ciphers(self->ssl); - if (!ciphers) + server_ciphers = SSL_get_ciphers(self->ssl); + if (!server_ciphers) Py_RETURN_NONE; - res = PyList_New(sk_SSL_CIPHER_num(ciphers)); + client_ciphers = SSL_get_client_ciphers(self->ssl); + if (!client_ciphers) + Py_RETURN_NONE; + + res = PyList_New(sk_SSL_CIPHER_num(server_ciphers)); if (!res) return NULL; - for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { - PyObject *tup = cipher_to_tuple(sk_SSL_CIPHER_value(ciphers, i)); + len = 0; + for (i = 0; i < sk_SSL_CIPHER_num(server_ciphers); i++) { + cipher = sk_SSL_CIPHER_value(server_ciphers, i); + if (sk_SSL_CIPHER_find(client_ciphers, cipher) < 0) + continue; + + PyObject *tup = cipher_to_tuple(cipher); if (!tup) { Py_DECREF(res); return NULL; } - PyList_SET_ITEM(res, i, tup); + PyList_SET_ITEM(res, len++, tup); } + Py_SET_SIZE(res, len); return res; } From webhook-mailer at python.org Fri Mar 24 08:33:41 2023 From: webhook-mailer at python.org (Yhg1s) Date: Fri, 24 Mar 2023 12:33:41 -0000 Subject: [Python-checkins] [3.10] gh-96931: Fix incorrect results in ssl.SSLSocket.shared_ciphers (GH-96932) (#102919) Message-ID: https://github.com/python/cpython/commit/0a2b63f6adfa010fa9b18c1deaac4e738bb99c84 commit: 0a2b63f6adfa010fa9b18c1deaac4e738bb99c84 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Yhg1s date: 2023-03-24T13:33:32+01:00 summary: [3.10] gh-96931: Fix incorrect results in ssl.SSLSocket.shared_ciphers (GH-96932) (#102919) gh-96931: Fix incorrect results in ssl.SSLSocket.shared_ciphers (GH-96932) (cherry picked from commit af9c34f6ef8dceb21871206eb3e4d350f6e3d3dc) Co-authored-by: Benjamin Fogle files: A Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst M Doc/library/ssl.rst M Lib/test/test_ssl.py M Modules/_ssl.c diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index de9edcb26210..36c852974da9 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1311,7 +1311,7 @@ SSL sockets also have the following additional methods and attributes: .. method:: SSLSocket.shared_ciphers() - Return the list of ciphers shared by the client during the handshake. Each + Return the list of ciphers available in both the client and server. Each entry of the returned list is a three-value tuple containing the name of the cipher, the version of the SSL protocol that defines its use, and the number of secret bits the cipher uses. :meth:`~SSLSocket.shared_ciphers` returns diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index f97227b11bcd..addfb6ce43d8 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2326,13 +2326,13 @@ def test_bio_handshake(self): self.assertIs(sslobj._sslobj.owner, sslobj) self.assertIsNone(sslobj.cipher()) self.assertIsNone(sslobj.version()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertRaises(ValueError, sslobj.getpeercert) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: self.assertIsNone(sslobj.get_channel_binding('tls-unique')) self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) self.assertTrue(sslobj.cipher()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertIsNotNone(sslobj.version()) self.assertTrue(sslobj.getpeercert()) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: @@ -4310,7 +4310,7 @@ def cb_wrong_return_type(ssl_sock, server_name, initial_context): def test_shared_ciphers(self): client_context, server_context, hostname = testing_context() client_context.set_ciphers("AES128:AES256") - server_context.set_ciphers("AES256") + server_context.set_ciphers("AES256:eNULL") expected_algs = [ "AES256", "AES-256", # TLS 1.3 ciphers are always enabled diff --git a/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst new file mode 100644 index 000000000000..766b1d4d477b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst @@ -0,0 +1 @@ +Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` diff --git a/Modules/_ssl.c b/Modules/_ssl.c index f1bb39f57b22..360eb864ad36 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -2005,24 +2005,44 @@ static PyObject * _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self) /*[clinic end generated code: output=3d174ead2e42c4fd input=0bfe149da8fe6306]*/ { - STACK_OF(SSL_CIPHER) *ciphers; - int i; + STACK_OF(SSL_CIPHER) *server_ciphers; + STACK_OF(SSL_CIPHER) *client_ciphers; + int i, len; PyObject *res; + const SSL_CIPHER* cipher; + + /* Rather than use SSL_get_shared_ciphers, we use an equivalent algorithm because: + + 1) It returns a colon seperated list of strings, in an undefined + order, that we would have to post process back into tuples. + 2) It will return a truncated string with no indication that it has + done so, if the buffer is too small. + */ - ciphers = SSL_get_ciphers(self->ssl); - if (!ciphers) + server_ciphers = SSL_get_ciphers(self->ssl); + if (!server_ciphers) Py_RETURN_NONE; - res = PyList_New(sk_SSL_CIPHER_num(ciphers)); + client_ciphers = SSL_get_client_ciphers(self->ssl); + if (!client_ciphers) + Py_RETURN_NONE; + + res = PyList_New(sk_SSL_CIPHER_num(server_ciphers)); if (!res) return NULL; - for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { - PyObject *tup = cipher_to_tuple(sk_SSL_CIPHER_value(ciphers, i)); + len = 0; + for (i = 0; i < sk_SSL_CIPHER_num(server_ciphers); i++) { + cipher = sk_SSL_CIPHER_value(server_ciphers, i); + if (sk_SSL_CIPHER_find(client_ciphers, cipher) < 0) + continue; + + PyObject *tup = cipher_to_tuple(cipher); if (!tup) { Py_DECREF(res); return NULL; } - PyList_SET_ITEM(res, i, tup); + PyList_SET_ITEM(res, len++, tup); } + Py_SET_SIZE(res, len); return res; } From webhook-mailer at python.org Fri Mar 24 08:40:30 2023 From: webhook-mailer at python.org (Yhg1s) Date: Fri, 24 Mar 2023 12:40:30 -0000 Subject: [Python-checkins] [3.11] gh-102027: Fix macro name (GH-102124) (#102916) Message-ID: https://github.com/python/cpython/commit/67161396ded841d201ef70bb7158f780b19b3356 commit: 67161396ded841d201ef70bb7158f780b19b3356 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Yhg1s date: 2023-03-24T13:40:22+01:00 summary: [3.11] gh-102027: Fix macro name (GH-102124) (#102916) gh-102027: Fix macro name (GH-102124) This fixes the ssse3 / sse2 detection when sse4 is available. (cherry picked from commit ea93bde4ece139d4152a59f2c38aa6568559447c) Co-authored-by: Max Bachmann Co-authored-by: Oleg Iarygin files: A Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst M Modules/_blake2/impl/blake2-config.h diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst new file mode 100644 index 000000000000..42d96b54677e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst @@ -0,0 +1,2 @@ +Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max +Bachmann. diff --git a/Modules/_blake2/impl/blake2-config.h b/Modules/_blake2/impl/blake2-config.h index f5dd6faa9e68..c09cb4bcf067 100644 --- a/Modules/_blake2/impl/blake2-config.h +++ b/Modules/_blake2/impl/blake2-config.h @@ -53,7 +53,7 @@ #endif #endif -#ifdef HAVE_SSE41 +#ifdef HAVE_SSE4_1 #ifndef HAVE_SSSE3 #define HAVE_SSSE3 #endif From webhook-mailer at python.org Fri Mar 24 08:40:39 2023 From: webhook-mailer at python.org (Yhg1s) Date: Fri, 24 Mar 2023 12:40:39 -0000 Subject: [Python-checkins] [3.10] gh-102027: Fix macro name (GH-102124) (#102917) Message-ID: https://github.com/python/cpython/commit/581dd8caba692f58087bb7beca7fc42f2eddfdda commit: 581dd8caba692f58087bb7beca7fc42f2eddfdda branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: Yhg1s date: 2023-03-24T13:40:32+01:00 summary: [3.10] gh-102027: Fix macro name (GH-102124) (#102917) gh-102027: Fix macro name (GH-102124) This fixes the ssse3 / sse2 detection when sse4 is available. (cherry picked from commit ea93bde4ece139d4152a59f2c38aa6568559447c) Co-authored-by: Max Bachmann Co-authored-by: Oleg Iarygin files: A Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst M Modules/_blake2/impl/blake2-config.h diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst new file mode 100644 index 000000000000..42d96b54677e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst @@ -0,0 +1,2 @@ +Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max +Bachmann. diff --git a/Modules/_blake2/impl/blake2-config.h b/Modules/_blake2/impl/blake2-config.h index f5dd6faa9e68..c09cb4bcf067 100644 --- a/Modules/_blake2/impl/blake2-config.h +++ b/Modules/_blake2/impl/blake2-config.h @@ -53,7 +53,7 @@ #endif #endif -#ifdef HAVE_SSE41 +#ifdef HAVE_SSE4_1 #ifndef HAVE_SSSE3 #define HAVE_SSSE3 #endif From webhook-mailer at python.org Fri Mar 24 09:04:39 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 24 Mar 2023 13:04:39 -0000 Subject: [Python-checkins] gh-100372: Use BIO_eof to detect EOF for SSL_FILETYPE_ASN1 (GH-100373) Message-ID: https://github.com/python/cpython/commit/acfe02f3b05436658d92add6b168538b30f357f0 commit: acfe02f3b05436658d92add6b168538b30f357f0 branch: main author: David Benjamin committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-24T06:04:30-07:00 summary: gh-100372: Use BIO_eof to detect EOF for SSL_FILETYPE_ASN1 (GH-100373) In PEM, we need to parse until error and then suppress `PEM_R_NO_START_LINE`, because PEM allows arbitrary leading and trailing data. DER, however, does not. Parsing until error and suppressing `ASN1_R_HEADER_TOO_LONG` doesn't quite work because that error also covers some cases that should be rejected. Instead, check `BIO_eof` early and stop the loop that way. Automerge-Triggered-By: GH:Yhg1s files: A Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst M Lib/test/test_ssl.py M Modules/_ssl.c diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 1317efb33c23..abf024fb89d2 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1289,6 +1289,8 @@ def test_load_verify_cadata(self): "not enough data: cadata does not contain a certificate" ): ctx.load_verify_locations(cadata=b"broken") + with self.assertRaises(ssl.SSLError): + ctx.load_verify_locations(cadata=cacert_der + b"A") @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows") def test_load_dh_params(self): diff --git a/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst b/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst new file mode 100644 index 000000000000..ec37aff5092c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst @@ -0,0 +1,2 @@ +:meth:`ssl.SSLContext.load_verify_locations` no longer incorrectly accepts +some cases of trailing data when parsing DER. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 36b66cdb5310..3fbb37332f67 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3930,7 +3930,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, { BIO *biobuf = NULL; X509_STORE *store; - int retval = -1, err, loaded = 0; + int retval = -1, err, loaded = 0, was_bio_eof = 0; assert(filetype == SSL_FILETYPE_ASN1 || filetype == SSL_FILETYPE_PEM); @@ -3958,6 +3958,10 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, int r; if (filetype == SSL_FILETYPE_ASN1) { + if (BIO_eof(biobuf)) { + was_bio_eof = 1; + break; + } cert = d2i_X509_bio(biobuf, NULL); } else { cert = PEM_read_bio_X509(biobuf, NULL, @@ -3993,9 +3997,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, } _setSSLError(get_state_ctx(self), msg, 0, __FILE__, __LINE__); retval = -1; - } else if ((filetype == SSL_FILETYPE_ASN1) && - (ERR_GET_LIB(err) == ERR_LIB_ASN1) && - (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG)) { + } else if ((filetype == SSL_FILETYPE_ASN1) && was_bio_eof) { /* EOF ASN1 file, not an error */ ERR_clear_error(); retval = 0; From webhook-mailer at python.org Fri Mar 24 11:00:47 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 24 Mar 2023 15:00:47 -0000 Subject: [Python-checkins] gh-102873: logging.LogRecord docs: improve description of `msg` parameter (#102875) Message-ID: https://github.com/python/cpython/commit/f2e5a6ee628502d307a97f587788d7022a200229 commit: f2e5a6ee628502d307a97f587788d7022a200229 branch: main author: Amin Alaee committer: AlexWaygood date: 2023-03-24T15:00:32Z summary: gh-102873: logging.LogRecord docs: improve description of `msg` parameter (#102875) Co-authored-by: Alex Waygood files: M Doc/library/logging.rst diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 34e98fc25770..22412e1a2113 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -813,8 +813,9 @@ wire). :type lineno: int :param msg: The event description message, - which can be a %-format string with placeholders for variable data. - :type msg: str + which can be a %-format string with placeholders for variable data, + or an arbitrary object (see :ref:`arbitrary-object-messages`). + :type msg: typing.Any :param args: Variable data to merge into the *msg* argument to obtain the event description. From webhook-mailer at python.org Fri Mar 24 11:07:59 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 24 Mar 2023 15:07:59 -0000 Subject: [Python-checkins] gh-102873: logging.LogRecord docs: improve description of `msg` parameter (GH-102875) Message-ID: https://github.com/python/cpython/commit/cbffc3ad38c2bb62a6a343c3c6ac57480f643767 commit: cbffc3ad38c2bb62a6a343c3c6ac57480f643767 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-24T08:07:46-07:00 summary: gh-102873: logging.LogRecord docs: improve description of `msg` parameter (GH-102875) (cherry picked from commit f2e5a6ee628502d307a97f587788d7022a200229) Co-authored-by: Amin Alaee Co-authored-by: Alex Waygood files: M Doc/library/logging.rst diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 13683c0766a3..79a8fd94ff87 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -796,8 +796,9 @@ wire). :type lineno: int :param msg: The event description message, - which can be a %-format string with placeholders for variable data. - :type msg: str + which can be a %-format string with placeholders for variable data, + or an arbitrary object (see :ref:`arbitrary-object-messages`). + :type msg: typing.Any :param args: Variable data to merge into the *msg* argument to obtain the event description. From webhook-mailer at python.org Fri Mar 24 11:08:56 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 24 Mar 2023 15:08:56 -0000 Subject: [Python-checkins] gh-102873: logging.LogRecord docs: improve description of `msg` parameter (GH-102875) Message-ID: https://github.com/python/cpython/commit/c834a4c713f2fb55de1658bffd77d8ef070cf2d2 commit: c834a4c713f2fb55de1658bffd77d8ef070cf2d2 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-24T08:08:48-07:00 summary: gh-102873: logging.LogRecord docs: improve description of `msg` parameter (GH-102875) (cherry picked from commit f2e5a6ee628502d307a97f587788d7022a200229) Co-authored-by: Amin Alaee Co-authored-by: Alex Waygood files: M Doc/library/logging.rst diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 9390f065fb26..6c47b9e206c4 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -796,8 +796,9 @@ wire). :type lineno: int :param msg: The event description message, - which can be a %-format string with placeholders for variable data. - :type msg: str + which can be a %-format string with placeholders for variable data, + or an arbitrary object (see :ref:`arbitrary-object-messages`). + :type msg: typing.Any :param args: Variable data to merge into the *msg* argument to obtain the event description. From webhook-mailer at python.org Fri Mar 24 16:50:13 2023 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 24 Mar 2023 20:50:13 -0000 Subject: [Python-checkins] gh-102980: Add tests for pdf's display, alias and where commands (#102981) Message-ID: https://github.com/python/cpython/commit/ded9a7fc194a1d5c0e38f475a45f8f77dbe9c6bc commit: ded9a7fc194a1d5c0e38f475a45f8f77dbe9c6bc branch: main author: gaogaotiantian committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-24T20:50:06Z summary: gh-102980: Add tests for pdf's display, alias and where commands (#102981) files: A Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst M Lib/test/test_pdb.py diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index d91bd0b2f03a..e96dc7fa1cf6 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -574,6 +574,156 @@ def test_pdb_whatis_command(): (Pdb) continue """ +def test_pdb_display_command(): + """Test display command + + >>> def test_function(): + ... a = 0 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... a = 1 + ... a = 2 + ... a = 3 + ... a = 4 + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'display a', + ... 'n', + ... 'display', + ... 'undisplay a', + ... 'n', + ... 'display a', + ... 'undisplay', + ... 'display a < 1', + ... 'n', + ... 'continue', + ... ]): + ... test_function() + > (4)test_function() + -> a = 1 + (Pdb) display a + display a: 0 + (Pdb) n + > (5)test_function() + -> a = 2 + display a: 1 [old: 0] + (Pdb) display + Currently displaying: + a: 1 + (Pdb) undisplay a + (Pdb) n + > (6)test_function() + -> a = 3 + (Pdb) display a + display a: 2 + (Pdb) undisplay + (Pdb) display a < 1 + display a < 1: False + (Pdb) n + > (7)test_function() + -> a = 4 + (Pdb) continue + """ + +def test_pdb_alias_command(): + """Test alias command + + >>> class A: + ... def __init__(self): + ... self.attr1 = 10 + ... self.attr2 = 'str' + ... def method(self): + ... pass + + >>> def test_function(): + ... o = A() + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... o.method() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}")', + ... 'alias ps pi self', + ... 'pi o', + ... 's', + ... 'ps', + ... 'continue', + ... ]): + ... test_function() + > (4)test_function() + -> o.method() + (Pdb) alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") + (Pdb) alias ps pi self + (Pdb) pi o + o.attr1 = 10 + o.attr2 = str + (Pdb) s + --Call-- + > (5)method() + -> def method(self): + (Pdb) ps + self.attr1 = 10 + self.attr2 = str + (Pdb) continue + """ + +def test_pdb_where_command(): + """Test where command + + >>> def g(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + + >>> def f(): + ... g(); + + >>> def test_function(): + ... f() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'w', + ... 'where', + ... 'u', + ... 'w', + ... 'continue', + ... ]): + ... test_function() + --Return-- + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) w + ... + (8)() + -> test_function() + (2)test_function() + -> f() + (2)f() + -> g(); + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) where + ... + (8)() + -> test_function() + (2)test_function() + -> f() + (2)f() + -> g(); + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) u + > (2)f() + -> g(); + (Pdb) w + ... + (8)() + -> test_function() + (2)test_function() + -> f() + > (2)f() + -> g(); + (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) continue + """ + def test_post_mortem(): """Test post mortem traceback debugging. diff --git a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst new file mode 100644 index 000000000000..48277367fc87 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst @@ -0,0 +1 @@ +Improve test coverage on :mod:`pdb`. From webhook-mailer at python.org Fri Mar 24 17:09:20 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 24 Mar 2023 21:09:20 -0000 Subject: [Python-checkins] gh-102980: Add tests for pdf's display, alias and where commands (GH-102981) Message-ID: https://github.com/python/cpython/commit/d3b4d3ace9db1b673d69737c740d56ab6da824b0 commit: d3b4d3ace9db1b673d69737c740d56ab6da824b0 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-24T14:09:11-07:00 summary: gh-102980: Add tests for pdf's display, alias and where commands (GH-102981) (cherry picked from commit ded9a7fc194a1d5c0e38f475a45f8f77dbe9c6bc) Co-authored-by: gaogaotiantian files: A Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst M Lib/test/test_pdb.py diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 889262b1f193..77f68084482d 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -562,6 +562,156 @@ def test_pdb_whatis_command(): (Pdb) continue """ +def test_pdb_display_command(): + """Test display command + + >>> def test_function(): + ... a = 0 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... a = 1 + ... a = 2 + ... a = 3 + ... a = 4 + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'display a', + ... 'n', + ... 'display', + ... 'undisplay a', + ... 'n', + ... 'display a', + ... 'undisplay', + ... 'display a < 1', + ... 'n', + ... 'continue', + ... ]): + ... test_function() + > (4)test_function() + -> a = 1 + (Pdb) display a + display a: 0 + (Pdb) n + > (5)test_function() + -> a = 2 + display a: 1 [old: 0] + (Pdb) display + Currently displaying: + a: 1 + (Pdb) undisplay a + (Pdb) n + > (6)test_function() + -> a = 3 + (Pdb) display a + display a: 2 + (Pdb) undisplay + (Pdb) display a < 1 + display a < 1: False + (Pdb) n + > (7)test_function() + -> a = 4 + (Pdb) continue + """ + +def test_pdb_alias_command(): + """Test alias command + + >>> class A: + ... def __init__(self): + ... self.attr1 = 10 + ... self.attr2 = 'str' + ... def method(self): + ... pass + + >>> def test_function(): + ... o = A() + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... o.method() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}")', + ... 'alias ps pi self', + ... 'pi o', + ... 's', + ... 'ps', + ... 'continue', + ... ]): + ... test_function() + > (4)test_function() + -> o.method() + (Pdb) alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") + (Pdb) alias ps pi self + (Pdb) pi o + o.attr1 = 10 + o.attr2 = str + (Pdb) s + --Call-- + > (5)method() + -> def method(self): + (Pdb) ps + self.attr1 = 10 + self.attr2 = str + (Pdb) continue + """ + +def test_pdb_where_command(): + """Test where command + + >>> def g(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + + >>> def f(): + ... g(); + + >>> def test_function(): + ... f() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'w', + ... 'where', + ... 'u', + ... 'w', + ... 'continue', + ... ]): + ... test_function() + --Return-- + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) w + ... + (8)() + -> test_function() + (2)test_function() + -> f() + (2)f() + -> g(); + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) where + ... + (8)() + -> test_function() + (2)test_function() + -> f() + (2)f() + -> g(); + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) u + > (2)f() + -> g(); + (Pdb) w + ... + (8)() + -> test_function() + (2)test_function() + -> f() + > (2)f() + -> g(); + (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) continue + """ + def test_post_mortem(): """Test post mortem traceback debugging. diff --git a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst new file mode 100644 index 000000000000..48277367fc87 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst @@ -0,0 +1 @@ +Improve test coverage on :mod:`pdb`. From webhook-mailer at python.org Fri Mar 24 17:17:43 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 24 Mar 2023 21:17:43 -0000 Subject: [Python-checkins] gh-102980: Add tests for pdf's display, alias and where commands (GH-102981) Message-ID: https://github.com/python/cpython/commit/a08b65faa00b4feedb8ae0d08922c7f068bf9789 commit: a08b65faa00b4feedb8ae0d08922c7f068bf9789 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-24T14:17:20-07:00 summary: gh-102980: Add tests for pdf's display, alias and where commands (GH-102981) (cherry picked from commit ded9a7fc194a1d5c0e38f475a45f8f77dbe9c6bc) Co-authored-by: gaogaotiantian files: A Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst M Lib/test/test_pdb.py diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index d91bd0b2f03a..e96dc7fa1cf6 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -574,6 +574,156 @@ def test_pdb_whatis_command(): (Pdb) continue """ +def test_pdb_display_command(): + """Test display command + + >>> def test_function(): + ... a = 0 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... a = 1 + ... a = 2 + ... a = 3 + ... a = 4 + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'display a', + ... 'n', + ... 'display', + ... 'undisplay a', + ... 'n', + ... 'display a', + ... 'undisplay', + ... 'display a < 1', + ... 'n', + ... 'continue', + ... ]): + ... test_function() + > (4)test_function() + -> a = 1 + (Pdb) display a + display a: 0 + (Pdb) n + > (5)test_function() + -> a = 2 + display a: 1 [old: 0] + (Pdb) display + Currently displaying: + a: 1 + (Pdb) undisplay a + (Pdb) n + > (6)test_function() + -> a = 3 + (Pdb) display a + display a: 2 + (Pdb) undisplay + (Pdb) display a < 1 + display a < 1: False + (Pdb) n + > (7)test_function() + -> a = 4 + (Pdb) continue + """ + +def test_pdb_alias_command(): + """Test alias command + + >>> class A: + ... def __init__(self): + ... self.attr1 = 10 + ... self.attr2 = 'str' + ... def method(self): + ... pass + + >>> def test_function(): + ... o = A() + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... o.method() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}")', + ... 'alias ps pi self', + ... 'pi o', + ... 's', + ... 'ps', + ... 'continue', + ... ]): + ... test_function() + > (4)test_function() + -> o.method() + (Pdb) alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") + (Pdb) alias ps pi self + (Pdb) pi o + o.attr1 = 10 + o.attr2 = str + (Pdb) s + --Call-- + > (5)method() + -> def method(self): + (Pdb) ps + self.attr1 = 10 + self.attr2 = str + (Pdb) continue + """ + +def test_pdb_where_command(): + """Test where command + + >>> def g(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + + >>> def f(): + ... g(); + + >>> def test_function(): + ... f() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'w', + ... 'where', + ... 'u', + ... 'w', + ... 'continue', + ... ]): + ... test_function() + --Return-- + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) w + ... + (8)() + -> test_function() + (2)test_function() + -> f() + (2)f() + -> g(); + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) where + ... + (8)() + -> test_function() + (2)test_function() + -> f() + (2)f() + -> g(); + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) u + > (2)f() + -> g(); + (Pdb) w + ... + (8)() + -> test_function() + (2)test_function() + -> f() + > (2)f() + -> g(); + (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) continue + """ + def test_post_mortem(): """Test post mortem traceback debugging. diff --git a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst new file mode 100644 index 000000000000..48277367fc87 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst @@ -0,0 +1 @@ +Improve test coverage on :mod:`pdb`. From webhook-mailer at python.org Fri Mar 24 17:52:14 2023 From: webhook-mailer at python.org (gpshead) Date: Fri, 24 Mar 2023 21:52:14 -0000 Subject: [Python-checkins] gh-100131: Add optional delete parameter to tempfile.TemporaryDirectory() (#100132) Message-ID: https://github.com/python/cpython/commit/64cb1a4f0f0bc733a33ad7a6520e749ca1cdd43f commit: 64cb1a4f0f0bc733a33ad7a6520e749ca1cdd43f branch: main author: JakobDev committer: gpshead date: 2023-03-24T14:52:06-07:00 summary: gh-100131: Add optional delete parameter to tempfile.TemporaryDirectory() (#100132) Add optional delete parameter to tempfile.TemporaryDirectory(). Co-authored-by: Gregory P. Smith files: A Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst M Doc/library/tempfile.rst M Lib/tempfile.py M Lib/test/test_tempfile.py diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index b6d4f5dd05bb..61358eb76925 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -173,7 +173,7 @@ The module defines the following user-callable items: or text *mode* was specified). -.. class:: TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False) +.. class:: TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False, *, delete=True) This class securely creates a temporary directory using the same rules as :func:`mkdtemp`. The resulting object can be used as a context manager (see @@ -195,6 +195,12 @@ The module defines the following user-callable items: (the :func:`cleanup` call, exiting the context manager, when the object is garbage-collected or during interpreter shutdown). + The *delete* parameter can be used to disable cleanup of the directory tree + upon exiting the context. While it may seem unusual for a context manager + to disable the action taken when exiting the context, it can be useful during + debugging or when you need your cleanup behavior to be conditional based on + other logic. + .. audit-event:: tempfile.mkdtemp fullpath tempfile.TemporaryDirectory .. versionadded:: 3.2 @@ -202,6 +208,9 @@ The module defines the following user-callable items: .. versionchanged:: 3.10 Added *ignore_cleanup_errors* parameter. + .. versionchanged:: 3.12 + Added the *delete* parameter. + .. function:: mkstemp(suffix=None, prefix=None, dir=None, text=False) diff --git a/Lib/tempfile.py b/Lib/tempfile.py index cf06092f826b..4732eb0efe1f 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -850,17 +850,26 @@ class TemporaryDirectory: ... Upon exiting the context, the directory and everything contained - in it are removed. + in it are removed (unless delete=False is passed or an exception + is raised during cleanup and ignore_cleanup_errors is not True). + + Optional Arguments: + suffix - A str suffix for the directory name. (see mkdtemp) + prefix - A str prefix for the directory name. (see mkdtemp) + dir - A directory to create this temp dir in. (see mkdtemp) + ignore_cleanup_errors - False; ignore exceptions during cleanup? + delete - True; whether the directory is automatically deleted. """ def __init__(self, suffix=None, prefix=None, dir=None, - ignore_cleanup_errors=False): + ignore_cleanup_errors=False, *, delete=True): self.name = mkdtemp(suffix, prefix, dir) self._ignore_cleanup_errors = ignore_cleanup_errors + self._delete = delete self._finalizer = _weakref.finalize( self, self._cleanup, self.name, warn_message="Implicitly cleaning up {!r}".format(self), - ignore_errors=self._ignore_cleanup_errors) + ignore_errors=self._ignore_cleanup_errors, delete=self._delete) @classmethod def _rmtree(cls, name, ignore_errors=False): @@ -894,9 +903,10 @@ def resetperms(path): _shutil.rmtree(name, onexc=onexc) @classmethod - def _cleanup(cls, name, warn_message, ignore_errors=False): - cls._rmtree(name, ignore_errors=ignore_errors) - _warnings.warn(warn_message, ResourceWarning) + def _cleanup(cls, name, warn_message, ignore_errors=False, delete=True): + if delete: + cls._rmtree(name, ignore_errors=ignore_errors) + _warnings.warn(warn_message, ResourceWarning) def __repr__(self): return "<{} {!r}>".format(self.__class__.__name__, self.name) @@ -905,7 +915,8 @@ def __enter__(self): return self.name def __exit__(self, exc, value, tb): - self.cleanup() + if self._delete: + self.cleanup() def cleanup(self): if self._finalizer.detach() or _os.path.exists(self.name): diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 7c2c8de7a2e6..90155487cff5 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -12,6 +12,7 @@ import types import weakref import gc +import shutil from unittest import mock import unittest @@ -1837,6 +1838,11 @@ def test_flags(self): d.cleanup() self.assertFalse(os.path.exists(d.name)) + def test_delete_false(self): + with tempfile.TemporaryDirectory(delete=False) as working_dir: + pass + self.assertTrue(os.path.exists(working_dir)) + shutil.rmtree(working_dir) if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst b/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst new file mode 100644 index 000000000000..07891f2c1e9e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst @@ -0,0 +1 @@ +Added an optional ``delete`` keyword argument to :class:`tempfile.TemporaryDirectory`. From webhook-mailer at python.org Sat Mar 25 03:15:32 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 25 Mar 2023 07:15:32 -0000 Subject: [Python-checkins] gh-101100: Test only Doc/ files in nit-picky mode (#103019) Message-ID: https://github.com/python/cpython/commit/87adc63d66349566b6459f93be60861b9d37782f commit: 87adc63d66349566b6459f93be60861b9d37782f branch: main author: Hugo van Kemenade committer: hugovk date: 2023-03-25T09:15:02+02:00 summary: gh-101100: Test only Doc/ files in nit-picky mode (#103019) gh-101100: Filter only Doc/ files files: M .github/workflows/doc.yml diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 9ec60c198eb3..29387d30d5a2 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -57,6 +57,8 @@ jobs: - name: 'Get list of changed files' id: changed_files uses: Ana06/get-changed-files at v2.2.0 + with: + filter: "Doc/**" - name: 'Build changed files in nit-picky mode' continue-on-error: true run: | From webhook-mailer at python.org Sat Mar 25 03:19:27 2023 From: webhook-mailer at python.org (rhettinger) Date: Sat, 25 Mar 2023 07:19:27 -0000 Subject: [Python-checkins] GH-102833: Mention the key function in the docstrings (GH-103009) Message-ID: https://github.com/python/cpython/commit/1fd603fad20187496619930e5b74aa7690425926 commit: 1fd603fad20187496619930e5b74aa7690425926 branch: main author: Raymond Hettinger committer: rhettinger date: 2023-03-25T02:19:20-05:00 summary: GH-102833: Mention the key function in the docstrings (GH-103009) files: M Lib/bisect.py M Modules/_bisectmodule.c M Modules/clinic/_bisectmodule.c.h diff --git a/Lib/bisect.py b/Lib/bisect.py index d37da74f7b40..ca6ca7240840 100644 --- a/Lib/bisect.py +++ b/Lib/bisect.py @@ -8,6 +8,8 @@ def insort_right(a, x, lo=0, hi=None, *, key=None): Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + + A custom key function can be supplied to customize the sort order. """ if key is None: lo = bisect_right(a, x, lo, hi) @@ -25,6 +27,8 @@ def bisect_right(a, x, lo=0, hi=None, *, key=None): Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + + A custom key function can be supplied to customize the sort order. """ if lo < 0: @@ -57,6 +61,8 @@ def insort_left(a, x, lo=0, hi=None, *, key=None): Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + + A custom key function can be supplied to customize the sort order. """ if key is None: @@ -74,6 +80,8 @@ def bisect_left(a, x, lo=0, hi=None, *, key=None): Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + + A custom key function can be supplied to customize the sort order. """ if lo < 0: diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c index d3bec535ee51..30801c2f87ee 100644 --- a/Modules/_bisectmodule.c +++ b/Modules/_bisectmodule.c @@ -162,12 +162,14 @@ insert just after the rightmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + +A custom key function can be supplied to customize the sort order. [clinic start generated code]*/ static Py_ssize_t _bisect_bisect_right_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=3a4bc09cc7c8a73d input=40fcc5afa06ae593]*/ +/*[clinic end generated code: output=3a4bc09cc7c8a73d input=43071869772dd53a]*/ { return internal_bisect_right(a, x, lo, hi, key); } @@ -188,12 +190,14 @@ If x is already in a, insert it to the right of the rightmost x. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + +A custom key function can be supplied to customize the sort order. [clinic start generated code]*/ static PyObject * _bisect_insort_right_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=ac3bf26d07aedda2 input=44e1708e26b7b802]*/ +/*[clinic end generated code: output=ac3bf26d07aedda2 input=f60777d2b6ddb239]*/ { PyObject *result, *key_x; Py_ssize_t index; @@ -343,12 +347,14 @@ insert just before the leftmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + +A custom key function can be supplied to customize the sort order. [clinic start generated code]*/ static Py_ssize_t _bisect_bisect_left_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=70749d6e5cae9284 input=90dd35b50ceb05e3]*/ +/*[clinic end generated code: output=70749d6e5cae9284 input=f29c4fe7f9b797c7]*/ { return internal_bisect_left(a, x, lo, hi, key); } @@ -370,12 +376,14 @@ If x is already in a, insert it to the left of the leftmost x. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + +A custom key function can be supplied to customize the sort order. [clinic start generated code]*/ static PyObject * _bisect_insort_left_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=b1d33e5e7ffff11e input=3ab65d8784f585b1]*/ +/*[clinic end generated code: output=b1d33e5e7ffff11e input=0a700a82edbd472c]*/ { PyObject *result, *key_x; Py_ssize_t index; diff --git a/Modules/clinic/_bisectmodule.c.h b/Modules/clinic/_bisectmodule.c.h index bbf456e4b0f4..7944f5219b02 100644 --- a/Modules/clinic/_bisectmodule.c.h +++ b/Modules/clinic/_bisectmodule.c.h @@ -19,7 +19,9 @@ PyDoc_STRVAR(_bisect_bisect_right__doc__, "insert just after the rightmost x already there.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" -"slice of a to be searched."); +"slice of a to be searched.\n" +"\n" +"A custom key function can be supplied to customize the sort order."); #define _BISECT_BISECT_RIGHT_METHODDEF \ {"bisect_right", _PyCFunction_CAST(_bisect_bisect_right), METH_FASTCALL|METH_KEYWORDS, _bisect_bisect_right__doc__}, @@ -125,7 +127,9 @@ PyDoc_STRVAR(_bisect_insort_right__doc__, "If x is already in a, insert it to the right of the rightmost x.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" -"slice of a to be searched."); +"slice of a to be searched.\n" +"\n" +"A custom key function can be supplied to customize the sort order."); #define _BISECT_INSORT_RIGHT_METHODDEF \ {"insort_right", _PyCFunction_CAST(_bisect_insort_right), METH_FASTCALL|METH_KEYWORDS, _bisect_insort_right__doc__}, @@ -228,7 +232,9 @@ PyDoc_STRVAR(_bisect_bisect_left__doc__, "insert just before the leftmost x already there.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" -"slice of a to be searched."); +"slice of a to be searched.\n" +"\n" +"A custom key function can be supplied to customize the sort order."); #define _BISECT_BISECT_LEFT_METHODDEF \ {"bisect_left", _PyCFunction_CAST(_bisect_bisect_left), METH_FASTCALL|METH_KEYWORDS, _bisect_bisect_left__doc__}, @@ -334,7 +340,9 @@ PyDoc_STRVAR(_bisect_insort_left__doc__, "If x is already in a, insert it to the left of the leftmost x.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" -"slice of a to be searched."); +"slice of a to be searched.\n" +"\n" +"A custom key function can be supplied to customize the sort order."); #define _BISECT_INSORT_LEFT_METHODDEF \ {"insort_left", _PyCFunction_CAST(_bisect_insort_left), METH_FASTCALL|METH_KEYWORDS, _bisect_insort_left__doc__}, @@ -425,4 +433,4 @@ _bisect_insort_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P exit: return return_value; } -/*[clinic end generated code: output=7dc87f7af75275a1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5a7fa64bf9b262f3 input=a9049054013a1b77]*/ From webhook-mailer at python.org Sat Mar 25 03:43:58 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 25 Mar 2023 07:43:58 -0000 Subject: [Python-checkins] [3.11] gh-101100: Document PyObject_ClearWeakRefs, gzip's name, and asyncio.iscoroutine (#103001) Message-ID: https://github.com/python/cpython/commit/85c686a1a5f362908138139d8d332ce7c033f2aa commit: 85c686a1a5f362908138139d8d332ce7c033f2aa branch: 3.11 author: Hugo van Kemenade committer: hugovk date: 2023-03-25T09:43:52+02:00 summary: [3.11] gh-101100: Document PyObject_ClearWeakRefs, gzip's name, and asyncio.iscoroutine (#103001) files: M Doc/c-api/weakref.rst M Doc/library/asyncio-task.rst M Doc/library/gzip.rst diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index ace743ba01c5..f27ec4411b4a 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -67,3 +67,13 @@ as much as it can. .. c:function:: PyObject* PyWeakref_GET_OBJECT(PyObject *ref) Similar to :c:func:`PyWeakref_GetObject`, but does no error checking. + + +.. c:function:: void PyObject_ClearWeakRefs(PyObject *object) + + This function is called by the :c:member:`~PyTypeObject.tp_dealloc` handler + to clear weak references. + + This iterates through the weak references for *object* and calls callbacks + for those references which have one. It returns when all callbacks have + been attempted. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 1e0a69c75e25..02fc38495879 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -956,6 +956,13 @@ Introspection .. versionadded:: 3.7 +.. function:: iscoroutine(obj) + + Return ``True`` if *obj* is a coroutine object. + + .. versionadded:: 3.4 + + Task Object =========== diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 8cea2649ee6c..9afaf86cb132 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -143,6 +143,12 @@ The module defines the following items: :func:`time.time` and the :attr:`~os.stat_result.st_mtime` attribute of the object returned by :func:`os.stat`. + .. attribute:: name + + The path to the gzip file on disk, as a :class:`str` or :class:`bytes`. + Equivalent to the output of :func:`os.fspath` on the original input path, + with no other normalization, resolution or expansion. + .. versionchanged:: 3.1 Support for the :keyword:`with` statement was added, along with the *mtime* constructor argument and :attr:`mtime` attribute. From webhook-mailer at python.org Sat Mar 25 03:44:12 2023 From: webhook-mailer at python.org (hugovk) Date: Sat, 25 Mar 2023 07:44:12 -0000 Subject: [Python-checkins] [3.10] gh-101100: Document PyObject_ClearWeakRefs and gzip's name (#103002) Message-ID: https://github.com/python/cpython/commit/7513c6b6fe50dd651abe4d9b0c2f207b032cabfe commit: 7513c6b6fe50dd651abe4d9b0c2f207b032cabfe branch: 3.10 author: Hugo van Kemenade committer: hugovk date: 2023-03-25T09:44:05+02:00 summary: [3.10] gh-101100: Document PyObject_ClearWeakRefs and gzip's name (#103002) files: M Doc/c-api/weakref.rst M Doc/library/gzip.rst diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index cb6aba33b568..b471260e1769 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -68,3 +68,13 @@ as much as it can. Similar to :c:func:`PyWeakref_GetObject`, but implemented as a macro that does no error checking. + + +.. c:function:: void PyObject_ClearWeakRefs(PyObject *object) + + This function is called by the :c:member:`~PyTypeObject.tp_dealloc` handler + to clear weak references. + + This iterates through the weak references for *object* and calls callbacks + for those references which have one. It returns when all callbacks have + been attempted. diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 33c40676f747..ec92fa2611bc 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -143,6 +143,12 @@ The module defines the following items: :func:`time.time` and the :attr:`~os.stat_result.st_mtime` attribute of the object returned by :func:`os.stat`. + .. attribute:: name + + The path to the gzip file on disk, as a :class:`str` or :class:`bytes`. + Equivalent to the output of :func:`os.fspath` on the original input path, + with no other normalization, resolution or expansion. + .. versionchanged:: 3.1 Support for the :keyword:`with` statement was added, along with the *mtime* constructor argument and :attr:`mtime` attribute. From webhook-mailer at python.org Sat Mar 25 05:12:17 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 25 Mar 2023 09:12:17 -0000 Subject: [Python-checkins] gh-103025: fix two ctypes doc issues (#103026) Message-ID: https://github.com/python/cpython/commit/0708437ad043657f992cb985fd5c37e1ac052f93 commit: 0708437ad043657f992cb985fd5c37e1ac052f93 branch: main author: Peter Jiping Xie committer: AlexWaygood date: 2023-03-25T09:12:00Z summary: gh-103025: fix two ctypes doc issues (#103026) files: M Doc/library/ctypes.rst diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 8fd681286b81..d49d702e9e79 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -375,8 +375,8 @@ that they can be converted to the required C data type:: .. _ctypes-calling-variadic-functions: -Calling varadic functions -^^^^^^^^^^^^^^^^^^^^^^^^^ +Calling variadic functions +^^^^^^^^^^^^^^^^^^^^^^^^^^ On a lot of platforms calling variadic functions through ctypes is exactly the same as calling functions with a fixed number of parameters. On some platforms, and in @@ -508,7 +508,7 @@ a string pointer and a char, and returns a pointer to a string:: If you want to avoid the ``ord("x")`` calls above, you can set the :attr:`argtypes` attribute, and the second argument will be converted from a -single character Python bytes object into a C char:: +single character Python bytes object into a C char: .. doctest:: From webhook-mailer at python.org Sat Mar 25 06:00:10 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 25 Mar 2023 10:00:10 -0000 Subject: [Python-checkins] [3.10] gh-103025: fix a ctypes doc typo (GH-103026) (#103030) Message-ID: https://github.com/python/cpython/commit/db5bf524699f217bfe8d49e652882e763e903099 commit: db5bf524699f217bfe8d49e652882e763e903099 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood date: 2023-03-25T10:00:03Z summary: [3.10] gh-103025: fix a ctypes doc typo (GH-103026) (#103030) * gh-103025: fix two ctypes doc issues (GH-103026) (cherry picked from commit 0708437ad043657f992cb985fd5c37e1ac052f93) files: M Doc/library/ctypes.rst diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index d1922aaf165a..8d4230ae1793 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -375,8 +375,8 @@ that they can be converted to the required C data type:: .. _ctypes-calling-variadic-functions: -Calling varadic functions -^^^^^^^^^^^^^^^^^^^^^^^^^ +Calling variadic functions +^^^^^^^^^^^^^^^^^^^^^^^^^^ On a lot of platforms calling variadic functions through ctypes is exactly the same as calling functions with a fixed number of parameters. On some platforms, and in From webhook-mailer at python.org Sat Mar 25 06:00:51 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Sat, 25 Mar 2023 10:00:51 -0000 Subject: [Python-checkins] [3.11] gh-103025: fix a ctypes doc typo (GH-103026) (#103029) Message-ID: https://github.com/python/cpython/commit/aae91fa63c65745c4118eafca0088447d87e65b0 commit: aae91fa63c65745c4118eafca0088447d87e65b0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: AlexWaygood date: 2023-03-25T10:00:44Z summary: [3.11] gh-103025: fix a ctypes doc typo (GH-103026) (#103029) * gh-103025: fix two ctypes doc issues (GH-103026) (cherry picked from commit 0708437ad043657f992cb985fd5c37e1ac052f93) Co-authored-by: Peter Jiping Xie files: M Doc/library/ctypes.rst diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 282dff38c206..8690f70fd2e0 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -374,8 +374,8 @@ that they can be converted to the required C data type:: .. _ctypes-calling-variadic-functions: -Calling varadic functions -^^^^^^^^^^^^^^^^^^^^^^^^^ +Calling variadic functions +^^^^^^^^^^^^^^^^^^^^^^^^^^ On a lot of platforms calling variadic functions through ctypes is exactly the same as calling functions with a fixed number of parameters. On some platforms, and in From webhook-mailer at python.org Sat Mar 25 15:36:44 2023 From: webhook-mailer at python.org (ericvsmith) Date: Sat, 25 Mar 2023 19:36:44 -0000 Subject: [Python-checkins] gh-103027: Update `dataclass.make_dataclass` docstring (gh-103028) Message-ID: https://github.com/python/cpython/commit/8ec6486462b920ab92ecb685a79fc3446681e1b8 commit: 8ec6486462b920ab92ecb685a79fc3446681e1b8 branch: main author: Nikita Sobolev committer: ericvsmith date: 2023-03-25T15:36:38-04:00 summary: gh-103027: Update `dataclass.make_dataclass` docstring (gh-103028) * gh-103027: Update `dataclass.make_dataclass` docstring files: M Lib/dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index e3fd0b3e380d..0e04469be3ca 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1421,8 +1421,11 @@ class C(Base): For the bases and namespace parameters, see the builtin type() function. - The parameters init, repr, eq, order, unsafe_hash, and frozen are passed to - dataclass(). + The parameters init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, + slots, and weakref_slot are passed to dataclass(). + + If module parameter is defined, the '__module__' attribute of the dataclass is + set to that value. """ if namespace is None: From webhook-mailer at python.org Sat Mar 25 17:27:11 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 25 Mar 2023 21:27:11 -0000 Subject: [Python-checkins] Fix typos in faulthandler, testcapi error messages (#103020) Message-ID: https://github.com/python/cpython/commit/11ed70b1dc69c9455d83638af5799dd0071b4ea8 commit: 11ed70b1dc69c9455d83638af5799dd0071b4ea8 branch: main author: Liyang Zhang committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-25T14:27:02-07:00 summary: Fix typos in faulthandler, testcapi error messages (#103020) files: M Modules/_testcapi/heaptype.c M Modules/faulthandler.c diff --git a/Modules/_testcapi/heaptype.c b/Modules/_testcapi/heaptype.c index df2a061ed82b..209cc182c069 100644 --- a/Modules/_testcapi/heaptype.c +++ b/Modules/_testcapi/heaptype.c @@ -174,7 +174,7 @@ test_from_spec_invalid_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED( } if (res == 0) { PyErr_SetString(PyExc_AssertionError, - "TypeError did not inlclude expected message."); + "TypeError did not include expected message."); goto finally; } result = Py_NewRef(Py_None); @@ -265,7 +265,7 @@ test_type_from_ephemeral_spec(PyObject *self, PyObject *Py_UNUSED(ignored)) /* deallocate the spec (and all contents) */ - // (Explicitly ovewrite memory before freeing, + // (Explicitly overwrite memory before freeing, // so bugs show themselves even without the debug allocator's help.) memset(spec, 0xdd, sizeof(PyType_Spec)); PyMem_Del(spec); diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index bfe35fed7a45..9b4e4199cdc2 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -120,7 +120,7 @@ faulthandler_get_fileno(PyObject **file_ptr) return -1; if (fd < 0) { PyErr_SetString(PyExc_ValueError, - "file is not a valid file descripter"); + "file is not a valid file descriptor"); return -1; } *file_ptr = NULL; From webhook-mailer at python.org Sat Mar 25 17:31:52 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 25 Mar 2023 21:31:52 -0000 Subject: [Python-checkins] Update pdb docs for arguments (#102965) Message-ID: https://github.com/python/cpython/commit/027223db96b0464c49a74513f82a1bf25aa510bd commit: 027223db96b0464c49a74513f82a1bf25aa510bd branch: main author: gaogaotiantian committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-25T14:31:45-07:00 summary: Update pdb docs for arguments (#102965) files: M Doc/library/pdb.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 5988477af03a..d80c5eebbf27 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -125,7 +125,7 @@ slightly different way: Evaluate the *expression* (given as a string or a code object) under debugger control. When :func:`runeval` returns, it returns the value of the - expression. Otherwise this function is similar to :func:`run`. + *expression*. Otherwise this function is similar to :func:`run`. .. function:: runcall(function, *args, **kwds) @@ -178,7 +178,7 @@ access further features, you have to do this yourself: that matches one of these patterns. [1]_ By default, Pdb sets a handler for the SIGINT signal (which is sent when the - user presses :kbd:`Ctrl-C` on the console) when you give a ``continue`` command. + user presses :kbd:`Ctrl-C` on the console) when you give a :pdbcmd:`continue` command. This allows you to break into the debugger again by pressing :kbd:`Ctrl-C`. If you want Pdb not to touch the SIGINT handler, set *nosigint* to true. @@ -328,9 +328,9 @@ can be overridden by the local file. .. pdbcommand:: ignore bpnumber [count] - Set the ignore count for the given breakpoint number. If count is omitted, + Set the ignore count for the given breakpoint number. If *count* is omitted, the ignore count is set to 0. A breakpoint becomes active when the ignore - count is zero. When non-zero, the count is decremented each time the + count is zero. When non-zero, the *count* is decremented each time the breakpoint is reached and the breakpoint is not disabled and any associated condition evaluates to true. @@ -369,7 +369,7 @@ can be overridden by the local file. breakpoint?which could have its own command list, leading to ambiguities about which list to execute. - If you use the 'silent' command in the command list, the usual message about + If you use the ``silent`` command in the command list, the usual message about stopping at a breakpoint is not printed. This may be desirable for breakpoints that are to print a specific message and then continue. If none of the other commands print anything, you see no sign that the breakpoint was reached. @@ -392,8 +392,8 @@ can be overridden by the local file. Without argument, continue execution until the line with a number greater than the current one is reached. - With a line number, continue execution until a line with a number greater or - equal to that is reached. In both cases, also stop when the current frame + With *lineno*, continue execution until a line with a number greater or + equal to *lineno* is reached. In both cases, also stop when the current frame returns. .. versionchanged:: 3.2 @@ -446,7 +446,7 @@ can be overridden by the local file. .. pdbcommand:: p expression - Evaluate the *expression* in the current context and print its value. + Evaluate *expression* in the current context and print its value. .. note:: @@ -456,32 +456,32 @@ can be overridden by the local file. .. pdbcommand:: pp expression - Like the :pdbcmd:`p` command, except the value of the expression is + Like the :pdbcmd:`p` command, except the value of *expression* is pretty-printed using the :mod:`pprint` module. .. pdbcommand:: whatis expression - Print the type of the *expression*. + Print the type of *expression*. .. pdbcommand:: source expression - Try to get source code for the given object and display it. + Try to get source code of *expression* and display it. .. versionadded:: 3.2 .. pdbcommand:: display [expression] - Display the value of the expression if it changed, each time execution stops + Display the value of *expression* if it changed, each time execution stops in the current frame. - Without expression, list all display expressions for the current frame. + Without *expression*, list all display expressions for the current frame. .. versionadded:: 3.2 .. pdbcommand:: undisplay [expression] - Do not display the expression any more in the current frame. Without - expression, clear all display expressions for the current frame. + Do not display *expression* anymore in the current frame. Without + *expression*, clear all display expressions for the current frame. .. versionadded:: 3.2 @@ -497,10 +497,10 @@ can be overridden by the local file. .. pdbcommand:: alias [name [command]] - Create an alias called *name* that executes *command*. The command must + Create an alias called *name* that executes *command*. The *command* must *not* be enclosed in quotes. Replaceable parameters can be indicated by ``%1``, ``%2``, and so on, while ``%*`` is replaced by all the parameters. - If no command is given, the current alias for *name* is shown. If no + If *command* is omitted, the current alias for *name* is shown. If no arguments are given, all aliases are listed. Aliases may be nested and can contain anything that can be legally typed at @@ -519,7 +519,7 @@ can be overridden by the local file. .. pdbcommand:: unalias name - Delete the specified alias. + Delete the specified alias *name*. .. pdbcommand:: ! statement @@ -535,7 +535,7 @@ can be overridden by the local file. .. pdbcommand:: run [args ...] restart [args ...] - Restart the debugged Python program. If an argument is supplied, it is split + Restart the debugged Python program. If *args* is supplied, it is split with :mod:`shlex` and the result is used as the new :data:`sys.argv`. History, breakpoints, actions and debugger options are preserved. :pdbcmd:`restart` is an alias for :pdbcmd:`run`. @@ -546,8 +546,8 @@ can be overridden by the local file. .. pdbcommand:: debug code - Enter a recursive debugger that steps through the code - argument (which is an arbitrary expression or statement to be + Enter a recursive debugger that steps through *code* + (which is an arbitrary expression or statement to be executed in the current environment). .. pdbcommand:: retval From webhook-mailer at python.org Sat Mar 25 17:38:33 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 25 Mar 2023 21:38:33 -0000 Subject: [Python-checkins] Update pdb docs for arguments (GH-102965) Message-ID: https://github.com/python/cpython/commit/ae8a721c2ba2a48de0cb69fa868fa8fc207b129d commit: ae8a721c2ba2a48de0cb69fa868fa8fc207b129d branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-25T14:38:26-07:00 summary: Update pdb docs for arguments (GH-102965) (cherry picked from commit 027223db96b0464c49a74513f82a1bf25aa510bd) Co-authored-by: gaogaotiantian files: M Doc/library/pdb.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 8df518c912a3..860d2064616e 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -125,7 +125,7 @@ slightly different way: Evaluate the *expression* (given as a string or a code object) under debugger control. When :func:`runeval` returns, it returns the value of the - expression. Otherwise this function is similar to :func:`run`. + *expression*. Otherwise this function is similar to :func:`run`. .. function:: runcall(function, *args, **kwds) @@ -178,7 +178,7 @@ access further features, you have to do this yourself: that matches one of these patterns. [1]_ By default, Pdb sets a handler for the SIGINT signal (which is sent when the - user presses :kbd:`Ctrl-C` on the console) when you give a ``continue`` command. + user presses :kbd:`Ctrl-C` on the console) when you give a :pdbcmd:`continue` command. This allows you to break into the debugger again by pressing :kbd:`Ctrl-C`. If you want Pdb not to touch the SIGINT handler, set *nosigint* to true. @@ -324,9 +324,9 @@ by the local file. .. pdbcommand:: ignore bpnumber [count] - Set the ignore count for the given breakpoint number. If count is omitted, + Set the ignore count for the given breakpoint number. If *count* is omitted, the ignore count is set to 0. A breakpoint becomes active when the ignore - count is zero. When non-zero, the count is decremented each time the + count is zero. When non-zero, the *count* is decremented each time the breakpoint is reached and the breakpoint is not disabled and any associated condition evaluates to true. @@ -365,7 +365,7 @@ by the local file. breakpoint?which could have its own command list, leading to ambiguities about which list to execute. - If you use the 'silent' command in the command list, the usual message about + If you use the ``silent`` command in the command list, the usual message about stopping at a breakpoint is not printed. This may be desirable for breakpoints that are to print a specific message and then continue. If none of the other commands print anything, you see no sign that the breakpoint was reached. @@ -388,8 +388,8 @@ by the local file. Without argument, continue execution until the line with a number greater than the current one is reached. - With a line number, continue execution until a line with a number greater or - equal to that is reached. In both cases, also stop when the current frame + With *lineno*, continue execution until a line with a number greater or + equal to *lineno* is reached. In both cases, also stop when the current frame returns. .. versionchanged:: 3.2 @@ -442,7 +442,7 @@ by the local file. .. pdbcommand:: p expression - Evaluate the *expression* in the current context and print its value. + Evaluate *expression* in the current context and print its value. .. note:: @@ -452,32 +452,32 @@ by the local file. .. pdbcommand:: pp expression - Like the :pdbcmd:`p` command, except the value of the expression is + Like the :pdbcmd:`p` command, except the value of *expression* is pretty-printed using the :mod:`pprint` module. .. pdbcommand:: whatis expression - Print the type of the *expression*. + Print the type of *expression*. .. pdbcommand:: source expression - Try to get source code for the given object and display it. + Try to get source code of *expression* and display it. .. versionadded:: 3.2 .. pdbcommand:: display [expression] - Display the value of the expression if it changed, each time execution stops + Display the value of *expression* if it changed, each time execution stops in the current frame. - Without expression, list all display expressions for the current frame. + Without *expression*, list all display expressions for the current frame. .. versionadded:: 3.2 .. pdbcommand:: undisplay [expression] - Do not display the expression any more in the current frame. Without - expression, clear all display expressions for the current frame. + Do not display *expression* anymore in the current frame. Without + *expression*, clear all display expressions for the current frame. .. versionadded:: 3.2 @@ -493,10 +493,10 @@ by the local file. .. pdbcommand:: alias [name [command]] - Create an alias called *name* that executes *command*. The command must + Create an alias called *name* that executes *command*. The *command* must *not* be enclosed in quotes. Replaceable parameters can be indicated by ``%1``, ``%2``, and so on, while ``%*`` is replaced by all the parameters. - If no command is given, the current alias for *name* is shown. If no + If *command* is omitted, the current alias for *name* is shown. If no arguments are given, all aliases are listed. Aliases may be nested and can contain anything that can be legally typed at @@ -515,7 +515,7 @@ by the local file. .. pdbcommand:: unalias name - Delete the specified alias. + Delete the specified alias *name*. .. pdbcommand:: ! statement @@ -531,7 +531,7 @@ by the local file. .. pdbcommand:: run [args ...] restart [args ...] - Restart the debugged Python program. If an argument is supplied, it is split + Restart the debugged Python program. If *args* is supplied, it is split with :mod:`shlex` and the result is used as the new :data:`sys.argv`. History, breakpoints, actions and debugger options are preserved. :pdbcmd:`restart` is an alias for :pdbcmd:`run`. @@ -542,8 +542,8 @@ by the local file. .. pdbcommand:: debug code - Enter a recursive debugger that steps through the code - argument (which is an arbitrary expression or statement to be + Enter a recursive debugger that steps through *code* + (which is an arbitrary expression or statement to be executed in the current environment). .. pdbcommand:: retval From webhook-mailer at python.org Sat Mar 25 17:40:18 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 25 Mar 2023 21:40:18 -0000 Subject: [Python-checkins] gh-98886: Fix issues with dataclass fields with special underscore names (#102032) Message-ID: https://github.com/python/cpython/commit/718e86671fe62a706c460b7f049b196e434cb5b3 commit: 718e86671fe62a706c460b7f049b196e434cb5b3 branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-25T14:40:11-07:00 summary: gh-98886: Fix issues with dataclass fields with special underscore names (#102032) This commit prefixes `__dataclass` to several things in the locals dict: - Names like `_dflt_` (which cause trouble, see first test) - Names like `_type_` (not known to be able to cause trouble) - `_return_type` (not known to able to cause trouble) - `_HAS_DEFAULT_FACTORY` (which causes trouble, see second test) In addition, this removes `MISSING` from the locals dict. As far as I can tell, this wasn't needed even in the initial implementation of dataclasses.py (and tests on that version passed with it removed). This makes me wary :-) This is basically a continuation of #96151, where fixing this was welcomed in https://github.com/python/cpython/pull/98143#issuecomment-1280306360 files: A Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst M Lib/dataclasses.py M Lib/test/test_dataclasses.py diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 0e04469be3ca..7558287bad44 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -432,8 +432,8 @@ def _create_fn(name, args, body, *, globals=None, locals=None, locals = {} return_annotation = '' if return_type is not MISSING: - locals['_return_type'] = return_type - return_annotation = '->_return_type' + locals['__dataclass_return_type__'] = return_type + return_annotation = '->__dataclass_return_type__' args = ','.join(args) body = '\n'.join(f' {b}' for b in body) @@ -467,14 +467,14 @@ def _field_init(f, frozen, globals, self_name, slots): # Return the text of the line in the body of __init__ that will # initialize this field. - default_name = f'_dflt_{f.name}' + default_name = f'__dataclass_dflt_{f.name}__' if f.default_factory is not MISSING: if f.init: # This field has a default factory. If a parameter is # given, use it. If not, call the factory. globals[default_name] = f.default_factory value = (f'{default_name}() ' - f'if {f.name} is _HAS_DEFAULT_FACTORY ' + f'if {f.name} is __dataclass_HAS_DEFAULT_FACTORY__ ' f'else {f.name}') else: # This is a field that's not in the __init__ params, but @@ -535,11 +535,11 @@ def _init_param(f): elif f.default is not MISSING: # There's a default, this will be the name that's used to look # it up. - default = f'=_dflt_{f.name}' + default = f'=__dataclass_dflt_{f.name}__' elif f.default_factory is not MISSING: # There's a factory function. Set a marker. - default = '=_HAS_DEFAULT_FACTORY' - return f'{f.name}:_type_{f.name}{default}' + default = '=__dataclass_HAS_DEFAULT_FACTORY__' + return f'{f.name}:__dataclass_type_{f.name}__{default}' def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, @@ -562,10 +562,9 @@ def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, raise TypeError(f'non-default argument {f.name!r} ' 'follows default argument') - locals = {f'_type_{f.name}': f.type for f in fields} + locals = {f'__dataclass_type_{f.name}__': f.type for f in fields} locals.update({ - 'MISSING': MISSING, - '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY, + '__dataclass_HAS_DEFAULT_FACTORY__': _HAS_DEFAULT_FACTORY, '__dataclass_builtins_object__': object, }) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index affd9cede19c..6888680105c4 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -285,6 +285,23 @@ class C: c = C(5) self.assertEqual(c.BUILTINS, 5) + def test_field_with_special_single_underscore_names(self): + # gh-98886 + + @dataclass + class X: + x: int = field(default_factory=lambda: 111) + _dflt_x: int = field(default_factory=lambda: 222) + + X() + + @dataclass + class Y: + y: int = field(default_factory=lambda: 111) + _HAS_DEFAULT_FACTORY: int = 222 + + assert Y(y=222).y == 222 + def test_field_named_like_builtin(self): # Attribute names can shadow built-in names # since code generation is used. diff --git a/Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst b/Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst new file mode 100644 index 000000000000..64e4d6eed2f6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst @@ -0,0 +1 @@ +Fix issues when defining dataclasses that have fields with specific underscore names that aren't clearly reserved by :mod:`dataclasses`. From webhook-mailer at python.org Sat Mar 25 17:42:35 2023 From: webhook-mailer at python.org (miss-islington) Date: Sat, 25 Mar 2023 21:42:35 -0000 Subject: [Python-checkins] Update pdb docs for arguments (GH-102965) Message-ID: https://github.com/python/cpython/commit/e1094c6e6a63637beacec731eced2c98bd076920 commit: e1094c6e6a63637beacec731eced2c98bd076920 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-25T14:42:28-07:00 summary: Update pdb docs for arguments (GH-102965) (cherry picked from commit 027223db96b0464c49a74513f82a1bf25aa510bd) Co-authored-by: gaogaotiantian files: M Doc/library/pdb.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 5988477af03a..d80c5eebbf27 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -125,7 +125,7 @@ slightly different way: Evaluate the *expression* (given as a string or a code object) under debugger control. When :func:`runeval` returns, it returns the value of the - expression. Otherwise this function is similar to :func:`run`. + *expression*. Otherwise this function is similar to :func:`run`. .. function:: runcall(function, *args, **kwds) @@ -178,7 +178,7 @@ access further features, you have to do this yourself: that matches one of these patterns. [1]_ By default, Pdb sets a handler for the SIGINT signal (which is sent when the - user presses :kbd:`Ctrl-C` on the console) when you give a ``continue`` command. + user presses :kbd:`Ctrl-C` on the console) when you give a :pdbcmd:`continue` command. This allows you to break into the debugger again by pressing :kbd:`Ctrl-C`. If you want Pdb not to touch the SIGINT handler, set *nosigint* to true. @@ -328,9 +328,9 @@ can be overridden by the local file. .. pdbcommand:: ignore bpnumber [count] - Set the ignore count for the given breakpoint number. If count is omitted, + Set the ignore count for the given breakpoint number. If *count* is omitted, the ignore count is set to 0. A breakpoint becomes active when the ignore - count is zero. When non-zero, the count is decremented each time the + count is zero. When non-zero, the *count* is decremented each time the breakpoint is reached and the breakpoint is not disabled and any associated condition evaluates to true. @@ -369,7 +369,7 @@ can be overridden by the local file. breakpoint?which could have its own command list, leading to ambiguities about which list to execute. - If you use the 'silent' command in the command list, the usual message about + If you use the ``silent`` command in the command list, the usual message about stopping at a breakpoint is not printed. This may be desirable for breakpoints that are to print a specific message and then continue. If none of the other commands print anything, you see no sign that the breakpoint was reached. @@ -392,8 +392,8 @@ can be overridden by the local file. Without argument, continue execution until the line with a number greater than the current one is reached. - With a line number, continue execution until a line with a number greater or - equal to that is reached. In both cases, also stop when the current frame + With *lineno*, continue execution until a line with a number greater or + equal to *lineno* is reached. In both cases, also stop when the current frame returns. .. versionchanged:: 3.2 @@ -446,7 +446,7 @@ can be overridden by the local file. .. pdbcommand:: p expression - Evaluate the *expression* in the current context and print its value. + Evaluate *expression* in the current context and print its value. .. note:: @@ -456,32 +456,32 @@ can be overridden by the local file. .. pdbcommand:: pp expression - Like the :pdbcmd:`p` command, except the value of the expression is + Like the :pdbcmd:`p` command, except the value of *expression* is pretty-printed using the :mod:`pprint` module. .. pdbcommand:: whatis expression - Print the type of the *expression*. + Print the type of *expression*. .. pdbcommand:: source expression - Try to get source code for the given object and display it. + Try to get source code of *expression* and display it. .. versionadded:: 3.2 .. pdbcommand:: display [expression] - Display the value of the expression if it changed, each time execution stops + Display the value of *expression* if it changed, each time execution stops in the current frame. - Without expression, list all display expressions for the current frame. + Without *expression*, list all display expressions for the current frame. .. versionadded:: 3.2 .. pdbcommand:: undisplay [expression] - Do not display the expression any more in the current frame. Without - expression, clear all display expressions for the current frame. + Do not display *expression* anymore in the current frame. Without + *expression*, clear all display expressions for the current frame. .. versionadded:: 3.2 @@ -497,10 +497,10 @@ can be overridden by the local file. .. pdbcommand:: alias [name [command]] - Create an alias called *name* that executes *command*. The command must + Create an alias called *name* that executes *command*. The *command* must *not* be enclosed in quotes. Replaceable parameters can be indicated by ``%1``, ``%2``, and so on, while ``%*`` is replaced by all the parameters. - If no command is given, the current alias for *name* is shown. If no + If *command* is omitted, the current alias for *name* is shown. If no arguments are given, all aliases are listed. Aliases may be nested and can contain anything that can be legally typed at @@ -519,7 +519,7 @@ can be overridden by the local file. .. pdbcommand:: unalias name - Delete the specified alias. + Delete the specified alias *name*. .. pdbcommand:: ! statement @@ -535,7 +535,7 @@ can be overridden by the local file. .. pdbcommand:: run [args ...] restart [args ...] - Restart the debugged Python program. If an argument is supplied, it is split + Restart the debugged Python program. If *args* is supplied, it is split with :mod:`shlex` and the result is used as the new :data:`sys.argv`. History, breakpoints, actions and debugger options are preserved. :pdbcmd:`restart` is an alias for :pdbcmd:`run`. @@ -546,8 +546,8 @@ can be overridden by the local file. .. pdbcommand:: debug code - Enter a recursive debugger that steps through the code - argument (which is an arbitrary expression or statement to be + Enter a recursive debugger that steps through *code* + (which is an arbitrary expression or statement to be executed in the current environment). .. pdbcommand:: retval From webhook-mailer at python.org Sat Mar 25 19:35:07 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 25 Mar 2023 23:35:07 -0000 Subject: [Python-checkins] =?utf-8?q?=5B3=2E11=5D_gh-102281=3A_Fix_potent?= =?utf-8?q?ial_nullptr_dereference_+_use_of_uninitia=E2=80=A6_=28=23103040?= =?utf-8?q?=29?= Message-ID: https://github.com/python/cpython/commit/b28f919007439b48a1d00d54134d7b020a683cda commit: b28f919007439b48a1d00d54134d7b020a683cda branch: 3.11 author: Max Bachmann committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-25T16:35:00-07:00 summary: [3.11] gh-102281: Fix potential nullptr dereference + use of uninitia? (#103040) [3.11] gh-102281: Fix potential nullptr dereference + use of uninitialized memory (gh-102282) (cherry picked from commit afa6092ee4260bacf7bc11905466e4c3f8556cbb) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst M Modules/getpath.c M Python/fileutils.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst new file mode 100644 index 000000000000..b0269dd3d92b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst @@ -0,0 +1 @@ +Fix potential nullptr dereference and use of uninitialized memory in fileutils. Patch by Max Bachmann. diff --git a/Modules/getpath.c b/Modules/getpath.c index ceacf36d8968..bc730fcd7dc7 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -452,7 +452,10 @@ getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args) if (s) { *s = L'\0'; } - path2 = _Py_normpath(_Py_join_relfile(path, resolved), -1); + path2 = _Py_join_relfile(path, resolved); + if (path2) { + path2 = _Py_normpath(path2, -1); + } PyMem_RawFree((void *)path); path = path2; } diff --git a/Python/fileutils.c b/Python/fileutils.c index 27924261f439..c86ed40b1993 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -2142,7 +2142,10 @@ _Py_join_relfile(const wchar_t *dirname, const wchar_t *relfile) } assert(wcslen(dirname) < MAXPATHLEN); assert(wcslen(relfile) < MAXPATHLEN - wcslen(dirname)); - join_relfile(filename, bufsize, dirname, relfile); + if (join_relfile(filename, bufsize, dirname, relfile) < 0) { + PyMem_RawFree(filename); + return NULL; + } return filename; } @@ -2180,6 +2183,7 @@ _Py_find_basename(const wchar_t *filename) wchar_t * _Py_normpath(wchar_t *path, Py_ssize_t size) { + assert(path != NULL); if (!path[0] || size == 0) { return path; } From webhook-mailer at python.org Sat Mar 25 19:38:30 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Sat, 25 Mar 2023 23:38:30 -0000 Subject: [Python-checkins] Fix typo in _swappedbytes_ in ctypes comment (#102773) Message-ID: https://github.com/python/cpython/commit/30a306c2ade6c2af3c0b1d988a17dae3916e0d27 commit: 30a306c2ade6c2af3c0b1d988a17dae3916e0d27 branch: main author: Matthias G?rgens committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-25T16:38:24-07:00 summary: Fix typo in _swappedbytes_ in ctypes comment (#102773) It's a minor typo, but it makes for a misleading comment. Let's fix it. files: M Lib/ctypes/_endian.py diff --git a/Lib/ctypes/_endian.py b/Lib/ctypes/_endian.py index 34dee64b1a65..b5446c049bc9 100644 --- a/Lib/ctypes/_endian.py +++ b/Lib/ctypes/_endian.py @@ -37,7 +37,7 @@ class _swapped_union_meta(_swapped_meta, type(Union)): pass ################################################################ # Note: The Structure metaclass checks for the *presence* (not the -# value!) of a _swapped_bytes_ attribute to determine the bit order in +# value!) of a _swappedbytes_ attribute to determine the bit order in # structures containing bit fields. if sys.byteorder == "little": From webhook-mailer at python.org Sun Mar 26 20:05:13 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Mon, 27 Mar 2023 00:05:13 -0000 Subject: [Python-checkins] =?utf-8?q?gh-102941=3A_Fix_=22=E2=80=98subobj?= =?utf-8?q?=E2=80=99_may_be_used_uninitialized_in_this_function=22_warning?= =?utf-8?b?IGluIGBieXRlc19tZXRob2RzLmNgICgjMTAyOTQyKQ==?= Message-ID: https://github.com/python/cpython/commit/2cdc5189a6bc3157fddd814662bde99ecfd77529 commit: 2cdc5189a6bc3157fddd814662bde99ecfd77529 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2023-03-26T17:05:06-07:00 summary: gh-102941: Fix "?subobj? may be used uninitialized in this function" warning in `bytes_methods.c` (#102942) files: M Objects/bytes_methods.c diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c index 6b8166385d37..ef9e65e566ec 100644 --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -774,7 +774,7 @@ _Py_bytes_tailmatch(const char *str, Py_ssize_t len, { Py_ssize_t start = 0; Py_ssize_t end = PY_SSIZE_T_MAX; - PyObject *subobj; + PyObject *subobj = NULL; int result; if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end)) From webhook-mailer at python.org Mon Mar 27 10:15:06 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 27 Mar 2023 14:15:06 -0000 Subject: [Python-checkins] [3.11] GH-95494: Fix transport EOF handling in OpenSSL 3.0 (GH-95495) (#103006) Message-ID: https://github.com/python/cpython/commit/13df5d3497e6148b2b42bed7b5593144f8f6216c commit: 13df5d3497e6148b2b42bed7b5593144f8f6216c branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2023-03-27T16:14:01+02:00 summary: [3.11] GH-95494: Fix transport EOF handling in OpenSSL 3.0 (GH-95495) (#103006) GH-25309 enabled SSL_OP_IGNORE_UNEXPECTED_EOF by default, with a comment that it restores OpenSSL 1.1.1 behavior, but this wasn't quite right. That option causes OpenSSL to treat transport EOF as the same as close_notify (i.e. SSL_ERROR_ZERO_RETURN), whereas Python actually has distinct SSLEOFError and SSLZeroReturnError exceptions. (The latter is usually mapped to a zero return from read.) In OpenSSL 1.1.1, the ssl module would raise them for transport EOF and close_notify, respectively. In OpenSSL 3.0, both act like close_notify. Fix this by, instead, just detecting SSL_R_UNEXPECTED_EOF_WHILE_READING and mapping that to the other exception type. There doesn't seem to have been any unit test of this error, so fill in the missing one. This had to be done with the BIO path because it's actually slightly tricky to simulate a transport EOF with Python's fd based APIs. (If you instruct the server to close the socket, it gets confused, probably because the server's SSL object is still referencing the now dead fd?) (cherry picked from commit 420bbb783b43216cc897dc8914851899db37a31d) Co-authored-by: David Benjamin files: A Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst M Lib/test/test_ssl.py M Modules/_ssl.c diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 5c6ddf12ec35..85a561f6b749 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -154,7 +154,6 @@ def data_file(*name): OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0) OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0) -OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0) # Ubuntu has patched OpenSSL and changed behavior of security level 2 # see https://bugs.python.org/issue41561#msg389003 @@ -1200,8 +1199,7 @@ def test_options(self): # SSLContext also enables these by default default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE | OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE | - OP_ENABLE_MIDDLEBOX_COMPAT | - OP_IGNORE_UNEXPECTED_EOF) + OP_ENABLE_MIDDLEBOX_COMPAT) self.assertEqual(default, ctx.options) with warnings_helper.check_warnings(): ctx.options |= ssl.OP_NO_TLSv1 @@ -2362,6 +2360,20 @@ def test_bio_read_write_data(self): self.assertEqual(buf, b'foo\n') self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap) + def test_transport_eof(self): + client_context, server_context, hostname = testing_context() + with socket.socket(socket.AF_INET) as sock: + sock.connect(self.server_addr) + incoming = ssl.MemoryBIO() + outgoing = ssl.MemoryBIO() + sslobj = client_context.wrap_bio(incoming, outgoing, + server_hostname=hostname) + self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) + + # Simulate EOF from the transport. + incoming.write_eof() + self.assertRaises(ssl.SSLEOFError, sslobj.read) + @support.requires_resource('network') class NetworkedTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst new file mode 100644 index 000000000000..d0f4ccbdd3e3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst @@ -0,0 +1,7 @@ +When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it +reported unauthenticated EOFs (i.e. without close_notify) as a clean TLS-level +EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior in previous +versions of OpenSSL. The :attr:`~ssl.SSLContext.options` attribute on +:class:`~ssl.SSLContext` also no longer includes +:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to +specify the previous OpenSSL 3.0 behavior. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 79f78007b68d..61490783e9ba 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -665,6 +665,16 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) ERR_GET_REASON(e) == SSL_R_CERTIFICATE_VERIFY_FAILED) { type = state->PySSLCertVerificationErrorObject; } +#if defined(SSL_R_UNEXPECTED_EOF_WHILE_READING) + /* OpenSSL 3.0 changed transport EOF from SSL_ERROR_SYSCALL with + * zero return value to SSL_ERROR_SSL with a special error code. */ + if (ERR_GET_LIB(e) == ERR_LIB_SSL && + ERR_GET_REASON(e) == SSL_R_UNEXPECTED_EOF_WHILE_READING) { + p = PY_SSL_ERROR_EOF; + type = state->PySSLEOFErrorObject; + errstr = "EOF occurred in violation of protocol"; + } +#endif break; } default: @@ -3133,10 +3143,6 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) #endif #ifdef SSL_OP_SINGLE_ECDH_USE options |= SSL_OP_SINGLE_ECDH_USE; -#endif -#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF - /* Make OpenSSL 3.0.0 behave like 1.1.1 */ - options |= SSL_OP_IGNORE_UNEXPECTED_EOF; #endif SSL_CTX_set_options(self->ctx, options); From webhook-mailer at python.org Mon Mar 27 10:15:33 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 27 Mar 2023 14:15:33 -0000 Subject: [Python-checkins] [3.10] GH-95494: Fix transport EOF handling in OpenSSL 3.0 (GH-95495) (#103007) Message-ID: https://github.com/python/cpython/commit/b5bf6c1b2275bfa93e77989bec0711c3e97932a6 commit: b5bf6c1b2275bfa93e77989bec0711c3e97932a6 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2023-03-27T16:14:24+02:00 summary: [3.10] GH-95494: Fix transport EOF handling in OpenSSL 3.0 (GH-95495) (#103007) GH-25309 enabled SSL_OP_IGNORE_UNEXPECTED_EOF by default, with a comment that it restores OpenSSL 1.1.1 behavior, but this wasn't quite right. That option causes OpenSSL to treat transport EOF as the same as close_notify (i.e. SSL_ERROR_ZERO_RETURN), whereas Python actually has distinct SSLEOFError and SSLZeroReturnError exceptions. (The latter is usually mapped to a zero return from read.) In OpenSSL 1.1.1, the ssl module would raise them for transport EOF and close_notify, respectively. In OpenSSL 3.0, both act like close_notify. Fix this by, instead, just detecting SSL_R_UNEXPECTED_EOF_WHILE_READING and mapping that to the other exception type. There doesn't seem to have been any unit test of this error, so fill in the missing one. This had to be done with the BIO path because it's actually slightly tricky to simulate a transport EOF with Python's fd based APIs. (If you instruct the server to close the socket, it gets confused, probably because the server's SSL object is still referencing the now dead fd?) (cherry picked from commit 420bbb783b43216cc897dc8914851899db37a31d) Co-authored-by: David Benjamin files: A Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst M Lib/test/test_ssl.py M Modules/_ssl.c diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index addfb6ce43d8..c28a574f8e05 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -155,7 +155,6 @@ def data_file(*name): OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0) OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0) -OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0) # Ubuntu has patched OpenSSL and changed behavior of security level 2 # see https://bugs.python.org/issue41561#msg389003 @@ -1199,8 +1198,7 @@ def test_options(self): # SSLContext also enables these by default default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE | OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE | - OP_ENABLE_MIDDLEBOX_COMPAT | - OP_IGNORE_UNEXPECTED_EOF) + OP_ENABLE_MIDDLEBOX_COMPAT) self.assertEqual(default, ctx.options) with warnings_helper.check_warnings(): ctx.options |= ssl.OP_NO_TLSv1 @@ -2362,6 +2360,20 @@ def test_bio_read_write_data(self): self.assertEqual(buf, b'foo\n') self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap) + def test_transport_eof(self): + client_context, server_context, hostname = testing_context() + with socket.socket(socket.AF_INET) as sock: + sock.connect(self.server_addr) + incoming = ssl.MemoryBIO() + outgoing = ssl.MemoryBIO() + sslobj = client_context.wrap_bio(incoming, outgoing, + server_hostname=hostname) + self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) + + # Simulate EOF from the transport. + incoming.write_eof() + self.assertRaises(ssl.SSLEOFError, sslobj.read) + @support.requires_resource('network') class NetworkedTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst new file mode 100644 index 000000000000..d0f4ccbdd3e3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst @@ -0,0 +1,7 @@ +When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it +reported unauthenticated EOFs (i.e. without close_notify) as a clean TLS-level +EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior in previous +versions of OpenSSL. The :attr:`~ssl.SSLContext.options` attribute on +:class:`~ssl.SSLContext` also no longer includes +:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to +specify the previous OpenSSL 3.0 behavior. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 360eb864ad36..7a28f2d37f6c 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -671,6 +671,16 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) ERR_GET_REASON(e) == SSL_R_CERTIFICATE_VERIFY_FAILED) { type = state->PySSLCertVerificationErrorObject; } +#if defined(SSL_R_UNEXPECTED_EOF_WHILE_READING) + /* OpenSSL 3.0 changed transport EOF from SSL_ERROR_SYSCALL with + * zero return value to SSL_ERROR_SSL with a special error code. */ + if (ERR_GET_LIB(e) == ERR_LIB_SSL && + ERR_GET_REASON(e) == SSL_R_UNEXPECTED_EOF_WHILE_READING) { + p = PY_SSL_ERROR_EOF; + type = state->PySSLEOFErrorObject; + errstr = "EOF occurred in violation of protocol"; + } +#endif break; } default: @@ -3133,10 +3143,6 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) #endif #ifdef SSL_OP_SINGLE_ECDH_USE options |= SSL_OP_SINGLE_ECDH_USE; -#endif -#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF - /* Make OpenSSL 3.0.0 behave like 1.1.1 */ - options |= SSL_OP_IGNORE_UNEXPECTED_EOF; #endif SSL_CTX_set_options(self->ctx, options); From webhook-mailer at python.org Mon Mar 27 16:37:32 2023 From: webhook-mailer at python.org (ambv) Date: Mon, 27 Mar 2023 20:37:32 -0000 Subject: [Python-checkins] gh-103023: Add SyntaxError check in pdb's `display` command (#103024) Message-ID: https://github.com/python/cpython/commit/36067532467ec58c87ac9c140e555e1866431981 commit: 36067532467ec58c87ac9c140e555e1866431981 branch: main author: gaogaotiantian committer: ambv date: 2023-03-27T22:37:22+02:00 summary: gh-103023: Add SyntaxError check in pdb's `display` command (#103024) Co-authored-by: ?ukasz Langa files: A Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index 3543f53282db..d402de1192f9 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -399,7 +399,7 @@ def preloop(self): displaying = self.displaying.get(self.curframe) if displaying: for expr, oldvalue in displaying.items(): - newvalue = self._getval_except(expr) + newvalue, _ = self._getval_except(expr) # check for identity first; this prevents custom __eq__ to # be called at every loop, and also prevents instances whose # fields are changed to be displayed @@ -1246,13 +1246,12 @@ def _getval(self, arg): def _getval_except(self, arg, frame=None): try: if frame is None: - return eval(arg, self.curframe.f_globals, self.curframe_locals) + return eval(arg, self.curframe.f_globals, self.curframe_locals), None else: - return eval(arg, frame.f_globals, frame.f_locals) - except: - exc_info = sys.exc_info()[:2] - err = traceback.format_exception_only(*exc_info)[-1].strip() - return _rstr('** raised %s **' % err) + return eval(arg, frame.f_globals, frame.f_locals), None + except BaseException as exc: + err = traceback.format_exception_only(exc)[-1].strip() + return _rstr('** raised %s **' % err), exc def _error_exc(self): exc_info = sys.exc_info()[:2] @@ -1437,13 +1436,19 @@ def do_display(self, arg): Without expression, list all display expressions for the current frame. """ if not arg: - self.message('Currently displaying:') - for item in self.displaying.get(self.curframe, {}).items(): - self.message('%s: %r' % item) + if self.displaying: + self.message('Currently displaying:') + for item in self.displaying.get(self.curframe, {}).items(): + self.message('%s: %r' % item) + else: + self.message('No expression is being displayed') else: - val = self._getval_except(arg) - self.displaying.setdefault(self.curframe, {})[arg] = val - self.message('display %s: %r' % (arg, val)) + val, exc = self._getval_except(arg) + if isinstance(exc, SyntaxError): + self.message('Unable to display %s: %r' % (arg, val)) + else: + self.displaying.setdefault(self.curframe, {})[arg] = val + self.message('display %s: %r' % (arg, val)) complete_display = _complete_expression diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index e96dc7fa1cf6..ae9c5d73e2da 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -586,6 +586,8 @@ def test_pdb_display_command(): ... a = 4 >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'display +', + ... 'display', ... 'display a', ... 'n', ... 'display', @@ -600,6 +602,10 @@ def test_pdb_display_command(): ... test_function() > (4)test_function() -> a = 1 + (Pdb) display + + Unable to display +: ** raised SyntaxError: invalid syntax ** + (Pdb) display + No expression is being displayed (Pdb) display a display a: 0 (Pdb) n diff --git a/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst b/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst new file mode 100644 index 000000000000..e7958f6f0020 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst @@ -0,0 +1,2 @@ +It's no longer possible to register expressions to display in +:class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. From webhook-mailer at python.org Mon Mar 27 18:22:14 2023 From: webhook-mailer at python.org (iritkatriel) Date: Mon, 27 Mar 2023 22:22:14 -0000 Subject: [Python-checkins] gh-103046: Display current line correctly for `dis.disco()` with CACHE entries (#103047) Message-ID: https://github.com/python/cpython/commit/34eb6f727632d9a1a6998f90c9421e420c785643 commit: 34eb6f727632d9a1a6998f90c9421e420c785643 branch: main author: gaogaotiantian committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-27T23:22:06+01:00 summary: gh-103046: Display current line correctly for `dis.disco()` with CACHE entries (#103047) files: A Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst M Lib/dis.py M Lib/test/test_dis.py diff --git a/Lib/dis.py b/Lib/dis.py index c3d152b4de04..b39b28353301 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -581,7 +581,12 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None, instr.offset > 0) if new_source_line: print(file=file) - is_current_instr = instr.offset == lasti + if show_caches: + is_current_instr = instr.offset == lasti + else: + # Each CACHE takes 2 bytes + is_current_instr = instr.offset <= lasti \ + <= instr.offset + 2 * _inline_cache_entries[_deoptop(instr.opcode)] print(instr._disassemble(lineno_width, is_current_instr, offset_width), file=file) if exception_entries: diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index ed66b362b080..7cad8d1bfe13 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1198,6 +1198,35 @@ def test_show_caches(self): self.assertEqual(caches.count(""), empty_caches) self.assertEqual(len(caches), total_caches) + @cpython_only + def test_show_currinstr_with_cache(self): + """ + Make sure that with lasti pointing to CACHE, it still shows the current + line correctly + """ + def f(): + print(a) + # The code above should generate a LOAD_GLOBAL which has CACHE instr after + # However, this might change in the future. So we explicitly try to find + # a CACHE entry in the instructions. If we can't do that, fail the test + + for inst in dis.get_instructions(f, show_caches=True): + if inst.opname == "CACHE": + op_offset = inst.offset - 2 + cache_offset = inst.offset + break + else: + self.fail("Can't find a CACHE entry in the function provided to do the test") + + assem_op = self.get_disassembly(f.__code__, lasti=op_offset, wrapper=False) + assem_cache = self.get_disassembly(f.__code__, lasti=cache_offset, wrapper=False) + + # Make sure --> exists and points to the correct offset + self.assertRegex(assem_op, fr"-->\s+{op_offset}") + # Make sure when lasti points to cache, it shows the same disassembly + self.assertEqual(assem_op, assem_cache) + + class DisWithFileTests(DisTests): # Run the tests again, using the file arg instead of print diff --git a/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst b/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst new file mode 100644 index 000000000000..f9bd0a10056e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst @@ -0,0 +1 @@ +Display current line label correctly in :mod:`dis` when ``show_caches`` is False and ``lasti`` points to a CACHE entry. From webhook-mailer at python.org Mon Mar 27 18:53:13 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Mon, 27 Mar 2023 22:53:13 -0000 Subject: [Python-checkins] gh-100227: Revert gh-102925 "gh-100227: Make the Global Interned Dict Safe for Isolated Interpreters" (gh-103063) Message-ID: https://github.com/python/cpython/commit/89e67ada6958cfd8d4eec221848f81b2619de099 commit: 89e67ada6958cfd8d4eec221848f81b2619de099 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-27T16:53:05-06:00 summary: gh-100227: Revert gh-102925 "gh-100227: Make the Global Interned Dict Safe for Isolated Interpreters" (gh-103063) This reverts commit 87be8d9. This approach to keeping the interned strings safe is turning out to be too complex for my taste (due to obmalloc isolation). For now I'm going with the simpler solution, making the dict per-interpreter. We can revisit that later if we want a sharing solution. files: M Include/internal/pycore_global_objects.h M Include/internal/pycore_pystate.h M Include/internal/pycore_runtime_init.h M Include/internal/pycore_unicodeobject.h M Objects/unicodeobject.c M Python/pylifecycle.c M Python/pystate.c diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 858321d67df4..9957da1fc5f2 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -28,10 +28,6 @@ extern "C" { struct _Py_cached_objects { PyObject *interned_strings; - /* A thread state tied to the main interpreter, - used exclusively for when a global object (e.g. interned strings) - is resized (i.e. deallocated + allocated) from an arbitrary thread. */ - PyThreadState main_tstate; }; #define _Py_GLOBAL_OBJECT(NAME) \ diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index f159b516e66b..7046ec8d9ada 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -127,11 +127,6 @@ PyAPI_FUNC(void) _PyThreadState_Init( PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); -extern void _PyThreadState_InitDetached(PyThreadState *, PyInterpreterState *); -extern void _PyThreadState_ClearDetached(PyThreadState *); - -extern PyObject * _Py_AddToGlobalDict(PyObject *, PyObject *, PyObject *); - static inline void _PyThreadState_UpdateTracingState(PyThreadState *tstate) diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index fd358b2da6cc..7cfa7c0c0249 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -59,9 +59,6 @@ extern PyTypeObject _PyExc_MemoryError; .types = { \ .next_version_tag = 1, \ }, \ - .cached_objects = { \ - .main_tstate = _PyThreadState_INIT, \ - }, \ .static_objects = { \ .singletons = { \ .small_ints = _Py_small_ints_INIT, \ diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index ed4feb603d6f..19faceebf1d8 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -34,7 +34,6 @@ struct _Py_unicode_runtime_ids { struct _Py_unicode_runtime_state { struct _Py_unicode_runtime_ids ids; - /* The interned dict is at _PyRuntime.cached_objects.interned_strings. */ }; /* fs_codec.encoding is initialized to NULL. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 891a65576ee2..b9fb53147b9b 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14609,11 +14609,16 @@ PyUnicode_InternInPlace(PyObject **p) } PyObject *interned = get_interned_dict(); - PyObject *t = _Py_AddToGlobalDict(interned, s, s); + assert(interned != NULL); + + PyObject *t = PyDict_SetDefault(interned, s, s); + if (t == NULL) { + PyErr_Clear(); + return; + } + if (t != s) { - if (t != NULL) { - Py_SETREF(*p, Py_NewRef(t)); - } + Py_SETREF(*p, Py_NewRef(t)); return; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5d7f86218330..8110d94ba175 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -636,8 +636,6 @@ pycore_create_interpreter(_PyRuntimeState *runtime, return status; } - _PyThreadState_InitDetached(&runtime->cached_objects.main_tstate, interp); - *tstate_p = tstate; return _PyStatus_OK(); } @@ -1934,8 +1932,6 @@ Py_FinalizeEx(void) // XXX Do this sooner during finalization. // XXX Ensure finalizer errors are handled properly. - _PyThreadState_ClearDetached(&runtime->cached_objects.main_tstate); - finalize_interp_clear(tstate); finalize_interp_delete(tstate->interp); diff --git a/Python/pystate.c b/Python/pystate.c index 394b12d24065..b17efdbefd12 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -565,124 +565,6 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) #endif -//--------------- -// global objects -//--------------- - -/* The global objects thread state is meant to be used in a very limited - way and should not be used to actually run any Python code. */ - -static PyThreadState * -bind_global_objects_state(_PyRuntimeState *runtime) -{ - PyThreadState *main_tstate = &runtime->cached_objects.main_tstate; - - bind_tstate(main_tstate); - /* Unlike _PyThreadState_Bind(), we do not modify gilstate TSS. */ - - return main_tstate; -} - -static void -unbind_global_objects_state(_PyRuntimeState *runtime) -{ - PyThreadState *main_tstate = &runtime->cached_objects.main_tstate; - assert(tstate_is_alive(main_tstate)); - assert(!main_tstate->_status.active); - assert(gilstate_tss_get(runtime) != main_tstate); - - unbind_tstate(main_tstate); - - /* This thread state may be bound/unbound repeatedly, - so we must erase evidence that it was ever bound (or unbound). */ - main_tstate->_status.bound = 0; - main_tstate->_status.unbound = 0; - - /* We must fully unlink the thread state from any OS thread, - to allow it to be bound more than once. */ - main_tstate->thread_id = 0; -#ifdef PY_HAVE_THREAD_NATIVE_ID - main_tstate->native_thread_id = 0; -#endif -} - -static inline void -acquire_global_objects_lock(_PyRuntimeState *runtime) -{ - /* For now we can rely on the GIL, so we don't actually - acquire a global lock here. */ - assert(current_fast_get(runtime) != NULL); -} - -static inline void -release_global_objects_lock(_PyRuntimeState *runtime) -{ - /* For now we can rely on the GIL, so we don't actually - release a global lock here. */ - assert(current_fast_get(runtime) != NULL); -} - -PyObject * -_Py_AddToGlobalDict(PyObject *dict, PyObject *key, PyObject *value) -{ - assert(dict != NULL); - assert(PyDict_CheckExact(dict)); - - /* All global objects are stored in _PyRuntime - and owned by the main interpreter. */ - _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *curts = current_fast_get(runtime); - PyInterpreterState *interp = curts->interp; - assert(interp != NULL); // The GIL must be held. - - /* Due to interpreter isolation we must hold a global lock, - starting at this point and ending before we return. - Note that the operations in this function are very fucused - and we should not expect any reentrancy. */ - acquire_global_objects_lock(runtime); - - /* Swap to the main interpreter, if necessary. */ - PyThreadState *oldts = NULL; - if (!_Py_IsMainInterpreter(interp)) { - PyThreadState *main_tstate = bind_global_objects_state(runtime); - - oldts = _PyThreadState_Swap(runtime, main_tstate); - assert(oldts != NULL); - assert(!_Py_IsMainInterpreter(oldts->interp)); - - /* The limitations of the global objects thread state apply - from this point to the point we swap back to oldts. */ - } - - /* This might trigger a resize, which is why we must "acquire" - the global object state. Also note that PyDict_SetDefault() - must be compatible with our reentrancy and global objects state - constraints. */ - PyObject *actual = PyDict_SetDefault(dict, key, value); - if (actual == NULL) { - /* Raising an exception from one interpreter in another - is problematic, so we clear it and let the caller deal - with the returned NULL. */ - assert(PyErr_ExceptionMatches(PyExc_MemoryError)); - PyErr_Clear(); - } - - /* Swap back, it it wasn't in the main interpreter already. */ - if (oldts != NULL) { - // The returned tstate should be _PyRuntime.cached_objects.main_tstate. - _PyThreadState_Swap(runtime, oldts); - - unbind_global_objects_state(runtime); - } - - release_global_objects_lock(runtime); - - // XXX Immortalize the key and value. - - return actual; -} - - /*************************************/ /* the per-interpreter runtime state */ /*************************************/ @@ -1335,7 +1217,8 @@ free_threadstate(PyThreadState *tstate) static void init_threadstate(PyThreadState *tstate, - PyInterpreterState *interp, uint64_t id) + PyInterpreterState *interp, uint64_t id, + PyThreadState *next) { if (tstate->_status.initialized) { Py_FatalError("thread state already initialized"); @@ -1344,13 +1227,18 @@ init_threadstate(PyThreadState *tstate, assert(interp != NULL); tstate->interp = interp; - // next/prev are set in add_threadstate(). - assert(tstate->next == NULL); - assert(tstate->prev == NULL); - assert(id > 0); tstate->id = id; + assert(interp->threads.head == tstate); + assert((next != NULL && id != 1) || (next == NULL && id == 1)); + if (next != NULL) { + assert(next->prev == NULL || next->prev == tstate); + next->prev = tstate; + } + tstate->next = next; + assert(tstate->prev == NULL); + // thread_id and native_thread_id are set in bind_tstate(). tstate->py_recursion_limit = interp->ceval.recursion_limit, @@ -1371,22 +1259,6 @@ init_threadstate(PyThreadState *tstate, tstate->_status.initialized = 1; } -static void -add_threadstate(PyInterpreterState *interp, PyThreadState *tstate, - PyThreadState *next) -{ - assert(interp->threads.head != tstate); - assert((next != NULL && tstate->id != 1) || - (next == NULL && tstate->id == 1)); - if (next != NULL) { - assert(next->prev == NULL || next->prev == tstate); - next->prev = tstate; - } - tstate->next = next; - assert(tstate->prev == NULL); - interp->threads.head = tstate; -} - static PyThreadState * new_threadstate(PyInterpreterState *interp) { @@ -1426,9 +1298,9 @@ new_threadstate(PyInterpreterState *interp) &initial._main_interpreter._initial_thread, sizeof(*tstate)); } + interp->threads.head = tstate; - init_threadstate(tstate, interp, id); - add_threadstate(interp, tstate, old_head); + init_threadstate(tstate, interp, id, old_head); HEAD_UNLOCK(runtime); if (!used_newtstate) { @@ -1475,33 +1347,6 @@ _PyThreadState_Init(PyThreadState *tstate) Py_FatalError("_PyThreadState_Init() is for internal use only"); } -void -_PyThreadState_InitDetached(PyThreadState *tstate, PyInterpreterState *interp) -{ - _PyRuntimeState *runtime = interp->runtime; - - HEAD_LOCK(runtime); - interp->threads.next_unique_id += 1; - uint64_t id = interp->threads.next_unique_id; - HEAD_UNLOCK(runtime); - - init_threadstate(tstate, interp, id); - // We do not call add_threadstate(). -} - - -static void -clear_datastack(PyThreadState *tstate) -{ - _PyStackChunk *chunk = tstate->datastack_chunk; - tstate->datastack_chunk = NULL; - while (chunk != NULL) { - _PyStackChunk *prev = chunk->previous; - _PyObject_VirtualFree(chunk, chunk->size); - chunk = prev; - } -} - void PyThreadState_Clear(PyThreadState *tstate) { @@ -1576,6 +1421,7 @@ PyThreadState_Clear(PyThreadState *tstate) // XXX Do it as early in the function as possible. } + /* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */ static void tstate_delete_common(PyThreadState *tstate) @@ -1608,25 +1454,17 @@ tstate_delete_common(PyThreadState *tstate) unbind_tstate(tstate); // XXX Move to PyThreadState_Clear()? - clear_datastack(tstate); + _PyStackChunk *chunk = tstate->datastack_chunk; + tstate->datastack_chunk = NULL; + while (chunk != NULL) { + _PyStackChunk *prev = chunk->previous; + _PyObject_VirtualFree(chunk, chunk->size); + chunk = prev; + } tstate->_status.finalized = 1; } -void -_PyThreadState_ClearDetached(PyThreadState *tstate) -{ - assert(!tstate->_status.bound); - assert(!tstate->_status.bound_gilstate); - assert(tstate->datastack_chunk == NULL); - assert(tstate->thread_id == 0); - assert(tstate->native_thread_id == 0); - assert(tstate->next == NULL); - assert(tstate->prev == NULL); - - PyThreadState_Clear(tstate); - clear_datastack(tstate); -} static void zapthreads(PyInterpreterState *interp) From webhook-mailer at python.org Mon Mar 27 19:21:15 2023 From: webhook-mailer at python.org (ethanfurman) Date: Mon, 27 Mar 2023 23:21:15 -0000 Subject: [Python-checkins] gh-74468: [tarfile] Fix incorrect name attribute of ExFileObject (GH-102424) Message-ID: https://github.com/python/cpython/commit/56d055a0d81a809e4ff8e1d56756a3bf32317efb commit: 56d055a0d81a809e4ff8e1d56756a3bf32317efb branch: main author: Oleg Iarygin committer: ethanfurman date: 2023-03-27T16:21:07-07:00 summary: gh-74468: [tarfile] Fix incorrect name attribute of ExFileObject (GH-102424) Co-authored-by: Simeon Visser files: A Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst M Lib/tarfile.py M Lib/test/test_tarfile.py diff --git a/Lib/tarfile.py b/Lib/tarfile.py index d686435d90ad..b733195c9c56 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -601,12 +601,12 @@ class _FileInFile(object): object. """ - def __init__(self, fileobj, offset, size, blockinfo=None): + def __init__(self, fileobj, offset, size, name, blockinfo=None): self.fileobj = fileobj self.offset = offset self.size = size self.position = 0 - self.name = getattr(fileobj, "name", None) + self.name = name self.closed = False if blockinfo is None: @@ -703,7 +703,7 @@ class ExFileObject(io.BufferedReader): def __init__(self, tarfile, tarinfo): fileobj = _FileInFile(tarfile.fileobj, tarinfo.offset_data, - tarinfo.size, tarinfo.sparse) + tarinfo.size, tarinfo.name, tarinfo.sparse) super().__init__(fileobj) #class ExFileObject diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 75b60e9a50e7..39f6f499c818 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -479,6 +479,13 @@ def test_length_zero_header(self): with tarfile.open(support.findfile('recursion.tar')) as tar: pass + def test_extractfile_name(self): + # gh-74468: TarFile.name must name a file, not a parent archive. + file = self.tar.getmember('ustar/regtype') + with self.tar.extractfile(file) as fobj: + self.assertEqual(fobj.name, 'ustar/regtype') + + class MiscReadTestBase(CommonReadTest): def requires_name_attribute(self): pass diff --git a/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst b/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst new file mode 100644 index 000000000000..8fad551f3a4e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst @@ -0,0 +1,3 @@ +Attribute name of the extracted :mod:`tarfile` file object now holds +filename of itself rather than of the archive it is contained in. +Patch by Oleg Iarygin. From webhook-mailer at python.org Mon Mar 27 19:25:26 2023 From: webhook-mailer at python.org (ethanfurman) Date: Mon, 27 Mar 2023 23:25:26 -0000 Subject: [Python-checkins] gh-103056: [Enum] ensure final _generate_next_value_ is a staticmethod (GH-103062) Message-ID: https://github.com/python/cpython/commit/b838d80085b0162cc2ae7b4db5d2a9d9c6a28366 commit: b838d80085b0162cc2ae7b4db5d2a9d9c6a28366 branch: main author: Ethan Furman committer: ethanfurman date: 2023-03-27T16:25:19-07:00 summary: gh-103056: [Enum] ensure final _generate_next_value_ is a staticmethod (GH-103062) files: A Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index ba927662a43b..2624a084dc63 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -518,8 +518,13 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k # # adjust the sunders _order_ = classdict.pop('_order_', None) + _gnv = classdict.get('_generate_next_value_') + if _gnv is not None and type(_gnv) is not staticmethod: + _gnv = staticmethod(_gnv) # convert to normal dict classdict = dict(classdict.items()) + if _gnv is not None: + classdict['_generate_next_value_'] = _gnv # # data type of member and the controlling Enum class member_type, first_enum = metacls._get_mixins_(cls, bases) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index bb163c46481a..58c80e7d228b 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -270,6 +270,17 @@ class NewSubEnum(NewBaseEnum): first = auto() self.NewSubEnum = NewSubEnum # + class LazyGNV(self.enum_type): + def _generate_next_value_(name, start, last, values): + pass + self.LazyGNV = LazyGNV + # + class BusyGNV(self.enum_type): + @staticmethod + def _generate_next_value_(name, start, last, values): + pass + self.BusyGNV = BusyGNV + # self.is_flag = False self.names = ['first', 'second', 'third'] if issubclass(MainEnum, StrEnum): @@ -466,6 +477,12 @@ def test_enum_in_enum_out(self): Main = self.MainEnum self.assertIs(Main(Main.first), Main.first) + def test_gnv_is_static(self): + lazy = self.LazyGNV + busy = self.BusyGNV + self.assertTrue(type(lazy.__dict__['_generate_next_value_']) is staticmethod) + self.assertTrue(type(busy.__dict__['_generate_next_value_']) is staticmethod) + def test_hash(self): MainEnum = self.MainEnum mapping = {} diff --git a/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst b/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst new file mode 100644 index 000000000000..c892d8376503 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst @@ -0,0 +1 @@ +Ensure final ``_generate_next_value_`` is a ``staticmethod``. From webhook-mailer at python.org Mon Mar 27 19:26:23 2023 From: webhook-mailer at python.org (ethanfurman) Date: Mon, 27 Mar 2023 23:26:23 -0000 Subject: [Python-checkins] gh-102558: [Enum] better handling of non-Enum EnumType classes (GH-103060) Message-ID: https://github.com/python/cpython/commit/f4ed2c6ae5915329e49b9f94033ef182400e29fa commit: f4ed2c6ae5915329e49b9f94033ef182400e29fa branch: main author: Ethan Furman committer: ethanfurman date: 2023-03-27T16:26:16-07:00 summary: gh-102558: [Enum] better handling of non-Enum EnumType classes (GH-103060) files: M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index 2624a084dc63..8c77117ce6ac 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -928,7 +928,7 @@ def _convert_(cls, name, module, filter, source=None, *, boundary=None, as_globa def _check_for_existing_members_(mcls, class_name, bases): for chain in bases: for base in chain.__mro__: - if issubclass(base, Enum) and base._member_names_: + if isinstance(base, EnumType) and base._member_names_: raise TypeError( " cannot extend %r" % (class_name, base) @@ -947,7 +947,7 @@ def _get_mixins_(mcls, class_name, bases): # ensure final parent class is an Enum derivative, find any concrete # data type, and check that Enum has no members first_enum = bases[-1] - if not issubclass(first_enum, Enum): + if not isinstance(first_enum, EnumType): raise TypeError("new enumerations should be created as " "`EnumName([mixin_type, ...] [data_type,] enum_type)`") member_type = mcls._find_data_type_(class_name, bases) or object @@ -959,7 +959,7 @@ def _find_data_repr_(mcls, class_name, bases): for base in chain.__mro__: if base is object: continue - elif issubclass(base, Enum): + elif isinstance(base, EnumType): # if we hit an Enum, use it's _value_repr_ return base._value_repr_ elif '__repr__' in base.__dict__: @@ -985,12 +985,12 @@ def _find_data_type_(mcls, class_name, bases): base_chain.add(base) if base is object: continue - elif issubclass(base, Enum): + elif isinstance(base, EnumType): if base._member_type_ is not object: data_types.add(base._member_type_) break elif '__new__' in base.__dict__ or '__init__' in base.__dict__: - if issubclass(base, Enum): + if isinstance(base, EnumType): continue data_types.add(candidate or base) break @@ -1191,8 +1191,6 @@ def _missing_(cls, value): return None def __repr__(self): - if not isinstance(self, Enum): - return repr(self) v_repr = self.__class__._value_repr_ or repr return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_)) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 58c80e7d228b..bea19542705d 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -1386,7 +1386,6 @@ def repr(self): class Huh(MyStr, MyInt, Enum): One = 1 - def test_pickle_enum(self): if isinstance(Stooges, Exception): raise Stooges From webhook-mailer at python.org Mon Mar 27 19:49:22 2023 From: webhook-mailer at python.org (miss-islington) Date: Mon, 27 Mar 2023 23:49:22 -0000 Subject: [Python-checkins] gh-102558: [Enum] better handling of non-Enum EnumType classes (GH-103060) Message-ID: https://github.com/python/cpython/commit/5ba5ce47f6770677d2e126b5360107ad34488210 commit: 5ba5ce47f6770677d2e126b5360107ad34488210 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-27T16:49:15-07:00 summary: gh-102558: [Enum] better handling of non-Enum EnumType classes (GH-103060) (cherry picked from commit f4ed2c6ae5915329e49b9f94033ef182400e29fa) Co-authored-by: Ethan Furman files: M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index ea55f7bbef86..76575500e424 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -936,7 +936,7 @@ def _convert_(cls, name, module, filter, source=None, *, boundary=None, as_globa def _check_for_existing_members_(mcls, class_name, bases): for chain in bases: for base in chain.__mro__: - if issubclass(base, Enum) and base._member_names_: + if isinstance(base, EnumType) and base._member_names_: raise TypeError( " cannot extend %r" % (class_name, base) @@ -958,7 +958,7 @@ def _get_mixins_(mcls, class_name, bases): # ensure final parent class is an Enum derivative, find any concrete # data type, and check that Enum has no members first_enum = bases[-1] - if not issubclass(first_enum, Enum): + if not isinstance(first_enum, EnumType): raise TypeError("new enumerations should be created as " "`EnumName([mixin_type, ...] [data_type,] enum_type)`") member_type = mcls._find_data_type_(class_name, bases) or object @@ -970,7 +970,7 @@ def _find_data_repr_(mcls, class_name, bases): for base in chain.__mro__: if base is object: continue - elif issubclass(base, Enum): + elif isinstance(base, EnumType): # if we hit an Enum, use it's _value_repr_ return base._value_repr_ elif '__repr__' in base.__dict__: @@ -988,12 +988,12 @@ def _find_data_type_(mcls, class_name, bases): base_chain.add(base) if base is object: continue - elif issubclass(base, Enum): + elif isinstance(base, EnumType): if base._member_type_ is not object: data_types.add(base._member_type_) break elif '__new__' in base.__dict__ or '__init__' in base.__dict__: - if issubclass(base, Enum): + if isinstance(base, EnumType): continue data_types.add(candidate or base) break @@ -1187,8 +1187,6 @@ def _missing_(cls, value): return None def __repr__(self): - if not isinstance(self, Enum): - return repr(self) v_repr = self.__class__._value_repr_ or repr return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_)) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 2a305e415cd9..e9dae29d2687 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -1321,7 +1321,6 @@ def repr(self): class Huh(MyStr, MyInt, Enum): One = 1 - def test_pickle_enum(self): if isinstance(Stooges, Exception): raise Stooges From webhook-mailer at python.org Tue Mar 28 04:52:41 2023 From: webhook-mailer at python.org (ambv) Date: Tue, 28 Mar 2023 08:52:41 -0000 Subject: [Python-checkins] GH-102711: Fix warnings found by clang (#102712) Message-ID: https://github.com/python/cpython/commit/7703def37e4fa7d25c3d23756de8f527daa4e165 commit: 7703def37e4fa7d25c3d23756de8f527daa4e165 branch: main author: Chenxi Mao committer: ambv date: 2023-03-28T10:52:22+02:00 summary: GH-102711: Fix warnings found by clang (#102712) There are some warnings if build python via clang: Parser/pegen.c:812:31: warning: a function declaration without a prototype is deprecated in all versions of C [-Wstrict-prototypes] _PyPegen_clear_memo_statistics() ^ void Parser/pegen.c:820:29: warning: a function declaration without a prototype is deprecated in all versions of C [-Wstrict-prototypes] _PyPegen_get_memo_statistics() ^ void Fix it to make clang happy. Signed-off-by: Chenxi Mao files: A Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst M Parser/pegen.c diff --git a/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst b/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst new file mode 100644 index 000000000000..511843968777 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst @@ -0,0 +1 @@ +Fix ``-Wstrict-prototypes`` compiler warnings. diff --git a/Parser/pegen.c b/Parser/pegen.c index 94dd9de8a431..b79ae4cb1fb3 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -250,7 +250,7 @@ _PyPegen_fill_token(Parser *p) #define memo_statistics _PyRuntime.parser.memo_statistics void -_PyPegen_clear_memo_statistics() +_PyPegen_clear_memo_statistics(void) { for (int i = 0; i < NSTATISTICS; i++) { memo_statistics[i] = 0; @@ -258,7 +258,7 @@ _PyPegen_clear_memo_statistics() } PyObject * -_PyPegen_get_memo_statistics() +_PyPegen_get_memo_statistics(void) { PyObject *ret = PyList_New(NSTATISTICS); if (ret == NULL) { From webhook-mailer at python.org Tue Mar 28 04:53:04 2023 From: webhook-mailer at python.org (ambv) Date: Tue, 28 Mar 2023 08:53:04 -0000 Subject: [Python-checkins] [3.9] gh-101997: Update bundled pip version to 23.0.1 (GH-101998). (#102243) Message-ID: https://github.com/python/cpython/commit/b5a94301a281854d3c746bc0a0167a7d6aaf91f5 commit: b5a94301a281854d3c746bc0a0167a7d6aaf91f5 branch: 3.9 author: Pradyun Gedam committer: ambv date: 2023-03-28T10:52:56+02:00 summary: [3.9] gh-101997: Update bundled pip version to 23.0.1 (GH-101998). (#102243) (cherry picked from commit 89d9ff0f48c51a85920c7372a7df4a2204e32ea5) files: A Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl A Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst D Lib/ensurepip/_bundled/pip-22.0.4-py3-none-any.whl M Lib/ensurepip/__init__.py diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 981534c4a094..07065c3cb7da 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -12,7 +12,7 @@ __all__ = ["version", "bootstrap"] _SETUPTOOLS_VERSION = "58.1.0" -_PIP_VERSION = "22.0.4" +_PIP_VERSION = "23.0.1" _PROJECTS = [ ("setuptools", _SETUPTOOLS_VERSION, "py3"), ("pip", _PIP_VERSION, "py3"), diff --git a/Lib/ensurepip/_bundled/pip-22.0.4-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-22.0.4-py3-none-any.whl deleted file mode 100644 index 7ba048e24522..000000000000 Binary files a/Lib/ensurepip/_bundled/pip-22.0.4-py3-none-any.whl and /dev/null differ diff --git a/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl new file mode 100644 index 000000000000..a855dc40e863 Binary files /dev/null and b/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl differ diff --git a/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst b/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst new file mode 100644 index 000000000000..f9dfd46d1ed4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst @@ -0,0 +1 @@ +Upgrade pip wheel bundled with ensurepip (pip 23.0.1) From webhook-mailer at python.org Tue Mar 28 04:55:45 2023 From: webhook-mailer at python.org (ambv) Date: Tue, 28 Mar 2023 08:55:45 -0000 Subject: [Python-checkins] [3.9] GH-102126: fix deadlock at shutdown when clearing thread states (GH-102222) (#102236) Message-ID: https://github.com/python/cpython/commit/7cb3a4474731f52c74b19dd3c99ca06e227dae3b commit: 7cb3a4474731f52c74b19dd3c99ca06e227dae3b branch: 3.9 author: Kumar Aditya <59607654+kumaraditya303 at users.noreply.github.com> committer: ambv date: 2023-03-28T10:55:36+02:00 summary: [3.9] GH-102126: fix deadlock at shutdown when clearing thread states (GH-102222) (#102236) (cherry picked from commit 5f11478ce7fda826d399530af4c5ca96c592f144) files: A Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst M Python/pystate.c diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst new file mode 100644 index 000000000000..68c43688c3df --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-24-17-59-39.gh-issue-102126.HTT8Vc.rst @@ -0,0 +1 @@ +Fix deadlock at shutdown when clearing thread states if any finalizer tries to acquire the runtime head lock. Patch by Kumar Aditya. diff --git a/Python/pystate.c b/Python/pystate.c index c3520c336a79..1cf9be1eabb7 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -288,11 +288,19 @@ PyInterpreterState_Clear(PyInterpreterState *interp) _PyErr_Clear(tstate); } + // Clear the current/main thread state last. HEAD_LOCK(runtime); - for (PyThreadState *p = interp->tstate_head; p != NULL; p = p->next) { + PyThreadState *p = interp->tstate_head; + HEAD_UNLOCK(runtime); + while (p != NULL) { + // See https://github.com/python/cpython/issues/102126 + // Must be called without HEAD_LOCK held as it can deadlock + // if any finalizer tries to acquire that lock. PyThreadState_Clear(p); + HEAD_LOCK(runtime); + p = p->next; + HEAD_UNLOCK(runtime); } - HEAD_UNLOCK(runtime); Py_CLEAR(interp->audit_hooks); From webhook-mailer at python.org Tue Mar 28 04:55:59 2023 From: webhook-mailer at python.org (ambv) Date: Tue, 28 Mar 2023 08:55:59 -0000 Subject: [Python-checkins] [3.8] gh-101997: Update bundled pip version to 23.0.1 (GH-101998). (#102244) Message-ID: https://github.com/python/cpython/commit/3205d1fbbbfcf613b74d236be9db7a8225f452ea commit: 3205d1fbbbfcf613b74d236be9db7a8225f452ea branch: 3.8 author: Pradyun Gedam committer: ambv date: 2023-03-28T10:55:50+02:00 summary: [3.8] gh-101997: Update bundled pip version to 23.0.1 (GH-101998). (#102244) (cherry picked from commit 89d9ff0f48c51a85920c7372a7df4a2204e32ea5) files: A Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl A Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst M Lib/ensurepip/__init__.py diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 88ddc63128f5..3dfc2da945cd 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,7 +10,7 @@ __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('setuptools', 'pip') _SETUPTOOLS_VERSION = "56.0.0" -_PIP_VERSION = "22.0.4" +_PIP_VERSION = "23.0.1" _PROJECTS = [ ("setuptools", _SETUPTOOLS_VERSION, "py3"), ("pip", _PIP_VERSION, "py3"), diff --git a/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl new file mode 100644 index 000000000000..a855dc40e863 Binary files /dev/null and b/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl differ diff --git a/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst b/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst new file mode 100644 index 000000000000..f9dfd46d1ed4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst @@ -0,0 +1 @@ +Upgrade pip wheel bundled with ensurepip (pip 23.0.1) From webhook-mailer at python.org Tue Mar 28 04:58:05 2023 From: webhook-mailer at python.org (ambv) Date: Tue, 28 Mar 2023 08:58:05 -0000 Subject: [Python-checkins] [3.10] gh-101997: Update bundled pip version to 23.0.1 (GH-101998). (#102241) Message-ID: https://github.com/python/cpython/commit/3288923b7aac4b4e5021b955c6f0b445cb034e46 commit: 3288923b7aac4b4e5021b955c6f0b445cb034e46 branch: 3.10 author: Pradyun Gedam committer: ambv date: 2023-03-28T10:57:55+02:00 summary: [3.10] gh-101997: Update bundled pip version to 23.0.1 (GH-101998). (#102241) (cherry picked from commit 89d9ff0f48c51a85920c7372a7df4a2204e32ea5) files: A Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl A Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst D Lib/ensurepip/_bundled/pip-22.3.1-py3-none-any.whl M Lib/ensurepip/__init__.py diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 71d3dfd824f4..c62882828db2 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -12,7 +12,7 @@ __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('setuptools', 'pip') _SETUPTOOLS_VERSION = "65.5.0" -_PIP_VERSION = "22.3.1" +_PIP_VERSION = "23.0.1" _PROJECTS = [ ("setuptools", _SETUPTOOLS_VERSION, "py3"), ("pip", _PIP_VERSION, "py3"), diff --git a/Lib/ensurepip/_bundled/pip-22.3.1-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl similarity index 73% rename from Lib/ensurepip/_bundled/pip-22.3.1-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl index c5b7753e757d..a855dc40e863 100644 Binary files a/Lib/ensurepip/_bundled/pip-22.3.1-py3-none-any.whl and b/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl differ diff --git a/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst b/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst new file mode 100644 index 000000000000..f9dfd46d1ed4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-17-18-44-27.gh-issue-101997.A6_blD.rst @@ -0,0 +1 @@ +Upgrade pip wheel bundled with ensurepip (pip 23.0.1) From webhook-mailer at python.org Tue Mar 28 04:59:01 2023 From: webhook-mailer at python.org (ambv) Date: Tue, 28 Mar 2023 08:59:01 -0000 Subject: [Python-checkins] [3.10] gh-88233: zipfile: handle extras after a zip64 extra (GH-96161) (#102087) Message-ID: https://github.com/python/cpython/commit/d445147dfa04bfd52f1cfa7058f4428ca4c7c694 commit: d445147dfa04bfd52f1cfa7058f4428ca4c7c694 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2023-03-28T10:58:51+02:00 summary: [3.10] gh-88233: zipfile: handle extras after a zip64 extra (GH-96161) (#102087) Previously, any data _after_ the zip64 extra would be removed. With many new tests. Fixes GH-88233 (cherry picked from commit 59e86caca812fc993c5eb7dc8ccd1508ffccba86) Co-authored-by: Tim Hatch files: A Misc/NEWS.d/next/Library/2022-09-05-12-17-34.gh-issue-88233.gff9qJ.rst M Lib/test/test_zipfile.py M Lib/zipfile.py diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index c7371f59859e..3495fc6548b4 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -3221,5 +3221,67 @@ def test_extract_orig_with_implied_dirs(self, alpharep): zf.extractall(source_path.parent) +class StripExtraTests(unittest.TestCase): + # Note: all of the "z" characters are technically invalid, but up + # to 3 bytes at the end of the extra will be passed through as they + # are too short to encode a valid extra. + + ZIP64_EXTRA = 1 + + def test_no_data(self): + s = struct.Struct(" https://github.com/python/cpython/commit/abd6e97020e5773ce2136228e31930a6d9e82dc0 commit: abd6e97020e5773ce2136228e31930a6d9e82dc0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2023-03-28T11:27:30+02:00 summary: [3.11] GH-102711: Fix warnings found by clang (GH-102712) (#103075) There are some warnings if build python via clang: Parser/pegen.c:812:31: warning: a function declaration without a prototype is deprecated in all versions of C [-Wstrict-prototypes] _PyPegen_clear_memo_statistics() ^ void Parser/pegen.c:820:29: warning: a function declaration without a prototype is deprecated in all versions of C [-Wstrict-prototypes] _PyPegen_get_memo_statistics() ^ void Fix it to make clang happy. (cherry picked from commit 7703def37e4fa7d25c3d23756de8f527daa4e165) Signed-off-by: Chenxi Mao Co-authored-by: Chenxi Mao files: A Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst M Parser/pegen.c diff --git a/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst b/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst new file mode 100644 index 000000000000..511843968777 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst @@ -0,0 +1 @@ +Fix ``-Wstrict-prototypes`` compiler warnings. diff --git a/Parser/pegen.c b/Parser/pegen.c index 556e50a104a9..87b47bacec55 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -262,7 +262,7 @@ _PyPegen_fill_token(Parser *p) static long memo_statistics[NSTATISTICS]; void -_PyPegen_clear_memo_statistics() +_PyPegen_clear_memo_statistics(void) { for (int i = 0; i < NSTATISTICS; i++) { memo_statistics[i] = 0; @@ -270,7 +270,7 @@ _PyPegen_clear_memo_statistics() } PyObject * -_PyPegen_get_memo_statistics() +_PyPegen_get_memo_statistics(void) { PyObject *ret = PyList_New(NSTATISTICS); if (ret == NULL) { From webhook-mailer at python.org Tue Mar 28 05:27:50 2023 From: webhook-mailer at python.org (ambv) Date: Tue, 28 Mar 2023 09:27:50 -0000 Subject: [Python-checkins] [3.10] GH-102711: Fix warnings found by clang (GH-102712) (#103076) Message-ID: https://github.com/python/cpython/commit/aae84a0e849adc7486115b72e082e6896eebc3d5 commit: aae84a0e849adc7486115b72e082e6896eebc3d5 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2023-03-28T11:27:41+02:00 summary: [3.10] GH-102711: Fix warnings found by clang (GH-102712) (#103076) There are some warnings if build python via clang: Parser/pegen.c:812:31: warning: a function declaration without a prototype is deprecated in all versions of C [-Wstrict-prototypes] _PyPegen_clear_memo_statistics() ^ void Parser/pegen.c:820:29: warning: a function declaration without a prototype is deprecated in all versions of C [-Wstrict-prototypes] _PyPegen_get_memo_statistics() ^ void Fix it to make clang happy. (cherry picked from commit 7703def37e4fa7d25c3d23756de8f527daa4e165) Signed-off-by: Chenxi Mao Co-authored-by: Chenxi Mao files: A Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst M Parser/pegen.c diff --git a/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst b/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst new file mode 100644 index 000000000000..511843968777 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-03-15-02-03-39.gh-issue-102711.zTkjts.rst @@ -0,0 +1 @@ +Fix ``-Wstrict-prototypes`` compiler warnings. diff --git a/Parser/pegen.c b/Parser/pegen.c index 95c2273e4b42..f440db4a1c9e 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -809,7 +809,7 @@ _PyPegen_fill_token(Parser *p) static long memo_statistics[NSTATISTICS]; void -_PyPegen_clear_memo_statistics() +_PyPegen_clear_memo_statistics(void) { for (int i = 0; i < NSTATISTICS; i++) { memo_statistics[i] = 0; @@ -817,7 +817,7 @@ _PyPegen_clear_memo_statistics() } PyObject * -_PyPegen_get_memo_statistics() +_PyPegen_get_memo_statistics(void) { PyObject *ret = PyList_New(NSTATISTICS); if (ret == NULL) { From webhook-mailer at python.org Tue Mar 28 08:13:46 2023 From: webhook-mailer at python.org (ambv) Date: Tue, 28 Mar 2023 12:13:46 -0000 Subject: [Python-checkins] [3.10] GH-87235: Make sure "python /dev/fd/9 9 https://github.com/python/cpython/commit/5ae5ea8375b6ad1fad1fa4c529980ee245250c70 commit: 5ae5ea8375b6ad1fad1fa4c529980ee245250c70 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: ambv date: 2023-03-28T14:13:37+02:00 summary: [3.10] GH-87235: Make sure "python /dev/fd/9 9 * Regen zipimport --------- Co-authored-by: Ronald Oussoren Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> Co-authored-by: ?ukasz Langa files: A Misc/NEWS.d/next/macOS/2022-11-25-09-23-20.gh-issue-87235.SifjCD.rst M Lib/test/test_cmd_line_script.py M Lib/zipimport.py M Python/importlib_zipimport.h diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index c93ed5be7fbd..ccacfd606d18 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -738,6 +738,20 @@ def test_nonexisting_script(self): self.assertIn(": can't open file ", err) self.assertNotEqual(proc.returncode, 0) + @unittest.skipUnless(os.path.exists('/dev/fd/0'), 'requires /dev/fd platform') + def test_script_as_dev_fd(self): + # GH-87235: On macOS passing a non-trivial script to /dev/fd/N can cause + # problems because all open /dev/fd/N file descriptors share the same + # offset. + script = 'print("12345678912345678912345")' + with os_helper.temp_dir() as work_dir: + script_name = _make_test_script(work_dir, 'script.py', script) + with open(script_name, "r") as fp: + p = spawn_python(f"/dev/fd/{fp.fileno()}", close_fds=False, pass_fds=(0,1,2,fp.fileno())) + out, err = p.communicate() + self.assertEqual(out, b"12345678912345678912345\n") + + def tearDownModule(): support.reap_children() diff --git a/Lib/zipimport.py b/Lib/zipimport.py index 25eaee9c0f29..28e4e0960ffa 100644 --- a/Lib/zipimport.py +++ b/Lib/zipimport.py @@ -406,114 +406,121 @@ def _read_directory(archive): raise ZipImportError(f"can't open Zip file: {archive!r}", path=archive) with fp: + # GH-87235: On macOS all file descriptors for /dev/fd/N share the same + # file offset, reset the file offset after scanning the zipfile diretory + # to not cause problems when some runs 'python3 /dev/fd/9 9 header_offset: - raise ZipImportError(f'bad local header offset: {archive!r}', path=archive) - file_offset += arc_offset - - try: - name = fp.read(name_size) + fp.seek(-END_CENTRAL_DIR_SIZE, 2) + header_position = fp.tell() + buffer = fp.read(END_CENTRAL_DIR_SIZE) except OSError: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) - if len(name) != name_size: + if len(buffer) != END_CENTRAL_DIR_SIZE: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) - # On Windows, calling fseek to skip over the fields we don't use is - # slower than reading the data because fseek flushes stdio's - # internal buffers. See issue #8745. + if buffer[:4] != STRING_END_ARCHIVE: + # Bad: End of Central Dir signature + # Check if there's a comment. + try: + fp.seek(0, 2) + file_size = fp.tell() + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", + path=archive) + max_comment_start = max(file_size - MAX_COMMENT_LEN - + END_CENTRAL_DIR_SIZE, 0) + try: + fp.seek(max_comment_start) + data = fp.read() + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", + path=archive) + pos = data.rfind(STRING_END_ARCHIVE) + if pos < 0: + raise ZipImportError(f'not a Zip file: {archive!r}', + path=archive) + buffer = data[pos:pos+END_CENTRAL_DIR_SIZE] + if len(buffer) != END_CENTRAL_DIR_SIZE: + raise ZipImportError(f"corrupt Zip file: {archive!r}", + path=archive) + header_position = file_size - len(data) + pos + + header_size = _unpack_uint32(buffer[12:16]) + header_offset = _unpack_uint32(buffer[16:20]) + if header_position < header_size: + raise ZipImportError(f'bad central directory size: {archive!r}', path=archive) + if header_position < header_offset: + raise ZipImportError(f'bad central directory offset: {archive!r}', path=archive) + header_position -= header_size + arc_offset = header_position - header_offset + if arc_offset < 0: + raise ZipImportError(f'bad central directory size or offset: {archive!r}', path=archive) + + files = {} + # Start of Central Directory + count = 0 try: - if len(fp.read(header_size - name_size)) != header_size - name_size: - raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + fp.seek(header_position) except OSError: raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + while True: + buffer = fp.read(46) + if len(buffer) < 4: + raise EOFError('EOF read where not expected') + # Start of file header + if buffer[:4] != b'PK\x01\x02': + break # Bad: Central Dir File Header + if len(buffer) != 46: + raise EOFError('EOF read where not expected') + flags = _unpack_uint16(buffer[8:10]) + compress = _unpack_uint16(buffer[10:12]) + time = _unpack_uint16(buffer[12:14]) + date = _unpack_uint16(buffer[14:16]) + crc = _unpack_uint32(buffer[16:20]) + data_size = _unpack_uint32(buffer[20:24]) + file_size = _unpack_uint32(buffer[24:28]) + name_size = _unpack_uint16(buffer[28:30]) + extra_size = _unpack_uint16(buffer[30:32]) + comment_size = _unpack_uint16(buffer[32:34]) + file_offset = _unpack_uint32(buffer[42:46]) + header_size = name_size + extra_size + comment_size + if file_offset > header_offset: + raise ZipImportError(f'bad local header offset: {archive!r}', path=archive) + file_offset += arc_offset - if flags & 0x800: - # UTF-8 file names extension - name = name.decode() - else: - # Historical ZIP filename encoding try: - name = name.decode('ascii') - except UnicodeDecodeError: - name = name.decode('latin1').translate(cp437_table) - - name = name.replace('/', path_sep) - path = _bootstrap_external._path_join(archive, name) - t = (path, compress, data_size, file_size, file_offset, time, date, crc) - files[name] = t - count += 1 + name = fp.read(name_size) + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + if len(name) != name_size: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + # On Windows, calling fseek to skip over the fields we don't use is + # slower than reading the data because fseek flushes stdio's + # internal buffers. See issue #8745. + try: + if len(fp.read(header_size - name_size)) != header_size - name_size: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + except OSError: + raise ZipImportError(f"can't read Zip file: {archive!r}", path=archive) + + if flags & 0x800: + # UTF-8 file names extension + name = name.decode() + else: + # Historical ZIP filename encoding + try: + name = name.decode('ascii') + except UnicodeDecodeError: + name = name.decode('latin1').translate(cp437_table) + + name = name.replace('/', path_sep) + path = _bootstrap_external._path_join(archive, name) + t = (path, compress, data_size, file_size, file_offset, time, date, crc) + files[name] = t + count += 1 + finally: + fp.seek(start_offset) _bootstrap._verbose_message('zipimport: found {} names in {!r}', count, archive) return files diff --git a/Misc/NEWS.d/next/macOS/2022-11-25-09-23-20.gh-issue-87235.SifjCD.rst b/Misc/NEWS.d/next/macOS/2022-11-25-09-23-20.gh-issue-87235.SifjCD.rst new file mode 100644 index 000000000000..3111e4975e87 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2022-11-25-09-23-20.gh-issue-87235.SifjCD.rst @@ -0,0 +1 @@ +On macOS ``python3 /dev/fd/9 9 https://github.com/python/cpython/commit/ba65a065cf07a7a9f53be61057a090f7311a5ad7 commit: ba65a065cf07a7a9f53be61057a090f7311a5ad7 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-28T12:52:28-06:00 summary: gh-100227: Move the Dict of Interned Strings to PyInterpreterState (gh-102339) We can revisit the options for keeping it global later, if desired. For now the approach seems quite complex, so we've gone with the simpler isolation solution in the meantime. https://github.com/python/cpython/issues/100227 files: M Include/internal/pycore_global_objects.h M Include/internal/pycore_runtime.h M Include/internal/pycore_unicodeobject.h M Include/internal/pycore_unicodeobject_generated.h M Objects/unicodeobject.c M Tools/build/generate_global_objects.py diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 9957da1fc5f2..64d9384df9c5 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -23,13 +23,6 @@ extern "C" { // Only immutable objects should be considered runtime-global. // All others must be per-interpreter. -#define _Py_CACHED_OBJECT(NAME) \ - _PyRuntime.cached_objects.NAME - -struct _Py_cached_objects { - PyObject *interned_strings; -}; - #define _Py_GLOBAL_OBJECT(NAME) \ _PyRuntime.static_objects.NAME #define _Py_SINGLETON(NAME) \ @@ -65,6 +58,8 @@ struct _Py_static_objects { (interp)->cached_objects.NAME struct _Py_interp_cached_objects { + PyObject *interned_strings; + /* AST */ PyObject *str_replace_inf; diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index de757dfa93bc..8877b282bc38 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -163,7 +163,6 @@ typedef struct pyruntimestate { } types; /* All the objects that are shared by the runtime's interpreters. */ - struct _Py_cached_objects cached_objects; struct _Py_static_objects static_objects; /* The following fields are here to avoid allocation during init. diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 19faceebf1d8..ff97b9a623d2 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -59,6 +59,7 @@ struct _Py_unicode_state { struct _Py_unicode_ids ids; }; +extern void _PyUnicode_InternInPlace(PyInterpreterState *interp, PyObject **p); extern void _PyUnicode_ClearInterned(PyInterpreterState *interp); diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 0a8865942e6d..7114a5416f25 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -10,2003 +10,2003 @@ extern "C" { /* The following is auto-generated by Tools/build/generate_global_objects.py. */ static inline void -_PyUnicode_InitStaticStrings(void) { +_PyUnicode_InitStaticStrings(PyInterpreterState *interp) { PyObject *string; string = &_Py_ID(CANCELLED); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(FINISHED); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(False); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(JSONDecodeError); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(PENDING); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(Py_Repr); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(TextIOWrapper); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(True); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(WarningMessage); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_WindowsConsoleIO); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__IOBase_closed); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__abc_tpflags__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__abs__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__abstractmethods__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__add__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__aenter__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__aexit__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__aiter__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__all__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__and__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__anext__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__annotations__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__args__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__asyncio_running_event_loop__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__await__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__bases__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__bool__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__build_class__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__builtins__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__bytes__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__call__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__cantrace__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__class__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__class_getitem__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__classcell__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__complex__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__contains__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__copy__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__ctypes_from_outparam__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__del__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__delattr__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__delete__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__delitem__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__dict__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__dictoffset__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__dir__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__divmod__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__doc__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__enter__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__eq__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__exit__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__file__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__float__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__floordiv__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__format__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__fspath__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__ge__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__get__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__getattr__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__getattribute__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__getinitargs__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__getitem__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__getnewargs__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__getnewargs_ex__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__getstate__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__gt__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__hash__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__iadd__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__iand__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__ifloordiv__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__ilshift__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__imatmul__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__imod__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__import__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__imul__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__index__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__init__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__init_subclass__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__instancecheck__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__int__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__invert__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__ior__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__ipow__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__irshift__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__isabstractmethod__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__isub__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__iter__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__itruediv__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__ixor__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__le__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__len__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__length_hint__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__lltrace__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__loader__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__lshift__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__lt__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__main__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__matmul__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__missing__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__mod__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__module__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__mro_entries__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__mul__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__name__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__ne__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__neg__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__new__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__newobj__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__newobj_ex__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__next__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__notes__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__or__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__orig_class__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__origin__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__package__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__parameters__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__path__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__pos__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__pow__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__prepare__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__qualname__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__radd__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rand__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rdivmod__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__reduce__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__reduce_ex__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__repr__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__reversed__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rfloordiv__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rlshift__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rmatmul__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rmod__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rmul__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__ror__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__round__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rpow__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rrshift__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rshift__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rsub__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rtruediv__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__rxor__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__set__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__set_name__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__setattr__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__setitem__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__setstate__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__sizeof__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__slotnames__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__slots__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__spec__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__str__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__sub__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__subclasscheck__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__subclasshook__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__truediv__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__trunc__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__typing_is_unpacked_typevartuple__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__typing_prepare_subst__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__typing_subst__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__typing_unpacked_tuple_args__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__warningregistry__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__weaklistoffset__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__weakref__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(__xor__); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_abc_impl); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_abstract_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_active); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_annotation); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_anonymous_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_argtypes_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_as_parameter_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_asyncio_future_blocking); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_blksize); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_bootstrap); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_check_retval_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_dealloc_warn); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_feature_version); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_fields_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_finalizing); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_find_and_load); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_fix_up_module); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_flags_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_get_sourcefile); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_handle_fromlist); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_initializing); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_io); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_is_text_encoding); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_length_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_limbo); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_lock_unlock_module); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_loop); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_needs_com_addref_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_pack_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_restype_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_showwarnmsg); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_shutdown); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_slotnames); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_strptime_datetime); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_swappedbytes_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_type_); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_uninitialized_submodules); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_warn_unawaited_coroutine); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(_xoptions); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(a); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(abs_tol); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(access); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(add); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(add_done_callback); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(after_in_child); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(after_in_parent); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(aggregate_class); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(append); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(argdefs); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(arguments); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(argv); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(as_integer_ratio); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(ast); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(attribute); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(authorizer_callback); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(autocommit); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(b); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(backtick); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(base); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(before); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(big); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(binary_form); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(block); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(buffer); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(buffer_callback); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(buffer_size); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(buffering); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(buffers); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(bufsize); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(builtins); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(byteorder); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(bytes); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(bytes_per_sep); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(c); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(c_call); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(c_exception); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(c_return); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(cached_statements); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(cadata); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(cafile); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(call); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(call_exception_handler); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(call_soon); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(cancel); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(capath); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(category); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(cb_type); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(certfile); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(check_same_thread); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(clear); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(close); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(closed); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(closefd); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(closure); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_argcount); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_cellvars); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_code); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_consts); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_exceptiontable); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_filename); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_firstlineno); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_flags); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_freevars); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_kwonlyargcount); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_linetable); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_name); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_names); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_nlocals); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_posonlyargcount); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_qualname); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_stacksize); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(co_varnames); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(code); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(command); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(comment_factory); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(consts); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(context); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(cookie); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(copy); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(copyreg); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(coro); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(count); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(cwd); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(d); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(data); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(database); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(decode); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(decoder); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(default); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(defaultaction); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(delete); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(depth); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(detect_types); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(deterministic); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(device); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(dict); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(dictcomp); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(difference_update); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(digest); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(digest_size); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(digestmod); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(dir_fd); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(discard); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(dispatch_table); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(displayhook); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(dklen); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(doc); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(dont_inherit); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(dst); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(dst_dir_fd); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(duration); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(e); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(effective_ids); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(element_factory); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(encode); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(encoding); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(end); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(end_lineno); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(end_offset); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(endpos); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(env); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(errors); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(event); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(eventmask); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(exc_type); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(exc_value); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(excepthook); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(exception); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(exp); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(extend); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(facility); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(factory); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(false); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(family); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fanout); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fd); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fd2); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fdel); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fget); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(file); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(file_actions); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(filename); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fileno); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(filepath); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fillvalue); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(filters); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(final); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(find_class); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fix_imports); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(flags); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(flush); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(follow_symlinks); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(format); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(frequency); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(from_param); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fromlist); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fromtimestamp); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fromutc); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(fset); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(func); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(future); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(generation); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(genexpr); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(get); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(get_debug); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(get_event_loop); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(get_loop); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(get_source); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(getattr); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(getstate); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(gid); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(globals); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(groupindex); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(groups); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(handle); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(hash_name); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(header); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(headers); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(hi); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(hook); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(id); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(ident); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(ignore); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(imag); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(importlib); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(in_fd); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(incoming); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(indexgroup); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(inf); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(inheritable); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(initial); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(initial_bytes); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(initial_value); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(initval); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(inner_size); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(input); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(insert_comments); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(insert_pis); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(instructions); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(intern); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(intersection); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(isatty); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(isinstance); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(isoformat); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(isolation_level); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(istext); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(item); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(items); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(iter); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(iterable); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(iterations); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(join); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(jump); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(keepends); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(key); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(keyfile); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(keys); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(kind); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(kw); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(kw1); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(kw2); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(lambda); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(last); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(last_exc); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(last_node); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(last_traceback); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(last_type); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(last_value); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(latin1); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(leaf_size); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(len); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(length); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(level); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(limit); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(line); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(line_buffering); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(lineno); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(listcomp); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(little); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(lo); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(locale); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(locals); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(logoption); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(loop); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(mapping); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(match); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(max_length); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(maxdigits); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(maxevents); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(maxmem); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(maxsplit); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(maxvalue); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(memLevel); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(memlimit); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(message); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(metaclass); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(method); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(mod); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(mode); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(module); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(module_globals); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(modules); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(mro); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(msg); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(mycmp); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(n); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(n_arg); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(n_fields); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(n_sequence_fields); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(n_unnamed_fields); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(name); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(name_from); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(namespace_separator); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(namespaces); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(narg); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(ndigits); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(new_limit); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(newline); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(newlines); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(next); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(node_depth); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(node_offset); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(ns); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(nstype); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(nt); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(null); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(number); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(obj); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(object); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(offset); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(offset_dst); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(offset_src); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(on_type_read); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(onceregistry); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(only_keys); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(oparg); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(opcode); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(open); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(opener); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(operation); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(optimize); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(options); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(order); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(out_fd); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(outgoing); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(overlapped); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(owner); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(p); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(pages); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(parent); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(password); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(path); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(pattern); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(peek); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(persistent_id); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(persistent_load); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(person); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(pi_factory); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(pid); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(policy); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(pos); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(pos1); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(pos2); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(posix); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(print_file_and_line); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(priority); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(progress); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(progress_handler); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(proto); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(protocol); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(ps1); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(ps2); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(query); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(quotetabs); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(r); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(raw); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(read); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(read1); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(readable); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(readall); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(readinto); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(readinto1); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(readline); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(readonly); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(real); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(reducer_override); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(registry); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(rel_tol); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(reload); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(repl); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(replace); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(reserved); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(reset); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(resetids); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(return); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(reverse); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(reversed); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(s); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(salt); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(sched_priority); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(scheduler); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(seek); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(seekable); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(selectors); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(self); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(send); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(sep); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(sequence); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(server_hostname); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(server_side); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(session); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(setcomp); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(setpgroup); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(setsid); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(setsigdef); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(setsigmask); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(setstate); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(shape); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(show_cmd); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(signed); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(size); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(sizehint); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(skip_file_prefixes); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(sleep); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(sock); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(sort); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(sound); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(source); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(source_traceback); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(src); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(src_dir_fd); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(stacklevel); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(start); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(statement); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(status); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(stderr); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(stdin); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(stdout); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(step); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(store_name); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(strategy); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(strftime); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(strict); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(strict_mode); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(string); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(sub_key); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(symmetric_difference_update); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tabsize); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tag); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(target); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(target_is_directory); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(task); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tb_frame); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tb_lasti); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tb_lineno); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tb_next); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tell); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(template); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(term); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(text); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(threading); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(throw); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(timeout); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(times); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(timetuple); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(top); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(trace_callback); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(traceback); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(trailers); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(translate); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(true); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(truncate); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(twice); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(txt); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(type); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tz); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(tzname); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(uid); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(unlink); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(unraisablehook); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(uri); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(usedforsecurity); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(value); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(values); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(version); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(volume); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(warnings); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(warnoptions); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(wbits); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(week); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(weekday); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(which); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(who); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(withdata); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(writable); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(write); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(write_through); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(x); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(year); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); string = &_Py_ID(zdict); assert(_PyUnicode_CheckConsistency(string, 1)); - PyUnicode_InternInPlace(&string); + _PyUnicode_InternInPlace(interp, &string); } /* End auto-generated code */ #ifdef __cplusplus diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index b9fb53147b9b..85e5ae735709 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -231,14 +231,32 @@ static inline PyObject* unicode_new_empty(void) Another way to look at this is that to say that the actual reference count of a string is: s->ob_refcnt + (s->state ? 2 : 0) */ -static inline PyObject *get_interned_dict(void) +static inline PyObject *get_interned_dict(PyInterpreterState *interp) { - return _Py_CACHED_OBJECT(interned_strings); + return _Py_INTERP_CACHED_OBJECT(interp, interned_strings); } -static inline void set_interned_dict(PyObject *dict) +static int +init_interned_dict(PyInterpreterState *interp) +{ + assert(get_interned_dict(interp) == NULL); + PyObject *interned = interned = PyDict_New(); + if (interned == NULL) { + return -1; + } + _Py_INTERP_CACHED_OBJECT(interp, interned_strings) = interned; + return 0; +} + +static void +clear_interned_dict(PyInterpreterState *interp) { - _Py_CACHED_OBJECT(interned_strings) = dict; + PyObject *interned = get_interned_dict(interp); + if (interned != NULL) { + PyDict_Clear(interned); + Py_DECREF(interned); + _Py_INTERP_CACHED_OBJECT(interp, interned_strings) = NULL; + } } #define _Py_RETURN_UNICODE_EMPTY() \ @@ -1520,12 +1538,12 @@ find_maxchar_surrogates(const wchar_t *begin, const wchar_t *end, static void unicode_dealloc(PyObject *unicode) { + PyInterpreterState *interp = _PyInterpreterState_GET(); #ifdef Py_DEBUG if (!unicode_is_finalizing() && unicode_is_singleton(unicode)) { _Py_FatalRefcountError("deallocating an Unicode singleton"); } #endif - PyObject *interned = get_interned_dict(); if (PyUnicode_CHECK_INTERNED(unicode)) { /* Revive the dead object temporarily. PyDict_DelItem() removes two references (key and value) which were ignored by @@ -1534,6 +1552,8 @@ unicode_dealloc(PyObject *unicode) PyDict_DelItem(). */ assert(Py_REFCNT(unicode) == 0); Py_SET_REFCNT(unicode, 3); + PyObject *interned = get_interned_dict(interp); + assert(interned != NULL); if (PyDict_DelItem(interned, unicode) != 0) { _PyErr_WriteUnraisableMsg("deletion of interned string failed", NULL); @@ -14529,34 +14549,29 @@ _PyUnicode_InitState(PyInterpreterState *interp) PyStatus _PyUnicode_InitGlobalObjects(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - return _PyStatus_OK(); - } - // Initialize the global interned dict - PyObject *interned = PyDict_New(); - if (interned == NULL) { + if (init_interned_dict(interp)) { PyErr_Clear(); return _PyStatus_ERR("failed to create interned dict"); } - set_interned_dict(interned); - - /* Intern statically allocated string identifiers and deepfreeze strings. - * This must be done before any module initialization so that statically - * allocated string identifiers are used instead of heap allocated strings. - * Deepfreeze uses the interned identifiers if present to save space - * else generates them and they are interned to speed up dict lookups. - */ - _PyUnicode_InitStaticStrings(); + if (_Py_IsMainInterpreter(interp)) { + /* Intern statically allocated string identifiers and deepfreeze strings. + * This must be done before any module initialization so that statically + * allocated string identifiers are used instead of heap allocated strings. + * Deepfreeze uses the interned identifiers if present to save space + * else generates them and they are interned to speed up dict lookups. + */ + _PyUnicode_InitStaticStrings(interp); #ifdef Py_DEBUG - assert(_PyUnicode_CheckConsistency(&_Py_STR(empty), 1)); + assert(_PyUnicode_CheckConsistency(&_Py_STR(empty), 1)); - for (int i = 0; i < 256; i++) { - assert(_PyUnicode_CheckConsistency(LATIN1(i), 1)); - } + for (int i = 0; i < 256; i++) { + assert(_PyUnicode_CheckConsistency(LATIN1(i), 1)); + } #endif + } return _PyStatus_OK(); } @@ -14586,7 +14601,7 @@ _PyUnicode_InitTypes(PyInterpreterState *interp) void -PyUnicode_InternInPlace(PyObject **p) +_PyUnicode_InternInPlace(PyInterpreterState *interp, PyObject **p) { PyObject *s = *p; #ifdef Py_DEBUG @@ -14608,7 +14623,7 @@ PyUnicode_InternInPlace(PyObject **p) return; } - PyObject *interned = get_interned_dict(); + PyObject *interned = get_interned_dict(interp); assert(interned != NULL); PyObject *t = PyDict_SetDefault(interned, s, s); @@ -14629,6 +14644,13 @@ PyUnicode_InternInPlace(PyObject **p) _PyUnicode_STATE(s).interned = 1; } +void +PyUnicode_InternInPlace(PyObject **p) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + _PyUnicode_InternInPlace(interp, p); +} + // Function kept for the stable ABI. PyAPI_FUNC(void) PyUnicode_InternImmortal(PyObject **); void @@ -14653,12 +14675,7 @@ PyUnicode_InternFromString(const char *cp) void _PyUnicode_ClearInterned(PyInterpreterState *interp) { - if (!_Py_IsMainInterpreter(interp)) { - // interned dict is shared by all interpreters - return; - } - - PyObject *interned = get_interned_dict(); + PyObject *interned = get_interned_dict(interp); if (interned == NULL) { return; } @@ -14693,9 +14710,7 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp) total_length); #endif - PyDict_Clear(interned); - Py_DECREF(interned); - set_interned_dict(NULL); + clear_interned_dict(interp); } @@ -15108,7 +15123,7 @@ _PyUnicode_EnableLegacyWindowsFSEncoding(void) static inline int unicode_is_finalizing(void) { - return (get_interned_dict() == NULL); + return (get_interned_dict(_PyInterpreterState_Main()) == NULL); } #endif @@ -15131,14 +15146,13 @@ _PyUnicode_Fini(PyInterpreterState *interp) { struct _Py_unicode_state *state = &interp->unicode; - if (_Py_IsMainInterpreter(interp)) { - // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini() - assert(get_interned_dict() == NULL); - // bpo-47182: force a unicodedata CAPI capsule re-import on - // subsequent initialization of main interpreter. - } + // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini() + assert(get_interned_dict(interp) == NULL); _PyUnicode_FiniEncodings(&state->fs_codec); + + // bpo-47182: force a unicodedata CAPI capsule re-import on + // subsequent initialization of interpreter. interp->unicode.ucnhash_capi = NULL; unicode_clear_identifiers(state); diff --git a/Tools/build/generate_global_objects.py b/Tools/build/generate_global_objects.py index 1f53f02d41ef..c27817702bf9 100644 --- a/Tools/build/generate_global_objects.py +++ b/Tools/build/generate_global_objects.py @@ -354,14 +354,14 @@ def generate_static_strings_initializer(identifiers, strings): printer.write(before) printer.write(START) printer.write("static inline void") - with printer.block("_PyUnicode_InitStaticStrings(void)"): + with printer.block("_PyUnicode_InitStaticStrings(PyInterpreterState *interp)"): printer.write(f'PyObject *string;') for i in sorted(identifiers): # This use of _Py_ID() is ignored by iter_global_strings() # since iter_files() ignores .h files. printer.write(f'string = &_Py_ID({i});') printer.write(f'assert(_PyUnicode_CheckConsistency(string, 1));') - printer.write(f'PyUnicode_InternInPlace(&string);') + printer.write(f'_PyUnicode_InternInPlace(interp, &string);') # XXX What about "strings"? printer.write(END) printer.write(after) From webhook-mailer at python.org Tue Mar 28 19:47:20 2023 From: webhook-mailer at python.org (zooba) Date: Tue, 28 Mar 2023 23:47:20 -0000 Subject: [Python-checkins] gh-103097: Add workaround for Windows ARM64 compiler bug (GH-103098) Message-ID: https://github.com/python/cpython/commit/24ba507b1dd70cf468a1beadea6ca6336fe1d40f commit: 24ba507b1dd70cf468a1beadea6ca6336fe1d40f branch: main author: Steve Dower committer: zooba date: 2023-03-29T00:47:13+01:00 summary: gh-103097: Add workaround for Windows ARM64 compiler bug (GH-103098) See https://developercommunity.visualstudio.com/t/Regression-in-MSVC-1433-1434-ARM64-co/10224361 for details of the issue. It only applies to version 14.34. files: M PCbuild/pyproject.props diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index 92c7849d3bcf..36c4c269d05d 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -21,6 +21,13 @@ false + + <_VCToolsVersion>$([System.Version]::Parse(`$(VCToolsVersion)`).Major).$([System.Version]::Parse(`$(VCToolsVersion)`).Minor) + + + true + + <_DebugPreprocessorDefinition>NDEBUG; <_DebugPreprocessorDefinition Condition="$(Configuration) == 'Debug'">_DEBUG; @@ -50,6 +57,7 @@ /utf-8 %(AdditionalOptions) -Wno-deprecated-non-prototype -Wno-unused-label -Wno-pointer-sign -Wno-incompatible-pointer-types-discards-qualifiers -Wno-unused-function %(AdditionalOptions) -flto %(AdditionalOptions) + -d2pattern-opt-disable:-932189325 %(AdditionalOptions) OnlyExplicitInline @@ -79,6 +87,7 @@ PGUpdate advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;%(AdditionalDependencies) /OPT:REF,NOICF %(AdditionalOptions) + -d2:-pattern-opt-disable:-932189325 %(AdditionalOptions) true From webhook-mailer at python.org Tue Mar 28 23:04:38 2023 From: webhook-mailer at python.org (JelleZijlstra) Date: Wed, 29 Mar 2023 03:04:38 -0000 Subject: [Python-checkins] gh-103054: typing: Improve `Callable` type substitution tests (#103055) Message-ID: https://github.com/python/cpython/commit/60bdc16b459cf8f7b359c7f87d8ae6c5928147a4 commit: 60bdc16b459cf8f7b359c7f87d8ae6c5928147a4 branch: main author: Nikita Sobolev committer: JelleZijlstra date: 2023-03-28T20:04:26-07:00 summary: gh-103054: typing: Improve `Callable` type substitution tests (#103055) Co-authored-by: Alex Waygood Co-authored-by: Eclips4 <80244920+Eclips4 at users.noreply.github.com> files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index f448b0ee60a9..23bf2b5e183a 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2049,6 +2049,48 @@ def test_concatenate(self): Callable[Concatenate[int, str, P2], int]) self.assertEqual(C[...], Callable[Concatenate[int, ...], int]) + def test_nested_paramspec(self): + # Since Callable has some special treatment, we want to be sure + # that substituion works correctly, see gh-103054 + Callable = self.Callable + P = ParamSpec('P') + P2 = ParamSpec('P2') + T = TypeVar('T') + T2 = TypeVar('T2') + Ts = TypeVarTuple('Ts') + class My(Generic[P, T]): + pass + + self.assertEqual(My.__parameters__, (P, T)) + + C1 = My[[int, T2], Callable[P2, T2]] + self.assertEqual(C1.__args__, ((int, T2), Callable[P2, T2])) + self.assertEqual(C1.__parameters__, (T2, P2)) + self.assertEqual(C1[str, [list[int], bytes]], + My[[int, str], Callable[[list[int], bytes], str]]) + + C2 = My[[Callable[[T2], int], list[T2]], str] + self.assertEqual(C2.__args__, ((Callable[[T2], int], list[T2]), str)) + self.assertEqual(C2.__parameters__, (T2,)) + self.assertEqual(C2[list[str]], + My[[Callable[[list[str]], int], list[list[str]]], str]) + + C3 = My[[Callable[P2, T2], T2], T2] + self.assertEqual(C3.__args__, ((Callable[P2, T2], T2), T2)) + self.assertEqual(C3.__parameters__, (P2, T2)) + self.assertEqual(C3[[], int], + My[[Callable[[], int], int], int]) + self.assertEqual(C3[[str, bool], int], + My[[Callable[[str, bool], int], int], int]) + self.assertEqual(C3[[str, bool], T][int], + My[[Callable[[str, bool], int], int], int]) + + C4 = My[[Callable[[int, *Ts, str], T2], T2], T2] + self.assertEqual(C4.__args__, ((Callable[[int, *Ts, str], T2], T2), T2)) + self.assertEqual(C4.__parameters__, (Ts, T2)) + self.assertEqual(C4[bool, bytes, float], + My[[Callable[[int, bool, bytes, str], float], float], float]) + def test_errors(self): Callable = self.Callable alias = Callable[[int, str], float] From webhook-mailer at python.org Tue Mar 28 23:28:41 2023 From: webhook-mailer at python.org (miss-islington) Date: Wed, 29 Mar 2023 03:28:41 -0000 Subject: [Python-checkins] gh-103054: typing: Improve `Callable` type substitution tests (GH-103055) Message-ID: https://github.com/python/cpython/commit/766038d995f26eec57d62b1143183e6f2c1b14e6 commit: 766038d995f26eec57d62b1143183e6f2c1b14e6 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-28T20:28:34-07:00 summary: gh-103054: typing: Improve `Callable` type substitution tests (GH-103055) (cherry picked from commit 60bdc16b459cf8f7b359c7f87d8ae6c5928147a4) Co-authored-by: Nikita Sobolev Co-authored-by: Alex Waygood Co-authored-by: Eclips4 <80244920+Eclips4 at users.noreply.github.com> files: M Lib/test/test_typing.py diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 558d928167ac..4de24472c2c0 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -2044,6 +2044,48 @@ def test_concatenate(self): Callable[Concatenate[int, str, P2], int]) self.assertEqual(C[...], Callable[Concatenate[int, ...], int]) + def test_nested_paramspec(self): + # Since Callable has some special treatment, we want to be sure + # that substituion works correctly, see gh-103054 + Callable = self.Callable + P = ParamSpec('P') + P2 = ParamSpec('P2') + T = TypeVar('T') + T2 = TypeVar('T2') + Ts = TypeVarTuple('Ts') + class My(Generic[P, T]): + pass + + self.assertEqual(My.__parameters__, (P, T)) + + C1 = My[[int, T2], Callable[P2, T2]] + self.assertEqual(C1.__args__, ((int, T2), Callable[P2, T2])) + self.assertEqual(C1.__parameters__, (T2, P2)) + self.assertEqual(C1[str, [list[int], bytes]], + My[[int, str], Callable[[list[int], bytes], str]]) + + C2 = My[[Callable[[T2], int], list[T2]], str] + self.assertEqual(C2.__args__, ((Callable[[T2], int], list[T2]), str)) + self.assertEqual(C2.__parameters__, (T2,)) + self.assertEqual(C2[list[str]], + My[[Callable[[list[str]], int], list[list[str]]], str]) + + C3 = My[[Callable[P2, T2], T2], T2] + self.assertEqual(C3.__args__, ((Callable[P2, T2], T2), T2)) + self.assertEqual(C3.__parameters__, (P2, T2)) + self.assertEqual(C3[[], int], + My[[Callable[[], int], int], int]) + self.assertEqual(C3[[str, bool], int], + My[[Callable[[str, bool], int], int], int]) + self.assertEqual(C3[[str, bool], T][int], + My[[Callable[[str, bool], int], int], int]) + + C4 = My[[Callable[[int, *Ts, str], T2], T2], T2] + self.assertEqual(C4.__args__, ((Callable[[int, *Ts, str], T2], T2), T2)) + self.assertEqual(C4.__parameters__, (Ts, T2)) + self.assertEqual(C4[bool, bytes, float], + My[[Callable[[int, bool, bytes, str], float], float], float]) + def test_errors(self): Callable = self.Callable alias = Callable[[int, str], float] From webhook-mailer at python.org Wed Mar 29 04:53:37 2023 From: webhook-mailer at python.org (vsajip) Date: Wed, 29 Mar 2023 08:53:37 -0000 Subject: [Python-checkins] gh-102582: Fix invalid JSON in Doc/howto/logging-cookbook.rst (GH-102635) Message-ID: https://github.com/python/cpython/commit/d835b3f05de7e2d800138e5969eeb9656b0ed860 commit: d835b3f05de7e2d800138e5969eeb9656b0ed860 branch: main author: Mat?j Cepl committer: vsajip date: 2023-03-29T09:52:53+01:00 summary: gh-102582: Fix invalid JSON in Doc/howto/logging-cookbook.rst (GH-102635) files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 1a0afb6940da..6ef252d709e7 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -340,10 +340,12 @@ adding a ``filters`` section parallel to ``formatters`` and ``handlers``: .. code-block:: json - "filters": { - "warnings_and_below": { - "()" : "__main__.filter_maker", - "level": "WARNING" + { + "filters": { + "warnings_and_below": { + "()" : "__main__.filter_maker", + "level": "WARNING" + } } } @@ -351,12 +353,14 @@ and changing the section on the ``stdout`` handler to add it: .. code-block:: json - "stdout": { - "class": "logging.StreamHandler", - "level": "INFO", - "formatter": "simple", - "stream": "ext://sys.stdout", - "filters": ["warnings_and_below"] + { + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + "filters": ["warnings_and_below"] + } } A filter is just a function, so we can define the ``filter_maker`` (a factory From webhook-mailer at python.org Wed Mar 29 05:05:02 2023 From: webhook-mailer at python.org (vsajip) Date: Wed, 29 Mar 2023 09:05:02 -0000 Subject: [Python-checkins] [3.11] gh-102582: Fix invalid JSON in Doc/howto/logging-cookbook.rst (GH-102635) (GH-103106) Message-ID: https://github.com/python/cpython/commit/d189e2db0bca60eba328cc31b86e62a1e2b3647a commit: d189e2db0bca60eba328cc31b86e62a1e2b3647a branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2023-03-29T10:04:53+01:00 summary: [3.11] gh-102582: Fix invalid JSON in Doc/howto/logging-cookbook.rst (GH-102635) (GH-103106) (cherry picked from commit d835b3f05de7e2d800138e5969eeb9656b0ed860) Co-authored-by: Mat?j Cepl files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index e4338ab912ae..ffb566c1e86d 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -340,10 +340,12 @@ adding a ``filters`` section parallel to ``formatters`` and ``handlers``: .. code-block:: json - "filters": { - "warnings_and_below": { - "()" : "__main__.filter_maker", - "level": "WARNING" + { + "filters": { + "warnings_and_below": { + "()" : "__main__.filter_maker", + "level": "WARNING" + } } } @@ -351,12 +353,14 @@ and changing the section on the ``stdout`` handler to add it: .. code-block:: json - "stdout": { - "class": "logging.StreamHandler", - "level": "INFO", - "formatter": "simple", - "stream": "ext://sys.stdout", - "filters": ["warnings_and_below"] + { + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + "filters": ["warnings_and_below"] + } } A filter is just a function, so we can define the ``filter_maker`` (a factory From webhook-mailer at python.org Wed Mar 29 05:05:37 2023 From: webhook-mailer at python.org (vsajip) Date: Wed, 29 Mar 2023 09:05:37 -0000 Subject: [Python-checkins] [3.10] gh-102582: Fix invalid JSON in Doc/howto/logging-cookbook.rst (GH-102635) (GH-103107) Message-ID: https://github.com/python/cpython/commit/473fd7bbf0508074f28f020801c207a8d379637b commit: 473fd7bbf0508074f28f020801c207a8d379637b branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: vsajip date: 2023-03-29T10:05:29+01:00 summary: [3.10] gh-102582: Fix invalid JSON in Doc/howto/logging-cookbook.rst (GH-102635) (GH-103107) (cherry picked from commit d835b3f05de7e2d800138e5969eeb9656b0ed860) Co-authored-by: Mat?j Cepl files: M Doc/howto/logging-cookbook.rst diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst index 1272ea1e3998..ee1471a35f1a 100644 --- a/Doc/howto/logging-cookbook.rst +++ b/Doc/howto/logging-cookbook.rst @@ -340,10 +340,12 @@ adding a ``filters`` section parallel to ``formatters`` and ``handlers``: .. code-block:: json - "filters": { - "warnings_and_below": { - "()" : "__main__.filter_maker", - "level": "WARNING" + { + "filters": { + "warnings_and_below": { + "()" : "__main__.filter_maker", + "level": "WARNING" + } } } @@ -351,12 +353,14 @@ and changing the section on the ``stdout`` handler to add it: .. code-block:: json - "stdout": { - "class": "logging.StreamHandler", - "level": "INFO", - "formatter": "simple", - "stream": "ext://sys.stdout", - "filters": ["warnings_and_below"] + { + "stdout": { + "class": "logging.StreamHandler", + "level": "INFO", + "formatter": "simple", + "stream": "ext://sys.stdout", + "filters": ["warnings_and_below"] + } } A filter is just a function, so we can define the ``filter_maker`` (a factory From webhook-mailer at python.org Wed Mar 29 06:09:20 2023 From: webhook-mailer at python.org (ambv) Date: Wed, 29 Mar 2023 10:09:20 -0000 Subject: [Python-checkins] gh-103068: Check condition expression of breakpoints for pdb (#103069) Message-ID: https://github.com/python/cpython/commit/e375bff03736f809fbc234010c087ef9d7e0d384 commit: e375bff03736f809fbc234010c087ef9d7e0d384 branch: main author: gaogaotiantian committer: ambv date: 2023-03-29T12:09:12+02:00 summary: gh-103068: Check condition expression of breakpoints for pdb (#103069) Co-authored-by: ?ukasz Langa Co-authored-by: Artem Mukhin files: A Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst M Lib/pdb.py M Lib/test/test_pdb.py diff --git a/Lib/pdb.py b/Lib/pdb.py index d402de1192f9..3a06cd00ad2b 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -377,8 +377,7 @@ def user_exception(self, frame, exc_info): # stop when the debuggee is returning from such generators. prefix = 'Internal ' if (not exc_traceback and exc_type is StopIteration) else '' - self.message('%s%s' % (prefix, - traceback.format_exception_only(exc_type, exc_value)[-1].strip())) + self.message('%s%s' % (prefix, self._format_exc(exc_value))) self.interaction(frame, exc_traceback) # General interaction function @@ -399,7 +398,7 @@ def preloop(self): displaying = self.displaying.get(self.curframe) if displaying: for expr, oldvalue in displaying.items(): - newvalue, _ = self._getval_except(expr) + newvalue = self._getval_except(expr) # check for identity first; this prevents custom __eq__ to # be called at every loop, and also prevents instances whose # fields are changed to be displayed @@ -702,6 +701,9 @@ def do_break(self, arg, temporary = 0): if comma > 0: # parse stuff after comma: "condition" cond = arg[comma+1:].lstrip() + if err := self._compile_error_message(cond): + self.error('Invalid condition %s: %r' % (cond, err)) + return arg = arg[:comma].rstrip() # parse stuff before comma: [filename:]lineno | function colon = arg.rfind(':') @@ -887,6 +889,9 @@ def do_condition(self, arg): args = arg.split(' ', 1) try: cond = args[1] + if err := self._compile_error_message(cond): + self.error('Invalid condition %s: %r' % (cond, err)) + return except IndexError: cond = None try: @@ -1246,16 +1251,15 @@ def _getval(self, arg): def _getval_except(self, arg, frame=None): try: if frame is None: - return eval(arg, self.curframe.f_globals, self.curframe_locals), None + return eval(arg, self.curframe.f_globals, self.curframe_locals) else: - return eval(arg, frame.f_globals, frame.f_locals), None + return eval(arg, frame.f_globals, frame.f_locals) except BaseException as exc: - err = traceback.format_exception_only(exc)[-1].strip() - return _rstr('** raised %s **' % err), exc + return _rstr('** raised %s **' % self._format_exc(exc)) def _error_exc(self): - exc_info = sys.exc_info()[:2] - self.error(traceback.format_exception_only(*exc_info)[-1].strip()) + exc = sys.exc_info()[1] + self.error(self._format_exc(exc)) def _msg_val_func(self, arg, func): try: @@ -1443,10 +1447,10 @@ def do_display(self, arg): else: self.message('No expression is being displayed') else: - val, exc = self._getval_except(arg) - if isinstance(exc, SyntaxError): - self.message('Unable to display %s: %r' % (arg, val)) + if err := self._compile_error_message(arg): + self.error('Unable to display %s: %r' % (arg, err)) else: + val = self._getval_except(arg) self.displaying.setdefault(self.curframe, {})[arg] = val self.message('display %s: %r' % (arg, val)) @@ -1647,6 +1651,16 @@ def _run(self, target: Union[_ModuleTarget, _ScriptTarget]): self.run(target.code) + def _format_exc(self, exc: BaseException): + return traceback.format_exception_only(exc)[-1].strip() + + def _compile_error_message(self, expr): + """Return the error message as string if compiling `expr` fails.""" + try: + compile(expr, "", "eval") + except SyntaxError as exc: + return _rstr(self._format_exc(exc)) + return "" # Collect all command help into docstring, if not run with -OO diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index ae9c5d73e2da..de2bab464957 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -240,9 +240,11 @@ def test_pdb_breakpoint_commands(): >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE ... 'break 3', + ... 'break 4, +', ... 'disable 1', ... 'ignore 1 10', ... 'condition 1 1 < 2', + ... 'condition 1 1 <', ... 'break 4', ... 'break 4', ... 'break', @@ -264,6 +266,8 @@ def test_pdb_breakpoint_commands(): ... 'commands 10', # out of range ... 'commands a', # display help ... 'commands 4', # already deleted + ... 'break 6, undefined', # condition causing `NameError` during evaluation + ... 'continue', # will stop, ignoring runtime error ... 'continue', ... ]): ... test_function() @@ -271,12 +275,16 @@ def test_pdb_breakpoint_commands(): -> print(1) (Pdb) break 3 Breakpoint 1 at :3 + (Pdb) break 4, + + *** Invalid condition +: SyntaxError: invalid syntax (Pdb) disable 1 Disabled breakpoint 1 at :3 (Pdb) ignore 1 10 Will ignore next 10 crossings of breakpoint 1. (Pdb) condition 1 1 < 2 New condition set for breakpoint 1. + (Pdb) condition 1 1 < + *** Invalid condition 1 <: SyntaxError: invalid syntax (Pdb) break 4 Breakpoint 2 at :4 (Pdb) break 4 @@ -331,8 +339,13 @@ def test_pdb_breakpoint_commands(): end (Pdb) commands 4 *** cannot set commands: Breakpoint 4 already deleted + (Pdb) break 6, undefined + Breakpoint 5 at :6 (Pdb) continue 3 + > (6)test_function() + -> print(4) + (Pdb) continue 4 """ @@ -597,13 +610,14 @@ def test_pdb_display_command(): ... 'undisplay', ... 'display a < 1', ... 'n', + ... 'display undefined', ... 'continue', ... ]): ... test_function() > (4)test_function() -> a = 1 (Pdb) display + - Unable to display +: ** raised SyntaxError: invalid syntax ** + *** Unable to display +: SyntaxError: invalid syntax (Pdb) display No expression is being displayed (Pdb) display a @@ -627,6 +641,8 @@ def test_pdb_display_command(): (Pdb) n > (7)test_function() -> a = 4 + (Pdb) display undefined + display undefined: ** raised NameError: name 'undefined' is not defined ** (Pdb) continue """ diff --git a/Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst b/Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst new file mode 100644 index 000000000000..71c142c30f4e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-28-05-14-59.gh-issue-103068.YQTmrA.rst @@ -0,0 +1,2 @@ +It's no longer possible to register conditional breakpoints in +:class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. From webhook-mailer at python.org Wed Mar 29 10:33:37 2023 From: webhook-mailer at python.org (zooba) Date: Wed, 29 Mar 2023 14:33:37 -0000 Subject: [Python-checkins] gh-103097: Add workaround for Windows ARM64 compiler bug (GH-103098) Message-ID: https://github.com/python/cpython/commit/cbe14c87c68af19aba3a0001fe35c5310a083ff0 commit: cbe14c87c68af19aba3a0001fe35c5310a083ff0 branch: 3.11 author: Steve Dower committer: zooba date: 2023-03-29T15:33:29+01:00 summary: gh-103097: Add workaround for Windows ARM64 compiler bug (GH-103098) See https://developercommunity.visualstudio.com/t/Regression-in-MSVC-1433-1434-ARM64-co/10224361 for details of the issue. It only applies to version 14.34. files: M PCbuild/pyproject.props diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index e398b333572e..b1b04472bb50 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -21,6 +21,13 @@ false + + <_VCToolsVersion>$([System.Version]::Parse(`$(VCToolsVersion)`).Major).$([System.Version]::Parse(`$(VCToolsVersion)`).Minor) + + + true + + <_DebugPreprocessorDefinition>NDEBUG; <_DebugPreprocessorDefinition Condition="$(Configuration) == 'Debug'">_DEBUG; @@ -47,6 +54,7 @@ $(EnableControlFlowGuard) /utf-8 %(AdditionalOptions) true + -d2pattern-opt-disable:-932189325 %(AdditionalOptions) OnlyExplicitInline @@ -76,6 +84,7 @@ PGUpdate advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;%(AdditionalDependencies) /OPT:REF,NOICF %(AdditionalOptions) + -d2:-pattern-opt-disable:-932189325 %(AdditionalOptions) true From webhook-mailer at python.org Wed Mar 29 10:33:47 2023 From: webhook-mailer at python.org (zooba) Date: Wed, 29 Mar 2023 14:33:47 -0000 Subject: [Python-checkins] gh-103097: Add workaround for Windows ARM64 compiler bug (GH-103098) Message-ID: https://github.com/python/cpython/commit/4abf1f1e3fe91f905faa6dd269c7a9aefea2a5a8 commit: 4abf1f1e3fe91f905faa6dd269c7a9aefea2a5a8 branch: 3.10 author: Steve Dower committer: zooba date: 2023-03-29T15:33:39+01:00 summary: gh-103097: Add workaround for Windows ARM64 compiler bug (GH-103098) See https://developercommunity.visualstudio.com/t/Regression-in-MSVC-1433-1434-ARM64-co/10224361 for details of the issue. It only applies to version 14.34. files: M PCbuild/pyproject.props diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index f3068978fcbc..28fa0e8bf287 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -21,6 +21,13 @@ false + + <_VCToolsVersion>$([System.Version]::Parse(`$(VCToolsVersion)`).Major).$([System.Version]::Parse(`$(VCToolsVersion)`).Minor) + + + true + + <_DebugPreprocessorDefinition>NDEBUG; <_DebugPreprocessorDefinition Condition="$(Configuration) == 'Debug'">_DEBUG; @@ -47,6 +54,7 @@ true $(EnableControlFlowGuard) /utf-8 %(AdditionalOptions) + -d2pattern-opt-disable:-932189325 %(AdditionalOptions) OnlyExplicitInline @@ -76,6 +84,7 @@ PGUpdate advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;%(AdditionalDependencies) /OPT:REF,NOICF /CGTHREADS:1 /PDBTHREADS:1 %(AdditionalOptions) + -d2:-pattern-opt-disable:-932189325 %(AdditionalOptions) true From webhook-mailer at python.org Wed Mar 29 15:22:07 2023 From: webhook-mailer at python.org (terryjreedy) Date: Wed, 29 Mar 2023 19:22:07 -0000 Subject: [Python-checkins] gh-103112: Add http.client.HTTPResponse.read docstring and fix pydoc output (#103113) Message-ID: https://github.com/python/cpython/commit/d052a383f1a0c599c176a12c73a761ca00436d8b commit: d052a383f1a0c599c176a12c73a761ca00436d8b branch: main author: Bernhard Wagner committer: terryjreedy date: 2023-03-29T15:21:56-04:00 summary: gh-103112: Add http.client.HTTPResponse.read docstring and fix pydoc output (#103113) Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Terry Jan Reedy Co-authored-by: ?ric files: A Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst M Lib/http/client.py diff --git a/Lib/http/client.py b/Lib/http/client.py index 15c5cf634cf5..bd55e7d239af 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -448,6 +448,7 @@ def isclosed(self): return self.fp is None def read(self, amt=None): + """Read and return the response body, or up to the next amt bytes.""" if self.fp is None: return b"" diff --git a/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst b/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst new file mode 100644 index 000000000000..babc81509661 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst @@ -0,0 +1 @@ +Add docstring to :meth:`http.client.HTTPResponse.read` to fix ``pydoc`` output. From webhook-mailer at python.org Wed Mar 29 16:28:17 2023 From: webhook-mailer at python.org (brettcannon) Date: Wed, 29 Mar 2023 20:28:17 -0000 Subject: [Python-checkins] GH-102973: add a dev container (GH-102975) Message-ID: https://github.com/python/cpython/commit/0b1d9c44f1f091a499856d81542eeafda25011e1 commit: 0b1d9c44f1f091a499856d81542eeafda25011e1 branch: main author: Brett Cannon committer: brettcannon date: 2023-03-29T13:28:08-07:00 summary: GH-102973: add a dev container (GH-102975) On content update, builds `python` and the docs. Also adds a Dockerfile that should include everything but autoconf 2.69 that's necessary to build CPython and the entire stdlib on Fedora. Co-authored-by: Ronald Oussoren Co-authored-by: Dusty Phillips files: A .devcontainer/Dockerfile A .devcontainer/devcontainer.json A Misc/NEWS.d/next/Build/2023-03-23-20-58-56.gh-issue-102973.EaJUrw.rst M Tools/wasm/Setup.local.example diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000000..ce8967337b02 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,24 @@ +FROM docker.io/library/fedora:37 + +ENV CC=clang + +ENV WASI_SDK_VERSION=19 +ENV WASI_SDK_PATH=/opt/wasi-sdk + +ENV WASMTIME_HOME=/opt/wasmtime +ENV WASMTIME_VERSION=7.0.0 +ENV WASMTIME_CPU_ARCH=x86_64 + +RUN dnf -y --nodocs install git clang xz python3-blurb dnf-plugins-core && \ + dnf -y --nodocs builddep python3 && \ + dnf -y clean all + +RUN mkdir ${WASI_SDK_PATH} && \ + curl --location https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_VERSION}.0-linux.tar.gz | \ + tar --strip-components 1 --directory ${WASI_SDK_PATH} --extract --gunzip + +RUN mkdir --parents ${WASMTIME_HOME} && \ + curl --location "https://github.com/bytecodealliance/wasmtime/releases/download/v${WASMTIME_VERSION}/wasmtime-v${WASMTIME_VERSION}-${WASMTIME_CPU_ARCH}-linux.tar.xz" | \ + xz --decompress | \ + tar --strip-components 1 --directory ${WASMTIME_HOME} -x && \ + ln -s ${WASMTIME_HOME}/wasmtime /usr/local/bin diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..e3fb4c6c88f4 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,75 @@ +{ + "build": { + "dockerfile": "Dockerfile" + }, + "onCreateCommand": [ + // Install common tooling. + "dnf", + "install", + "-y", + "which", + "zsh", + "fish" + ], + "updateContentCommand": { + // Using the shell for `nproc` usage. + "python": "./configure --config-cache --with-pydebug && make -s -j `nproc`", + "docs": [ + "make", + "--directory", + "Doc", + "venv", + "html" + ] + }, + "customizations": { + "vscode": { + "extensions": [ + // Highlighting for Parser/Python.asdl. + "brettcannon.zephyr-asdl", + // Highlighting for configure.ac. + "maelvalais.autoconf", + // C auto-complete. + "ms-vscode.cpptools", + // To view built docs. + "ms-vscode.live-server" + // https://github.com/microsoft/vscode-python/issues/18073 + // "ms-python.python" + ], + "settings": { + "C_Cpp.default.cStandard": "c11", + "C_Cpp.default.defines": [ + "Py_BUILD_CORE" + ], + // https://github.com/microsoft/vscode-cpptools/issues/10732 + "C_Cpp.errorSquiggles": "disabled", + "editor.insertSpaces": true, + "editor.rulers": [ + 80 + ], + "editor.tabSize": 4, + "editor.trimAutoWhitespace": true, + "files.associations": { + "*.h": "c" + }, + "files.encoding": "utf8", + "files.eol": "\n", + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "python.analysis.diagnosticSeverityOverrides": { + // Complains about shadowing the stdlib w/ the stdlib. + "reportShadowedImports": "none", + // Doesn't like _frozen_importlib. + "reportMissingImports": "none" + }, + "python.analysis.extraPaths": [ + "Lib" + ], + "python.defaultInterpreterPath": "./python", + "[restructuredtext]": { + "editor.tabSize": 3 + } + } + } + } +} diff --git a/Misc/NEWS.d/next/Build/2023-03-23-20-58-56.gh-issue-102973.EaJUrw.rst b/Misc/NEWS.d/next/Build/2023-03-23-20-58-56.gh-issue-102973.EaJUrw.rst new file mode 100644 index 000000000000..38b02391266f --- /dev/null +++ b/Misc/NEWS.d/next/Build/2023-03-23-20-58-56.gh-issue-102973.EaJUrw.rst @@ -0,0 +1,2 @@ +Add a dev container (along with accompanying Dockerfile) for development +purposes. diff --git a/Tools/wasm/Setup.local.example b/Tools/wasm/Setup.local.example index ad58c31a2efe..cfb9f7fc8755 100644 --- a/Tools/wasm/Setup.local.example +++ b/Tools/wasm/Setup.local.example @@ -5,6 +5,7 @@ audioop _bz2 _crypt _decimal +nis _pickle pyexpat _elementtree _sha3 _blake2 From webhook-mailer at python.org Wed Mar 29 18:08:47 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 29 Mar 2023 22:08:47 -0000 Subject: [Python-checkins] gh-90110: Bring the whitelists up to date. (gh-103114) Message-ID: https://github.com/python/cpython/commit/e647dbaded898e5399d01d06771c1b42b5631be8 commit: e647dbaded898e5399d01d06771c1b42b5631be8 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-29T16:08:40-06:00 summary: gh-90110: Bring the whitelists up to date. (gh-103114) https://github.com/python/cpython/issues/90110 files: M Tools/c-analyzer/cpython/globals-to-fix.tsv M Tools/c-analyzer/cpython/ignored.tsv diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 57b8542fb464..e0e45265209f 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -457,7 +457,6 @@ Modules/_decimal/_decimal.c - extended_context_template - Modules/_decimal/_decimal.c - round_map - Modules/_decimal/_decimal.c - Rational - Modules/_decimal/_decimal.c - SignalTuple - -Modules/arraymodule.c array_array___reduce_ex___impl array_reconstructor - ## state Modules/_asynciomodule.c - fi_freelist - @@ -539,7 +538,6 @@ Modules/_tkinter.c - command_mutex - Modules/_tkinter.c - HeadFHCD - Modules/_tkinter.c - stdin_ready - Modules/_tkinter.c - event_tstate - -Modules/_xxinterpchannelsmodule.c - _globals - Modules/readline.c - completer_word_break_characters - Modules/readline.c - _history_length - Modules/readline.c - should_auto_add_history - diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 9203c1888149..a8ba88efc732 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -156,6 +156,9 @@ Modules/faulthandler.c faulthandler_dump_traceback reentrant - Python/pylifecycle.c _Py_FatalErrorFormat reentrant - Python/pylifecycle.c fatal_error reentrant - +# explicitly protected, internal-only +Modules/_xxinterpchannelsmodule.c - _globals - + ################################## ## not significant From webhook-mailer at python.org Wed Mar 29 18:30:12 2023 From: webhook-mailer at python.org (terryjreedy) Date: Wed, 29 Mar 2023 22:30:12 -0000 Subject: [Python-checkins] [3.11] gh-103112: Add http.client.HTTPResponse.read docstring and fix pydoc output (GH-103113) (#103119) Message-ID: https://github.com/python/cpython/commit/ae42c1d168a3672964ffbb248e419417812ad9c0 commit: ae42c1d168a3672964ffbb248e419417812ad9c0 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy date: 2023-03-29T18:30:03-04:00 summary: [3.11] gh-103112: Add http.client.HTTPResponse.read docstring and fix pydoc output (GH-103113) (#103119) (cherry picked from commit d052a383f1a0c599c176a12c73a761ca00436d8b) Co-authored-by: Bernhard Wagner Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Terry Jan Reedy Co-authored-by: ?ric files: A Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst M Lib/http/client.py diff --git a/Lib/http/client.py b/Lib/http/client.py index 4622a8f4297d..eabb0ca26940 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -448,6 +448,7 @@ def isclosed(self): return self.fp is None def read(self, amt=None): + """Read and return the response body, or up to the next amt bytes.""" if self.fp is None: return b"" diff --git a/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst b/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst new file mode 100644 index 000000000000..babc81509661 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst @@ -0,0 +1 @@ +Add docstring to :meth:`http.client.HTTPResponse.read` to fix ``pydoc`` output. From webhook-mailer at python.org Wed Mar 29 18:30:34 2023 From: webhook-mailer at python.org (terryjreedy) Date: Wed, 29 Mar 2023 22:30:34 -0000 Subject: [Python-checkins] [3.10] gh-103112: Add http.client.HTTPResponse.read docstring and fix pydoc output (GH-103113) (#103120) Message-ID: https://github.com/python/cpython/commit/3a27be79527368804c3a1c19c5bbe07a8e8ce41e commit: 3a27be79527368804c3a1c19c5bbe07a8e8ce41e branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: terryjreedy date: 2023-03-29T18:30:27-04:00 summary: [3.10] gh-103112: Add http.client.HTTPResponse.read docstring and fix pydoc output (GH-103113) (#103120) (cherry picked from commit d052a383f1a0c599c176a12c73a761ca00436d8b) Co-authored-by: Bernhard Wagner Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Terry Jan Reedy Co-authored-by: ?ric files: A Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst M Lib/http/client.py diff --git a/Lib/http/client.py b/Lib/http/client.py index 28527fa8786e..d1b7b1048c91 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -448,6 +448,7 @@ def isclosed(self): return self.fp is None def read(self, amt=None): + """Read and return the response body, or up to the next amt bytes.""" if self.fp is None: return b"" diff --git a/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst b/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst new file mode 100644 index 000000000000..babc81509661 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-03-29-14-51-39.gh-issue-103112.XgGSEO.rst @@ -0,0 +1 @@ +Add docstring to :meth:`http.client.HTTPResponse.read` to fix ``pydoc`` output. From webhook-mailer at python.org Wed Mar 29 18:53:45 2023 From: webhook-mailer at python.org (brandtbucher) Date: Wed, 29 Mar 2023 22:53:45 -0000 Subject: [Python-checkins] GH-89987: Shrink the BINARY_SUBSCR caches (GH-103022) Message-ID: https://github.com/python/cpython/commit/121057aa3600c4d4d392539aeb79e1b09fd5659d commit: 121057aa3600c4d4d392539aeb79e1b09fd5659d branch: main author: Brandt Bucher committer: brandtbucher date: 2023-03-29T15:53:30-07:00 summary: GH-89987: Shrink the BINARY_SUBSCR caches (GH-103022) files: A Misc/NEWS.d/next/Core and Builtins/2023-03-24-02-50-33.gh-issue-89987.oraTzh.rst M Include/cpython/object.h M Include/internal/pycore_code.h M Include/internal/pycore_opcode.h M Lib/importlib/_bootstrap_external.py M Lib/opcode.py M Lib/test/test_dis.py M Lib/test/test_sys.py M Objects/typeobject.c M Programs/test_frozenmain.h M Python/bytecodes.c M Python/generated_cases.c.h M Python/opcode_metadata.h M Python/specialize.c diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 859ffb91e223..98cc51cd7fee 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -234,7 +234,18 @@ struct _typeobject { * It should should be treated as an opaque blob * by code other than the specializer and interpreter. */ struct _specialization_cache { + // In order to avoid bloating the bytecode with lots of inline caches, the + // members of this structure have a somewhat unique contract. They are set + // by the specialization machinery, and are invalidated by PyType_Modified. + // The rules for using them are as follows: + // - If getitem is non-NULL, then it is the same Python function that + // PyType_Lookup(cls, "__getitem__") would return. + // - If getitem is NULL, then getitem_version is meaningless. + // - If getitem->func_version == getitem_version, then getitem can be called + // with two positional arguments and no keyword arguments, and has neither + // *args nor **kwargs (as required by BINARY_SUBSCR_GETITEM): PyObject *getitem; + uint32_t getitem_version; }; /* The *real* layout of a type object when allocated on the heap */ diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 3359dfd8a499..7f3148a38ff1 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -47,8 +47,6 @@ typedef struct { typedef struct { uint16_t counter; - uint16_t type_version[2]; - uint16_t func_version; } _PyBinarySubscrCache; #define INLINE_CACHE_ENTRIES_BINARY_SUBSCR CACHE_ENTRIES(_PyBinarySubscrCache) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 4a0b27a13ae9..22914da07994 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -41,7 +41,7 @@ static const uint32_t _PyOpcode_Jump[9] = { }; const uint8_t _PyOpcode_Caches[256] = { - [BINARY_SUBSCR] = 4, + [BINARY_SUBSCR] = 1, [STORE_SUBSCR] = 1, [UNPACK_SEQUENCE] = 1, [FOR_ITER] = 1, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 28e55fdc8b7d..9c4c5f907744 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -435,7 +435,9 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a6 3519 (Modify SEND instruction) # Python 3.12a6 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) # Python 3.12a7 3521 (Shrink the LOAD_GLOBAL caches) +# Python 3.12a7 3522 (Removed JUMP_IF_FALSE_OR_POP/JUMP_IF_TRUE_OR_POP) # Python 3.12a7 3523 (Convert COMPARE_AND_BRANCH back to COMPARE_OP) +# Python 3.12a7 3524 (Shrink the BINARY_SUBSCR caches) # Python 3.13 will start with 3550 @@ -452,7 +454,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3523).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3524).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 60670f571fdc..16a61dff47b5 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -392,8 +392,6 @@ def pseudo_op(name, op, real_ops): }, "BINARY_SUBSCR": { "counter": 1, - "type_version": 2, - "func_version": 1, }, "FOR_ITER": { "counter": 1, diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 7cad8d1bfe13..7e501045662f 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1108,7 +1108,7 @@ def test_binary_specialize(self): 1 2 LOAD_NAME 0 (a) 4 LOAD_CONST 0 (0) 6 %s - 16 RETURN_VALUE + 10 RETURN_VALUE """ co_list = compile('a[0]', "", "eval") self.code_quicken(lambda: exec(co_list, {}, {'a': [0]})) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index fb578c5ae6e5..d7456d6d9480 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1556,7 +1556,7 @@ def delx(self): del self.__x '10P' # PySequenceMethods '2P' # PyBufferProcs '6P' - '1P' # Specializer cache + '1PI' # Specializer cache ) class newstyleclass(object): pass # Separate block for PyDictKeysObject with 8 keys and 5 entries diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-24-02-50-33.gh-issue-89987.oraTzh.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-24-02-50-33.gh-issue-89987.oraTzh.rst new file mode 100644 index 000000000000..507f68b0c5af --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-24-02-50-33.gh-issue-89987.oraTzh.rst @@ -0,0 +1,2 @@ +Reduce the number of inline :opcode:`CACHE` entries for +:opcode:`BINARY_SUBSCR`. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 69e84743f13a..24541bddbbc3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -510,6 +510,11 @@ PyType_Modified(PyTypeObject *type) type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; type->tp_version_tag = 0; /* 0 is not a valid version tag */ + if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { + // This field *must* be invalidated if the type is modified (see the + // comment on struct _specialization_cache): + ((PyHeapTypeObject *)type)->_spec_cache.getitem = NULL; + } } static void @@ -563,6 +568,11 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) { clear: type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; type->tp_version_tag = 0; /* 0 is not a valid version tag */ + if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) { + // This field *must* be invalidated if the type is modified (see the + // comment on struct _specialization_cache): + ((PyHeapTypeObject *)type)->_spec_cache.getitem = NULL; + } } static int diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 8e5055bd7bce..c33bb18f4da8 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,39 +1,38 @@ // 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,8,0,0, - 0,0,0,0,0,243,182,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,243,170,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, 100,2,171,1,0,0,0,0,0,0,0,0,1,0,2,0, 101,2,100,3,101,0,106,6,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,171,2,0,0,0,0, 0,0,0,0,1,0,2,0,101,1,106,8,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,171,0, - 0,0,0,0,0,0,0,0,100,4,25,0,0,0,0,0, - 0,0,0,0,90,5,100,5,68,0,93,23,0,0,90,6, - 2,0,101,2,100,6,101,6,155,0,100,7,101,5,101,6, - 25,0,0,0,0,0,0,0,0,0,155,0,157,4,171,1, - 0,0,0,0,0,0,0,0,1,0,140,25,4,0,121,1, - 41,8,233,0,0,0,0,78,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,41,5, - 218,12,112,114,111,103,114,97,109,95,110,97,109,101,218,10, - 101,120,101,99,117,116,97,98,108,101,218,15,117,115,101,95, - 101,110,118,105,114,111,110,109,101,110,116,218,17,99,111,110, - 102,105,103,117,114,101,95,99,95,115,116,100,105,111,218,14, - 98,117,102,102,101,114,101,100,95,115,116,100,105,111,122,7, - 99,111,110,102,105,103,32,122,2,58,32,41,7,218,3,115, - 121,115,218,17,95,116,101,115,116,105,110,116,101,114,110,97, - 108,99,97,112,105,218,5,112,114,105,110,116,218,4,97,114, - 103,118,218,11,103,101,116,95,99,111,110,102,105,103,115,114, - 3,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0, - 250,18,116,101,115,116,95,102,114,111,122,101,110,109,97,105, - 110,46,112,121,250,8,60,109,111,100,117,108,101,62,114,18, - 0,0,0,1,0,0,0,115,100,0,0,0,240,3,1,1, - 1,243,8,0,1,11,219,0,24,225,0,5,208,6,26,213, - 0,27,217,0,5,128,106,144,35,151,40,145,40,213,0,27, - 216,9,38,208,9,26,215,9,38,209,9,38,212,9,40,168, - 24,212,9,50,128,6,240,2,6,12,2,242,0,7,1,42, - 128,67,241,14,0,5,10,208,10,40,144,67,209,10,40,152, - 54,160,35,156,59,209,10,40,214,4,41,241,15,7,1,42, - 114,16,0,0,0, + 0,0,0,0,0,0,0,0,100,4,25,0,0,0,90,5, + 100,5,68,0,93,20,0,0,90,6,2,0,101,2,100,6, + 101,6,155,0,100,7,101,5,101,6,25,0,0,0,155,0, + 157,4,171,1,0,0,0,0,0,0,0,0,1,0,140,22, + 4,0,121,1,41,8,233,0,0,0,0,78,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,41,5,218,12,112,114,111,103,114,97,109,95,110,97, + 109,101,218,10,101,120,101,99,117,116,97,98,108,101,218,15, + 117,115,101,95,101,110,118,105,114,111,110,109,101,110,116,218, + 17,99,111,110,102,105,103,117,114,101,95,99,95,115,116,100, + 105,111,218,14,98,117,102,102,101,114,101,100,95,115,116,100, + 105,111,122,7,99,111,110,102,105,103,32,122,2,58,32,41, + 7,218,3,115,121,115,218,17,95,116,101,115,116,105,110,116, + 101,114,110,97,108,99,97,112,105,218,5,112,114,105,110,116, + 218,4,97,114,103,118,218,11,103,101,116,95,99,111,110,102, + 105,103,115,114,3,0,0,0,218,3,107,101,121,169,0,243, + 0,0,0,0,250,18,116,101,115,116,95,102,114,111,122,101, + 110,109,97,105,110,46,112,121,250,8,60,109,111,100,117,108, + 101,62,114,18,0,0,0,1,0,0,0,115,100,0,0,0, + 240,3,1,1,1,243,8,0,1,11,219,0,24,225,0,5, + 208,6,26,213,0,27,217,0,5,128,106,144,35,151,40,145, + 40,213,0,27,216,9,38,208,9,26,215,9,38,209,9,38, + 212,9,40,168,24,209,9,50,128,6,240,2,6,12,2,242, + 0,7,1,42,128,67,241,14,0,5,10,208,10,40,144,67, + 209,10,40,152,54,160,35,153,59,209,10,40,214,4,41,241, + 15,7,1,42,114,16,0,0,0, }; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 2fe85dfeedf4..484f6e6b1a1c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -292,7 +292,7 @@ dummy_func( BINARY_SUBSCR_TUPLE_INT, }; - inst(BINARY_SUBSCR, (unused/4, container, sub -- res)) { + inst(BINARY_SUBSCR, (unused/1, container, sub -- res)) { #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -339,7 +339,7 @@ dummy_func( ERROR_IF(err, error); } - inst(BINARY_SUBSCR_LIST_INT, (unused/4, list, sub -- res)) { + inst(BINARY_SUBSCR_LIST_INT, (unused/1, list, sub -- res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -356,7 +356,7 @@ dummy_func( Py_DECREF(list); } - inst(BINARY_SUBSCR_TUPLE_INT, (unused/4, tuple, sub -- res)) { + inst(BINARY_SUBSCR_TUPLE_INT, (unused/1, tuple, sub -- res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -373,7 +373,7 @@ dummy_func( Py_DECREF(tuple); } - inst(BINARY_SUBSCR_DICT, (unused/4, dict, sub -- res)) { + inst(BINARY_SUBSCR_DICT, (unused/1, dict, sub -- res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -389,14 +389,16 @@ dummy_func( DECREF_INPUTS(); } - inst(BINARY_SUBSCR_GETITEM, (unused/1, type_version/2, func_version/1, container, sub -- unused)) { + inst(BINARY_SUBSCR_GETITEM, (unused/1, container, sub -- unused)) { PyTypeObject *tp = Py_TYPE(container); - DEOPT_IF(tp->tp_version_tag != type_version, BINARY_SUBSCR); - assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); - PyObject *cached = ((PyHeapTypeObject *)tp)->_spec_cache.getitem; + DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); + PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; + PyObject *cached = ht->_spec_cache.getitem; + DEOPT_IF(cached == NULL, BINARY_SUBSCR); assert(PyFunction_Check(cached)); PyFunctionObject *getitem = (PyFunctionObject *)cached; - DEOPT_IF(getitem->func_version != func_version, BINARY_SUBSCR); + uint32_t cached_version = ht->_spec_cache.getitem_version; + DEOPT_IF(getitem->func_version != cached_version, BINARY_SUBSCR); PyCodeObject *code = (PyCodeObject *)getitem->func_code; assert(code->co_argcount == 2); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d793c1e23bc4..d9c66343430f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -461,7 +461,7 @@ TARGET(BINARY_SUBSCR) { PREDICTED(BINARY_SUBSCR); - static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 4, "incorrect cache size"); + static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; @@ -486,7 +486,7 @@ #line 487 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 1; DISPATCH(); } @@ -559,7 +559,7 @@ #line 560 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 1; DISPATCH(); } @@ -585,7 +585,7 @@ #line 586 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 1; DISPATCH(); } @@ -614,23 +614,23 @@ Py_DECREF(sub); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + next_instr += 1; DISPATCH(); } TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - uint32_t type_version = read_u32(&next_instr[1].cache); - uint16_t func_version = read_u16(&next_instr[3].cache); #line 393 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(container); - DEOPT_IF(tp->tp_version_tag != type_version, BINARY_SUBSCR); - assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); - PyObject *cached = ((PyHeapTypeObject *)tp)->_spec_cache.getitem; + DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); + PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; + PyObject *cached = ht->_spec_cache.getitem; + DEOPT_IF(cached == NULL, BINARY_SUBSCR); assert(PyFunction_Check(cached)); PyFunctionObject *getitem = (PyFunctionObject *)cached; - DEOPT_IF(getitem->func_version != func_version, BINARY_SUBSCR); + uint32_t cached_version = ht->_spec_cache.getitem_version; + DEOPT_IF(getitem->func_version != cached_version, BINARY_SUBSCR); PyCodeObject *code = (PyCodeObject *)getitem->func_code; assert(code->co_argcount == 2); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR); @@ -648,7 +648,7 @@ TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 414 "Python/bytecodes.c" + #line 416 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 654 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -659,11 +659,11 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 419 "Python/bytecodes.c" + #line 421 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 665 "Python/generated_cases.c.h" Py_DECREF(v); - #line 421 "Python/bytecodes.c" + #line 423 "Python/bytecodes.c" if (err) goto pop_1_error; #line 669 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -678,7 +678,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 432 "Python/bytecodes.c" + #line 434 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -698,7 +698,7 @@ Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 448 "Python/bytecodes.c" + #line 450 "Python/bytecodes.c" if (err) goto pop_3_error; #line 704 "Python/generated_cases.c.h" STACK_SHRINK(3); @@ -710,7 +710,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 452 "Python/bytecodes.c" + #line 454 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -738,7 +738,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 472 "Python/bytecodes.c" + #line 474 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); @@ -754,13 +754,13 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 481 "Python/bytecodes.c" + #line 483 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 761 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 484 "Python/bytecodes.c" + #line 486 "Python/bytecodes.c" if (err) goto pop_2_error; #line 766 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -770,12 +770,12 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 488 "Python/bytecodes.c" + #line 490 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 777 "Python/generated_cases.c.h" Py_DECREF(value); - #line 491 "Python/bytecodes.c" + #line 493 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 781 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -786,13 +786,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 495 "Python/bytecodes.c" + #line 497 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 793 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 498 "Python/bytecodes.c" + #line 500 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 798 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -802,7 +802,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 502 "Python/bytecodes.c" + #line 504 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -825,7 +825,7 @@ TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 522 "Python/bytecodes.c" + #line 524 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -842,7 +842,7 @@ TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 536 "Python/bytecodes.c" + #line 538 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -860,7 +860,7 @@ } TARGET(RETURN_CONST) { - #line 552 "Python/bytecodes.c" + #line 554 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -881,7 +881,7 @@ TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 569 "Python/bytecodes.c" + #line 571 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -896,14 +896,14 @@ type->tp_name); #line 898 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 582 "Python/bytecodes.c" + #line 584 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 905 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 587 "Python/bytecodes.c" + #line 589 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -924,7 +924,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 602 "Python/bytecodes.c" + #line 604 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -979,7 +979,7 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 649 "Python/bytecodes.c" + #line 651 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -988,7 +988,7 @@ #line 990 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 656 "Python/bytecodes.c" + #line 658 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1017,7 +1017,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 682 "Python/bytecodes.c" + #line 684 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1062,7 +1062,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 720 "Python/bytecodes.c" + #line 722 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1083,7 +1083,7 @@ TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 738 "Python/bytecodes.c" + #line 740 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1107,7 +1107,7 @@ TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 759 "Python/bytecodes.c" + #line 761 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 1114 "Python/generated_cases.c.h" @@ -1118,7 +1118,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 764 "Python/bytecodes.c" + #line 766 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1142,13 +1142,13 @@ TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 784 "Python/bytecodes.c" + #line 786 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { #line 1149 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 787 "Python/bytecodes.c" + #line 789 "Python/bytecodes.c" } else { Py_INCREF(exc); @@ -1166,7 +1166,7 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 796 "Python/bytecodes.c" + #line 798 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { @@ -1175,7 +1175,7 @@ Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 801 "Python/bytecodes.c" + #line 803 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { @@ -1191,7 +1191,7 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 810 "Python/bytecodes.c" + #line 812 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 1197 "Python/generated_cases.c.h" STACK_GROW(1); @@ -1201,7 +1201,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 814 "Python/bytecodes.c" + #line 816 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1231,7 +1231,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 838 "Python/bytecodes.c" + #line 840 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1240,7 +1240,7 @@ "no locals found when storing %R", name); #line 1242 "Python/generated_cases.c.h" Py_DECREF(v); - #line 845 "Python/bytecodes.c" + #line 847 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -1249,7 +1249,7 @@ err = PyObject_SetItem(ns, name, v); #line 1251 "Python/generated_cases.c.h" Py_DECREF(v); - #line 852 "Python/bytecodes.c" + #line 854 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1255 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1257,7 +1257,7 @@ } TARGET(DELETE_NAME) { - #line 856 "Python/bytecodes.c" + #line 858 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1282,7 +1282,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 882 "Python/bytecodes.c" + #line 884 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1298,7 +1298,7 @@ int res = unpack_iterable(tstate, seq, oparg, -1, top); #line 1300 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 896 "Python/bytecodes.c" + #line 898 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1304 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1310,7 +1310,7 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 900 "Python/bytecodes.c" + #line 902 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -1328,7 +1328,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 910 "Python/bytecodes.c" + #line 912 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1347,7 +1347,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 921 "Python/bytecodes.c" + #line 923 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1365,13 +1365,13 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 932 "Python/bytecodes.c" + #line 934 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); #line 1373 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 936 "Python/bytecodes.c" + #line 938 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1377 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -1384,7 +1384,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 947 "Python/bytecodes.c" + #line 949 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -1404,7 +1404,7 @@ #line 1405 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 964 "Python/bytecodes.c" + #line 966 "Python/bytecodes.c" if (err) goto pop_2_error; #line 1410 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -1414,12 +1414,12 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 968 "Python/bytecodes.c" + #line 970 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 1421 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 971 "Python/bytecodes.c" + #line 973 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1425 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1428,12 +1428,12 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 975 "Python/bytecodes.c" + #line 977 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 1435 "Python/generated_cases.c.h" Py_DECREF(v); - #line 978 "Python/bytecodes.c" + #line 980 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1439 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1441,7 +1441,7 @@ } TARGET(DELETE_GLOBAL) { - #line 982 "Python/bytecodes.c" + #line 984 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1459,7 +1459,7 @@ TARGET(LOAD_NAME) { PyObject *v; - #line 996 "Python/bytecodes.c" + #line 998 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1529,7 +1529,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1063 "Python/bytecodes.c" + #line 1065 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1596,7 +1596,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1118 "Python/bytecodes.c" + #line 1120 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -1623,7 +1623,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1132 "Python/bytecodes.c" + #line 1134 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); @@ -1648,7 +1648,7 @@ } TARGET(DELETE_FAST) { - #line 1149 "Python/bytecodes.c" + #line 1151 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); @@ -1657,7 +1657,7 @@ } TARGET(MAKE_CELL) { - #line 1155 "Python/bytecodes.c" + #line 1157 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1671,7 +1671,7 @@ } TARGET(DELETE_DEREF) { - #line 1166 "Python/bytecodes.c" + #line 1168 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1688,7 +1688,7 @@ TARGET(LOAD_CLASSDEREF) { PyObject *value; - #line 1179 "Python/bytecodes.c" + #line 1181 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1728,7 +1728,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1213 "Python/bytecodes.c" + #line 1215 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1744,7 +1744,7 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1223 "Python/bytecodes.c" + #line 1225 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); @@ -1755,7 +1755,7 @@ } TARGET(COPY_FREE_VARS) { - #line 1230 "Python/bytecodes.c" + #line 1232 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1773,13 +1773,13 @@ TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1243 "Python/bytecodes.c" + #line 1245 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 1779 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1245 "Python/bytecodes.c" + #line 1247 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 1785 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -1791,7 +1791,7 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1249 "Python/bytecodes.c" + #line 1251 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 1798 "Python/generated_cases.c.h" @@ -1804,7 +1804,7 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1254 "Python/bytecodes.c" + #line 1256 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 1811 "Python/generated_cases.c.h" @@ -1817,7 +1817,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1259 "Python/bytecodes.c" + #line 1261 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1830,7 +1830,7 @@ } #line 1832 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1270 "Python/bytecodes.c" + #line 1272 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); @@ -1843,11 +1843,11 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1277 "Python/bytecodes.c" + #line 1279 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 1849 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1279 "Python/bytecodes.c" + #line 1281 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 1853 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1857,7 +1857,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1283 "Python/bytecodes.c" + #line 1285 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1882,7 +1882,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1300 "Python/bytecodes.c" + #line 1302 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1894,7 +1894,7 @@ for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1308 "Python/bytecodes.c" + #line 1310 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 1900 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); @@ -1904,7 +1904,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1312 "Python/bytecodes.c" + #line 1314 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1952,7 +1952,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1354 "Python/bytecodes.c" + #line 1356 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1967,7 +1967,7 @@ Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1364 "Python/bytecodes.c" + #line 1366 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 1973 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -1977,7 +1977,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1368 "Python/bytecodes.c" + #line 1370 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1987,7 +1987,7 @@ } #line 1989 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1376 "Python/bytecodes.c" + #line 1378 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 1994 "Python/generated_cases.c.h" @@ -1998,14 +1998,14 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1382 "Python/bytecodes.c" + #line 1384 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); #line 2007 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1387 "Python/bytecodes.c" + #line 1389 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2012 "Python/generated_cases.c.h" @@ -2018,7 +2018,7 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1394 "Python/bytecodes.c" + #line 1396 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ @@ -2036,7 +2036,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1417 "Python/bytecodes.c" + #line 1419 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2073,7 +2073,7 @@ */ #line 2075 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1452 "Python/bytecodes.c" + #line 1454 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2084,7 +2084,7 @@ res = PyObject_GetAttr(owner, name); #line 2086 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1461 "Python/bytecodes.c" + #line 1463 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 2091 "Python/generated_cases.c.h" @@ -2101,7 +2101,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1466 "Python/bytecodes.c" + #line 1468 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2130,7 +2130,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1483 "Python/bytecodes.c" + #line 1485 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; @@ -2159,7 +2159,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1500 "Python/bytecodes.c" + #line 1502 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2202,7 +2202,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1531 "Python/bytecodes.c" + #line 1533 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2228,7 +2228,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1545 "Python/bytecodes.c" + #line 1547 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); @@ -2255,7 +2255,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1561 "Python/bytecodes.c" + #line 1563 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); @@ -2287,7 +2287,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1587 "Python/bytecodes.c" + #line 1589 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2321,7 +2321,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1615 "Python/bytecodes.c" + #line 1617 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2351,7 +2351,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1636 "Python/bytecodes.c" + #line 1638 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2402,7 +2402,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1678 "Python/bytecodes.c" + #line 1680 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2425,7 +2425,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1698 "Python/bytecodes.c" + #line 1700 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2442,7 +2442,7 @@ #line 2443 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1712 "Python/bytecodes.c" + #line 1714 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2448 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2455,7 +2455,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1716 "Python/bytecodes.c" + #line 1718 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); @@ -2479,7 +2479,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1732 "Python/bytecodes.c" + #line 1734 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); @@ -2507,7 +2507,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1752 "Python/bytecodes.c" + #line 1754 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); @@ -2532,12 +2532,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1768 "Python/bytecodes.c" + #line 1770 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 2538 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1770 "Python/bytecodes.c" + #line 1772 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); #line 2543 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2549,12 +2549,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1774 "Python/bytecodes.c" + #line 1776 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 2555 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1776 "Python/bytecodes.c" + #line 1778 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); #line 2561 "Python/generated_cases.c.h" @@ -2568,12 +2568,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1781 "Python/bytecodes.c" + #line 1783 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 2574 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1783 "Python/bytecodes.c" + #line 1785 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2584,7 +2584,7 @@ #line 2585 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1791 "Python/bytecodes.c" + #line 1793 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2603,19 +2603,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1802 "Python/bytecodes.c" + #line 1804 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 2610 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1805 "Python/bytecodes.c" + #line 1807 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 2617 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1810 "Python/bytecodes.c" + #line 1812 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); #line 2621 "Python/generated_cases.c.h" stack_pointer[-1] = b; @@ -2626,13 +2626,13 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 1814 "Python/bytecodes.c" + #line 1816 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); #line 2633 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 1817 "Python/bytecodes.c" + #line 1819 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2638 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2643,7 +2643,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 1821 "Python/bytecodes.c" + #line 1823 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; @@ -2654,7 +2654,7 @@ } TARGET(JUMP_FORWARD) { - #line 1827 "Python/bytecodes.c" + #line 1829 "Python/bytecodes.c" JUMPBY(oparg); #line 2660 "Python/generated_cases.c.h" DISPATCH(); @@ -2662,7 +2662,7 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 1831 "Python/bytecodes.c" + #line 1833 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); #line 2669 "Python/generated_cases.c.h" @@ -2673,7 +2673,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 1837 "Python/bytecodes.c" + #line 1839 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2685,7 +2685,7 @@ int err = PyObject_IsTrue(cond); #line 2687 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1847 "Python/bytecodes.c" + #line 1849 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2700,7 +2700,7 @@ TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 1857 "Python/bytecodes.c" + #line 1859 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2712,7 +2712,7 @@ int err = PyObject_IsTrue(cond); #line 2714 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1867 "Python/bytecodes.c" + #line 1869 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2727,11 +2727,11 @@ TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 1877 "Python/bytecodes.c" + #line 1879 "Python/bytecodes.c" if (!Py_IsNone(value)) { #line 2733 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1879 "Python/bytecodes.c" + #line 1881 "Python/bytecodes.c" JUMPBY(oparg); } else { @@ -2744,7 +2744,7 @@ TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 1887 "Python/bytecodes.c" + #line 1889 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); @@ -2752,7 +2752,7 @@ else { #line 2754 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1893 "Python/bytecodes.c" + #line 1895 "Python/bytecodes.c" } #line 2758 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2760,7 +2760,7 @@ } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 1897 "Python/bytecodes.c" + #line 1899 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. @@ -2774,7 +2774,7 @@ TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 1906 "Python/bytecodes.c" + #line 1908 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -2791,7 +2791,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 1914 "Python/bytecodes.c" + #line 1916 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -2800,7 +2800,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 1919 "Python/bytecodes.c" + #line 1921 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2817,7 +2817,7 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1929 "Python/bytecodes.c" + #line 1931 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); #line 2824 "Python/generated_cases.c.h" @@ -2830,7 +2830,7 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1935 "Python/bytecodes.c" + #line 1937 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); #line 2837 "Python/generated_cases.c.h" @@ -2844,7 +2844,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 1941 "Python/bytecodes.c" + #line 1943 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -2857,12 +2857,12 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 1947 "Python/bytecodes.c" + #line 1949 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 2864 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1950 "Python/bytecodes.c" + #line 1952 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 2868 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -2872,7 +2872,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 1954 "Python/bytecodes.c" + #line 1956 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2897,7 +2897,7 @@ } #line 2899 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1977 "Python/bytecodes.c" + #line 1979 "Python/bytecodes.c" } #line 2903 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -2910,7 +2910,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 1996 "Python/bytecodes.c" + #line 1998 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2953,7 +2953,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2031 "Python/bytecodes.c" + #line 2033 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -2984,7 +2984,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2054 "Python/bytecodes.c" + #line 2056 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -3015,7 +3015,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2077 "Python/bytecodes.c" + #line 2079 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -3043,7 +3043,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2098 "Python/bytecodes.c" + #line 2100 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3065,7 +3065,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2115 "Python/bytecodes.c" + #line 2117 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3090,7 +3090,7 @@ } #line 3092 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2138 "Python/bytecodes.c" + #line 2140 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3109,7 +3109,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2148 "Python/bytecodes.c" + #line 2150 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3137,7 +3137,7 @@ } #line 3139 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2174 "Python/bytecodes.c" + #line 2176 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3156,7 +3156,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2183 "Python/bytecodes.c" + #line 2185 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3186,7 +3186,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2206 "Python/bytecodes.c" + #line 2208 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3210,7 +3210,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2218 "Python/bytecodes.c" + #line 2220 "Python/bytecodes.c" /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -3242,7 +3242,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2238 "Python/bytecodes.c" + #line 2240 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3267,7 +3267,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2251 "Python/bytecodes.c" + #line 2253 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3291,7 +3291,7 @@ } TARGET(KW_NAMES) { - #line 2268 "Python/bytecodes.c" + #line 2270 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); @@ -3306,7 +3306,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2304 "Python/bytecodes.c" + #line 2306 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3390,7 +3390,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2382 "Python/bytecodes.c" + #line 2384 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3409,7 +3409,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2394 "Python/bytecodes.c" + #line 2396 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3443,7 +3443,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); uint16_t min_args = read_u16(&next_instr[3].cache); - #line 2421 "Python/bytecodes.c" + #line 2423 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3481,7 +3481,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2453 "Python/bytecodes.c" + #line 2455 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3505,7 +3505,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2466 "Python/bytecodes.c" + #line 2468 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3531,7 +3531,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2481 "Python/bytecodes.c" + #line 2483 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3556,7 +3556,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2495 "Python/bytecodes.c" + #line 2497 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3592,7 +3592,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2520 "Python/bytecodes.c" + #line 2522 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3635,7 +3635,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2552 "Python/bytecodes.c" + #line 2554 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3682,7 +3682,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2588 "Python/bytecodes.c" + #line 2590 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3729,7 +3729,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2624 "Python/bytecodes.c" + #line 2626 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3768,7 +3768,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2652 "Python/bytecodes.c" + #line 2654 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3808,7 +3808,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2683 "Python/bytecodes.c" + #line 2685 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3834,7 +3834,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2704 "Python/bytecodes.c" + #line 2706 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3878,7 +3878,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2738 "Python/bytecodes.c" + #line 2740 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3920,7 +3920,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2770 "Python/bytecodes.c" + #line 2772 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -3962,7 +3962,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2802 "Python/bytecodes.c" + #line 2804 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4005,7 +4005,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 2833 "Python/bytecodes.c" + #line 2835 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -4028,7 +4028,7 @@ Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 2852 "Python/bytecodes.c" + #line 2854 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } @@ -4047,7 +4047,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 2863 "Python/bytecodes.c" + #line 2865 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4083,7 +4083,7 @@ } TARGET(RETURN_GENERATOR) { - #line 2894 "Python/bytecodes.c" + #line 2896 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4112,13 +4112,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 2917 "Python/bytecodes.c" + #line 2919 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 4118 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 2919 "Python/bytecodes.c" + #line 2921 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 4124 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -4131,7 +4131,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 2923 "Python/bytecodes.c" + #line 2925 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4175,7 +4175,7 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 2960 "Python/bytecodes.c" + #line 2962 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 4182 "Python/generated_cases.c.h" @@ -4190,7 +4190,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 2965 "Python/bytecodes.c" + #line 2967 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4209,7 +4209,7 @@ #line 4210 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 2981 "Python/bytecodes.c" + #line 2983 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 4215 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -4221,7 +4221,7 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 2986 "Python/bytecodes.c" + #line 2988 "Python/bytecodes.c" assert(oparg >= 2); #line 4227 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; @@ -4230,7 +4230,7 @@ } TARGET(EXTENDED_ARG) { - #line 2990 "Python/bytecodes.c" + #line 2992 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; @@ -4241,7 +4241,7 @@ } TARGET(CACHE) { - #line 2999 "Python/bytecodes.c" + #line 3001 "Python/bytecodes.c" Py_UNREACHABLE(); #line 4247 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 347a84dad463..08032519f383 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -731,13 +731,13 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IX }, [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC }, [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC }, - [BINARY_SUBSCR] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR] = { true, INSTR_FMT_IXC }, [BINARY_SLICE] = { true, INSTR_FMT_IX }, [STORE_SLICE] = { true, INSTR_FMT_IX }, - [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC }, + [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC }, + [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC }, + [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC }, [LIST_APPEND] = { true, INSTR_FMT_IB }, [SET_ADD] = { true, INSTR_FMT_IB }, [STORE_SUBSCR] = { true, INSTR_FMT_IXC }, diff --git a/Python/specialize.c b/Python/specialize.c index dd5b22dd2346..9187438d519b 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1330,16 +1330,16 @@ _Py_Specialize_BinarySubscr( SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); goto fail; } - assert(cls->tp_version_tag != 0); - write_u32(cache->type_version, cls->tp_version_tag); - int version = _PyFunction_GetVersionForCurrentState(func); - if (version == 0 || version != (uint16_t)version) { - SPECIALIZATION_FAIL(BINARY_SUBSCR, version == 0 ? - SPEC_FAIL_OUT_OF_VERSIONS : SPEC_FAIL_OUT_OF_RANGE); + uint32_t version = _PyFunction_GetVersionForCurrentState(func); + if (version == 0) { + SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } - cache->func_version = version; - ((PyHeapTypeObject *)container_type)->_spec_cache.getitem = descriptor; + PyHeapTypeObject *ht = (PyHeapTypeObject *)container_type; + // This pointer is invalidated by PyType_Modified (see the comment on + // struct _specialization_cache): + ht->_spec_cache.getitem = descriptor; + ht->_spec_cache.getitem_version = version; instr->op.code = BINARY_SUBSCR_GETITEM; goto success; } From webhook-mailer at python.org Wed Mar 29 19:16:17 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Wed, 29 Mar 2023 23:16:17 -0000 Subject: [Python-checkins] gh-100227: Make the Global PyModuleDef Cache Safe for Isolated Interpreters (gh-103084) Message-ID: https://github.com/python/cpython/commit/dcd6f226d6596b25b6f4004058a67acabe012120 commit: dcd6f226d6596b25b6f4004058a67acabe012120 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-29T17:15:43-06:00 summary: gh-100227: Make the Global PyModuleDef Cache Safe for Isolated Interpreters (gh-103084) Sharing mutable (or non-immortal) objects between interpreters is generally not safe. We can work around that but not easily. There are two restrictions that are critical for objects that break interpreter isolation. The first is that the object's state be guarded by a global lock. For now the GIL meets this requirement, but a granular global lock is needed once we have a per-interpreter GIL. The second restriction is that the object (and, for a container, its items) be deallocated/resized only when the interpreter in which it was allocated is the current one. This is because every interpreter has (or will have, see gh-101660) its own object allocator. Deallocating an object with a different allocator can cause crashes. The dict for the cache of module defs is completely internal, which simplifies what we have to do to meet those requirements. To do so, we do the following: * add a mechanism for re-using a temporary thread state tied to the main interpreter in an arbitrary thread * add _PyRuntime.imports.extensions.main_tstate` * add _PyThreadState_InitDetached() and _PyThreadState_ClearDetached() (pystate.c) * add _PyThreadState_BindDetached() and _PyThreadState_UnbindDetached() (pystate.c) * make sure the cache dict (_PyRuntime.imports.extensions.dict) and its items are all owned by the main interpreter) * add a placeholder using for a granular global lock Note that the cache is only used for legacy extension modules and not for multi-phase init modules. https://github.com/python/cpython/issues/100227 files: M Include/internal/pycore_import.h M Include/internal/pycore_pystate.h M Include/internal/pycore_runtime_init.h M Python/import.c M Python/pystate.c diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index 69ed6273b7e6..7a78a91aa617 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -14,13 +14,19 @@ struct _import_runtime_state { which is just about every time an extension module is imported. See PyInterpreterState.modules_by_index for more info. */ Py_ssize_t last_module_index; - /* A dict mapping (filename, name) to PyModuleDef for modules. - Only legacy (single-phase init) extension modules are added - and only if they support multiple initialization (m_size >- 0) - or are imported in the main interpreter. - This is initialized lazily in _PyImport_FixupExtensionObject(). - Modules are added there and looked up in _imp.find_extension(). */ - PyObject *extensions; + struct { + /* A thread state tied to the main interpreter, + used exclusively for when the extensions dict is access/modified + from an arbitrary thread. */ + PyThreadState main_tstate; + /* A dict mapping (filename, name) to PyModuleDef for modules. + Only legacy (single-phase init) extension modules are added + and only if they support multiple initialization (m_size >- 0) + or are imported in the main interpreter. + This is initialized lazily in _PyImport_FixupExtensionObject(). + Modules are added there and looked up in _imp.find_extension(). */ + PyObject *dict; + } extensions; /* Package context -- the full module name for package imports */ const char * pkgcontext; }; diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 7046ec8d9ada..b5408622d9d4 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -127,6 +127,11 @@ PyAPI_FUNC(void) _PyThreadState_Init( PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); +extern void _PyThreadState_InitDetached(PyThreadState *, PyInterpreterState *); +extern void _PyThreadState_ClearDetached(PyThreadState *); +extern void _PyThreadState_BindDetached(PyThreadState *); +extern void _PyThreadState_UnbindDetached(PyThreadState *); + static inline void _PyThreadState_UpdateTracingState(PyThreadState *tstate) diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 7cfa7c0c0249..5b09a45e41cd 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -41,6 +41,11 @@ extern PyTypeObject _PyExc_MemoryError; in accordance with the specification. */ \ .autoTSSkey = Py_tss_NEEDS_INIT, \ .parser = _parser_runtime_state_INIT, \ + .imports = { \ + .extensions = { \ + .main_tstate = _PyThreadState_INIT, \ + }, \ + }, \ .ceval = { \ .perf = _PyEval_RUNTIME_PERF_INIT, \ }, \ diff --git a/Python/import.c b/Python/import.c index c68bd1f7db42..a45b3bfaacb2 100644 --- a/Python/import.c +++ b/Python/import.c @@ -862,6 +862,18 @@ Generally, when multiple interpreters are involved, some of the above gets even messier. */ +static inline void +extensions_lock_acquire(void) +{ + // XXX For now the GIL is sufficient. +} + +static inline void +extensions_lock_release(void) +{ + // XXX For now the GIL is sufficient. +} + /* Magic for extension modules (built-in as well as dynamically loaded). To prevent initializing an extension module more than once, we keep a static dictionary 'extensions' keyed by the tuple @@ -878,71 +890,170 @@ gets even messier. dictionary, to avoid loading shared libraries twice. */ +static void +_extensions_cache_init(void) +{ + /* The runtime (i.e. main interpreter) must be initializing, + so we don't need to worry about the lock. */ + _PyThreadState_InitDetached(&EXTENSIONS.main_tstate, + _PyInterpreterState_Main()); +} + static PyModuleDef * _extensions_cache_get(PyObject *filename, PyObject *name) { - PyObject *extensions = EXTENSIONS; - if (extensions == NULL) { - return NULL; - } + PyModuleDef *def = NULL; + extensions_lock_acquire(); + PyObject *key = PyTuple_Pack(2, filename, name); if (key == NULL) { - return NULL; + goto finally; + } + + PyObject *extensions = EXTENSIONS.dict; + if (extensions == NULL) { + goto finally; } - PyModuleDef *def = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); - Py_DECREF(key); + def = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); + +finally: + Py_XDECREF(key); + extensions_lock_release(); return def; } static int _extensions_cache_set(PyObject *filename, PyObject *name, PyModuleDef *def) { - PyObject *extensions = EXTENSIONS; + int res = -1; + PyThreadState *oldts = NULL; + extensions_lock_acquire(); + + /* Swap to the main interpreter, if necessary. This matters if + the dict hasn't been created yet or if the item isn't in the + dict yet. In both cases we must ensure the relevant objects + are created using the main interpreter. */ + PyThreadState *main_tstate = &EXTENSIONS.main_tstate; + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!_Py_IsMainInterpreter(interp)) { + _PyThreadState_BindDetached(main_tstate); + oldts = _PyThreadState_Swap(interp->runtime, main_tstate); + assert(!_Py_IsMainInterpreter(oldts->interp)); + + /* Make sure the name and filename objects are owned + by the main interpreter. */ + name = PyUnicode_InternFromString(PyUnicode_AsUTF8(name)); + assert(name != NULL); + filename = PyUnicode_InternFromString(PyUnicode_AsUTF8(filename)); + assert(filename != NULL); + } + + PyObject *key = PyTuple_Pack(2, filename, name); + if (key == NULL) { + goto finally; + } + + PyObject *extensions = EXTENSIONS.dict; if (extensions == NULL) { extensions = PyDict_New(); if (extensions == NULL) { - return -1; + goto finally; } - EXTENSIONS = extensions; + EXTENSIONS.dict = extensions; } - PyObject *key = PyTuple_Pack(2, filename, name); - if (key == NULL) { - return -1; + + PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); + if (PyErr_Occurred()) { + goto finally; + } + else if (actual != NULL) { + /* We expect it to be static, so it must be the same pointer. */ + assert(def == actual); + res = 0; + goto finally; } - int res = PyDict_SetItem(extensions, key, (PyObject *)def); - Py_DECREF(key); + + /* This might trigger a resize, which is why we must switch + to the main interpreter. */ + res = PyDict_SetItem(extensions, key, (PyObject *)def); if (res < 0) { - return -1; + res = -1; + goto finally; } - return 0; + res = 0; + +finally: + if (oldts != NULL) { + _PyThreadState_Swap(interp->runtime, oldts); + _PyThreadState_UnbindDetached(main_tstate); + Py_DECREF(name); + Py_DECREF(filename); + } + Py_XDECREF(key); + extensions_lock_release(); + return res; } static int _extensions_cache_delete(PyObject *filename, PyObject *name) { - PyObject *extensions = EXTENSIONS; - if (extensions == NULL) { - return 0; - } + int res = -1; + PyThreadState *oldts = NULL; + extensions_lock_acquire(); + PyObject *key = PyTuple_Pack(2, filename, name); if (key == NULL) { - return -1; + goto finally; + } + + PyObject *extensions = EXTENSIONS.dict; + if (extensions == NULL) { + res = 0; + goto finally; } + + PyModuleDef *actual = (PyModuleDef *)PyDict_GetItemWithError(extensions, key); + if (PyErr_Occurred()) { + goto finally; + } + else if (actual == NULL) { + /* It was already removed or never added. */ + res = 0; + goto finally; + } + + /* Swap to the main interpreter, if necessary. */ + PyThreadState *main_tstate = &EXTENSIONS.main_tstate; + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (!_Py_IsMainInterpreter(interp)) { + _PyThreadState_BindDetached(main_tstate); + oldts = _PyThreadState_Swap(interp->runtime, main_tstate); + assert(!_Py_IsMainInterpreter(oldts->interp)); + } + if (PyDict_DelItem(extensions, key) < 0) { - if (!PyErr_ExceptionMatches(PyExc_KeyError)) { - Py_DECREF(key); - return -1; - } - PyErr_Clear(); + goto finally; } - Py_DECREF(key); - return 0; + res = 0; + +finally: + if (oldts != NULL) { + _PyThreadState_Swap(interp->runtime, oldts); + _PyThreadState_UnbindDetached(main_tstate); + } + Py_XDECREF(key); + extensions_lock_release(); + return res; } static void _extensions_cache_clear_all(void) { - Py_CLEAR(EXTENSIONS); + /* The runtime (i.e. main interpreter) must be finalizing, + so we don't need to worry about the lock. */ + // XXX assert(_Py_IsMainInterpreter(_PyInterpreterState_GET())); + Py_CLEAR(EXTENSIONS.dict); + _PyThreadState_ClearDetached(&EXTENSIONS.main_tstate); } @@ -2941,6 +3052,10 @@ _PyImport_Fini2(void) PyStatus _PyImport_InitCore(PyThreadState *tstate, PyObject *sysmod, int importlib) { + if (_Py_IsMainInterpreter(tstate->interp)) { + _extensions_cache_init(); + } + // XXX Initialize here: interp->modules and interp->import_func. // XXX Initialize here: sys.modules and sys.meta_path. diff --git a/Python/pystate.c b/Python/pystate.c index b17efdbefd12..1e59a8c5f897 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1217,8 +1217,7 @@ free_threadstate(PyThreadState *tstate) static void init_threadstate(PyThreadState *tstate, - PyInterpreterState *interp, uint64_t id, - PyThreadState *next) + PyInterpreterState *interp, uint64_t id) { if (tstate->_status.initialized) { Py_FatalError("thread state already initialized"); @@ -1227,18 +1226,13 @@ init_threadstate(PyThreadState *tstate, assert(interp != NULL); tstate->interp = interp; + // next/prev are set in add_threadstate(). + assert(tstate->next == NULL); + assert(tstate->prev == NULL); + assert(id > 0); tstate->id = id; - assert(interp->threads.head == tstate); - assert((next != NULL && id != 1) || (next == NULL && id == 1)); - if (next != NULL) { - assert(next->prev == NULL || next->prev == tstate); - next->prev = tstate; - } - tstate->next = next; - assert(tstate->prev == NULL); - // thread_id and native_thread_id are set in bind_tstate(). tstate->py_recursion_limit = interp->ceval.recursion_limit, @@ -1259,6 +1253,22 @@ init_threadstate(PyThreadState *tstate, tstate->_status.initialized = 1; } +static void +add_threadstate(PyInterpreterState *interp, PyThreadState *tstate, + PyThreadState *next) +{ + assert(interp->threads.head != tstate); + assert((next != NULL && tstate->id != 1) || + (next == NULL && tstate->id == 1)); + if (next != NULL) { + assert(next->prev == NULL || next->prev == tstate); + next->prev = tstate; + } + tstate->next = next; + assert(tstate->prev == NULL); + interp->threads.head = tstate; +} + static PyThreadState * new_threadstate(PyInterpreterState *interp) { @@ -1298,9 +1308,9 @@ new_threadstate(PyInterpreterState *interp) &initial._main_interpreter._initial_thread, sizeof(*tstate)); } - interp->threads.head = tstate; - init_threadstate(tstate, interp, id, old_head); + init_threadstate(tstate, interp, id); + add_threadstate(interp, tstate, old_head); HEAD_UNLOCK(runtime); if (!used_newtstate) { @@ -1347,6 +1357,19 @@ _PyThreadState_Init(PyThreadState *tstate) Py_FatalError("_PyThreadState_Init() is for internal use only"); } + +static void +clear_datastack(PyThreadState *tstate) +{ + _PyStackChunk *chunk = tstate->datastack_chunk; + tstate->datastack_chunk = NULL; + while (chunk != NULL) { + _PyStackChunk *prev = chunk->previous; + _PyObject_VirtualFree(chunk, chunk->size); + chunk = prev; + } +} + void PyThreadState_Clear(PyThreadState *tstate) { @@ -1421,7 +1444,6 @@ PyThreadState_Clear(PyThreadState *tstate) // XXX Do it as early in the function as possible. } - /* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */ static void tstate_delete_common(PyThreadState *tstate) @@ -1454,18 +1476,11 @@ tstate_delete_common(PyThreadState *tstate) unbind_tstate(tstate); // XXX Move to PyThreadState_Clear()? - _PyStackChunk *chunk = tstate->datastack_chunk; - tstate->datastack_chunk = NULL; - while (chunk != NULL) { - _PyStackChunk *prev = chunk->previous; - _PyObject_VirtualFree(chunk, chunk->size); - chunk = prev; - } + clear_datastack(tstate); tstate->_status.finalized = 1; } - static void zapthreads(PyInterpreterState *interp) { @@ -1552,6 +1567,75 @@ _PyThreadState_DeleteExcept(PyThreadState *tstate) } +//------------------------- +// "detached" thread states +//------------------------- + +void +_PyThreadState_InitDetached(PyThreadState *tstate, PyInterpreterState *interp) +{ + _PyRuntimeState *runtime = interp->runtime; + + HEAD_LOCK(runtime); + interp->threads.next_unique_id += 1; + uint64_t id = interp->threads.next_unique_id; + HEAD_UNLOCK(runtime); + + init_threadstate(tstate, interp, id); + // We do not call add_threadstate(). +} + +void +_PyThreadState_ClearDetached(PyThreadState *tstate) +{ + assert(!tstate->_status.bound); + assert(!tstate->_status.bound_gilstate); + assert(tstate->datastack_chunk == NULL); + assert(tstate->thread_id == 0); + assert(tstate->native_thread_id == 0); + assert(tstate->next == NULL); + assert(tstate->prev == NULL); + + PyThreadState_Clear(tstate); + clear_datastack(tstate); +} + +void +_PyThreadState_BindDetached(PyThreadState *tstate) +{ + assert(!_Py_IsMainInterpreter( + current_fast_get(tstate->interp->runtime)->interp)); + assert(_Py_IsMainInterpreter(tstate->interp)); + bind_tstate(tstate); + /* Unlike _PyThreadState_Bind(), we do not modify gilstate TSS. */ +} + +void +_PyThreadState_UnbindDetached(PyThreadState *tstate) +{ + assert(!_Py_IsMainInterpreter( + current_fast_get(tstate->interp->runtime)->interp)); + assert(_Py_IsMainInterpreter(tstate->interp)); + assert(tstate_is_alive(tstate)); + assert(!tstate->_status.active); + assert(gilstate_tss_get(tstate->interp->runtime) != tstate); + + unbind_tstate(tstate); + + /* This thread state may be bound/unbound repeatedly, + so we must erase evidence that it was ever bound (or unbound). */ + tstate->_status.bound = 0; + tstate->_status.unbound = 0; + + /* We must fully unlink the thread state from any OS thread, + to allow it to be bound more than once. */ + tstate->thread_id = 0; +#ifdef PY_HAVE_THREAD_NATIVE_ID + tstate->native_thread_id = 0; +#endif +} + + //---------- // accessors //---------- From webhook-mailer at python.org Thu Mar 30 04:32:46 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Thu, 30 Mar 2023 08:32:46 -0000 Subject: [Python-checkins] gh-103099: Link mypy docs from typing.rst (#103100) Message-ID: https://github.com/python/cpython/commit/fda95aa19447fe444ac2670afbf98ec42aca0c6f commit: fda95aa19447fe444ac2670afbf98ec42aca0c6f branch: main author: Shantanu <12621235+hauntsaninja at users.noreply.github.com> committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-30T01:32:09-07:00 summary: gh-103099: Link mypy docs from typing.rst (#103100) files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 08ffa0310f0f..384458d3aa66 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -41,10 +41,17 @@ For a summary of deprecated features and a deprecation timeline, please see .. seealso:: + For a quick overview of type hints, refer to + `this cheat sheet `_. + + The "Type System Reference" section of https://mypy.readthedocs.io/ -- since + the Python typing system is standardised via PEPs, this reference should + broadly apply to most Python type checkers, although some parts may still be + specific to mypy. + The documentation at https://typing.readthedocs.io/ serves as useful reference for type system features, useful typing related tools and typing best practices. - .. _relevant-peps: Relevant PEPs From webhook-mailer at python.org Thu Mar 30 04:39:58 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 30 Mar 2023 08:39:58 -0000 Subject: [Python-checkins] gh-103099: Link mypy docs from typing.rst (GH-103100) Message-ID: https://github.com/python/cpython/commit/1b40618247b7645b331ed5f42d704a2737cd52cb commit: 1b40618247b7645b331ed5f42d704a2737cd52cb branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-30T01:39:49-07:00 summary: gh-103099: Link mypy docs from typing.rst (GH-103100) (cherry picked from commit fda95aa19447fe444ac2670afbf98ec42aca0c6f) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index df6ddb6726cf..60f49d7029df 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -41,10 +41,17 @@ For a summary of deprecated features and a deprecation timeline, please see .. seealso:: + For a quick overview of type hints, refer to + `this cheat sheet `_. + + The "Type System Reference" section of https://mypy.readthedocs.io/ -- since + the Python typing system is standardised via PEPs, this reference should + broadly apply to most Python type checkers, although some parts may still be + specific to mypy. + The documentation at https://typing.readthedocs.io/ serves as useful reference for type system features, useful typing related tools and typing best practices. - .. _relevant-peps: Relevant PEPs From webhook-mailer at python.org Thu Mar 30 04:41:12 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 30 Mar 2023 08:41:12 -0000 Subject: [Python-checkins] gh-103099: Link mypy docs from typing.rst (GH-103100) Message-ID: https://github.com/python/cpython/commit/ba755a245b4c90511da0c1c41cfdbd1a9e7bb5bd commit: ba755a245b4c90511da0c1c41cfdbd1a9e7bb5bd branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-30T01:41:04-07:00 summary: gh-103099: Link mypy docs from typing.rst (GH-103100) (cherry picked from commit fda95aa19447fe444ac2670afbf98ec42aca0c6f) Co-authored-by: Shantanu <12621235+hauntsaninja at users.noreply.github.com> files: M Doc/library/typing.rst diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 00f779647e0b..8cf24521ca6c 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -38,6 +38,14 @@ provides backports of these new features to older versions of Python. .. seealso:: + For a quick overview of type hints, refer to + `this cheat sheet `_. + + The "Type System Reference" section of https://mypy.readthedocs.io/ -- since + the Python typing system is standardised via PEPs, this reference should + broadly apply to most Python type checkers, although some parts may still be + specific to mypy. + The documentation at https://typing.readthedocs.io/ serves as useful reference for type system features, useful typing related tools and typing best practices. From webhook-mailer at python.org Thu Mar 30 12:24:10 2023 From: webhook-mailer at python.org (corona10) Date: Thu, 30 Mar 2023 16:24:10 -0000 Subject: [Python-checkins] gh-103085: Fix python locale.getencoding not to emit deprecation warning (gh-103086) Message-ID: https://github.com/python/cpython/commit/21e9de3bf0ecf32cd61296009518bfb9fdfcd04f commit: 21e9de3bf0ecf32cd61296009518bfb9fdfcd04f branch: main author: Jeong, YunWon <69878+youknowone at users.noreply.github.com> committer: corona10 date: 2023-03-31T01:23:43+09:00 summary: gh-103085: Fix python locale.getencoding not to emit deprecation warning (gh-103086) files: A Misc/NEWS.d/next/Library/2023-03-28-15-12-53.gh-issue-103085.DqNehf.rst M Lib/locale.py diff --git a/Lib/locale.py b/Lib/locale.py index c2c7a04b2807..4127d9174659 100644 --- a/Lib/locale.py +++ b/Lib/locale.py @@ -545,7 +545,9 @@ def getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')): "Use setlocale(), getencoding() and getlocale() instead", DeprecationWarning, stacklevel=2 ) + return _getdefaultlocale(envvars) +def _getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')): try: # check if it's supported by the _locale module import _locale @@ -639,7 +641,7 @@ def getencoding(): # On Android langinfo.h and CODESET are missing, and UTF-8 is # always used in mbstowcs() and wcstombs(). return 'utf-8' - encoding = getdefaultlocale()[1] + encoding = _getdefaultlocale()[1] if encoding is None: # LANG not set, default to UTF-8 encoding = 'utf-8' diff --git a/Misc/NEWS.d/next/Library/2023-03-28-15-12-53.gh-issue-103085.DqNehf.rst b/Misc/NEWS.d/next/Library/2023-03-28-15-12-53.gh-issue-103085.DqNehf.rst new file mode 100644 index 000000000000..fa07fa5226c0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-28-15-12-53.gh-issue-103085.DqNehf.rst @@ -0,0 +1 @@ +Pure python :func:`locale.getencoding()` will not warn deprecation. From webhook-mailer at python.org Thu Mar 30 14:03:58 2023 From: webhook-mailer at python.org (hugovk) Date: Thu, 30 Mar 2023 18:03:58 -0000 Subject: [Python-checkins] gh-101100: Fix Sphinx warning in gc.rst and refactor docs clean list (#103116) Message-ID: https://github.com/python/cpython/commit/f192a558f538489ad1be30aa145e71d942798d1c commit: f192a558f538489ad1be30aa145e71d942798d1c branch: main author: Hugo van Kemenade committer: hugovk date: 2023-03-30T21:03:50+03:00 summary: gh-101100: Fix Sphinx warning in gc.rst and refactor docs clean list (#103116) Co-authored-by: C.A.M. Gerlach files: A Doc/tools/clean-files.txt A Doc/tools/touch-clean-files.py M .github/workflows/doc.yml M Doc/library/gc.rst diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 29387d30d5a2..314a7da647ff 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -72,8 +72,7 @@ jobs: - name: 'Build known-good files in nit-picky mode' run: | # Mark files that must pass nit-picky - touch Doc/whatsnew/3.12.rst - touch Doc/library/sqlite3.rst + python Doc/tools/touch-clean-files.py # Build docs with the '-n' (nit-picky) option, convert warnings to errors (-W) make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n -W --keep-going" html 2>&1 diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst index 69a1a8313b75..832ebaf497f3 100644 --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -251,7 +251,7 @@ values but should not rebind them): are printed. .. versionchanged:: 3.4 - Following :pep:`442`, objects with a :meth:`__del__` method don't end + Following :pep:`442`, objects with a :meth:`~object.__del__` method don't end up in :attr:`gc.garbage` anymore. .. data:: callbacks diff --git a/Doc/tools/clean-files.txt b/Doc/tools/clean-files.txt new file mode 100644 index 000000000000..a6197998f504 --- /dev/null +++ b/Doc/tools/clean-files.txt @@ -0,0 +1,10 @@ +# These files must pass Sphinx nit-picky mode, as tested on the CI +# via touch-clean-files.py in doc.yml. +# Add blank lines between files and keep them sorted lexicographically +# to help avoid merge conflicts. + +Doc/library/gc.rst + +Doc/library/sqlite3.rst + +Doc/whatsnew/3.12.rst diff --git a/Doc/tools/touch-clean-files.py b/Doc/tools/touch-clean-files.py new file mode 100644 index 000000000000..07f3e509a09f --- /dev/null +++ b/Doc/tools/touch-clean-files.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +""" +Touch files that must pass Sphinx nit-picky mode +so they are rebuilt and we can catch regressions. +""" + +from pathlib import Path + +# Input file has blank line between entries to reduce merge conflicts +with Path("Doc/tools/clean-files.txt").open() as clean_files: + CLEAN = [ + Path(filename.strip()) + for filename in clean_files + if filename.strip() and not filename.startswith("#") + ] + +print("Touching:") +for filename in CLEAN: + print(filename) + filename.touch() From webhook-mailer at python.org Thu Mar 30 14:41:16 2023 From: webhook-mailer at python.org (gpshead) Date: Thu, 30 Mar 2023 18:41:16 -0000 Subject: [Python-checkins] Add IPv6 into to the docstring for socket.getsockname (#102961) Message-ID: https://github.com/python/cpython/commit/ecc5441505cd7cb54f3d38409c732e2e9f102137 commit: ecc5441505cd7cb54f3d38409c732e2e9f102137 branch: main author: Brian Haley committer: gpshead date: 2023-03-30T11:40:58-07:00 summary: Add IPv6 into to the docstring for socket.getsockname (#102961) Signed-off-by: Brian Haley files: M Modules/socketmodule.c diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 6a6f8cf7392e..c2b8283d84e5 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -3538,7 +3538,8 @@ PyDoc_STRVAR(getsockname_doc, \n\ Return the address of the local endpoint. The format depends on the\n\ address family. For IPv4 sockets, the address info is a pair\n\ -(hostaddr, port)."); +(hostaddr, port). For IPv6 sockets, the address info is a 4-tuple\n\ +(hostaddr, port, flowinfo, scope_id)."); #endif From webhook-mailer at python.org Thu Mar 30 16:49:17 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 30 Mar 2023 20:49:17 -0000 Subject: [Python-checkins] gh-102110: Add all tools description missed (GH-102625) Message-ID: https://github.com/python/cpython/commit/01a49d17454b9072a0c46b550573ea430048684a commit: 01a49d17454b9072a0c46b550573ea430048684a branch: main author: Missoupro <80458944+Missoupro at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-30T13:49:07-07:00 summary: gh-102110: Add all tools description missed (GH-102625) Added missing descriptions of some tools. Automerge-Triggered-By: GH:hugovk files: M Tools/README M Tools/scripts/README diff --git a/Tools/README b/Tools/README index 04612b8013db..e51624f453c5 100644 --- a/Tools/README +++ b/Tools/README @@ -1,10 +1,21 @@ This directory contains a number of Python programs that are useful while building or extending Python. +build Automatically generated directory by the build system + contain build artifacts and intermediate files. + buildbot Batchfiles for running on Windows buildbot workers. +c-analyzer Tools to check no new global variables have been added. + +cases_generator Tooling to generate interpreters. + ccbench A Python threads-based concurrency benchmark. (*) +clinic A preprocessor for CPython C files in order to automate + the boilerplate involved with writing argument parsing + code for "builtins". + freeze Create a stand-alone executable from a Python program. gdb Python code to be run inside gdb, to make it easier to @@ -15,11 +26,16 @@ i18n Tools for internationalization. pygettext.py and msgfmt.py generates a binary message catalog from a catalog in text format. +importbench A set of micro-benchmarks for various import scenarios. + iobench Benchmark for the new Python I/O system. (*) msi Support for packaging Python as an MSI package on Windows. -parser Un-parsing tool to generate code from an AST. +nuget Files for the NuGet package manager for .NET. + +patchcheck Tools for checking and applying patches to the Python source code + and verifying the integrity of patch files. peg_generator PEG-based parser generator (pegen) used for new parser. @@ -28,9 +44,14 @@ scripts A number of useful single-file programs, e.g. tabnanny.py tabs and spaces, and 2to3, which converts Python 2 code to Python 3 code. +ssl Scripts to generate ssl_data.h from OpenSSL sources, and run + tests against multiple installations of OpenSSL and LibreSSL. + stringbench A suite of micro-benchmarks for various operations on strings (both 8-bit and unicode). (*) +tz A script to dump timezone from /usr/share/zoneinfo. + unicode Tools for generating unicodedata and codecs from unicode.org and other mapping files (by Fredrik Lundh, Marc-Andre Lemburg and Martin von Loewis). @@ -38,6 +59,8 @@ unicode Tools for generating unicodedata and codecs from unicode.org unittestgui A Tkinter based GUI test runner for unittest, with test discovery. +wasm Config and helpers to facilitate cross compilation of CPython + to WebAssembly (WASM). (*) A generic benchmark suite is maintained separately at https://github.com/python/performance diff --git a/Tools/scripts/README b/Tools/scripts/README index b95226815959..9dbb89a8dae6 100644 --- a/Tools/scripts/README +++ b/Tools/scripts/README @@ -2,9 +2,15 @@ This directory contains a collection of executable Python scripts that are useful while building, extending or managing Python. 2to3 Main script for running the 2to3 conversion tool +checkpip.py Checks the version of the projects bundled in ensurepip + are the latest available combinerefs.py A helper for analyzing PYTHONDUMPREFS output +divmod_threshold.py Determine threshold for switching from longobject.c + divmod to _pylong.int_divmod() idle3 Main program to start IDLE -parse_html5_entities.py Utility for parsing HTML5 entity definitions pydoc3 Python documentation browser run_tests.py Run the test suite with more sensible default options -stable_abi.py Stable ABI checks and file generators. +summarize_stats.py Summarize specialization stats for all files in the + default stats folders +var_access_benchmark.py Show relative speeds of local, nonlocal, global, + and built-in access From webhook-mailer at python.org Thu Mar 30 18:51:43 2023 From: webhook-mailer at python.org (hauntsaninja) Date: Thu, 30 Mar 2023 22:51:43 -0000 Subject: [Python-checkins] Minor docs improvements fix for `codeop` (#103123) Message-ID: https://github.com/python/cpython/commit/c1e71ce56fdb3eab62ad3190d09130f800e54610 commit: c1e71ce56fdb3eab62ad3190d09130f800e54610 branch: main author: gaogaotiantian committer: hauntsaninja <12621235+hauntsaninja at users.noreply.github.com> date: 2023-03-30T15:51:36-07:00 summary: Minor docs improvements fix for `codeop` (#103123) files: M Doc/library/codeop.rst diff --git a/Doc/library/codeop.rst b/Doc/library/codeop.rst index c66b9d3ec0a2..90df499f8207 100644 --- a/Doc/library/codeop.rst +++ b/Doc/library/codeop.rst @@ -19,10 +19,10 @@ module instead. There are two parts to this job: -#. Being able to tell if a line of input completes a Python statement: in +#. Being able to tell if a line of input completes a Python statement: in short, telling whether to print '``>>>``' or '``...``' next. -#. Remembering which future statements the user has entered, so subsequent +#. Remembering which future statements the user has entered, so subsequent input can be compiled with these in effect. The :mod:`codeop` module provides a way of doing each of these things, and a way @@ -33,9 +33,9 @@ To do just the former: .. function:: compile_command(source, filename="", symbol="single") Tries to compile *source*, which should be a string of Python code and return a - code object if *source* is valid Python code. In that case, the filename + code object if *source* is valid Python code. In that case, the filename attribute of the code object will be *filename*, which defaults to - ``''``. Returns ``None`` if *source* is *not* valid Python code, but is a + ``''``. Returns ``None`` if *source* is *not* valid Python code, but is a prefix of valid Python code. If there is a problem with *source*, an exception will be raised. @@ -43,9 +43,9 @@ To do just the former: :exc:`OverflowError` or :exc:`ValueError` if there is an invalid literal. The *symbol* argument determines whether *source* is compiled as a statement - (``'single'``, the default), as a sequence of statements (``'exec'``) or + (``'single'``, the default), as a sequence of :term:`statement` (``'exec'``) or as an :term:`expression` (``'eval'``). Any other value will - cause :exc:`ValueError` to be raised. + cause :exc:`ValueError` to be raised. .. note:: @@ -69,5 +69,5 @@ To do just the former: Instances of this class have :meth:`__call__` methods identical in signature to :func:`compile_command`; the difference is that if the instance compiles program - text containing a ``__future__`` statement, the instance 'remembers' and + text containing a :mod:`__future__` statement, the instance 'remembers' and compiles all subsequent program texts with the statement in force. From webhook-mailer at python.org Thu Mar 30 18:58:43 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 30 Mar 2023 22:58:43 -0000 Subject: [Python-checkins] Minor docs improvements fix for `codeop` (GH-103123) Message-ID: https://github.com/python/cpython/commit/d58ff6a616276c205e480225f588140f480271b7 commit: d58ff6a616276c205e480225f588140f480271b7 branch: 3.10 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-30T15:58:36-07:00 summary: Minor docs improvements fix for `codeop` (GH-103123) (cherry picked from commit c1e71ce56fdb3eab62ad3190d09130f800e54610) Co-authored-by: gaogaotiantian files: M Doc/library/codeop.rst diff --git a/Doc/library/codeop.rst b/Doc/library/codeop.rst index c66b9d3ec0a2..90df499f8207 100644 --- a/Doc/library/codeop.rst +++ b/Doc/library/codeop.rst @@ -19,10 +19,10 @@ module instead. There are two parts to this job: -#. Being able to tell if a line of input completes a Python statement: in +#. Being able to tell if a line of input completes a Python statement: in short, telling whether to print '``>>>``' or '``...``' next. -#. Remembering which future statements the user has entered, so subsequent +#. Remembering which future statements the user has entered, so subsequent input can be compiled with these in effect. The :mod:`codeop` module provides a way of doing each of these things, and a way @@ -33,9 +33,9 @@ To do just the former: .. function:: compile_command(source, filename="", symbol="single") Tries to compile *source*, which should be a string of Python code and return a - code object if *source* is valid Python code. In that case, the filename + code object if *source* is valid Python code. In that case, the filename attribute of the code object will be *filename*, which defaults to - ``''``. Returns ``None`` if *source* is *not* valid Python code, but is a + ``''``. Returns ``None`` if *source* is *not* valid Python code, but is a prefix of valid Python code. If there is a problem with *source*, an exception will be raised. @@ -43,9 +43,9 @@ To do just the former: :exc:`OverflowError` or :exc:`ValueError` if there is an invalid literal. The *symbol* argument determines whether *source* is compiled as a statement - (``'single'``, the default), as a sequence of statements (``'exec'``) or + (``'single'``, the default), as a sequence of :term:`statement` (``'exec'``) or as an :term:`expression` (``'eval'``). Any other value will - cause :exc:`ValueError` to be raised. + cause :exc:`ValueError` to be raised. .. note:: @@ -69,5 +69,5 @@ To do just the former: Instances of this class have :meth:`__call__` methods identical in signature to :func:`compile_command`; the difference is that if the instance compiles program - text containing a ``__future__`` statement, the instance 'remembers' and + text containing a :mod:`__future__` statement, the instance 'remembers' and compiles all subsequent program texts with the statement in force. From webhook-mailer at python.org Thu Mar 30 18:59:01 2023 From: webhook-mailer at python.org (miss-islington) Date: Thu, 30 Mar 2023 22:59:01 -0000 Subject: [Python-checkins] Minor docs improvements fix for `codeop` (GH-103123) Message-ID: https://github.com/python/cpython/commit/41e3ea13964bffa6ec9b0e036d70b6b8e9f2e120 commit: 41e3ea13964bffa6ec9b0e036d70b6b8e9f2e120 branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-30T15:58:54-07:00 summary: Minor docs improvements fix for `codeop` (GH-103123) (cherry picked from commit c1e71ce56fdb3eab62ad3190d09130f800e54610) Co-authored-by: gaogaotiantian files: M Doc/library/codeop.rst diff --git a/Doc/library/codeop.rst b/Doc/library/codeop.rst index c66b9d3ec0a2..90df499f8207 100644 --- a/Doc/library/codeop.rst +++ b/Doc/library/codeop.rst @@ -19,10 +19,10 @@ module instead. There are two parts to this job: -#. Being able to tell if a line of input completes a Python statement: in +#. Being able to tell if a line of input completes a Python statement: in short, telling whether to print '``>>>``' or '``...``' next. -#. Remembering which future statements the user has entered, so subsequent +#. Remembering which future statements the user has entered, so subsequent input can be compiled with these in effect. The :mod:`codeop` module provides a way of doing each of these things, and a way @@ -33,9 +33,9 @@ To do just the former: .. function:: compile_command(source, filename="", symbol="single") Tries to compile *source*, which should be a string of Python code and return a - code object if *source* is valid Python code. In that case, the filename + code object if *source* is valid Python code. In that case, the filename attribute of the code object will be *filename*, which defaults to - ``''``. Returns ``None`` if *source* is *not* valid Python code, but is a + ``''``. Returns ``None`` if *source* is *not* valid Python code, but is a prefix of valid Python code. If there is a problem with *source*, an exception will be raised. @@ -43,9 +43,9 @@ To do just the former: :exc:`OverflowError` or :exc:`ValueError` if there is an invalid literal. The *symbol* argument determines whether *source* is compiled as a statement - (``'single'``, the default), as a sequence of statements (``'exec'``) or + (``'single'``, the default), as a sequence of :term:`statement` (``'exec'``) or as an :term:`expression` (``'eval'``). Any other value will - cause :exc:`ValueError` to be raised. + cause :exc:`ValueError` to be raised. .. note:: @@ -69,5 +69,5 @@ To do just the former: Instances of this class have :meth:`__call__` methods identical in signature to :func:`compile_command`; the difference is that if the instance compiles program - text containing a ``__future__`` statement, the instance 'remembers' and + text containing a :mod:`__future__` statement, the instance 'remembers' and compiles all subsequent program texts with the statement in force. From webhook-mailer at python.org Fri Mar 31 06:23:14 2023 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 31 Mar 2023 10:23:14 -0000 Subject: [Python-checkins] gh-102799: use exception instance instead of sys.exc_info() (#102885) Message-ID: https://github.com/python/cpython/commit/44bd3fe570da9115bec67694404b8da26716a1d7 commit: 44bd3fe570da9115bec67694404b8da26716a1d7 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-31T11:23:02+01:00 summary: gh-102799: use exception instance instead of sys.exc_info() (#102885) files: M Lib/logging/__init__.py M Lib/pickle.py M Lib/site.py M Lib/test/inspect_fodder.py M Lib/test/test_inspect.py M Lib/test/test_with.py M Lib/tkinter/filedialog.py diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index 9241d73d0fd0..056380fb2287 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -173,8 +173,8 @@ def currentframe(): """Return the frame object for the caller's stack frame.""" try: raise Exception - except Exception: - return sys.exc_info()[2].tb_frame.f_back + except Exception as exc: + return exc.__traceback__.tb_frame.f_back # # _srcfile is used when walking the stack to check when we've got the first diff --git a/Lib/pickle.py b/Lib/pickle.py index 15fa5f6e5799..fe86f80f51d3 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -1481,7 +1481,7 @@ def _instantiate(self, klass, args): value = klass(*args) except TypeError as err: raise TypeError("in constructor for %s: %s" % - (klass.__name__, str(err)), sys.exc_info()[2]) + (klass.__name__, str(err)), err.__traceback__) else: value = klass.__new__(klass) self.append(value) diff --git a/Lib/site.py b/Lib/site.py index 7faf1c6f6af2..5c1ff31f4e0f 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -190,11 +190,11 @@ def addpackage(sitedir, name, known_paths): if not dircase in known_paths and os.path.exists(dir): sys.path.append(dir) known_paths.add(dircase) - except Exception: + except Exception as exc: print("Error processing line {:d} of {}:\n".format(n+1, fullname), file=sys.stderr) import traceback - for record in traceback.format_exception(*sys.exc_info()): + for record in traceback.format_exception(exc): for line in record.splitlines(): print(' '+line, file=sys.stderr) print("\nRemainder of file ignored", file=sys.stderr) diff --git a/Lib/test/inspect_fodder.py b/Lib/test/inspect_fodder.py index e1287a315901..567dfbab8048 100644 --- a/Lib/test/inspect_fodder.py +++ b/Lib/test/inspect_fodder.py @@ -1,7 +1,7 @@ # line 1 'A module docstring.' -import sys, inspect +import inspect # line 5 # line 7 @@ -41,8 +41,8 @@ def abuse(self, a, b, c): def argue(self, a, b, c): try: spam(a, b, c) - except: - self.ex = sys.exc_info() + except BaseException as e: + self.ex = e self.tr = inspect.trace() @property @@ -78,8 +78,8 @@ async def lobbest(grenade): currentframe = inspect.currentframe() try: raise Exception() -except: - tb = sys.exc_info()[2] +except BaseException as e: + tb = e.__traceback__ class Callable: def __call__(self, *args): diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 803b259d961f..3a3646f1861e 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -430,7 +430,7 @@ def __init__(self, *args, **kwargs): git.abuse(7, 8, 9) def test_abuse_done(self): - self.istest(inspect.istraceback, 'git.ex[2]') + self.istest(inspect.istraceback, 'git.ex.__traceback__') self.istest(inspect.isframe, 'mod.fr') def test_stack(self): diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py index 07522bda6a55..d81902327a7e 100644 --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -79,11 +79,11 @@ def __exit__(self, *exc_info): try: if mgr.__exit__(*ex): ex = (None, None, None) - except: - ex = sys.exc_info() + except BaseException as e: + ex = (type(e), e, e.__traceback__) self.entered = None if ex is not exc_info: - raise ex[0](ex[1]).with_traceback(ex[2]) + raise ex class MockNested(Nested): diff --git a/Lib/tkinter/filedialog.py b/Lib/tkinter/filedialog.py index 600d0bd49fe2..e2eff98e601c 100644 --- a/Lib/tkinter/filedialog.py +++ b/Lib/tkinter/filedialog.py @@ -461,7 +461,6 @@ def test(): # Start off with UTF-8 enc = "utf-8" - import sys # See whether CODESET is defined try: @@ -477,9 +476,9 @@ def test(): try: fp=open(openfilename,"r") fp.close() - except: + except BaseException as exc: print("Could not open File: ") - print(sys.exc_info()[1]) + print(exc) print("open", openfilename.encode(enc)) From webhook-mailer at python.org Fri Mar 31 06:48:54 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 31 Mar 2023 10:48:54 -0000 Subject: [Python-checkins] gh-101100: Expand list of clean docs (GH-103135) Message-ID: https://github.com/python/cpython/commit/20c0f196ff63546a6a0460a46c92de12b975bc1a commit: 20c0f196ff63546a6a0460a46c92de12b975bc1a branch: main author: Hugo van Kemenade committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-31T03:48:46-07:00 summary: gh-101100: Expand list of clean docs (GH-103135) Follow on from https://github.com/python/cpython/pull/103116. Expand list of clean docs files from 3 to 181. These files have no Sphinx warnings, and their presence in this list means that any new warnings introduced will fail the build. The list was created by subtracting the list of files with warnings from a list of all files. I tested with all of those, but found that `touch`ing two clean files (https://github.com/python/cpython/blob/main/Doc/includes/wasm-notavail.rst and https://github.com/python/cpython/blob/main/Doc/whatsnew/changelog.rst) caused a cascade effect and resulted in a number of dirty files being rebuilt too, and failing the build. So those two have been omitted. Automerge-Triggered-By: GH:hugovk files: M Doc/tools/clean-files.txt M Doc/tools/touch-clean-files.py diff --git a/Doc/tools/clean-files.txt b/Doc/tools/clean-files.txt index a6197998f504..baef7c2f8958 100644 --- a/Doc/tools/clean-files.txt +++ b/Doc/tools/clean-files.txt @@ -3,8 +3,364 @@ # Add blank lines between files and keep them sorted lexicographically # to help avoid merge conflicts. +Doc/about.rst + +Doc/bugs.rst + +Doc/c-api/abstract.rst + +Doc/c-api/bytearray.rst + +Doc/c-api/concrete.rst + +Doc/c-api/contextvars.rst + +Doc/c-api/coro.rst + +Doc/c-api/frame.rst + +Doc/c-api/function.rst + +Doc/c-api/gen.rst + +Doc/c-api/index.rst + +Doc/c-api/iter.rst + +Doc/c-api/list.rst + +Doc/c-api/method.rst + +Doc/c-api/number.rst + +Doc/c-api/objbuffer.rst + +Doc/c-api/objimpl.rst + +Doc/c-api/reflection.rst + +Doc/c-api/slice.rst + +Doc/c-api/utilities.rst + +Doc/contents.rst + +Doc/copyright.rst + +Doc/distributing/index.rst + +Doc/extending/building.rst + +Doc/extending/index.rst + +Doc/extending/windows.rst + +Doc/faq/general.rst + +Doc/faq/index.rst + +Doc/faq/installed.rst + +Doc/faq/windows.rst + +Doc/howto/annotations.rst + +Doc/howto/clinic.rst + +Doc/howto/cporting.rst + +Doc/howto/index.rst + +Doc/howto/ipaddress.rst + +Doc/howto/perf_profiling.rst + +Doc/howto/pyporting.rst + +Doc/howto/sockets.rst + +Doc/installing/index.rst + +Doc/library/__main__.rst + +Doc/library/allos.rst + +Doc/library/archiving.rst + +Doc/library/array.rst + +Doc/library/asyncio-api-index.rst + +Doc/library/asyncio-exceptions.rst + +Doc/library/asyncio-llapi-index.rst + +Doc/library/asyncio-platforms.rst + +Doc/library/asyncio-protocol.rst + +Doc/library/asyncio-queue.rst + +Doc/library/asyncio-runner.rst + +Doc/library/asyncio-sync.rst + +Doc/library/asyncio.rst + +Doc/library/atexit.rst + +Doc/library/audit_events.rst + +Doc/library/base64.rst + +Doc/library/binary.rst + +Doc/library/binascii.rst + +Doc/library/builtins.rst + +Doc/library/cgitb.rst + +Doc/library/colorsys.rst + +Doc/library/concurrency.rst + +Doc/library/contextvars.rst + +Doc/library/copyreg.rst + +Doc/library/crypt.rst + +Doc/library/crypto.rst + +Doc/library/curses.panel.rst + +Doc/library/custominterp.rst + +Doc/library/datatypes.rst + +Doc/library/debug.rst + +Doc/library/development.rst + +Doc/library/dialog.rst + +Doc/library/distribution.rst + +Doc/library/email.contentmanager.rst + +Doc/library/email.examples.rst + +Doc/library/email.header.rst + +Doc/library/email.iterators.rst + +Doc/library/email.rst + +Doc/library/email.utils.rst + +Doc/library/ensurepip.rst + +Doc/library/errno.rst + +Doc/library/fileformats.rst + +Doc/library/filesys.rst + +Doc/library/fnmatch.rst + +Doc/library/frameworks.rst + +Doc/library/functional.rst + Doc/library/gc.rst +Doc/library/glob.rst + +Doc/library/grp.rst + +Doc/library/heapq.rst + +Doc/library/hmac.rst + +Doc/library/html.entities.rst + +Doc/library/html.parser.rst + +Doc/library/html.rst + +Doc/library/http.rst + +Doc/library/i18n.rst + +Doc/library/imaplib.rst + +Doc/library/imghdr.rst + +Doc/library/importlib.metadata.rst + +Doc/library/index.rst + +Doc/library/internet.rst + +Doc/library/intro.rst + +Doc/library/ipaddress.rst + +Doc/library/ipc.rst + +Doc/library/itertools.rst + +Doc/library/keyword.rst + +Doc/library/language.rst + +Doc/library/linecache.rst + +Doc/library/mailcap.rst + +Doc/library/markup.rst + +Doc/library/marshal.rst + +Doc/library/math.rst + +Doc/library/mimetypes.rst + +Doc/library/mm.rst + +Doc/library/modulefinder.rst + +Doc/library/modules.rst + +Doc/library/netdata.rst + +Doc/library/nis.rst + +Doc/library/numeric.rst + +Doc/library/pathlib.rst + +Doc/library/pdb.rst + +Doc/library/persistence.rst + +Doc/library/pipes.rst + +Doc/library/pwd.rst + +Doc/library/python.rst + +Doc/library/queue.rst + +Doc/library/quopri.rst + +Doc/library/runpy.rst + +Doc/library/secrets.rst + +Doc/library/security_warnings.rst + +Doc/library/shlex.rst + +Doc/library/sndhdr.rst + +Doc/library/spwd.rst + Doc/library/sqlite3.rst +Doc/library/statistics.rst + +Doc/library/stringprep.rst + +Doc/library/superseded.rst + +Doc/library/symtable.rst + +Doc/library/tabnanny.rst + +Doc/library/text.rst + +Doc/library/timeit.rst + +Doc/library/tk.rst + +Doc/library/tkinter.colorchooser.rst + +Doc/library/tkinter.dnd.rst + +Doc/library/tkinter.font.rst + +Doc/library/tkinter.messagebox.rst + +#Doc/library/token.rst + +Doc/library/tokenize.rst + +Doc/library/tomllib.rst + +Doc/library/trace.rst + +Doc/library/tracemalloc.rst + +Doc/library/types.rst + +Doc/library/typing.rst + +Doc/library/unicodedata.rst + +Doc/library/unix.rst + +Doc/library/urllib.robotparser.rst + +Doc/library/urllib.rst + +Doc/library/uu.rst + +Doc/library/venv.rst + +Doc/library/warnings.rst + +Doc/library/windows.rst + +Doc/library/zipapp.rst + +Doc/library/zipfile.rst + +Doc/library/zipimport.rst + +Doc/library/zoneinfo.rst + +Doc/reference/executionmodel.rst + +Doc/reference/grammar.rst + +Doc/reference/index.rst + +Doc/reference/introduction.rst + +Doc/reference/toplevel_components.rst + +Doc/tutorial/appetite.rst + +Doc/tutorial/floatingpoint.rst + +Doc/tutorial/index.rst + +Doc/tutorial/interpreter.rst + +Doc/tutorial/stdlib.rst + +Doc/tutorial/venv.rst + +Doc/tutorial/whatnow.rst + +Doc/using/editors.rst + +Doc/using/index.rst + +Doc/using/mac.rst + Doc/whatsnew/3.12.rst + +Doc/whatsnew/index.rst diff --git a/Doc/tools/touch-clean-files.py b/Doc/tools/touch-clean-files.py index 07f3e509a09f..9f55e9446ba7 100644 --- a/Doc/tools/touch-clean-files.py +++ b/Doc/tools/touch-clean-files.py @@ -18,3 +18,4 @@ for filename in CLEAN: print(filename) filename.touch() +print(f"Touched {len(CLEAN)} files") From webhook-mailer at python.org Fri Mar 31 08:40:46 2023 From: webhook-mailer at python.org (encukou) Date: Fri, 31 Mar 2023 12:40:46 -0000 Subject: [Python-checkins] Quote literal tokens in standard format specifier grammar (GH-102902) Message-ID: https://github.com/python/cpython/commit/f6405a46627e1f74c279f712c8776a165b0ba9fd commit: f6405a46627e1f74c279f712c8776a165b0ba9fd branch: main author: Petr Viktorin committer: encukou date: 2023-03-31T14:40:38+02:00 summary: Quote literal tokens in standard format specifier grammar (GH-102902) Reported by Damian Dureck: https://mail.python.org/archives/list/docs at python.org/thread/UZTWBJIXC3MBKTHXVTIBPGDPKBNWZ5LN/ files: M Doc/library/string.rst diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 3b96813e6838..5ada82732818 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -310,7 +310,7 @@ non-empty format specification typically modifies the result. The general form of a *standard format specifier* is: .. productionlist:: format-spec - format_spec: [[`fill`]`align`][`sign`][z][#][0][`width`][`grouping_option`][.`precision`][`type`] + format_spec: [[`fill`]`align`][`sign`]["z"]["#"]["0"][`width`][`grouping_option`]["." `precision`][`type`] fill: align: "<" | ">" | "=" | "^" sign: "+" | "-" | " " From webhook-mailer at python.org Fri Mar 31 08:53:00 2023 From: webhook-mailer at python.org (miss-islington) Date: Fri, 31 Mar 2023 12:53:00 -0000 Subject: [Python-checkins] Quote literal tokens in standard format specifier grammar (GH-102902) Message-ID: https://github.com/python/cpython/commit/4664a7cf689946f0c9854cadee7c6aa9c276a8cf commit: 4664a7cf689946f0c9854cadee7c6aa9c276a8cf branch: 3.11 author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com> committer: miss-islington <31488909+miss-islington at users.noreply.github.com> date: 2023-03-31T05:52:52-07:00 summary: Quote literal tokens in standard format specifier grammar (GH-102902) Reported by Damian Dureck: https://mail.python.org/archives/list/docs at python.org/thread/UZTWBJIXC3MBKTHXVTIBPGDPKBNWZ5LN/ (cherry picked from commit f6405a46627e1f74c279f712c8776a165b0ba9fd) Co-authored-by: Petr Viktorin files: M Doc/library/string.rst diff --git a/Doc/library/string.rst b/Doc/library/string.rst index 3b96813e6838..5ada82732818 100644 --- a/Doc/library/string.rst +++ b/Doc/library/string.rst @@ -310,7 +310,7 @@ non-empty format specification typically modifies the result. The general form of a *standard format specifier* is: .. productionlist:: format-spec - format_spec: [[`fill`]`align`][`sign`][z][#][0][`width`][`grouping_option`][.`precision`][`type`] + format_spec: [[`fill`]`align`][`sign`]["z"]["#"]["0"][`width`][`grouping_option`]["." `precision`][`type`] fill: align: "<" | ">" | "=" | "^" sign: "+" | "-" | " " From webhook-mailer at python.org Fri Mar 31 09:54:24 2023 From: webhook-mailer at python.org (terryjreedy) Date: Fri, 31 Mar 2023 13:54:24 -0000 Subject: [Python-checkins] GH-84783: Mention Author for GH-101264 (make slices hashable) (#103146) Message-ID: https://github.com/python/cpython/commit/048d6243d45b9381dd4fcaad28ae9c5d443b8b4b commit: 048d6243d45b9381dd4fcaad28ae9c5d443b8b4b branch: main author: Furkan Onder committer: terryjreedy date: 2023-03-31T09:54:17-04:00 summary: GH-84783: Mention Author for GH-101264 (make slices hashable) (#103146) Will Bradshaw contributed original patch on bpo-40603. --------- Co-authored-by: Terry Jan Reedy files: M Doc/whatsnew/3.12.rst M Misc/NEWS.d/3.12.0a6.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index e5bcfdecd9a4..00a51ab3c137 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -190,7 +190,7 @@ Other Language Changes (Contributed by Nikita Sobolev in :gh:`100581`.) * :class:`slice` objects are now hashable, allowing them to be used as dict keys and - set items. (Contributed by Furkan Onder in :gh:`101264`.) + set items. (Contributed by Will Bradshaw and Furkan Onder in :gh:`101264`.) New Modules =========== diff --git a/Misc/NEWS.d/3.12.0a6.rst b/Misc/NEWS.d/3.12.0a6.rst index 2bcb4c8c854d..f6beb5b7ec3d 100644 --- a/Misc/NEWS.d/3.12.0a6.rst +++ b/Misc/NEWS.d/3.12.0a6.rst @@ -189,7 +189,7 @@ not just glibc. This fixes support for musl. .. nonce: _P5sMa .. section: Core and Builtins -Make the slice object hashable. +Make the slice object hashable. Patch by Will Bradshaw and Furkan Onder. .. From webhook-mailer at python.org Fri Mar 31 11:03:02 2023 From: webhook-mailer at python.org (merwok) Date: Fri, 31 Mar 2023 15:03:02 -0000 Subject: [Python-checkins] gh-102871: Remove obsolete browsers from webbrowser (#102872) Message-ID: https://github.com/python/cpython/commit/b0422e140df8fdc83c51cc64a3ed5426188de7f1 commit: b0422e140df8fdc83c51cc64a3ed5426188de7f1 branch: main author: James De Bias <81095953+DBJim at users.noreply.github.com> committer: merwok date: 2023-03-31T11:02:47-04:00 summary: gh-102871: Remove obsolete browsers from webbrowser (#102872) files: A Misc/NEWS.d/next/Library/2023-03-21-15-17-07.gh-issue-102871.U9mchn.rst M Doc/library/webbrowser.rst M Doc/whatsnew/3.12.rst M Lib/test/test_webbrowser.py M Lib/webbrowser.py diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst index 734b6321e5a7..61db80420936 100644 --- a/Doc/library/webbrowser.rst +++ b/Doc/library/webbrowser.rst @@ -115,13 +115,7 @@ for the controller classes, all defined in this module. +------------------------+-----------------------------------------+-------+ | ``'firefox'`` | :class:`Mozilla('mozilla')` | | +------------------------+-----------------------------------------+-------+ -| ``'netscape'`` | :class:`Mozilla('netscape')` | | -+------------------------+-----------------------------------------+-------+ -| ``'galeon'`` | :class:`Galeon('galeon')` | | -+------------------------+-----------------------------------------+-------+ -| ``'epiphany'`` | :class:`Galeon('epiphany')` | | -+------------------------+-----------------------------------------+-------+ -| ``'skipstone'`` | :class:`BackgroundBrowser('skipstone')` | | +| ``'epiphany'`` | :class:`Epiphany('epiphany')` | | +------------------------+-----------------------------------------+-------+ | ``'kfmclient'`` | :class:`Konqueror()` | \(1) | +------------------------+-----------------------------------------+-------+ @@ -129,12 +123,8 @@ for the controller classes, all defined in this module. +------------------------+-----------------------------------------+-------+ | ``'kfm'`` | :class:`Konqueror()` | \(1) | +------------------------+-----------------------------------------+-------+ -| ``'mosaic'`` | :class:`BackgroundBrowser('mosaic')` | | -+------------------------+-----------------------------------------+-------+ | ``'opera'`` | :class:`Opera()` | | +------------------------+-----------------------------------------+-------+ -| ``'grail'`` | :class:`Grail()` | | -+------------------------+-----------------------------------------+-------+ | ``'links'`` | :class:`GenericBrowser('links')` | | +------------------------+-----------------------------------------+-------+ | ``'elinks'`` | :class:`Elinks('elinks')` | | @@ -176,6 +166,11 @@ Notes: .. versionadded:: 3.3 Support for Chrome/Chromium has been added. +.. versionchanged:: 3.12 + Support for several obsolete browsers has been removed. + Removed browsers include Grail, Mosaic, Netscape, Galeon, + Skipstone, Iceape, and Firefox versions 35 and below. + .. deprecated-removed:: 3.11 3.13 :class:`MacOSX` is deprecated, use :class:`MacOSXOSAScript` instead. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 00a51ab3c137..bd9be531fdd7 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -777,6 +777,10 @@ Removed *context* parameter instead. (Contributed by Victor Stinner in :gh:`94172`.) +* Remove support for obsolete browsers from :mod:`webbrowser`. + Removed browsers include: Grail, Mosaic, Netscape, Galeon, Skipstone, + Iceape, Firebird, and Firefox versions 35 and below (:gh:`102871`). + Porting to Python 3.12 ====================== diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py index 9d608d63a01e..147a113c7fd7 100644 --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py @@ -11,7 +11,7 @@ if not support.has_subprocess_support: raise unittest.SkipTest("test webserver requires subprocess") -URL = 'http://www.example.com' +URL = 'https://www.example.com' CMD_NAME = 'test' @@ -120,34 +120,9 @@ def test_open_new_tab(self): arguments=['-new-tab', URL]) -class NetscapeCommandTest(CommandTestMixin, unittest.TestCase): +class EpiphanyCommandTest(CommandTestMixin, unittest.TestCase): - browser_class = webbrowser.Netscape - - def test_open(self): - self._test('open', - options=['-raise', '-remote'], - arguments=['openURL({})'.format(URL)]) - - def test_open_with_autoraise_false(self): - self._test('open', kw=dict(autoraise=False), - options=['-noraise', '-remote'], - arguments=['openURL({})'.format(URL)]) - - def test_open_new(self): - self._test('open_new', - options=['-raise', '-remote'], - arguments=['openURL({},new-window)'.format(URL)]) - - def test_open_new_tab(self): - self._test('open_new_tab', - options=['-raise', '-remote'], - arguments=['openURL({},new-tab)'.format(URL)]) - - -class GaleonCommandTest(CommandTestMixin, unittest.TestCase): - - browser_class = webbrowser.Galeon + browser_class = webbrowser.Epiphany def test_open(self): self._test('open', diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 4336597e68f6..d98c5997d2f4 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -292,19 +292,8 @@ class Mozilla(UnixBrowser): background = True -class Netscape(UnixBrowser): - """Launcher class for Netscape browser.""" - - raise_opts = ["-noraise", "-raise"] - remote_args = ['-remote', 'openURL(%s%action)'] - remote_action = "" - remote_action_newwin = ",new-window" - remote_action_newtab = ",new-tab" - background = True - - -class Galeon(UnixBrowser): - """Launcher class for Galeon/Epiphany browsers.""" +class Epiphany(UnixBrowser): + """Launcher class for Epiphany browser.""" raise_opts = ["-noraise", ""] remote_args = ['%action', '%s'] @@ -402,44 +391,6 @@ def open(self, url, new=0, autoraise=True): return (p.poll() is None) -class Grail(BaseBrowser): - # There should be a way to maintain a connection to Grail, but the - # Grail remote control protocol doesn't really allow that at this - # point. It probably never will! - def _find_grail_rc(self): - import glob - import pwd - import socket - import tempfile - tempdir = os.path.join(tempfile.gettempdir(), - ".grail-unix") - user = pwd.getpwuid(os.getuid())[0] - filename = os.path.join(glob.escape(tempdir), glob.escape(user) + "-*") - maybes = glob.glob(filename) - if not maybes: - return None - s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - for fn in maybes: - # need to PING each one until we find one that's live - try: - s.connect(fn) - except OSError: - # no good; attempt to clean it out, but don't fail: - try: - os.unlink(fn) - except OSError: - pass - else: - return s - - def _remote(self, action): - s = self._find_grail_rc() - if not s: - return 0 - s.send(action) - s.close() - return 1 - def open(self, url, new=0, autoraise=True): sys.audit("webbrowser.open", url) if new: @@ -475,35 +426,25 @@ def register_X_browsers(): if "KDE_FULL_SESSION" in os.environ and shutil.which("kfmclient"): register("kfmclient", Konqueror, Konqueror("kfmclient")) + # Common symbolic link for the default X11 browser if shutil.which("x-www-browser"): register("x-www-browser", None, BackgroundBrowser("x-www-browser")) # The Mozilla browsers - for browser in ("firefox", "iceweasel", "iceape", "seamonkey"): + for browser in ("firefox", "iceweasel", "seamonkey", "mozilla-firefox", + "mozilla"): if shutil.which(browser): register(browser, None, Mozilla(browser)) - # The Netscape and old Mozilla browsers - for browser in ("mozilla-firefox", - "mozilla-firebird", "firebird", - "mozilla", "netscape"): - if shutil.which(browser): - register(browser, None, Netscape(browser)) - # Konqueror/kfm, the KDE browser. if shutil.which("kfm"): register("kfm", Konqueror, Konqueror("kfm")) elif shutil.which("konqueror"): register("konqueror", Konqueror, Konqueror("konqueror")) - # Gnome's Galeon and Epiphany - for browser in ("galeon", "epiphany"): - if shutil.which(browser): - register(browser, None, Galeon(browser)) - - # Skipstone, another Gtk/Mozilla based browser - if shutil.which("skipstone"): - register("skipstone", None, BackgroundBrowser("skipstone")) + # Gnome's Epiphany + if shutil.which("epiphany"): + register("epiphany", None, Epiphany("epiphany")) # Google Chrome/Chromium browsers for browser in ("google-chrome", "chrome", "chromium", "chromium-browser"): @@ -514,13 +455,6 @@ def register_X_browsers(): if shutil.which("opera"): register("opera", None, Opera("opera")) - # Next, Mosaic -- old but still in use. - if shutil.which("mosaic"): - register("mosaic", None, BackgroundBrowser("mosaic")) - - # Grail, the Python browser. Does anybody still use it? - if shutil.which("grail"): - register("grail", Grail, None) def register_standard_browsers(): global _tryorder @@ -549,7 +483,7 @@ def register_standard_browsers(): # location in 32-bit Windows edge32 = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), "Microsoft\\Edge\\Application\\msedge.exe") - for browser in ("firefox", "firebird", "seamonkey", "mozilla", + for browser in ("firefox", "seamonkey", "mozilla", "chrome", "opera", edge64, edge32): if shutil.which(browser): register(browser, None, BackgroundBrowser(browser)) @@ -570,14 +504,15 @@ def register_standard_browsers(): # Also try console browsers if os.environ.get("TERM"): + # Common symbolic link for the default text-based browser if shutil.which("www-browser"): register("www-browser", None, GenericBrowser("www-browser")) - # The Links/elinks browsers + # The Links/elinks browsers if shutil.which("links"): register("links", None, GenericBrowser("links")) if shutil.which("elinks"): register("elinks", None, Elinks("elinks")) - # The Lynx browser , + # The Lynx browser , if shutil.which("lynx"): register("lynx", None, GenericBrowser("lynx")) # The w3m browser @@ -727,7 +662,7 @@ def main(): for o, a in opts: if o == '-n': new_win = 1 elif o == '-t': new_win = 2 - elif o == '-h' or o == '--help': + elif o == '-h' or o == '--help': print(usage, file=sys.stderr) sys.exit() if len(args) != 1: diff --git a/Misc/NEWS.d/next/Library/2023-03-21-15-17-07.gh-issue-102871.U9mchn.rst b/Misc/NEWS.d/next/Library/2023-03-21-15-17-07.gh-issue-102871.U9mchn.rst new file mode 100644 index 000000000000..3ef0e74d21ca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-21-15-17-07.gh-issue-102871.U9mchn.rst @@ -0,0 +1,3 @@ +Remove support for obsolete browsers from :mod:`webbrowser`. +Removed browsers include Grail, Mosaic, Netscape, Galeon, Skipstone, +Iceape, Firebird, and Firefox versions 35 and below. From webhook-mailer at python.org Fri Mar 31 13:18:11 2023 From: webhook-mailer at python.org (iritkatriel) Date: Fri, 31 Mar 2023 17:18:11 -0000 Subject: [Python-checkins] gh-87092: move CFG related code from compile.c to flowgraph.c (#103021) Message-ID: https://github.com/python/cpython/commit/80163e17d3f826067c5d95198db7696287beb416 commit: 80163e17d3f826067c5d95198db7696287beb416 branch: main author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com> committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com> date: 2023-03-31T18:17:59+01:00 summary: gh-87092: move CFG related code from compile.c to flowgraph.c (#103021) files: A Include/internal/pycore_flowgraph.h A Include/internal/pycore_opcode_utils.h A Python/flowgraph.c M Include/internal/pycore_compile.h M Include/internal/pycore_opcode.h M Makefile.pre.in M PCbuild/_freeze_module.vcxproj M PCbuild/_freeze_module.vcxproj.filters M PCbuild/pythoncore.vcxproj M PCbuild/pythoncore.vcxproj.filters M Python/compile.c M Python/opcode_metadata.h M Tools/build/generate_opcode_h.py M Tools/cases_generator/generate_cases.py diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h index 511f0689c938..6a1e02c0b895 100644 --- a/Include/internal/pycore_compile.h +++ b/Include/internal/pycore_compile.h @@ -33,6 +33,16 @@ extern int _PyAST_Optimize( struct _arena *arena, _PyASTOptimizeState *state); +/* Utility for a number of growing arrays used in the compiler */ +int _PyCompile_EnsureArrayLargeEnough( + int idx, + void **array, + int *alloc, + int default_alloc, + size_t item_size); + +int _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj); + /* Access compiler internals for unit testing */ PyAPI_FUNC(PyObject*) _PyCompile_CodeGen( diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h new file mode 100644 index 000000000000..7c0b8fe980c3 --- /dev/null +++ b/Include/internal/pycore_flowgraph.h @@ -0,0 +1,117 @@ +#ifndef Py_INTERNAL_CFG_H +#define Py_INTERNAL_CFG_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include "pycore_opcode_utils.h" + +static const _PyCompilerSrcLocation NO_LOCATION = {-1, -1, -1, -1}; + +typedef struct { + int i_opcode; + int i_oparg; + _PyCompilerSrcLocation i_loc; + struct _PyCfgBasicblock_ *i_target; /* target block (if jump instruction) */ + struct _PyCfgBasicblock_ *i_except; /* target block when exception is raised */ +} _PyCfgInstruction; + +typedef struct { + int id; +} _PyCfgJumpTargetLabel; + + +typedef struct { + struct _PyCfgBasicblock_ *handlers[CO_MAXBLOCKS+1]; + int depth; +} _PyCfgExceptStack; + +typedef struct _PyCfgBasicblock_ { + /* Each basicblock in a compilation unit is linked via b_list in the + reverse order that the block are allocated. b_list points to the next + block, not to be confused with b_next, which is next by control flow. */ + struct _PyCfgBasicblock_ *b_list; + /* The label of this block if it is a jump target, -1 otherwise */ + _PyCfgJumpTargetLabel b_label; + /* Exception stack at start of block, used by assembler to create the exception handling table */ + _PyCfgExceptStack *b_exceptstack; + /* pointer to an array of instructions, initially NULL */ + _PyCfgInstruction *b_instr; + /* If b_next is non-NULL, it is a pointer to the next + block reached by normal control flow. */ + struct _PyCfgBasicblock_ *b_next; + /* number of instructions used */ + int b_iused; + /* length of instruction array (b_instr) */ + int b_ialloc; + /* Used by add_checks_for_loads_of_unknown_variables */ + uint64_t b_unsafe_locals_mask; + /* Number of predecessors that a block has. */ + int b_predecessors; + /* depth of stack upon entry of block, computed by stackdepth() */ + int b_startdepth; + /* instruction offset for block, computed by assemble_jump_offsets() */ + int b_offset; + /* Basic block is an exception handler that preserves lasti */ + unsigned b_preserve_lasti : 1; + /* Used by compiler passes to mark whether they have visited a basic block. */ + unsigned b_visited : 1; + /* b_except_handler is used by the cold-detection algorithm to mark exception targets */ + unsigned b_except_handler : 1; + /* b_cold is true if this block is not perf critical (like an exception handler) */ + unsigned b_cold : 1; + /* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */ + unsigned b_warm : 1; +} _PyCfgBasicblock; + +int _PyBasicblock_InsertInstruction(_PyCfgBasicblock *block, int pos, _PyCfgInstruction *instr); + +typedef struct cfg_builder_ { + /* The entryblock, at which control flow begins. All blocks of the + CFG are reachable through the b_next links */ + _PyCfgBasicblock *g_entryblock; + /* Pointer to the most recently allocated block. By following + b_list links, you can reach all allocated blocks. */ + _PyCfgBasicblock *g_block_list; + /* pointer to the block currently being constructed */ + _PyCfgBasicblock *g_curblock; + /* label for the next instruction to be placed */ + _PyCfgJumpTargetLabel g_current_label; +} _PyCfgBuilder; + +int _PyCfgBuilder_UseLabel(_PyCfgBuilder *g, _PyCfgJumpTargetLabel lbl); +int _PyCfgBuilder_Addop(_PyCfgBuilder *g, int opcode, int oparg, _PyCompilerSrcLocation loc); + +int _PyCfgBuilder_Init(_PyCfgBuilder *g); +void _PyCfgBuilder_Fini(_PyCfgBuilder *g); + +_PyCfgInstruction* _PyCfg_BasicblockLastInstr(const _PyCfgBasicblock *b); +int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache, + int code_flags, int nlocals, int nparams); +int _PyCfg_Stackdepth(_PyCfgBasicblock *entryblock, int code_flags); +void _PyCfg_ConvertExceptionHandlersToNops(_PyCfgBasicblock *entryblock); +int _PyCfg_ResolveLineNumbers(_PyCfgBuilder *g, int firstlineno); +int _PyCfg_ResolveJumps(_PyCfgBuilder *g); +int _PyCfg_InstrSize(_PyCfgInstruction *instruction); + + +static inline int +basicblock_nofallthrough(const _PyCfgBasicblock *b) { + _PyCfgInstruction *last = _PyCfg_BasicblockLastInstr(b); + return (last && + (IS_SCOPE_EXIT_OPCODE(last->i_opcode) || + IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode))); +} + +#define BB_NO_FALLTHROUGH(B) (basicblock_nofallthrough(B)) +#define BB_HAS_FALLTHROUGH(B) (!basicblock_nofallthrough(B)) + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_CFG_H */ diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 22914da07994..58f7da51aebd 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -12,12 +12,16 @@ extern "C" { #include "opcode.h" +extern const uint32_t _PyOpcode_RelativeJump[9]; + +extern const uint32_t _PyOpcode_Jump[9]; + extern const uint8_t _PyOpcode_Caches[256]; extern const uint8_t _PyOpcode_Deopt[256]; #ifdef NEED_OPCODE_TABLES -static const uint32_t _PyOpcode_RelativeJump[9] = { +const uint32_t _PyOpcode_RelativeJump[9] = { 0U, 0U, 536870912U, @@ -28,7 +32,7 @@ static const uint32_t _PyOpcode_RelativeJump[9] = { 0U, 48U, }; -static const uint32_t _PyOpcode_Jump[9] = { +const uint32_t _PyOpcode_Jump[9] = { 0U, 0U, 536870912U, diff --git a/Include/internal/pycore_opcode_utils.h b/Include/internal/pycore_opcode_utils.h new file mode 100644 index 000000000000..96bb4d743bf2 --- /dev/null +++ b/Include/internal/pycore_opcode_utils.h @@ -0,0 +1,95 @@ +#ifndef Py_INTERNAL_OPCODE_UTILS_H +#define Py_INTERNAL_OPCODE_UTILS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include "pycore_opcode.h" // _PyOpcode_RelativeJump + + +#define MAX_REAL_OPCODE 254 + +#define IS_WITHIN_OPCODE_RANGE(opcode) \ + (((opcode) >= 0 && (opcode) <= MAX_REAL_OPCODE) || \ + IS_PSEUDO_OPCODE(opcode)) + +#define IS_JUMP_OPCODE(opcode) \ + is_bit_set_in_table(_PyOpcode_Jump, opcode) + +#define IS_BLOCK_PUSH_OPCODE(opcode) \ + ((opcode) == SETUP_FINALLY || \ + (opcode) == SETUP_WITH || \ + (opcode) == SETUP_CLEANUP) + +#define HAS_TARGET(opcode) \ + (IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)) + +/* opcodes that must be last in the basicblock */ +#define IS_TERMINATOR_OPCODE(opcode) \ + (IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode)) + +/* opcodes which are not emitted in codegen stage, only by the assembler */ +#define IS_ASSEMBLER_OPCODE(opcode) \ + ((opcode) == JUMP_FORWARD || \ + (opcode) == JUMP_BACKWARD || \ + (opcode) == JUMP_BACKWARD_NO_INTERRUPT) + +#define IS_BACKWARDS_JUMP_OPCODE(opcode) \ + ((opcode) == JUMP_BACKWARD || \ + (opcode) == JUMP_BACKWARD_NO_INTERRUPT) + +#define IS_UNCONDITIONAL_JUMP_OPCODE(opcode) \ + ((opcode) == JUMP || \ + (opcode) == JUMP_NO_INTERRUPT || \ + (opcode) == JUMP_FORWARD || \ + (opcode) == JUMP_BACKWARD || \ + (opcode) == JUMP_BACKWARD_NO_INTERRUPT) + +#define IS_SCOPE_EXIT_OPCODE(opcode) \ + ((opcode) == RETURN_VALUE || \ + (opcode) == RETURN_CONST || \ + (opcode) == RAISE_VARARGS || \ + (opcode) == RERAISE) + +#define IS_SUPERINSTRUCTION_OPCODE(opcode) \ + ((opcode) == LOAD_FAST__LOAD_FAST || \ + (opcode) == LOAD_FAST__LOAD_CONST || \ + (opcode) == LOAD_CONST__LOAD_FAST || \ + (opcode) == STORE_FAST__LOAD_FAST || \ + (opcode) == STORE_FAST__STORE_FAST) + + +#define LOG_BITS_PER_INT 5 +#define MASK_LOW_LOG_BITS 31 + +static inline int +is_bit_set_in_table(const uint32_t *table, int bitindex) { + /* Is the relevant bit set in the relevant word? */ + /* 512 bits fit into 9 32-bits words. + * Word is indexed by (bitindex>>ln(size of int in bits)). + * Bit within word is the low bits of bitindex. + */ + if (bitindex >= 0 && bitindex < 512) { + uint32_t word = table[bitindex >> LOG_BITS_PER_INT]; + return (word >> (bitindex & MASK_LOW_LOG_BITS)) & 1; + } + else { + return 0; + } +} + +#undef LOG_BITS_PER_INT +#undef MASK_LOW_LOG_BITS + +#define IS_RELATIVE_JUMP(opcode) (is_bit_set_in_table(_PyOpcode_RelativeJump, opcode)) + + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_OPCODE_UTILS_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index 74e4171b010d..b97daaf6f445 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -374,6 +374,7 @@ PYTHON_OBJS= \ Python/ast_unparse.o \ Python/bltinmodule.o \ Python/ceval.o \ + Python/flowgraph.o \ Python/codecs.o \ Python/compile.o \ Python/context.o \ @@ -1702,6 +1703,8 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_object_state.h \ $(srcdir)/Include/internal/pycore_obmalloc.h \ $(srcdir)/Include/internal/pycore_obmalloc_init.h \ + $(srcdir)/Include/internal/pycore_opcode.h \ + $(srcdir)/Include/internal/pycore_opcode_utils.h \ $(srcdir)/Include/internal/pycore_pathconfig.h \ $(srcdir)/Include/internal/pycore_pyarena.h \ $(srcdir)/Include/internal/pycore_pyerrors.h \ diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 4f39756019e6..28eced6d4b28 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -183,6 +183,7 @@ + diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 7d7c4587b9a3..e4faa89bb831 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -76,6 +76,9 @@ Source Files + + Source Files + Source Files diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index c754b2165745..8fab60033416 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -205,6 +205,7 @@ + @@ -504,6 +505,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 90ed0602821b..6c5d8dd89f5b 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -1106,6 +1106,9 @@ Python + + Python + Python diff --git a/Python/compile.c b/Python/compile.c index 192deaa4b35f..fed9ae7066e4 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -23,23 +23,21 @@ #include -// Need _PyOpcode_RelativeJump of pycore_opcode.h -#define NEED_OPCODE_TABLES - #include "Python.h" #include "pycore_ast.h" // _PyAST_GetDocString() +#define NEED_OPCODE_TABLES +#include "pycore_opcode_utils.h" +#undef NEED_OPCODE_TABLES +#include "pycore_flowgraph.h" #include "pycore_code.h" // _PyCode_New() #include "pycore_compile.h" #include "pycore_intrinsics.h" #include "pycore_long.h" // _PyLong_GetZero() -#include "pycore_opcode.h" // _PyOpcode_Caches #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_symtable.h" // PySTEntryObject, _PyFuture_FromAST() #include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed - -#define DEFAULT_BLOCK_SIZE 16 #define DEFAULT_CODE_SIZE 128 #define DEFAULT_LNOTAB_SIZE 16 #define DEFAULT_CNOTAB_SIZE 32 @@ -83,68 +81,17 @@ */ #define MAX_ALLOWED_STACK_USE (STACK_USE_GUIDELINE * 100) - -#define MAX_REAL_OPCODE 254 - -#define IS_WITHIN_OPCODE_RANGE(opcode) \ - (((opcode) >= 0 && (opcode) <= MAX_REAL_OPCODE) || \ - IS_PSEUDO_OPCODE(opcode)) - -#define IS_JUMP_OPCODE(opcode) \ - is_bit_set_in_table(_PyOpcode_Jump, opcode) - -#define IS_BLOCK_PUSH_OPCODE(opcode) \ - ((opcode) == SETUP_FINALLY || \ - (opcode) == SETUP_WITH || \ - (opcode) == SETUP_CLEANUP) - -#define HAS_TARGET(opcode) \ - (IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)) - -/* opcodes that must be last in the basicblock */ -#define IS_TERMINATOR_OPCODE(opcode) \ - (IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode)) - -/* opcodes which are not emitted in codegen stage, only by the assembler */ -#define IS_ASSEMBLER_OPCODE(opcode) \ - ((opcode) == JUMP_FORWARD || \ - (opcode) == JUMP_BACKWARD || \ - (opcode) == JUMP_BACKWARD_NO_INTERRUPT) - -#define IS_BACKWARDS_JUMP_OPCODE(opcode) \ - ((opcode) == JUMP_BACKWARD || \ - (opcode) == JUMP_BACKWARD_NO_INTERRUPT) - -#define IS_UNCONDITIONAL_JUMP_OPCODE(opcode) \ - ((opcode) == JUMP || \ - (opcode) == JUMP_NO_INTERRUPT || \ - (opcode) == JUMP_FORWARD || \ - (opcode) == JUMP_BACKWARD || \ - (opcode) == JUMP_BACKWARD_NO_INTERRUPT) - -#define IS_SCOPE_EXIT_OPCODE(opcode) \ - ((opcode) == RETURN_VALUE || \ - (opcode) == RETURN_CONST || \ - (opcode) == RAISE_VARARGS || \ - (opcode) == RERAISE) - -#define IS_SUPERINSTRUCTION_OPCODE(opcode) \ - ((opcode) == LOAD_FAST__LOAD_FAST || \ - (opcode) == LOAD_FAST__LOAD_CONST || \ - (opcode) == LOAD_CONST__LOAD_FAST || \ - (opcode) == STORE_FAST__LOAD_FAST || \ - (opcode) == STORE_FAST__STORE_FAST) - #define IS_TOP_LEVEL_AWAIT(C) ( \ ((C)->c_flags.cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \ && ((C)->u->u_ste->ste_type == ModuleBlock)) typedef _PyCompilerSrcLocation location; +typedef _PyCfgInstruction cfg_instr; +typedef _PyCfgBasicblock basicblock; +typedef _PyCfgBuilder cfg_builder; #define LOCATION(LNO, END_LNO, COL, END_COL) \ - ((const location){(LNO), (END_LNO), (COL), (END_COL)}) - -static location NO_LOCATION = {-1, -1, -1, -1}; + ((const _PyCompilerSrcLocation){(LNO), (END_LNO), (COL), (END_COL)}) /* Return true if loc1 starts after loc2 ends. */ static inline bool @@ -165,11 +112,9 @@ same_location(location a, location b) #define LOC(x) SRC_LOCATION_FROM_AST(x) -typedef struct jump_target_label_ { - int id; -} jump_target_label; +typedef _PyCfgJumpTargetLabel jump_target_label; -static struct jump_target_label_ NO_LABEL = {-1}; +static jump_target_label NO_LABEL = {-1}; #define SAME_LABEL(L1, L2) ((L1).id == (L2).id) #define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) @@ -183,88 +128,9 @@ static struct jump_target_label_ NO_LABEL = {-1}; #define USE_LABEL(C, LBL) \ RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id)) -struct cfg_instr { - int i_opcode; - int i_oparg; - location i_loc; - struct basicblock_ *i_target; /* target block (if jump instruction) */ - struct basicblock_ *i_except; /* target block when exception is raised */ -}; - -/* One arg*/ -#define INSTR_SET_OP1(I, OP, ARG) \ - do { \ - assert(HAS_ARG(OP)); \ - struct cfg_instr *_instr__ptr_ = (I); \ - _instr__ptr_->i_opcode = (OP); \ - _instr__ptr_->i_oparg = (ARG); \ - } while (0); - -/* No args*/ -#define INSTR_SET_OP0(I, OP) \ - do { \ - assert(!HAS_ARG(OP)); \ - struct cfg_instr *_instr__ptr_ = (I); \ - _instr__ptr_->i_opcode = (OP); \ - _instr__ptr_->i_oparg = 0; \ - } while (0); - -typedef struct exceptstack { - struct basicblock_ *handlers[CO_MAXBLOCKS+1]; - int depth; -} ExceptStack; - -#define LOG_BITS_PER_INT 5 -#define MASK_LOW_LOG_BITS 31 - -static inline int -is_bit_set_in_table(const uint32_t *table, int bitindex) { - /* Is the relevant bit set in the relevant word? */ - /* 512 bits fit into 9 32-bits words. - * Word is indexed by (bitindex>>ln(size of int in bits)). - * Bit within word is the low bits of bitindex. - */ - if (bitindex >= 0 && bitindex < 512) { - uint32_t word = table[bitindex >> LOG_BITS_PER_INT]; - return (word >> (bitindex & MASK_LOW_LOG_BITS)) & 1; - } - else { - return 0; - } -} - -static inline int -is_relative_jump(struct cfg_instr *i) -{ - return is_bit_set_in_table(_PyOpcode_RelativeJump, i->i_opcode); -} - -static inline int -is_block_push(struct cfg_instr *i) -{ - return IS_BLOCK_PUSH_OPCODE(i->i_opcode); -} - -static inline int -is_jump(struct cfg_instr *i) -{ - return IS_JUMP_OPCODE(i->i_opcode); -} - -static int -instr_size(struct cfg_instr *instruction) -{ - int opcode = instruction->i_opcode; - assert(!IS_PSEUDO_OPCODE(opcode)); - int oparg = instruction->i_oparg; - assert(HAS_ARG(opcode) || oparg == 0); - int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg); - int caches = _PyOpcode_Caches[opcode]; - return extended_args + 1 + caches; -} static void -write_instr(_Py_CODEUNIT *codestr, struct cfg_instr *instruction, int ilen) +write_instr(_Py_CODEUNIT *codestr, cfg_instr *instruction, int ilen) { int opcode = instruction->i_opcode; assert(!IS_PSEUDO_OPCODE(opcode)); @@ -302,71 +168,6 @@ write_instr(_Py_CODEUNIT *codestr, struct cfg_instr *instruction, int ilen) } } -typedef struct basicblock_ { - /* Each basicblock in a compilation unit is linked via b_list in the - reverse order that the block are allocated. b_list points to the next - block, not to be confused with b_next, which is next by control flow. */ - struct basicblock_ *b_list; - /* The label of this block if it is a jump target, -1 otherwise */ - jump_target_label b_label; - /* Exception stack at start of block, used by assembler to create the exception handling table */ - ExceptStack *b_exceptstack; - /* pointer to an array of instructions, initially NULL */ - struct cfg_instr *b_instr; - /* If b_next is non-NULL, it is a pointer to the next - block reached by normal control flow. */ - struct basicblock_ *b_next; - /* number of instructions used */ - int b_iused; - /* length of instruction array (b_instr) */ - int b_ialloc; - /* Used by add_checks_for_loads_of_unknown_variables */ - uint64_t b_unsafe_locals_mask; - /* Number of predecessors that a block has. */ - int b_predecessors; - /* depth of stack upon entry of block, computed by stackdepth() */ - int b_startdepth; - /* instruction offset for block, computed by assemble_jump_offsets() */ - int b_offset; - /* Basic block is an exception handler that preserves lasti */ - unsigned b_preserve_lasti : 1; - /* Used by compiler passes to mark whether they have visited a basic block. */ - unsigned b_visited : 1; - /* b_except_handler is used by the cold-detection algorithm to mark exception targets */ - unsigned b_except_handler : 1; - /* b_cold is true if this block is not perf critical (like an exception handler) */ - unsigned b_cold : 1; - /* b_warm is used by the cold-detection algorithm to mark blocks which are definitely not cold */ - unsigned b_warm : 1; -} basicblock; - - -static struct cfg_instr * -basicblock_last_instr(const basicblock *b) { - assert(b->b_iused >= 0); - if (b->b_iused > 0) { - assert(b->b_instr != NULL); - return &b->b_instr[b->b_iused - 1]; - } - return NULL; -} - -static inline int -basicblock_exits_scope(const basicblock *b) { - struct cfg_instr *last = basicblock_last_instr(b); - return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode); -} - -static inline int -basicblock_nofallthrough(const basicblock *b) { - struct cfg_instr *last = basicblock_last_instr(b); - return (last && - (IS_SCOPE_EXIT_OPCODE(last->i_opcode) || - IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode))); -} - -#define BB_NO_FALLTHROUGH(B) (basicblock_nofallthrough(B)) -#define BB_HAS_FALLTHROUGH(B) (!basicblock_nofallthrough(B)) /* fblockinfo tracks the current frame block. @@ -397,26 +198,12 @@ enum { COMPILER_SCOPE_COMPREHENSION, }; -typedef struct cfg_builder_ { - /* The entryblock, at which control flow begins. All blocks of the - CFG are reachable through the b_next links */ - basicblock *g_entryblock; - /* Pointer to the most recently allocated block. By following - b_list links, you can reach all allocated blocks. */ - basicblock *g_block_list; - /* pointer to the block currently being constructed */ - basicblock *g_curblock; - /* label for the next instruction to be placed */ - jump_target_label g_current_label; -} cfg_builder; - typedef struct { int i_opcode; int i_oparg; location i_loc; } instruction; - typedef struct instr_sequence_ { instruction *s_instrs; int s_allocated; @@ -440,10 +227,11 @@ typedef struct instr_sequence_ { * item_size: size of each item * */ -static int -ensure_array_large_enough(int idx, void **arr_, int *alloc, int default_alloc, size_t item_size) +int +_PyCompile_EnsureArrayLargeEnough(int idx, void **array, int *alloc, + int default_alloc, size_t item_size) { - void *arr = *arr_; + void *arr = *array; if (arr == NULL) { int new_alloc = default_alloc; if (idx >= new_alloc) { @@ -480,7 +268,7 @@ ensure_array_large_enough(int idx, void **arr_, int *alloc, int default_alloc, s memset((char *)arr + oldsize, 0, newsize - oldsize); } - *arr_ = arr; + *array = arr; return SUCCESS; } @@ -489,11 +277,11 @@ instr_sequence_next_inst(instr_sequence *seq) { assert(seq->s_instrs != NULL || seq->s_used == 0); RETURN_IF_ERROR( - ensure_array_large_enough(seq->s_used + 1, - (void**)&seq->s_instrs, - &seq->s_allocated, - INITIAL_INSTR_SEQUENCE_SIZE, - sizeof(instruction))); + _PyCompile_EnsureArrayLargeEnough(seq->s_used + 1, + (void**)&seq->s_instrs, + &seq->s_allocated, + INITIAL_INSTR_SEQUENCE_SIZE, + sizeof(instruction))); assert(seq->s_used < seq->s_allocated); return seq->s_used++; } @@ -509,11 +297,11 @@ static int instr_sequence_use_label(instr_sequence *seq, int lbl) { int old_size = seq->s_labelmap_size; RETURN_IF_ERROR( - ensure_array_large_enough(lbl, - (void**)&seq->s_labelmap, - &seq->s_labelmap_size, - INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE, - sizeof(int))); + _PyCompile_EnsureArrayLargeEnough(lbl, + (void**)&seq->s_labelmap, + &seq->s_labelmap_size, + INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE, + sizeof(int))); for(int i = old_size; i < seq->s_labelmap_size; i++) { seq->s_labelmap[i] = -111; /* something weird, for debugging */ @@ -572,29 +360,11 @@ instr_sequence_fini(instr_sequence *seq) { seq->s_instrs = NULL; } -static int basicblock_addop(basicblock *b, int opcode, int oparg, location loc); -static int cfg_builder_maybe_start_new_block(cfg_builder *g); - -static int -cfg_builder_use_label(cfg_builder *g, jump_target_label lbl) -{ - g->g_current_label = lbl; - return cfg_builder_maybe_start_new_block(g); -} - -static int -cfg_builder_addop(cfg_builder *g, int opcode, int oparg, location loc) -{ - RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); - return basicblock_addop(g->g_curblock, opcode, oparg, loc); -} - -static int cfg_builder_init(cfg_builder *g); static int instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { memset(g, 0, sizeof(cfg_builder)); - RETURN_IF_ERROR(cfg_builder_init(g)); + RETURN_IF_ERROR(_PyCfgBuilder_Init(g)); /* There can be more than one label for the same offset. The * offset2lbl maping selects one of them which we use consistently. @@ -621,7 +391,7 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { if (lbl >= 0) { assert (lbl < seq->s_labelmap_size); jump_target_label lbl_ = {lbl}; - if (cfg_builder_use_label(g, lbl_) < 0) { + if (_PyCfgBuilder_UseLabel(g, lbl_) < 0) { goto error; } } @@ -635,7 +405,7 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { assert(lbl >= 0 && lbl < seq->s_labelmap_size); oparg = lbl; } - if (cfg_builder_addop(g, opcode, oparg, instr->i_loc) < 0) { + if (_PyCfgBuilder_Addop(g, opcode, oparg, instr->i_loc) < 0) { goto error; } } @@ -746,8 +516,6 @@ typedef struct { Py_ssize_t on_top; } pattern_context; -static int basicblock_next_instr(basicblock *); - static int codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc); static void compiler_free(struct compiler *); @@ -798,8 +566,6 @@ static int compiler_match(struct compiler *, stmt_ty); static int compiler_pattern_subpattern(struct compiler *, pattern_ty, pattern_context *); -static int remove_redundant_nops(basicblock *bb); - static PyCodeObject *assemble(struct compiler *, int addNone); #define CAPSULE_NAME "compile.c compiler unit" @@ -979,57 +745,6 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset) return dest; } -#ifndef NDEBUG -static bool -cfg_builder_check(cfg_builder *g) -{ - assert(g->g_entryblock->b_iused > 0); - for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) { - assert(!_PyMem_IsPtrFreed(block)); - if (block->b_instr != NULL) { - assert(block->b_ialloc > 0); - assert(block->b_iused >= 0); - assert(block->b_ialloc >= block->b_iused); - } - else { - assert (block->b_iused == 0); - assert (block->b_ialloc == 0); - } - } - return true; -} -#endif - -static basicblock *cfg_builder_new_block(cfg_builder *g); - -static int -cfg_builder_init(cfg_builder *g) -{ - g->g_block_list = NULL; - basicblock *block = cfg_builder_new_block(g); - if (block == NULL) { - return ERROR; - } - g->g_curblock = g->g_entryblock = block; - g->g_current_label = NO_LABEL; - return SUCCESS; -} - -static void -cfg_builder_fini(cfg_builder* g) -{ - assert(cfg_builder_check(g)); - basicblock *b = g->g_block_list; - while (b != NULL) { - if (b->b_instr) { - PyObject_Free((void *)b->b_instr); - } - basicblock *next = b->b_list; - PyObject_Free((void *)b); - b = next; - } -} - static void compiler_unit_free(struct compiler_unit *u) { @@ -1119,85 +834,6 @@ compiler_set_qualname(struct compiler *c) return SUCCESS; } -/* Allocate a new block and return a pointer to it. - Returns NULL on error. -*/ -static basicblock * -cfg_builder_new_block(cfg_builder *g) -{ - basicblock *b = (basicblock *)PyObject_Calloc(1, sizeof(basicblock)); - if (b == NULL) { - PyErr_NoMemory(); - return NULL; - } - /* Extend the singly linked list of blocks with new block. */ - b->b_list = g->g_block_list; - g->g_block_list = b; - b->b_label = NO_LABEL; - return b; -} - -static basicblock * -cfg_builder_use_next_block(cfg_builder *g, basicblock *block) -{ - assert(block != NULL); - g->g_curblock->b_next = block; - g->g_curblock = block; - return block; -} - -static inline int -basicblock_append_instructions(basicblock *target, basicblock *source) -{ - for (int i = 0; i < source->b_iused; i++) { - int n = basicblock_next_instr(target); - if (n < 0) { - return ERROR; - } - target->b_instr[n] = source->b_instr[i]; - } - return SUCCESS; -} - -static basicblock * -copy_basicblock(cfg_builder *g, basicblock *block) -{ - /* Cannot copy a block if it has a fallthrough, since - * a block can only have one fallthrough predecessor. - */ - assert(BB_NO_FALLTHROUGH(block)); - basicblock *result = cfg_builder_new_block(g); - if (result == NULL) { - return NULL; - } - if (basicblock_append_instructions(result, block) < 0) { - return NULL; - } - return result; -} - -/* Returns the offset of the next instruction in the current block's - b_instr array. Resizes the b_instr as necessary. - Returns -1 on failure. -*/ - -static int -basicblock_next_instr(basicblock *b) -{ - assert(b != NULL); - - RETURN_IF_ERROR( - ensure_array_large_enough( - b->b_iused + 1, - (void**)&b->b_instr, - &b->b_ialloc, - DEFAULT_BLOCK_SIZE, - sizeof(struct cfg_instr))); - - return b->b_iused++; -} - - /* Return the stack effect of opcode with argument oparg. Some opcodes have different stack effect when jump to the target and @@ -1290,62 +926,6 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg) return stack_effect(opcode, oparg, -1); } -static int -basicblock_addop(basicblock *b, int opcode, int oparg, location loc) -{ - assert(IS_WITHIN_OPCODE_RANGE(opcode)); - assert(!IS_ASSEMBLER_OPCODE(opcode)); - assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); - assert(0 <= oparg && oparg < (1 << 30)); - - int off = basicblock_next_instr(b); - if (off < 0) { - return ERROR; - } - struct cfg_instr *i = &b->b_instr[off]; - i->i_opcode = opcode; - i->i_oparg = oparg; - i->i_target = NULL; - i->i_loc = loc; - - return SUCCESS; -} - -static bool -cfg_builder_current_block_is_terminated(cfg_builder *g) -{ - struct cfg_instr *last = basicblock_last_instr(g->g_curblock); - if (last && IS_TERMINATOR_OPCODE(last->i_opcode)) { - return true; - } - if (IS_LABEL(g->g_current_label)) { - if (last || IS_LABEL(g->g_curblock->b_label)) { - return true; - } - else { - /* current block is empty, label it */ - g->g_curblock->b_label = g->g_current_label; - g->g_current_label = NO_LABEL; - } - } - return false; -} - -static int -cfg_builder_maybe_start_new_block(cfg_builder *g) -{ - if (cfg_builder_current_block_is_terminated(g)) { - basicblock *b = cfg_builder_new_block(g); - if (b == NULL) { - return ERROR; - } - b->b_label = g->g_current_label; - g->g_current_label = NO_LABEL; - cfg_builder_use_next_block(g, b); - } - return SUCCESS; -} - static int codegen_addop_noarg(instr_sequence *seq, int opcode, location loc) { @@ -2520,16 +2100,6 @@ compiler_check_debug_args(struct compiler *c, arguments_ty args) return SUCCESS; } -static inline int -insert_instruction(basicblock *block, int pos, struct cfg_instr *instr) { - RETURN_IF_ERROR(basicblock_next_instr(block)); - for (int i = block->b_iused - 1; i > pos; i--) { - block->b_instr[i] = block->b_instr[i-1]; - } - block->b_instr[pos] = *instr; - return SUCCESS; -} - static int wrap_in_stopiteration_handler(struct compiler *c) { @@ -7037,101 +6607,6 @@ struct assembler { int a_location_off; /* offset of last written location info frame */ }; -static basicblock** -make_cfg_traversal_stack(basicblock *entryblock) { - int nblocks = 0; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - b->b_visited = 0; - nblocks++; - } - basicblock **stack = (basicblock **)PyMem_Malloc(sizeof(basicblock *) * nblocks); - if (!stack) { - PyErr_NoMemory(); - } - return stack; -} - -Py_LOCAL_INLINE(void) -stackdepth_push(basicblock ***sp, basicblock *b, int depth) -{ - assert(b->b_startdepth < 0 || b->b_startdepth == depth); - if (b->b_startdepth < depth && b->b_startdepth < 100) { - assert(b->b_startdepth < 0); - b->b_startdepth = depth; - *(*sp)++ = b; - } -} - -/* Find the flow path that needs the largest stack. We assume that - * cycles in the flow graph have no net effect on the stack depth. - */ -static int -stackdepth(basicblock *entryblock, int code_flags) -{ - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - b->b_startdepth = INT_MIN; - } - basicblock **stack = make_cfg_traversal_stack(entryblock); - if (!stack) { - return ERROR; - } - - int maxdepth = 0; - basicblock **sp = stack; - if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { - stackdepth_push(&sp, entryblock, 1); - } else { - stackdepth_push(&sp, entryblock, 0); - } - - while (sp != stack) { - basicblock *b = *--sp; - int depth = b->b_startdepth; - assert(depth >= 0); - basicblock *next = b->b_next; - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - int effect = stack_effect(instr->i_opcode, instr->i_oparg, 0); - if (effect == PY_INVALID_STACK_EFFECT) { - PyErr_Format(PyExc_SystemError, - "compiler stack_effect(opcode=%d, arg=%i) failed", - instr->i_opcode, instr->i_oparg); - return ERROR; - } - int new_depth = depth + effect; - assert(new_depth >= 0); /* invalid code or bug in stackdepth() */ - if (new_depth > maxdepth) { - maxdepth = new_depth; - } - if (HAS_TARGET(instr->i_opcode)) { - effect = stack_effect(instr->i_opcode, instr->i_oparg, 1); - assert(effect != PY_INVALID_STACK_EFFECT); - int target_depth = depth + effect; - assert(target_depth >= 0); /* invalid code or bug in stackdepth() */ - if (target_depth > maxdepth) { - maxdepth = target_depth; - } - stackdepth_push(&sp, instr->i_target, target_depth); - } - depth = new_depth; - assert(!IS_ASSEMBLER_OPCODE(instr->i_opcode)); - if (IS_UNCONDITIONAL_JUMP_OPCODE(instr->i_opcode) || - IS_SCOPE_EXIT_OPCODE(instr->i_opcode)) - { - /* remaining code is dead */ - next = NULL; - break; - } - } - if (next != NULL) { - assert(BB_HAS_FALLTHROUGH(b)); - stackdepth_push(&sp, next, depth); - } - } - PyMem_Free(stack); - return maxdepth; -} - static int assemble_init(struct assembler *a, int firstlineno) { @@ -7168,389 +6643,47 @@ assemble_free(struct assembler *a) Py_XDECREF(a->a_except_table); } -static int -blocksize(basicblock *b) -{ - int size = 0; - for (int i = 0; i < b->b_iused; i++) { - size += instr_size(&b->b_instr[i]); - } - return size; -} - -static basicblock * -push_except_block(ExceptStack *stack, struct cfg_instr *setup) { - assert(is_block_push(setup)); - int opcode = setup->i_opcode; - basicblock * target = setup->i_target; - if (opcode == SETUP_WITH || opcode == SETUP_CLEANUP) { - target->b_preserve_lasti = 1; - } - stack->handlers[++stack->depth] = target; - return target; -} - -static basicblock * -pop_except_block(ExceptStack *stack) { - assert(stack->depth > 0); - return stack->handlers[--stack->depth]; +static inline void +write_except_byte(struct assembler *a, int byte) { + unsigned char *p = (unsigned char *) PyBytes_AS_STRING(a->a_except_table); + p[a->a_except_table_off++] = byte; } -static basicblock * -except_stack_top(ExceptStack *stack) { - return stack->handlers[stack->depth]; -} +#define CONTINUATION_BIT 64 -static ExceptStack * -make_except_stack(void) { - ExceptStack *new = PyMem_Malloc(sizeof(ExceptStack)); - if (new == NULL) { - PyErr_NoMemory(); - return NULL; +static void +assemble_emit_exception_table_item(struct assembler *a, int value, int msb) +{ + assert ((msb | 128) == 128); + assert(value >= 0 && value < (1 << 30)); + if (value >= 1 << 24) { + write_except_byte(a, (value >> 24) | CONTINUATION_BIT | msb); + msb = 0; } - new->depth = 0; - new->handlers[0] = NULL; - return new; -} - -static ExceptStack * -copy_except_stack(ExceptStack *stack) { - ExceptStack *copy = PyMem_Malloc(sizeof(ExceptStack)); - if (copy == NULL) { - PyErr_NoMemory(); - return NULL; + if (value >= 1 << 18) { + write_except_byte(a, ((value >> 18)&0x3f) | CONTINUATION_BIT | msb); + msb = 0; + } + if (value >= 1 << 12) { + write_except_byte(a, ((value >> 12)&0x3f) | CONTINUATION_BIT | msb); + msb = 0; } - memcpy(copy, stack, sizeof(ExceptStack)); - return copy; + if (value >= 1 << 6) { + write_except_byte(a, ((value >> 6)&0x3f) | CONTINUATION_BIT | msb); + msb = 0; + } + write_except_byte(a, (value&0x3f) | msb); } +/* See Objects/exception_handling_notes.txt for details of layout */ +#define MAX_SIZE_OF_ENTRY 20 + static int -label_exception_targets(basicblock *entryblock) { - basicblock **todo_stack = make_cfg_traversal_stack(entryblock); - if (todo_stack == NULL) { - return ERROR; - } - ExceptStack *except_stack = make_except_stack(); - if (except_stack == NULL) { - PyMem_Free(todo_stack); - PyErr_NoMemory(); - return ERROR; - } - except_stack->depth = 0; - todo_stack[0] = entryblock; - entryblock->b_visited = 1; - entryblock->b_exceptstack = except_stack; - basicblock **todo = &todo_stack[1]; - basicblock *handler = NULL; - while (todo > todo_stack) { - todo--; - basicblock *b = todo[0]; - assert(b->b_visited == 1); - except_stack = b->b_exceptstack; - assert(except_stack != NULL); - b->b_exceptstack = NULL; - handler = except_stack_top(except_stack); - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - if (is_block_push(instr)) { - if (!instr->i_target->b_visited) { - ExceptStack *copy = copy_except_stack(except_stack); - if (copy == NULL) { - goto error; - } - instr->i_target->b_exceptstack = copy; - todo[0] = instr->i_target; - instr->i_target->b_visited = 1; - todo++; - } - handler = push_except_block(except_stack, instr); - } - else if (instr->i_opcode == POP_BLOCK) { - handler = pop_except_block(except_stack); - } - else if (is_jump(instr)) { - instr->i_except = handler; - assert(i == b->b_iused -1); - if (!instr->i_target->b_visited) { - if (BB_HAS_FALLTHROUGH(b)) { - ExceptStack *copy = copy_except_stack(except_stack); - if (copy == NULL) { - goto error; - } - instr->i_target->b_exceptstack = copy; - } - else { - instr->i_target->b_exceptstack = except_stack; - except_stack = NULL; - } - todo[0] = instr->i_target; - instr->i_target->b_visited = 1; - todo++; - } - } - else { - if (instr->i_opcode == YIELD_VALUE) { - instr->i_oparg = except_stack->depth; - } - instr->i_except = handler; - } - } - if (BB_HAS_FALLTHROUGH(b) && !b->b_next->b_visited) { - assert(except_stack != NULL); - b->b_next->b_exceptstack = except_stack; - todo[0] = b->b_next; - b->b_next->b_visited = 1; - todo++; - } - else if (except_stack != NULL) { - PyMem_Free(except_stack); - } - } -#ifdef Py_DEBUG - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - assert(b->b_exceptstack == NULL); - } -#endif - PyMem_Free(todo_stack); - return SUCCESS; -error: - PyMem_Free(todo_stack); - PyMem_Free(except_stack); - return ERROR; -} - - -static int -mark_except_handlers(basicblock *entryblock) { -#ifndef NDEBUG - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - assert(!b->b_except_handler); - } -#endif - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - for (int i=0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - if (is_block_push(instr)) { - instr->i_target->b_except_handler = 1; - } - } - } - return SUCCESS; -} - -static int -mark_warm(basicblock *entryblock) { - basicblock **stack = make_cfg_traversal_stack(entryblock); - if (stack == NULL) { - return ERROR; - } - basicblock **sp = stack; - - *sp++ = entryblock; - entryblock->b_visited = 1; - while (sp > stack) { - basicblock *b = *(--sp); - assert(!b->b_except_handler); - b->b_warm = 1; - basicblock *next = b->b_next; - if (next && BB_HAS_FALLTHROUGH(b) && !next->b_visited) { - *sp++ = next; - next->b_visited = 1; - } - for (int i=0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - if (is_jump(instr) && !instr->i_target->b_visited) { - *sp++ = instr->i_target; - instr->i_target->b_visited = 1; - } - } - } - PyMem_Free(stack); - return SUCCESS; -} - -static int -mark_cold(basicblock *entryblock) { - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - assert(!b->b_cold && !b->b_warm); - } - if (mark_warm(entryblock) < 0) { - return ERROR; - } - - basicblock **stack = make_cfg_traversal_stack(entryblock); - if (stack == NULL) { - return ERROR; - } - - basicblock **sp = stack; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (b->b_except_handler) { - assert(!b->b_warm); - *sp++ = b; - b->b_visited = 1; - } - } - - while (sp > stack) { - basicblock *b = *(--sp); - b->b_cold = 1; - basicblock *next = b->b_next; - if (next && BB_HAS_FALLTHROUGH(b)) { - if (!next->b_warm && !next->b_visited) { - *sp++ = next; - next->b_visited = 1; - } - } - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - if (is_jump(instr)) { - assert(i == b->b_iused - 1); - basicblock *target = b->b_instr[i].i_target; - if (!target->b_warm && !target->b_visited) { - *sp++ = target; - target->b_visited = 1; - } - } - } - } - PyMem_Free(stack); - return SUCCESS; -} - -static int -remove_redundant_jumps(cfg_builder *g); - -static int -push_cold_blocks_to_end(cfg_builder *g, int code_flags) { - basicblock *entryblock = g->g_entryblock; - if (entryblock->b_next == NULL) { - /* single basicblock, no need to reorder */ - return SUCCESS; - } - RETURN_IF_ERROR(mark_cold(entryblock)); - - /* If we have a cold block with fallthrough to a warm block, add */ - /* an explicit jump instead of fallthrough */ - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (b->b_cold && BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_next->b_warm) { - basicblock *explicit_jump = cfg_builder_new_block(g); - if (explicit_jump == NULL) { - return ERROR; - } - basicblock_addop(explicit_jump, JUMP, b->b_next->b_label.id, NO_LOCATION); - explicit_jump->b_cold = 1; - explicit_jump->b_next = b->b_next; - b->b_next = explicit_jump; - - /* set target */ - struct cfg_instr *last = basicblock_last_instr(explicit_jump); - last->i_target = explicit_jump->b_next; - } - } - - assert(!entryblock->b_cold); /* First block can't be cold */ - basicblock *cold_blocks = NULL; - basicblock *cold_blocks_tail = NULL; - - basicblock *b = entryblock; - while(b->b_next) { - assert(!b->b_cold); - while (b->b_next && !b->b_next->b_cold) { - b = b->b_next; - } - if (b->b_next == NULL) { - /* no more cold blocks */ - break; - } - - /* b->b_next is the beginning of a cold streak */ - assert(!b->b_cold && b->b_next->b_cold); - - basicblock *b_end = b->b_next; - while (b_end->b_next && b_end->b_next->b_cold) { - b_end = b_end->b_next; - } - - /* b_end is the end of the cold streak */ - assert(b_end && b_end->b_cold); - assert(b_end->b_next == NULL || !b_end->b_next->b_cold); - - if (cold_blocks == NULL) { - cold_blocks = b->b_next; - } - else { - cold_blocks_tail->b_next = b->b_next; - } - cold_blocks_tail = b_end; - b->b_next = b_end->b_next; - b_end->b_next = NULL; - } - assert(b != NULL && b->b_next == NULL); - b->b_next = cold_blocks; - - if (cold_blocks != NULL) { - RETURN_IF_ERROR(remove_redundant_jumps(g)); - } - return SUCCESS; -} - -static void -convert_exception_handlers_to_nops(basicblock *entryblock) { - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) { - INSTR_SET_OP0(instr, NOP); - } - } - } - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - remove_redundant_nops(b); - } -} - -static inline void -write_except_byte(struct assembler *a, int byte) { - unsigned char *p = (unsigned char *) PyBytes_AS_STRING(a->a_except_table); - p[a->a_except_table_off++] = byte; -} - -#define CONTINUATION_BIT 64 - -static void -assemble_emit_exception_table_item(struct assembler *a, int value, int msb) -{ - assert ((msb | 128) == 128); - assert(value >= 0 && value < (1 << 30)); - if (value >= 1 << 24) { - write_except_byte(a, (value >> 24) | CONTINUATION_BIT | msb); - msb = 0; - } - if (value >= 1 << 18) { - write_except_byte(a, ((value >> 18)&0x3f) | CONTINUATION_BIT | msb); - msb = 0; - } - if (value >= 1 << 12) { - write_except_byte(a, ((value >> 12)&0x3f) | CONTINUATION_BIT | msb); - msb = 0; - } - if (value >= 1 << 6) { - write_except_byte(a, ((value >> 6)&0x3f) | CONTINUATION_BIT | msb); - msb = 0; - } - write_except_byte(a, (value&0x3f) | msb); -} - -/* See Objects/exception_handling_notes.txt for details of layout */ -#define MAX_SIZE_OF_ENTRY 20 - -static int -assemble_emit_exception_table_entry(struct assembler *a, int start, int end, basicblock *handler) -{ - Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table); - if (a->a_except_table_off + MAX_SIZE_OF_ENTRY >= len) { - RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, len * 2)); +assemble_emit_exception_table_entry(struct assembler *a, int start, int end, basicblock *handler) +{ + Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table); + if (a->a_except_table_off + MAX_SIZE_OF_ENTRY >= len) { + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, len * 2)); } int size = end-start; assert(end > start); @@ -7578,7 +6711,7 @@ assemble_exception_table(struct assembler *a, basicblock *entryblock) for (b = entryblock; b != NULL; b = b->b_next) { ioffset = b->b_offset; for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; + cfg_instr *instr = &b->b_instr[i]; if (instr->i_except != handler) { if (handler != NULL) { RETURN_IF_ERROR( @@ -7587,7 +6720,7 @@ assemble_exception_table(struct assembler *a, basicblock *entryblock) start = ioffset; handler = instr->i_except; } - ioffset += instr_size(instr); + ioffset += _PyCfg_InstrSize(instr); } } if (handler != NULL) { @@ -7755,7 +6888,7 @@ assemble_location_info(struct assembler *a, basicblock *entryblock, int firstlin loc = b->b_instr[j].i_loc; size = 0; } - size += instr_size(&b->b_instr[j]); + size += _PyCfg_InstrSize(&b->b_instr[j]); } } RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); @@ -7768,12 +6901,12 @@ assemble_location_info(struct assembler *a, basicblock *entryblock, int firstlin */ static int -assemble_emit_instr(struct assembler *a, struct cfg_instr *i) +assemble_emit_instr(struct assembler *a, cfg_instr *i) { Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); _Py_CODEUNIT *code; - int size = instr_size(i); + int size = _PyCfg_InstrSize(i); if (a->a_offset + size >= len / (int)sizeof(_Py_CODEUNIT)) { if (len > PY_SSIZE_T_MAX / 2) { return ERROR; @@ -7786,8 +6919,6 @@ assemble_emit_instr(struct assembler *a, struct cfg_instr *i) return SUCCESS; } -static int merge_const_one(PyObject *const_cache, PyObject **obj); - static int assemble_emit(struct assembler *a, basicblock *entryblock, int first_lineno, PyObject *const_cache) @@ -7805,391 +6936,95 @@ assemble_emit(struct assembler *a, basicblock *entryblock, int first_lineno, RETURN_IF_ERROR(assemble_exception_table(a, entryblock)); RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off)); - RETURN_IF_ERROR(merge_const_one(const_cache, &a->a_except_table)); + RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_except_table)); RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, a->a_location_off)); - RETURN_IF_ERROR(merge_const_one(const_cache, &a->a_linetable)); + RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_linetable)); RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT))); - RETURN_IF_ERROR(merge_const_one(const_cache, &a->a_bytecode)); + RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_bytecode)); return SUCCESS; } -static int -normalize_jumps_in_block(cfg_builder *g, basicblock *b) { - struct cfg_instr *last = basicblock_last_instr(b); - if (last == NULL || !is_jump(last)) { - return SUCCESS; - } - assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); - bool is_forward = last->i_target->b_visited == 0; - switch(last->i_opcode) { - case JUMP: - last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; - return SUCCESS; - case JUMP_NO_INTERRUPT: - last->i_opcode = is_forward ? - JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; - return SUCCESS; - } - int reversed_opcode = 0; - switch(last->i_opcode) { - case POP_JUMP_IF_NOT_NONE: - reversed_opcode = POP_JUMP_IF_NONE; - break; - case POP_JUMP_IF_NONE: - reversed_opcode = POP_JUMP_IF_NOT_NONE; - break; - case POP_JUMP_IF_FALSE: - reversed_opcode = POP_JUMP_IF_TRUE; - break; - case POP_JUMP_IF_TRUE: - reversed_opcode = POP_JUMP_IF_FALSE; - break; - } - if (is_forward) { - return SUCCESS; +static PyObject * +dict_keys_inorder(PyObject *dict, Py_ssize_t offset) +{ + PyObject *tuple, *k, *v; + Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict); + + tuple = PyTuple_New(size); + if (tuple == NULL) + return NULL; + while (PyDict_Next(dict, &pos, &k, &v)) { + i = PyLong_AS_LONG(v); + assert((i - offset) < size); + assert((i - offset) >= 0); + PyTuple_SET_ITEM(tuple, i - offset, Py_NewRef(k)); } + return tuple; +} - /* transform 'conditional jump T' to - * 'reversed_jump b_next' followed by 'jump_backwards T' - */ +static PyObject * +consts_dict_keys_inorder(PyObject *dict) +{ + PyObject *consts, *k, *v; + Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict); - basicblock *target = last->i_target; - basicblock *backwards_jump = cfg_builder_new_block(g); - if (backwards_jump == NULL) { - return ERROR; + consts = PyList_New(size); /* PyCode_Optimize() requires a list */ + if (consts == NULL) + return NULL; + while (PyDict_Next(dict, &pos, &k, &v)) { + i = PyLong_AS_LONG(v); + /* The keys of the dictionary can be tuples wrapping a constant. + * (see dict_add_o and _PyCode_ConstantKey). In that case + * the object we want is always second. */ + if (PyTuple_CheckExact(k)) { + k = PyTuple_GET_ITEM(k, 1); + } + assert(i < size); + assert(i >= 0); + PyList_SET_ITEM(consts, i, Py_NewRef(k)); } - basicblock_addop(backwards_jump, JUMP, target->b_label.id, NO_LOCATION); - backwards_jump->b_instr[0].i_target = target; - last->i_opcode = reversed_opcode; - last->i_target = b->b_next; - - backwards_jump->b_cold = b->b_cold; - backwards_jump->b_next = b->b_next; - b->b_next = backwards_jump; - return SUCCESS; + return consts; } static int -normalize_jumps(cfg_builder *g) +compute_code_flags(struct compiler *c) { - basicblock *entryblock = g->g_entryblock; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - b->b_visited = 0; - } - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - b->b_visited = 1; - RETURN_IF_ERROR(normalize_jumps_in_block(g, b)); + PySTEntryObject *ste = c->u->u_ste; + int flags = 0; + if (ste->ste_type == FunctionBlock) { + flags |= CO_NEWLOCALS | CO_OPTIMIZED; + if (ste->ste_nested) + flags |= CO_NESTED; + if (ste->ste_generator && !ste->ste_coroutine) + flags |= CO_GENERATOR; + if (!ste->ste_generator && ste->ste_coroutine) + flags |= CO_COROUTINE; + if (ste->ste_generator && ste->ste_coroutine) + flags |= CO_ASYNC_GENERATOR; + if (ste->ste_varargs) + flags |= CO_VARARGS; + if (ste->ste_varkeywords) + flags |= CO_VARKEYWORDS; } - return SUCCESS; -} - -static void -assemble_jump_offsets(basicblock *entryblock) -{ - int bsize, totsize, extended_arg_recompile; - - /* Compute the size of each block and fixup jump args. - Replace block pointer with position in bytecode. */ - do { - totsize = 0; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - bsize = blocksize(b); - b->b_offset = totsize; - totsize += bsize; - } - extended_arg_recompile = 0; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - bsize = b->b_offset; - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - int isize = instr_size(instr); - /* Relative jumps are computed relative to - the instruction pointer after fetching - the jump instruction. - */ - bsize += isize; - if (is_jump(instr)) { - instr->i_oparg = instr->i_target->b_offset; - if (is_relative_jump(instr)) { - if (instr->i_oparg < bsize) { - assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); - instr->i_oparg = bsize - instr->i_oparg; - } - else { - assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); - instr->i_oparg -= bsize; - } - } - else { - assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); - } - if (instr_size(instr) != isize) { - extended_arg_recompile = 1; - } - } - } - } - /* XXX: This is an awful hack that could hurt performance, but - on the bright side it should work until we come up - with a better solution. + /* (Only) inherit compilerflags in PyCF_MASK */ + flags |= (c->c_flags.cf_flags & PyCF_MASK); - The issue is that in the first loop blocksize() is called - which calls instr_size() which requires i_oparg be set - appropriately. There is a bootstrap problem because - i_oparg is calculated in the second loop above. + if ((IS_TOP_LEVEL_AWAIT(c)) && + ste->ste_coroutine && + !ste->ste_generator) { + flags |= CO_COROUTINE; + } - So we loop until we stop seeing new EXTENDED_ARGs. - The only EXTENDED_ARGs that could be popping up are - ones in jump instructions. So this should converge - fairly quickly. - */ - } while (extended_arg_recompile); + return flags; } - -// helper functions for add_checks_for_loads_of_unknown_variables -static inline void -maybe_push(basicblock *b, uint64_t unsafe_mask, basicblock ***sp) -{ - // Push b if the unsafe mask is giving us any new information. - // To avoid overflowing the stack, only allow each block once. - // Use b->b_visited=1 to mean that b is currently on the stack. - uint64_t both = b->b_unsafe_locals_mask | unsafe_mask; - if (b->b_unsafe_locals_mask != both) { - b->b_unsafe_locals_mask = both; - // More work left to do. - if (!b->b_visited) { - // not on the stack, so push it. - *(*sp)++ = b; - b->b_visited = 1; - } - } -} - -static void -scan_block_for_locals(basicblock *b, basicblock ***sp) -{ - // bit i is set if local i is potentially uninitialized - uint64_t unsafe_mask = b->b_unsafe_locals_mask; - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - assert(instr->i_opcode != EXTENDED_ARG); - assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); - if (instr->i_except != NULL) { - maybe_push(instr->i_except, unsafe_mask, sp); - } - if (instr->i_oparg >= 64) { - continue; - } - assert(instr->i_oparg >= 0); - uint64_t bit = (uint64_t)1 << instr->i_oparg; - switch (instr->i_opcode) { - case DELETE_FAST: - unsafe_mask |= bit; - break; - case STORE_FAST: - unsafe_mask &= ~bit; - break; - case LOAD_FAST_CHECK: - // If this doesn't raise, then the local is defined. - unsafe_mask &= ~bit; - break; - case LOAD_FAST: - if (unsafe_mask & bit) { - instr->i_opcode = LOAD_FAST_CHECK; - } - unsafe_mask &= ~bit; - break; - } - } - if (b->b_next && BB_HAS_FALLTHROUGH(b)) { - maybe_push(b->b_next, unsafe_mask, sp); - } - struct cfg_instr *last = basicblock_last_instr(b); - if (last && is_jump(last)) { - assert(last->i_target != NULL); - maybe_push(last->i_target, unsafe_mask, sp); - } -} - -static int -fast_scan_many_locals(basicblock *entryblock, int nlocals) -{ - assert(nlocals > 64); - Py_ssize_t *states = PyMem_Calloc(nlocals - 64, sizeof(Py_ssize_t)); - if (states == NULL) { - PyErr_NoMemory(); - return ERROR; - } - Py_ssize_t blocknum = 0; - // state[i - 64] == blocknum if local i is guaranteed to - // be initialized, i.e., if it has had a previous LOAD_FAST or - // STORE_FAST within that basicblock (not followed by DELETE_FAST). - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - blocknum++; - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - assert(instr->i_opcode != EXTENDED_ARG); - assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); - int arg = instr->i_oparg; - if (arg < 64) { - continue; - } - assert(arg >= 0); - switch (instr->i_opcode) { - case DELETE_FAST: - states[arg - 64] = blocknum - 1; - break; - case STORE_FAST: - states[arg - 64] = blocknum; - break; - case LOAD_FAST: - if (states[arg - 64] != blocknum) { - instr->i_opcode = LOAD_FAST_CHECK; - } - states[arg - 64] = blocknum; - break; - case LOAD_FAST_CHECK: - Py_UNREACHABLE(); - } - } - } - PyMem_Free(states); - return SUCCESS; -} - -static int -add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock, - int nlocals, - int nparams) -{ - if (nlocals == 0) { - return SUCCESS; - } - if (nlocals > 64) { - // To avoid O(nlocals**2) compilation, locals beyond the first - // 64 are only analyzed one basicblock at a time: initialization - // info is not passed between basicblocks. - if (fast_scan_many_locals(entryblock, nlocals) < 0) { - return ERROR; - } - nlocals = 64; - } - basicblock **stack = make_cfg_traversal_stack(entryblock); - if (stack == NULL) { - return ERROR; - } - basicblock **sp = stack; - - // First origin of being uninitialized: - // The non-parameter locals in the entry block. - uint64_t start_mask = 0; - for (int i = nparams; i < nlocals; i++) { - start_mask |= (uint64_t)1 << i; - } - maybe_push(entryblock, start_mask, &sp); - - // Second origin of being uninitialized: - // There could be DELETE_FAST somewhere, so - // be sure to scan each basicblock at least once. - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - scan_block_for_locals(b, &sp); - } - - // Now propagate the uncertainty from the origins we found: Use - // LOAD_FAST_CHECK for any LOAD_FAST where the local could be undefined. - while (sp > stack) { - basicblock *b = *--sp; - // mark as no longer on stack - b->b_visited = 0; - scan_block_for_locals(b, &sp); - } - PyMem_Free(stack); - return SUCCESS; -} - -static PyObject * -dict_keys_inorder(PyObject *dict, Py_ssize_t offset) -{ - PyObject *tuple, *k, *v; - Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict); - - tuple = PyTuple_New(size); - if (tuple == NULL) - return NULL; - while (PyDict_Next(dict, &pos, &k, &v)) { - i = PyLong_AS_LONG(v); - assert((i - offset) < size); - assert((i - offset) >= 0); - PyTuple_SET_ITEM(tuple, i - offset, Py_NewRef(k)); - } - return tuple; -} - -static PyObject * -consts_dict_keys_inorder(PyObject *dict) -{ - PyObject *consts, *k, *v; - Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict); - - consts = PyList_New(size); /* PyCode_Optimize() requires a list */ - if (consts == NULL) - return NULL; - while (PyDict_Next(dict, &pos, &k, &v)) { - i = PyLong_AS_LONG(v); - /* The keys of the dictionary can be tuples wrapping a constant. - * (see dict_add_o and _PyCode_ConstantKey). In that case - * the object we want is always second. */ - if (PyTuple_CheckExact(k)) { - k = PyTuple_GET_ITEM(k, 1); - } - assert(i < size); - assert(i >= 0); - PyList_SET_ITEM(consts, i, Py_NewRef(k)); - } - return consts; -} - -static int -compute_code_flags(struct compiler *c) -{ - PySTEntryObject *ste = c->u->u_ste; - int flags = 0; - if (ste->ste_type == FunctionBlock) { - flags |= CO_NEWLOCALS | CO_OPTIMIZED; - if (ste->ste_nested) - flags |= CO_NESTED; - if (ste->ste_generator && !ste->ste_coroutine) - flags |= CO_GENERATOR; - if (!ste->ste_generator && ste->ste_coroutine) - flags |= CO_COROUTINE; - if (ste->ste_generator && ste->ste_coroutine) - flags |= CO_ASYNC_GENERATOR; - if (ste->ste_varargs) - flags |= CO_VARARGS; - if (ste->ste_varkeywords) - flags |= CO_VARKEYWORDS; - } - - /* (Only) inherit compilerflags in PyCF_MASK */ - flags |= (c->c_flags.cf_flags & PyCF_MASK); - - if ((IS_TOP_LEVEL_AWAIT(c)) && - ste->ste_coroutine && - !ste->ste_generator) { - flags |= CO_COROUTINE; - } - - return flags; -} - -// Merge *obj* with constant cache. -// Unlike merge_consts_recursive(), this function doesn't work recursively. -static int -merge_const_one(PyObject *const_cache, PyObject **obj) +// Merge *obj* with constant cache. +// Unlike merge_consts_recursive(), this function doesn't work recursively. +int +_PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj) { assert(PyDict_CheckExact(const_cache)); PyObject *key = _PyCode_ConstantKey(*obj); @@ -8279,7 +7114,7 @@ makecode(struct compiler_unit *u, struct assembler *a, PyObject *const_cache, if (!names) { goto error; } - if (merge_const_one(const_cache, &names) < 0) { + if (_PyCompile_ConstCacheMergeOne(const_cache, &names) < 0) { goto error; } @@ -8287,7 +7122,7 @@ makecode(struct compiler_unit *u, struct assembler *a, PyObject *const_cache, if (consts == NULL) { goto error; } - if (merge_const_one(const_cache, &consts) < 0) { + if (_PyCompile_ConstCacheMergeOne(const_cache, &consts) < 0) { goto error; } @@ -8338,7 +7173,7 @@ makecode(struct compiler_unit *u, struct assembler *a, PyObject *const_cache, goto error; } - if (merge_const_one(const_cache, &localsplusnames) < 0) { + if (_PyCompile_ConstCacheMergeOne(const_cache, &localsplusnames) < 0) { goto error; } con.localsplusnames = localsplusnames; @@ -8357,64 +7192,6 @@ makecode(struct compiler_unit *u, struct assembler *a, PyObject *const_cache, } -/* For debugging purposes only */ -#if 0 -static void -dump_instr(struct cfg_instr *i) -{ - const char *jrel = (is_relative_jump(i)) ? "jrel " : ""; - const char *jabs = (is_jump(i) && !is_relative_jump(i))? "jabs " : ""; - - char arg[128]; - - *arg = '\0'; - if (HAS_ARG(i->i_opcode)) { - sprintf(arg, "arg: %d ", i->i_oparg); - } - if (HAS_TARGET(i->i_opcode)) { - sprintf(arg, "target: %p [%d] ", i->i_target, i->i_oparg); - } - fprintf(stderr, "line: %d, opcode: %d %s%s%s\n", - i->i_loc.lineno, i->i_opcode, arg, jabs, jrel); -} - -static inline int -basicblock_returns(const basicblock *b) { - struct cfg_instr *last = basicblock_last_instr(b); - return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST); -} - -static void -dump_basicblock(const basicblock *b) -{ - const char *b_return = basicblock_returns(b) ? "return " : ""; - fprintf(stderr, "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, offset: %d %s\n", - b->b_label.id, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, - b->b_startdepth, b->b_offset, b_return); - if (b->b_instr) { - int i; - for (i = 0; i < b->b_iused; i++) { - fprintf(stderr, " [%02d] ", i); - dump_instr(b->b_instr + i); - } - } -} -#endif - - -static int -translate_jump_labels_to_targets(basicblock *entryblock); - -static int -optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache); - -static int -remove_unused_consts(basicblock *entryblock, PyObject *consts); - -/* Duplicates exit BBs, so that line numbers can be propagated to them */ -static int -duplicate_exits_without_lineno(cfg_builder *g); - static int * build_cellfixedoffsets(struct compiler_unit *u) { @@ -8456,20 +7233,20 @@ insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock, /* Add the generator prefix instructions. */ if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { - struct cfg_instr make_gen = { + cfg_instr make_gen = { .i_opcode = RETURN_GENERATOR, .i_oparg = 0, .i_loc = LOCATION(u->u_firstlineno, u->u_firstlineno, -1, -1), .i_target = NULL, }; - RETURN_IF_ERROR(insert_instruction(entryblock, 0, &make_gen)); - struct cfg_instr pop_top = { + RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen)); + cfg_instr pop_top = { .i_opcode = POP_TOP, .i_oparg = 0, .i_loc = NO_LOCATION, .i_target = NULL, }; - RETURN_IF_ERROR(insert_instruction(entryblock, 1, &pop_top)); + RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 1, &pop_top)); } /* Set up cells for any variable that escapes, to be put in a closure. */ @@ -8492,60 +7269,32 @@ insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock, if (oldindex == -1) { continue; } - struct cfg_instr make_cell = { + cfg_instr make_cell = { .i_opcode = MAKE_CELL, // This will get fixed in offset_derefs(). .i_oparg = oldindex, .i_loc = NO_LOCATION, .i_target = NULL, }; - RETURN_IF_ERROR(insert_instruction(entryblock, ncellsused, &make_cell)); + RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, ncellsused, &make_cell)); ncellsused += 1; } PyMem_RawFree(sorted); } if (nfreevars) { - struct cfg_instr copy_frees = { + cfg_instr copy_frees = { .i_opcode = COPY_FREE_VARS, .i_oparg = nfreevars, .i_loc = NO_LOCATION, .i_target = NULL, }; - RETURN_IF_ERROR(insert_instruction(entryblock, 0, ©_frees)); + RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, ©_frees)); } return SUCCESS; } -/* Make sure that all returns have a line number, even if early passes - * have failed to propagate a correct line number. - * The resulting line number may not be correct according to PEP 626, - * but should be "good enough", and no worse than in older versions. */ -static void -guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) { - int lineno = firstlineno; - assert(lineno > 0); - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - struct cfg_instr *last = basicblock_last_instr(b); - if (last == NULL) { - continue; - } - if (last->i_loc.lineno < 0) { - if (last->i_opcode == RETURN_VALUE) { - for (int i = 0; i < b->b_iused; i++) { - assert(b->b_instr[i].i_loc.lineno < 0); - - b->b_instr[i].i_loc.lineno = lineno; - } - } - } - else { - lineno = last->i_loc.lineno; - } - } -} - static int fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap) { @@ -8569,7 +7318,7 @@ fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap) // Then update offsets, either relative to locals or by cell2arg. for (basicblock *b = entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *inst = &b->b_instr[i]; + cfg_instr *inst = &b->b_instr[i]; // This is called before extended args are generated. assert(inst->i_opcode != EXTENDED_ARG); int oldoffset = inst->i_oparg; @@ -8592,100 +7341,6 @@ fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap) } -#ifndef NDEBUG - -static bool -no_redundant_nops(cfg_builder *g) { - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - if (remove_redundant_nops(b) != 0) { - return false; - } - } - return true; -} - -static bool -no_redundant_jumps(cfg_builder *g) { - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - struct cfg_instr *last = basicblock_last_instr(b); - if (last != NULL) { - if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { - assert(last->i_target != b->b_next); - if (last->i_target == b->b_next) { - return false; - } - } - } - } - return true; -} - -static bool -opcode_metadata_is_sane(cfg_builder *g) { - bool result = true; - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - int opcode = instr->i_opcode; - int oparg = instr->i_oparg; - assert(opcode <= MAX_REAL_OPCODE); - for (int jump = 0; jump <= 1; jump++) { - int popped = _PyOpcode_num_popped(opcode, oparg, jump ? true : false); - int pushed = _PyOpcode_num_pushed(opcode, oparg, jump ? true : false); - assert((pushed < 0) == (popped < 0)); - if (pushed >= 0) { - assert(_PyOpcode_opcode_metadata[opcode].valid_entry); - int effect = stack_effect(opcode, instr->i_oparg, jump); - if (effect != pushed - popped) { - fprintf(stderr, - "op=%d arg=%d jump=%d: stack_effect (%d) != pushed (%d) - popped (%d)\n", - opcode, oparg, jump, effect, pushed, popped); - result = false; - } - } - } - } - } - return result; -} - -static bool -no_empty_basic_blocks(cfg_builder *g) { - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - if (b->b_iused == 0) { - return false; - } - } - return true; -} -#endif - -static int -remove_redundant_jumps(cfg_builder *g) { - /* If a non-empty block ends with a jump instruction, check if the next - * non-empty block reached through normal flow control is the target - * of that jump. If it is, then the jump instruction is redundant and - * can be deleted. - */ - assert(no_empty_basic_blocks(g)); - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - struct cfg_instr *last = basicblock_last_instr(b); - assert(last != NULL); - assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); - if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { - if (last->i_target == NULL) { - PyErr_SetString(PyExc_SystemError, "jump with NULL target"); - return ERROR; - } - if (last->i_target == b->b_next) { - assert(b->b_next->b_iused); - INSTR_SET_OP0(last, NOP); - } - } - } - return SUCCESS; -} - static int prepare_localsplus(struct compiler_unit* u, cfg_builder *g, int code_flags) { @@ -8734,47 +7389,6 @@ add_return_at_end(struct compiler *c, int addNone) return SUCCESS; } -static void propagate_line_numbers(basicblock *entryblock); - -static int -resolve_line_numbers(struct compiler_unit *u, cfg_builder *g) -{ - /* Set firstlineno if it wasn't explicitly set. */ - if (!u->u_firstlineno) { - if (g->g_entryblock->b_instr && g->g_entryblock->b_instr->i_loc.lineno) { - u->u_firstlineno = g->g_entryblock->b_instr->i_loc.lineno; - } - else { - u->u_firstlineno = 1; - } - } - RETURN_IF_ERROR(duplicate_exits_without_lineno(g)); - propagate_line_numbers(g->g_entryblock); - guarantee_lineno_for_exits(g->g_entryblock, u->u_firstlineno); - return SUCCESS; -} - -static int -optimize_code_unit(cfg_builder *g, PyObject *consts, PyObject *const_cache, - int code_flags, int nlocals, int nparams) -{ - assert(cfg_builder_check(g)); - /** Preprocessing **/ - /* Map labels to targets and mark exception handlers */ - RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock)); - RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock)); - RETURN_IF_ERROR(label_exception_targets(g->g_entryblock)); - - /** Optimization **/ - RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache)); - RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts)); - RETURN_IF_ERROR( - add_checks_for_loads_of_uninitialized_variables( - g->g_entryblock, nlocals, nparams)); - - RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags)); - return SUCCESS; -} static PyCodeObject * assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, @@ -8791,13 +7405,21 @@ assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, } int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); - if (optimize_code_unit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { + if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { goto error; } /** Assembly **/ - - if (resolve_line_numbers(u, &g) < 0) { + /* Set firstlineno if it wasn't explicitly set. */ + if (!u->u_firstlineno) { + if (g.g_entryblock->b_instr && g.g_entryblock->b_instr->i_loc.lineno) { + u->u_firstlineno = g.g_entryblock->b_instr->i_loc.lineno; + } + else { + u->u_firstlineno = 1; + } + } + if (_PyCfg_ResolveLineNumbers(&g, u->u_firstlineno) < 0) { goto error; } @@ -8806,23 +7428,21 @@ assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, goto error; } - int maxdepth = stackdepth(g.g_entryblock, code_flags); + int maxdepth = _PyCfg_Stackdepth(g.g_entryblock, code_flags); if (maxdepth < 0) { goto error; } /* TO DO -- For 3.12, make sure that `maxdepth <= MAX_ALLOWED_STACK_USE` */ - convert_exception_handlers_to_nops(g.g_entryblock); + _PyCfg_ConvertExceptionHandlersToNops(g.g_entryblock); /* Order of basic blocks must have been determined by now */ - if (normalize_jumps(&g) < 0) { + + if (_PyCfg_ResolveJumps(&g) < 0) { goto error; } - assert(no_redundant_jumps(&g)); - assert(opcode_metadata_is_sane(&g)); /* Can't modify the bytecode after computing jump offsets. */ - assemble_jump_offsets(g.g_entryblock); struct assembler a; int res = assemble_emit(&a, g.g_entryblock, u->u_firstlineno, const_cache); @@ -8834,7 +7454,7 @@ assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, error: Py_XDECREF(consts); - cfg_builder_fini(&g); + _PyCfgBuilder_Fini(&g); return co; } @@ -8857,941 +7477,6 @@ assemble(struct compiler *c, int addNone) return assemble_code_unit(u, const_cache, code_flags, filename); } -static PyObject* -get_const_value(int opcode, int oparg, PyObject *co_consts) -{ - PyObject *constant = NULL; - assert(HAS_CONST(opcode)); - if (opcode == LOAD_CONST) { - constant = PyList_GET_ITEM(co_consts, oparg); - } - - if (constant == NULL) { - PyErr_SetString(PyExc_SystemError, - "Internal error: failed to get value of a constant"); - return NULL; - } - return Py_NewRef(constant); -} - -/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n - with LOAD_CONST (c1, c2, ... cn). - The consts table must still be in list form so that the - new constant (c1, c2, ... cn) can be appended. - Called with codestr pointing to the first LOAD_CONST. -*/ -static int -fold_tuple_on_constants(PyObject *const_cache, - struct cfg_instr *inst, - int n, PyObject *consts) -{ - /* Pre-conditions */ - assert(PyDict_CheckExact(const_cache)); - assert(PyList_CheckExact(consts)); - assert(inst[n].i_opcode == BUILD_TUPLE); - assert(inst[n].i_oparg == n); - - for (int i = 0; i < n; i++) { - if (!HAS_CONST(inst[i].i_opcode)) { - return SUCCESS; - } - } - - /* Buildup new tuple of constants */ - PyObject *newconst = PyTuple_New(n); - if (newconst == NULL) { - return ERROR; - } - for (int i = 0; i < n; i++) { - int op = inst[i].i_opcode; - int arg = inst[i].i_oparg; - PyObject *constant = get_const_value(op, arg, consts); - if (constant == NULL) { - return ERROR; - } - PyTuple_SET_ITEM(newconst, i, constant); - } - if (merge_const_one(const_cache, &newconst) < 0) { - Py_DECREF(newconst); - return ERROR; - } - - Py_ssize_t index; - for (index = 0; index < PyList_GET_SIZE(consts); index++) { - if (PyList_GET_ITEM(consts, index) == newconst) { - break; - } - } - if (index == PyList_GET_SIZE(consts)) { - if ((size_t)index >= (size_t)INT_MAX - 1) { - Py_DECREF(newconst); - PyErr_SetString(PyExc_OverflowError, "too many constants"); - return ERROR; - } - if (PyList_Append(consts, newconst)) { - Py_DECREF(newconst); - return ERROR; - } - } - Py_DECREF(newconst); - for (int i = 0; i < n; i++) { - INSTR_SET_OP0(&inst[i], NOP); - } - INSTR_SET_OP1(&inst[n], LOAD_CONST, (int)index); - return SUCCESS; -} - -#define VISITED (-1) - -// Replace an arbitrary run of SWAPs and NOPs with an optimal one that has the -// same effect. -static int -swaptimize(basicblock *block, int *ix) -{ - // NOTE: "./python -m test test_patma" serves as a good, quick stress test - // for this function. Make sure to blow away cached *.pyc files first! - assert(*ix < block->b_iused); - struct cfg_instr *instructions = &block->b_instr[*ix]; - // Find the length of the current sequence of SWAPs and NOPs, and record the - // maximum depth of the stack manipulations: - assert(instructions[0].i_opcode == SWAP); - int depth = instructions[0].i_oparg; - int len = 0; - int more = false; - int limit = block->b_iused - *ix; - while (++len < limit) { - int opcode = instructions[len].i_opcode; - if (opcode == SWAP) { - depth = Py_MAX(depth, instructions[len].i_oparg); - more = true; - } - else if (opcode != NOP) { - break; - } - } - // It's already optimal if there's only one SWAP: - if (!more) { - return SUCCESS; - } - // Create an array with elements {0, 1, 2, ..., depth - 1}: - int *stack = PyMem_Malloc(depth * sizeof(int)); - if (stack == NULL) { - PyErr_NoMemory(); - return ERROR; - } - for (int i = 0; i < depth; i++) { - stack[i] = i; - } - // Simulate the combined effect of these instructions by "running" them on - // our "stack": - for (int i = 0; i < len; i++) { - if (instructions[i].i_opcode == SWAP) { - int oparg = instructions[i].i_oparg; - int top = stack[0]; - // SWAPs are 1-indexed: - stack[0] = stack[oparg - 1]; - stack[oparg - 1] = top; - } - } - // Now we can begin! Our approach here is based on a solution to a closely - // related problem (https://cs.stackexchange.com/a/13938). It's easiest to - // think of this algorithm as determining the steps needed to efficiently - // "un-shuffle" our stack. By performing the moves in *reverse* order, - // though, we can efficiently *shuffle* it! For this reason, we will be - // replacing instructions starting from the *end* of the run. Since the - // solution is optimal, we don't need to worry about running out of space: - int current = len - 1; - for (int i = 0; i < depth; i++) { - // Skip items that have already been visited, or just happen to be in - // the correct location: - if (stack[i] == VISITED || stack[i] == i) { - continue; - } - // Okay, we've found an item that hasn't been visited. It forms a cycle - // with other items; traversing the cycle and swapping each item with - // the next will put them all in the correct place. The weird - // loop-and-a-half is necessary to insert 0 into every cycle, since we - // can only swap from that position: - int j = i; - while (true) { - // Skip the actual swap if our item is zero, since swapping the top - // item with itself is pointless: - if (j) { - assert(0 <= current); - // SWAPs are 1-indexed: - instructions[current].i_opcode = SWAP; - instructions[current--].i_oparg = j + 1; - } - if (stack[j] == VISITED) { - // Completed the cycle: - assert(j == i); - break; - } - int next_j = stack[j]; - stack[j] = VISITED; - j = next_j; - } - } - // NOP out any unused instructions: - while (0 <= current) { - INSTR_SET_OP0(&instructions[current--], NOP); - } - PyMem_Free(stack); - *ix += len - 1; - return SUCCESS; -} - -// This list is pretty small, since it's only okay to reorder opcodes that: -// - can't affect control flow (like jumping or raising exceptions) -// - can't invoke arbitrary code (besides finalizers) -// - only touch the TOS (and pop it when finished) -#define SWAPPABLE(opcode) \ - ((opcode) == STORE_FAST || (opcode) == POP_TOP) - -static int -next_swappable_instruction(basicblock *block, int i, int lineno) -{ - while (++i < block->b_iused) { - struct cfg_instr *instruction = &block->b_instr[i]; - if (0 <= lineno && instruction->i_loc.lineno != lineno) { - // Optimizing across this instruction could cause user-visible - // changes in the names bound between line tracing events! - return -1; - } - if (instruction->i_opcode == NOP) { - continue; - } - if (SWAPPABLE(instruction->i_opcode)) { - return i; - } - return -1; - } - return -1; -} - -// Attempt to apply SWAPs statically by swapping *instructions* rather than -// stack items. For example, we can replace SWAP(2), POP_TOP, STORE_FAST(42) -// with the more efficient NOP, STORE_FAST(42), POP_TOP. -static void -apply_static_swaps(basicblock *block, int i) -{ - // SWAPs are to our left, and potential swaperands are to our right: - for (; 0 <= i; i--) { - assert(i < block->b_iused); - struct cfg_instr *swap = &block->b_instr[i]; - if (swap->i_opcode != SWAP) { - if (swap->i_opcode == NOP || SWAPPABLE(swap->i_opcode)) { - // Nope, but we know how to handle these. Keep looking: - continue; - } - // We can't reason about what this instruction does. Bail: - return; - } - int j = next_swappable_instruction(block, i, -1); - if (j < 0) { - return; - } - int k = j; - int lineno = block->b_instr[j].i_loc.lineno; - for (int count = swap->i_oparg - 1; 0 < count; count--) { - k = next_swappable_instruction(block, k, lineno); - if (k < 0) { - return; - } - } - // Success! - INSTR_SET_OP0(swap, NOP); - struct cfg_instr temp = block->b_instr[j]; - block->b_instr[j] = block->b_instr[k]; - block->b_instr[k] = temp; - } -} - -// Attempt to eliminate jumps to jumps by updating inst to jump to -// target->i_target using the provided opcode. Return whether or not the -// optimization was successful. -static bool -jump_thread(struct cfg_instr *inst, struct cfg_instr *target, int opcode) -{ - assert(is_jump(inst)); - assert(is_jump(target)); - // bpo-45773: If inst->i_target == target->i_target, then nothing actually - // changes (and we fall into an infinite loop): - if ((inst->i_loc.lineno == target->i_loc.lineno || target->i_loc.lineno == -1) && - inst->i_target != target->i_target) - { - inst->i_target = target->i_target; - inst->i_opcode = opcode; - return true; - } - return false; -} - -/* Maximum size of basic block that should be copied in optimizer */ -#define MAX_COPY_SIZE 4 - -/* Optimization */ -static int -optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) -{ - assert(PyDict_CheckExact(const_cache)); - assert(PyList_CheckExact(consts)); - struct cfg_instr nop; - INSTR_SET_OP0(&nop, NOP); - struct cfg_instr *target = &nop; - int opcode = 0; - int oparg = 0; - int nextop = 0; - for (int i = 0; i < bb->b_iused; i++) { - struct cfg_instr *inst = &bb->b_instr[i]; - bool is_copy_of_load_const = (opcode == LOAD_CONST && - inst->i_opcode == COPY && - inst->i_oparg == 1); - if (! is_copy_of_load_const) { - opcode = inst->i_opcode; - oparg = inst->i_oparg; - if (HAS_TARGET(opcode)) { - assert(inst->i_target->b_iused > 0); - target = &inst->i_target->b_instr[0]; - assert(!IS_ASSEMBLER_OPCODE(target->i_opcode)); - } - else { - target = &nop; - } - } - nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0; - assert(!IS_ASSEMBLER_OPCODE(opcode)); - switch (opcode) { - /* Remove LOAD_CONST const; conditional jump */ - case LOAD_CONST: - { - PyObject* cnt; - int is_true; - int jump_if_true; - switch(nextop) { - case POP_JUMP_IF_FALSE: - case POP_JUMP_IF_TRUE: - cnt = get_const_value(opcode, oparg, consts); - if (cnt == NULL) { - goto error; - } - is_true = PyObject_IsTrue(cnt); - Py_DECREF(cnt); - if (is_true == -1) { - goto error; - } - INSTR_SET_OP0(inst, NOP); - jump_if_true = nextop == POP_JUMP_IF_TRUE; - if (is_true == jump_if_true) { - bb->b_instr[i+1].i_opcode = JUMP; - } - else { - INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); - } - break; - case IS_OP: - cnt = get_const_value(opcode, oparg, consts); - if (cnt == NULL) { - goto error; - } - int jump_op = i+2 < bb->b_iused ? bb->b_instr[i+2].i_opcode : 0; - if (Py_IsNone(cnt) && (jump_op == POP_JUMP_IF_FALSE || jump_op == POP_JUMP_IF_TRUE)) { - unsigned char nextarg = bb->b_instr[i+1].i_oparg; - INSTR_SET_OP0(inst, NOP); - INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); - bb->b_instr[i+2].i_opcode = nextarg ^ (jump_op == POP_JUMP_IF_FALSE) ? - POP_JUMP_IF_NOT_NONE : POP_JUMP_IF_NONE; - } - Py_DECREF(cnt); - break; - case RETURN_VALUE: - INSTR_SET_OP0(inst, NOP); - INSTR_SET_OP1(&bb->b_instr[++i], RETURN_CONST, oparg); - break; - } - break; - } - - /* Try to fold tuples of constants. - Skip over BUILD_TUPLE(1) UNPACK_SEQUENCE(1). - Replace BUILD_TUPLE(2) UNPACK_SEQUENCE(2) with SWAP(2). - Replace BUILD_TUPLE(3) UNPACK_SEQUENCE(3) with SWAP(3). */ - case BUILD_TUPLE: - if (nextop == UNPACK_SEQUENCE && oparg == bb->b_instr[i+1].i_oparg) { - switch(oparg) { - case 1: - INSTR_SET_OP0(inst, NOP); - INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); - continue; - case 2: - case 3: - INSTR_SET_OP0(inst, NOP); - bb->b_instr[i+1].i_opcode = SWAP; - continue; - } - } - if (i >= oparg) { - if (fold_tuple_on_constants(const_cache, inst-oparg, oparg, consts)) { - goto error; - } - } - break; - case POP_JUMP_IF_NOT_NONE: - case POP_JUMP_IF_NONE: - switch (target->i_opcode) { - case JUMP: - i -= jump_thread(inst, target, inst->i_opcode); - } - break; - case POP_JUMP_IF_FALSE: - switch (target->i_opcode) { - case JUMP: - i -= jump_thread(inst, target, POP_JUMP_IF_FALSE); - } - break; - case POP_JUMP_IF_TRUE: - switch (target->i_opcode) { - case JUMP: - i -= jump_thread(inst, target, POP_JUMP_IF_TRUE); - } - break; - case JUMP: - switch (target->i_opcode) { - case JUMP: - i -= jump_thread(inst, target, JUMP); - } - break; - case FOR_ITER: - if (target->i_opcode == JUMP) { - /* This will not work now because the jump (at target) could - * be forward or backward and FOR_ITER only jumps forward. We - * can re-enable this if ever we implement a backward version - * of FOR_ITER. - */ - /* - i -= jump_thread(inst, target, FOR_ITER); - */ - } - break; - case SWAP: - if (oparg == 1) { - INSTR_SET_OP0(inst, NOP); - break; - } - if (swaptimize(bb, &i) < 0) { - goto error; - } - apply_static_swaps(bb, i); - break; - case KW_NAMES: - break; - case PUSH_NULL: - if (nextop == LOAD_GLOBAL && (inst[1].i_opcode & 1) == 0) { - INSTR_SET_OP0(inst, NOP); - inst[1].i_oparg |= 1; - } - break; - default: - /* All HAS_CONST opcodes should be handled with LOAD_CONST */ - assert (!HAS_CONST(inst->i_opcode)); - } - } - return SUCCESS; -error: - return ERROR; -} - -/* If this block ends with an unconditional jump to a small exit block, then - * remove the jump and extend this block with the target. - * Returns 1 if extended, 0 if no change, and -1 on error. - */ -static int -inline_small_exit_blocks(basicblock *bb) { - struct cfg_instr *last = basicblock_last_instr(bb); - if (last == NULL) { - return 0; - } - if (!IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { - return 0; - } - basicblock *target = last->i_target; - if (basicblock_exits_scope(target) && target->b_iused <= MAX_COPY_SIZE) { - INSTR_SET_OP0(last, NOP); - RETURN_IF_ERROR(basicblock_append_instructions(bb, target)); - return 1; - } - return 0; -} - - -static int -remove_redundant_nops_and_pairs(basicblock *entryblock) -{ - bool done = false; - - while (! done) { - done = true; - struct cfg_instr *prev_instr = NULL; - struct cfg_instr *instr = NULL; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - remove_redundant_nops(b); - if (IS_LABEL(b->b_label)) { - /* this block is a jump target, forget instr */ - instr = NULL; - } - for (int i = 0; i < b->b_iused; i++) { - prev_instr = instr; - instr = &b->b_instr[i]; - int prev_opcode = prev_instr ? prev_instr->i_opcode : 0; - int prev_oparg = prev_instr ? prev_instr->i_oparg : 0; - int opcode = instr->i_opcode; - bool is_redundant_pair = false; - if (opcode == POP_TOP) { - if (prev_opcode == LOAD_CONST) { - is_redundant_pair = true; - } - else if (prev_opcode == COPY && prev_oparg == 1) { - is_redundant_pair = true; - } - } - if (is_redundant_pair) { - INSTR_SET_OP0(prev_instr, NOP); - INSTR_SET_OP0(instr, NOP); - done = false; - } - } - if ((instr && is_jump(instr)) || !BB_HAS_FALLTHROUGH(b)) { - instr = NULL; - } - } - } - return SUCCESS; -} - - -static int -remove_redundant_nops(basicblock *bb) { - /* Remove NOPs when legal to do so. */ - int dest = 0; - int prev_lineno = -1; - for (int src = 0; src < bb->b_iused; src++) { - int lineno = bb->b_instr[src].i_loc.lineno; - if (bb->b_instr[src].i_opcode == NOP) { - /* Eliminate no-op if it doesn't have a line number */ - if (lineno < 0) { - continue; - } - /* or, if the previous instruction had the same line number. */ - if (prev_lineno == lineno) { - continue; - } - /* or, if the next instruction has same line number or no line number */ - if (src < bb->b_iused - 1) { - int next_lineno = bb->b_instr[src+1].i_loc.lineno; - if (next_lineno == lineno) { - continue; - } - if (next_lineno < 0) { - bb->b_instr[src+1].i_loc = bb->b_instr[src].i_loc; - continue; - } - } - else { - basicblock* next = bb->b_next; - while (next && next->b_iused == 0) { - next = next->b_next; - } - /* or if last instruction in BB and next BB has same line number */ - if (next) { - if (lineno == next->b_instr[0].i_loc.lineno) { - continue; - } - } - } - - } - if (dest != src) { - bb->b_instr[dest] = bb->b_instr[src]; - } - dest++; - prev_lineno = lineno; - } - assert(dest <= bb->b_iused); - int num_removed = bb->b_iused - dest; - bb->b_iused = dest; - return num_removed; -} - -static int -check_cfg(cfg_builder *g) { - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - /* Raise SystemError if jump or exit is not last instruction in the block. */ - for (int i = 0; i < b->b_iused; i++) { - int opcode = b->b_instr[i].i_opcode; - assert(!IS_ASSEMBLER_OPCODE(opcode)); - if (IS_TERMINATOR_OPCODE(opcode)) { - if (i != b->b_iused - 1) { - PyErr_SetString(PyExc_SystemError, "malformed control flow graph."); - return ERROR; - } - } - } - } - return SUCCESS; -} - -static int -mark_reachable(basicblock *entryblock) { - basicblock **stack = make_cfg_traversal_stack(entryblock); - if (stack == NULL) { - return ERROR; - } - basicblock **sp = stack; - entryblock->b_predecessors = 1; - *sp++ = entryblock; - while (sp > stack) { - basicblock *b = *(--sp); - b->b_visited = 1; - if (b->b_next && BB_HAS_FALLTHROUGH(b)) { - if (!b->b_next->b_visited) { - assert(b->b_next->b_predecessors == 0); - *sp++ = b->b_next; - } - b->b_next->b_predecessors++; - } - for (int i = 0; i < b->b_iused; i++) { - basicblock *target; - struct cfg_instr *instr = &b->b_instr[i]; - if (is_jump(instr) || is_block_push(instr)) { - target = instr->i_target; - if (!target->b_visited) { - assert(target->b_predecessors == 0 || target == b->b_next); - *sp++ = target; - } - target->b_predecessors++; - } - } - } - PyMem_Free(stack); - return SUCCESS; -} - -static void -eliminate_empty_basic_blocks(cfg_builder *g) { - /* Eliminate empty blocks */ - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - basicblock *next = b->b_next; - while (next && next->b_iused == 0) { - next = next->b_next; - } - b->b_next = next; - } - while(g->g_entryblock && g->g_entryblock->b_iused == 0) { - g->g_entryblock = g->g_entryblock->b_next; - } - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - assert(b->b_iused > 0); - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - if (HAS_TARGET(instr->i_opcode)) { - basicblock *target = instr->i_target; - while (target->b_iused == 0) { - target = target->b_next; - } - instr->i_target = target; - assert(instr->i_target && instr->i_target->b_iused > 0); - } - } - } -} - - -/* If an instruction has no line number, but it's predecessor in the BB does, - * then copy the line number. If a successor block has no line number, and only - * one predecessor, then inherit the line number. - * This ensures that all exit blocks (with one predecessor) receive a line number. - * Also reduces the size of the line number table, - * but has no impact on the generated line number events. - */ -static void -propagate_line_numbers(basicblock *entryblock) { - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - struct cfg_instr *last = basicblock_last_instr(b); - if (last == NULL) { - continue; - } - - location prev_location = NO_LOCATION; - for (int i = 0; i < b->b_iused; i++) { - if (b->b_instr[i].i_loc.lineno < 0) { - b->b_instr[i].i_loc = prev_location; - } - else { - prev_location = b->b_instr[i].i_loc; - } - } - if (BB_HAS_FALLTHROUGH(b) && b->b_next->b_predecessors == 1) { - assert(b->b_next->b_iused); - if (b->b_next->b_instr[0].i_loc.lineno < 0) { - b->b_next->b_instr[0].i_loc = prev_location; - } - } - if (is_jump(last)) { - basicblock *target = last->i_target; - if (target->b_predecessors == 1) { - if (target->b_instr[0].i_loc.lineno < 0) { - target->b_instr[0].i_loc = prev_location; - } - } - } - } -} - - -/* Calculate the actual jump target from the target_label */ -static int -translate_jump_labels_to_targets(basicblock *entryblock) -{ - int max_label = -1; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (b->b_label.id > max_label) { - max_label = b->b_label.id; - } - } - size_t mapsize = sizeof(basicblock *) * (max_label + 1); - basicblock **label2block = (basicblock **)PyMem_Malloc(mapsize); - if (!label2block) { - PyErr_NoMemory(); - return ERROR; - } - memset(label2block, 0, mapsize); - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (b->b_label.id >= 0) { - label2block[b->b_label.id] = b; - } - } - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; - assert(instr->i_target == NULL); - if (HAS_TARGET(instr->i_opcode)) { - int lbl = instr->i_oparg; - assert(lbl >= 0 && lbl <= max_label); - instr->i_target = label2block[lbl]; - assert(instr->i_target != NULL); - assert(instr->i_target->b_label.id == lbl); - } - } - } - PyMem_Free(label2block); - return SUCCESS; -} - -/* Perform optimizations on a control flow graph. - The consts object should still be in list form to allow new constants - to be appended. - - Code trasnformations that reduce code size initially fill the gaps with - NOPs. Later those NOPs are removed. -*/ - -static int -optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache) -{ - assert(PyDict_CheckExact(const_cache)); - RETURN_IF_ERROR(check_cfg(g)); - eliminate_empty_basic_blocks(g); - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - RETURN_IF_ERROR(inline_small_exit_blocks(b)); - } - assert(no_empty_basic_blocks(g)); - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts)); - assert(b->b_predecessors == 0); - } - RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock)); - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - RETURN_IF_ERROR(inline_small_exit_blocks(b)); - } - RETURN_IF_ERROR(mark_reachable(g->g_entryblock)); - - /* Delete unreachable instructions */ - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - if (b->b_predecessors == 0) { - b->b_iused = 0; - } - } - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - remove_redundant_nops(b); - } - eliminate_empty_basic_blocks(g); - assert(no_redundant_nops(g)); - RETURN_IF_ERROR(remove_redundant_jumps(g)); - return SUCCESS; -} - - -static int -remove_unused_consts(basicblock *entryblock, PyObject *consts) -{ - assert(PyList_CheckExact(consts)); - Py_ssize_t nconsts = PyList_GET_SIZE(consts); - if (nconsts == 0) { - return SUCCESS; /* nothing to do */ - } - - Py_ssize_t *index_map = NULL; - Py_ssize_t *reverse_index_map = NULL; - int err = ERROR; - - index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t)); - if (index_map == NULL) { - goto end; - } - for (Py_ssize_t i = 1; i < nconsts; i++) { - index_map[i] = -1; - } - // The first constant may be docstring; keep it always. - index_map[0] = 0; - - /* mark used consts */ - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - for (int i = 0; i < b->b_iused; i++) { - if (HAS_CONST(b->b_instr[i].i_opcode)) { - int index = b->b_instr[i].i_oparg; - index_map[index] = index; - } - } - } - /* now index_map[i] == i if consts[i] is used, -1 otherwise */ - - /* condense consts */ - Py_ssize_t n_used_consts = 0; - for (int i = 0; i < nconsts; i++) { - if (index_map[i] != -1) { - assert(index_map[i] == i); - index_map[n_used_consts++] = index_map[i]; - } - } - if (n_used_consts == nconsts) { - /* nothing to do */ - err = SUCCESS; - goto end; - } - - /* move all used consts to the beginning of the consts list */ - assert(n_used_consts < nconsts); - for (Py_ssize_t i = 0; i < n_used_consts; i++) { - Py_ssize_t old_index = index_map[i]; - assert(i <= old_index && old_index < nconsts); - if (i != old_index) { - PyObject *value = PyList_GET_ITEM(consts, index_map[i]); - assert(value != NULL); - PyList_SetItem(consts, i, Py_NewRef(value)); - } - } - - /* truncate the consts list at its new size */ - if (PyList_SetSlice(consts, n_used_consts, nconsts, NULL) < 0) { - goto end; - } - - /* adjust const indices in the bytecode */ - reverse_index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t)); - if (reverse_index_map == NULL) { - goto end; - } - for (Py_ssize_t i = 0; i < nconsts; i++) { - reverse_index_map[i] = -1; - } - for (Py_ssize_t i = 0; i < n_used_consts; i++) { - assert(index_map[i] != -1); - assert(reverse_index_map[index_map[i]] == -1); - reverse_index_map[index_map[i]] = i; - } - - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - for (int i = 0; i < b->b_iused; i++) { - if (HAS_CONST(b->b_instr[i].i_opcode)) { - int index = b->b_instr[i].i_oparg; - assert(reverse_index_map[index] >= 0); - assert(reverse_index_map[index] < n_used_consts); - b->b_instr[i].i_oparg = (int)reverse_index_map[index]; - } - } - } - - err = SUCCESS; -end: - PyMem_Free(index_map); - PyMem_Free(reverse_index_map); - return err; -} - -static inline bool -is_exit_without_lineno(basicblock *b) { - if (!basicblock_exits_scope(b)) { - return false; - } - for (int i = 0; i < b->b_iused; i++) { - if (b->b_instr[i].i_loc.lineno >= 0) { - return false; - } - } - return true; -} - -/* PEP 626 mandates that the f_lineno of a frame is correct - * after a frame terminates. It would be prohibitively expensive - * to continuously update the f_lineno field at runtime, - * so we make sure that all exiting instruction (raises and returns) - * have a valid line number, allowing us to compute f_lineno lazily. - * We can do this by duplicating the exit blocks without line number - * so that none have more than one predecessor. We can then safely - * copy the line number from the sole predecessor block. - */ -static int -duplicate_exits_without_lineno(cfg_builder *g) -{ - assert(no_empty_basic_blocks(g)); - /* Copy all exit blocks without line number that are targets of a jump. - */ - basicblock *entryblock = g->g_entryblock; - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - struct cfg_instr *last = basicblock_last_instr(b); - assert(last != NULL); - if (is_jump(last)) { - basicblock *target = last->i_target; - if (is_exit_without_lineno(target) && target->b_predecessors > 1) { - basicblock *new_target = copy_basicblock(g, target); - if (new_target == NULL) { - return ERROR; - } - new_target->b_instr[0].i_loc = last->i_loc; - last->i_target = new_target; - target->b_predecessors--; - new_target->b_predecessors = 1; - new_target->b_next = target->b_next; - target->b_next = new_target; - } - } - } - - /* Any remaining reachable exit blocks without line number can only be reached by - * fall through, and thus can only have a single predecessor */ - for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) { - if (is_exit_without_lineno(b->b_next)) { - struct cfg_instr *last = basicblock_last_instr(b); - assert(last != NULL); - b->b_next->b_instr[0].i_loc = last->i_loc; - } - } - } - return SUCCESS; -} - - /* Access to compiler optimizations for unit tests. * * _PyCompile_CodeGen takes and AST, applies code-gen and @@ -9842,7 +7527,7 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) for (int i = 0; i < num_insts; i++) { if (is_target[i]) { jump_target_label lbl = {i}; - RETURN_IF_ERROR(cfg_builder_use_label(g, lbl)); + RETURN_IF_ERROR(_PyCfgBuilder_UseLabel(g, lbl)); } PyObject *item = PyList_GET_ITEM(instructions, i); if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 6) { @@ -9880,11 +7565,11 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) if (PyErr_Occurred()) { goto error; } - RETURN_IF_ERROR(cfg_builder_addop(g, opcode, oparg, loc)); + RETURN_IF_ERROR(_PyCfgBuilder_Addop(g, opcode, oparg, loc)); } - struct cfg_instr *last = basicblock_last_instr(g->g_curblock); + cfg_instr *last = _PyCfg_BasicblockLastInstr(g->g_curblock); if (last && !IS_TERMINATOR_OPCODE(last->i_opcode)) { - RETURN_IF_ERROR(cfg_builder_addop(g, RETURN_VALUE, 0, NO_LOCATION)); + RETURN_IF_ERROR(_PyCfgBuilder_Addop(g, RETURN_VALUE, 0, NO_LOCATION)); } PyMem_Free(is_target); return SUCCESS; @@ -9939,7 +7624,7 @@ cfg_to_instructions(cfg_builder *g) } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { for (int i = 0; i < b->b_iused; i++) { - struct cfg_instr *instr = &b->b_instr[i]; + cfg_instr *instr = &b->b_instr[i]; location loc = instr->i_loc; int arg = HAS_TARGET(instr->i_opcode) ? instr->i_target->b_label.id : instr->i_oparg; @@ -10018,26 +7703,26 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) cfg_builder g; memset(&g, 0, sizeof(cfg_builder)); - if (cfg_builder_init(&g) < 0) { + if (_PyCfgBuilder_Init(&g) < 0) { goto error; } if (instructions_to_cfg(instructions, &g) < 0) { goto error; } int code_flags = 0, nlocals = 0, nparams = 0; - if (optimize_code_unit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { + if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { goto error; } res = cfg_to_instructions(&g); error: Py_DECREF(const_cache); - cfg_builder_fini(&g); + _PyCfgBuilder_Fini(&g); return res; } /* Retained for API compatibility. - * Optimization is now done in optimize_cfg */ + * Optimization is now done in _PyCfg_OptimizeCodeUnit */ PyObject * PyCode_Optimize(PyObject *code, PyObject* Py_UNUSED(consts), diff --git a/Python/flowgraph.c b/Python/flowgraph.c new file mode 100644 index 000000000000..cecddbd39c94 --- /dev/null +++ b/Python/flowgraph.c @@ -0,0 +1,2160 @@ + +#include + +#include "Python.h" +#include "pycore_flowgraph.h" +#include "pycore_compile.h" +#include "pycore_pymem.h" // _PyMem_IsPtrFreed() + +#include "pycore_opcode_utils.h" +#define NEED_OPCODE_METADATA +#include "opcode_metadata.h" // _PyOpcode_opcode_metadata, _PyOpcode_num_popped/pushed +#undef NEED_OPCODE_METADATA + + +#undef SUCCESS +#undef ERROR +#define SUCCESS 0 +#define ERROR -1 + +#define RETURN_IF_ERROR(X) \ + if ((X) == -1) { \ + return ERROR; \ + } + +#define DEFAULT_BLOCK_SIZE 16 + +typedef _PyCompilerSrcLocation location; +typedef _PyCfgJumpTargetLabel jump_target_label; +typedef _PyCfgBasicblock basicblock; +typedef _PyCfgBuilder cfg_builder; +typedef _PyCfgInstruction cfg_instr; + +static const jump_target_label NO_LABEL = {-1}; + +#define SAME_LABEL(L1, L2) ((L1).id == (L2).id) +#define IS_LABEL(L) (!SAME_LABEL((L), (NO_LABEL))) + + +static inline int +is_block_push(cfg_instr *i) +{ + return IS_BLOCK_PUSH_OPCODE(i->i_opcode); +} + +static inline int +is_relative_jump(cfg_instr *i) +{ + return IS_RELATIVE_JUMP(i->i_opcode); +} + +static inline int +is_jump(cfg_instr *i) +{ + return IS_JUMP_OPCODE(i->i_opcode); +} + +/* One arg*/ +#define INSTR_SET_OP1(I, OP, ARG) \ + do { \ + assert(HAS_ARG(OP)); \ + _PyCfgInstruction *_instr__ptr_ = (I); \ + _instr__ptr_->i_opcode = (OP); \ + _instr__ptr_->i_oparg = (ARG); \ + } while (0); + +/* No args*/ +#define INSTR_SET_OP0(I, OP) \ + do { \ + assert(!HAS_ARG(OP)); \ + _PyCfgInstruction *_instr__ptr_ = (I); \ + _instr__ptr_->i_opcode = (OP); \ + _instr__ptr_->i_oparg = 0; \ + } while (0); + +/***** Blocks *****/ + +/* Returns the offset of the next instruction in the current block's + b_instr array. Resizes the b_instr as necessary. + Returns -1 on failure. +*/ +static int +basicblock_next_instr(basicblock *b) +{ + assert(b != NULL); + RETURN_IF_ERROR( + _PyCompile_EnsureArrayLargeEnough( + b->b_iused + 1, + (void**)&b->b_instr, + &b->b_ialloc, + DEFAULT_BLOCK_SIZE, + sizeof(cfg_instr))); + return b->b_iused++; +} + +/* Allocate a new block and return a pointer to it. + Returns NULL on error. +*/ + +static basicblock * +cfg_builder_new_block(cfg_builder *g) +{ + basicblock *b = (basicblock *)PyObject_Calloc(1, sizeof(basicblock)); + if (b == NULL) { + PyErr_NoMemory(); + return NULL; + } + /* Extend the singly linked list of blocks with new block. */ + b->b_list = g->g_block_list; + g->g_block_list = b; + b->b_label = NO_LABEL; + return b; +} + +static int +basicblock_addop(basicblock *b, int opcode, int oparg, location loc) +{ + assert(IS_WITHIN_OPCODE_RANGE(opcode)); + assert(!IS_ASSEMBLER_OPCODE(opcode)); + assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0); + assert(0 <= oparg && oparg < (1 << 30)); + + int off = basicblock_next_instr(b); + if (off < 0) { + return ERROR; + } + cfg_instr *i = &b->b_instr[off]; + i->i_opcode = opcode; + i->i_oparg = oparg; + i->i_target = NULL; + i->i_loc = loc; + + return SUCCESS; +} + +static inline int +basicblock_append_instructions(basicblock *target, basicblock *source) +{ + for (int i = 0; i < source->b_iused; i++) { + int n = basicblock_next_instr(target); + if (n < 0) { + return ERROR; + } + target->b_instr[n] = source->b_instr[i]; + } + return SUCCESS; +} + +static basicblock * +copy_basicblock(cfg_builder *g, basicblock *block) +{ + /* Cannot copy a block if it has a fallthrough, since + * a block can only have one fallthrough predecessor. + */ + assert(BB_NO_FALLTHROUGH(block)); + basicblock *result = cfg_builder_new_block(g); + if (result == NULL) { + return NULL; + } + if (basicblock_append_instructions(result, block) < 0) { + return NULL; + } + return result; +} + +int +_PyBasicblock_InsertInstruction(basicblock *block, int pos, cfg_instr *instr) { + RETURN_IF_ERROR(basicblock_next_instr(block)); + for (int i = block->b_iused - 1; i > pos; i--) { + block->b_instr[i] = block->b_instr[i-1]; + } + block->b_instr[pos] = *instr; + return SUCCESS; +} + +int +_PyCfg_InstrSize(cfg_instr *instruction) +{ + int opcode = instruction->i_opcode; + assert(!IS_PSEUDO_OPCODE(opcode)); + int oparg = instruction->i_oparg; + assert(HAS_ARG(opcode) || oparg == 0); + int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg); + int caches = _PyOpcode_Caches[opcode]; + return extended_args + 1 + caches; +} + +static int +blocksize(basicblock *b) +{ + int size = 0; + for (int i = 0; i < b->b_iused; i++) { + size += _PyCfg_InstrSize(&b->b_instr[i]); + } + return size; +} + +/* For debugging purposes only */ +#if 0 +static void +dump_instr(cfg_instr *i) +{ + const char *jrel = (is_relative_jump(i)) ? "jrel " : ""; + const char *jabs = (is_jump(i) && !is_relative_jump(i))? "jabs " : ""; + + char arg[128]; + + *arg = '\0'; + if (HAS_ARG(i->i_opcode)) { + sprintf(arg, "arg: %d ", i->i_oparg); + } + if (HAS_TARGET(i->i_opcode)) { + sprintf(arg, "target: %p [%d] ", i->i_target, i->i_oparg); + } + fprintf(stderr, "line: %d, opcode: %d %s%s%s\n", + i->i_loc.lineno, i->i_opcode, arg, jabs, jrel); +} + +static inline int +basicblock_returns(const basicblock *b) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + return last && (last->i_opcode == RETURN_VALUE || last->i_opcode == RETURN_CONST); +} + +static void +dump_basicblock(const basicblock *b) +{ + const char *b_return = basicblock_returns(b) ? "return " : ""; + fprintf(stderr, "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, offset: %d %s\n", + b->b_label.id, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, + b->b_startdepth, b->b_offset, b_return); + if (b->b_instr) { + int i; + for (i = 0; i < b->b_iused; i++) { + fprintf(stderr, " [%02d] ", i); + dump_instr(b->b_instr + i); + } + } +} +#endif + + +/***** CFG construction and modification *****/ + +static basicblock * +cfg_builder_use_next_block(cfg_builder *g, basicblock *block) +{ + assert(block != NULL); + g->g_curblock->b_next = block; + g->g_curblock = block; + return block; +} + +cfg_instr * +_PyCfg_BasicblockLastInstr(const basicblock *b) { + assert(b->b_iused >= 0); + if (b->b_iused > 0) { + assert(b->b_instr != NULL); + return &b->b_instr[b->b_iused - 1]; + } + return NULL; +} + +static inline int +basicblock_exits_scope(const basicblock *b) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode); +} + +static bool +cfg_builder_current_block_is_terminated(cfg_builder *g) +{ + cfg_instr *last = _PyCfg_BasicblockLastInstr(g->g_curblock); + if (last && IS_TERMINATOR_OPCODE(last->i_opcode)) { + return true; + } + if (IS_LABEL(g->g_current_label)) { + if (last || IS_LABEL(g->g_curblock->b_label)) { + return true; + } + else { + /* current block is empty, label it */ + g->g_curblock->b_label = g->g_current_label; + g->g_current_label = NO_LABEL; + } + } + return false; +} + +static int +cfg_builder_maybe_start_new_block(cfg_builder *g) +{ + if (cfg_builder_current_block_is_terminated(g)) { + basicblock *b = cfg_builder_new_block(g); + if (b == NULL) { + return ERROR; + } + b->b_label = g->g_current_label; + g->g_current_label = NO_LABEL; + cfg_builder_use_next_block(g, b); + } + return SUCCESS; +} + +#ifndef NDEBUG +static bool +cfg_builder_check(cfg_builder *g) +{ + assert(g->g_entryblock->b_iused > 0); + for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) { + assert(!_PyMem_IsPtrFreed(block)); + if (block->b_instr != NULL) { + assert(block->b_ialloc > 0); + assert(block->b_iused >= 0); + assert(block->b_ialloc >= block->b_iused); + } + else { + assert (block->b_iused == 0); + assert (block->b_ialloc == 0); + } + } + return true; +} +#endif + +int +_PyCfgBuilder_Init(cfg_builder *g) +{ + g->g_block_list = NULL; + basicblock *block = cfg_builder_new_block(g); + if (block == NULL) { + return ERROR; + } + g->g_curblock = g->g_entryblock = block; + g->g_current_label = NO_LABEL; + return SUCCESS; +} + +void +_PyCfgBuilder_Fini(cfg_builder* g) +{ + assert(cfg_builder_check(g)); + basicblock *b = g->g_block_list; + while (b != NULL) { + if (b->b_instr) { + PyObject_Free((void *)b->b_instr); + } + basicblock *next = b->b_list; + PyObject_Free((void *)b); + b = next; + } +} + +int +_PyCfgBuilder_UseLabel(cfg_builder *g, jump_target_label lbl) +{ + g->g_current_label = lbl; + return cfg_builder_maybe_start_new_block(g); +} + +int +_PyCfgBuilder_Addop(cfg_builder *g, int opcode, int oparg, location loc) +{ + RETURN_IF_ERROR(cfg_builder_maybe_start_new_block(g)); + return basicblock_addop(g->g_curblock, opcode, oparg, loc); +} + + +/***** debugging helpers *****/ + +#ifndef NDEBUG +static int remove_redundant_nops(basicblock *bb); + +static bool +no_redundant_nops(cfg_builder *g) { + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + if (remove_redundant_nops(b) != 0) { + return false; + } + } + return true; +} + +static bool +no_empty_basic_blocks(cfg_builder *g) { + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + if (b->b_iused == 0) { + return false; + } + } + return true; +} + +static bool +no_redundant_jumps(cfg_builder *g) { + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + if (last != NULL) { + if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { + assert(last->i_target != b->b_next); + if (last->i_target == b->b_next) { + return false; + } + } + } + } + return true; +} + +#endif + +/***** CFG preprocessing (jump targets and exceptions) *****/ + +static int +normalize_jumps_in_block(cfg_builder *g, basicblock *b) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + if (last == NULL || !is_jump(last)) { + return SUCCESS; + } + assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); + bool is_forward = last->i_target->b_visited == 0; + switch(last->i_opcode) { + case JUMP: + last->i_opcode = is_forward ? JUMP_FORWARD : JUMP_BACKWARD; + return SUCCESS; + case JUMP_NO_INTERRUPT: + last->i_opcode = is_forward ? + JUMP_FORWARD : JUMP_BACKWARD_NO_INTERRUPT; + return SUCCESS; + } + int reversed_opcode = 0; + switch(last->i_opcode) { + case POP_JUMP_IF_NOT_NONE: + reversed_opcode = POP_JUMP_IF_NONE; + break; + case POP_JUMP_IF_NONE: + reversed_opcode = POP_JUMP_IF_NOT_NONE; + break; + case POP_JUMP_IF_FALSE: + reversed_opcode = POP_JUMP_IF_TRUE; + break; + case POP_JUMP_IF_TRUE: + reversed_opcode = POP_JUMP_IF_FALSE; + break; + } + if (is_forward) { + return SUCCESS; + } + /* transform 'conditional jump T' to + * 'reversed_jump b_next' followed by 'jump_backwards T' + */ + + basicblock *target = last->i_target; + basicblock *backwards_jump = cfg_builder_new_block(g); + if (backwards_jump == NULL) { + return ERROR; + } + basicblock_addop(backwards_jump, JUMP, target->b_label.id, NO_LOCATION); + backwards_jump->b_instr[0].i_target = target; + last->i_opcode = reversed_opcode; + last->i_target = b->b_next; + + backwards_jump->b_cold = b->b_cold; + backwards_jump->b_next = b->b_next; + b->b_next = backwards_jump; + return SUCCESS; +} + + +static int +normalize_jumps(_PyCfgBuilder *g) +{ + basicblock *entryblock = g->g_entryblock; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + b->b_visited = 0; + } + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + b->b_visited = 1; + RETURN_IF_ERROR(normalize_jumps_in_block(g, b)); + } + return SUCCESS; +} + +static void +resolve_jump_offsets(basicblock *entryblock) +{ + int bsize, totsize, extended_arg_recompile; + + /* Compute the size of each block and fixup jump args. + Replace block pointer with position in bytecode. */ + do { + totsize = 0; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + bsize = blocksize(b); + b->b_offset = totsize; + totsize += bsize; + } + extended_arg_recompile = 0; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + bsize = b->b_offset; + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + int isize = _PyCfg_InstrSize(instr); + /* Relative jumps are computed relative to + the instruction pointer after fetching + the jump instruction. + */ + bsize += isize; + if (is_jump(instr)) { + instr->i_oparg = instr->i_target->b_offset; + if (is_relative_jump(instr)) { + if (instr->i_oparg < bsize) { + assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); + instr->i_oparg = bsize - instr->i_oparg; + } + else { + assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); + instr->i_oparg -= bsize; + } + } + else { + assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode)); + } + if (_PyCfg_InstrSize(instr) != isize) { + extended_arg_recompile = 1; + } + } + } + } + + /* XXX: This is an awful hack that could hurt performance, but + on the bright side it should work until we come up + with a better solution. + + The issue is that in the first loop blocksize() is called + which calls _PyCfg_InstrSize() which requires i_oparg be set + appropriately. There is a bootstrap problem because + i_oparg is calculated in the second loop above. + + So we loop until we stop seeing new EXTENDED_ARGs. + The only EXTENDED_ARGs that could be popping up are + ones in jump instructions. So this should converge + fairly quickly. + */ + } while (extended_arg_recompile); +} + +int +_PyCfg_ResolveJumps(_PyCfgBuilder *g) +{ + RETURN_IF_ERROR(normalize_jumps(g)); + assert(no_redundant_jumps(g)); + resolve_jump_offsets(g->g_entryblock); + return SUCCESS; +} + +static int +check_cfg(cfg_builder *g) { + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + /* Raise SystemError if jump or exit is not last instruction in the block. */ + for (int i = 0; i < b->b_iused; i++) { + int opcode = b->b_instr[i].i_opcode; + assert(!IS_ASSEMBLER_OPCODE(opcode)); + if (IS_TERMINATOR_OPCODE(opcode)) { + if (i != b->b_iused - 1) { + PyErr_SetString(PyExc_SystemError, "malformed control flow graph."); + return ERROR; + } + } + } + } + return SUCCESS; +} + +/* Calculate the actual jump target from the target_label */ +static int +translate_jump_labels_to_targets(basicblock *entryblock) +{ + int max_label = -1; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + if (b->b_label.id > max_label) { + max_label = b->b_label.id; + } + } + size_t mapsize = sizeof(basicblock *) * (max_label + 1); + basicblock **label2block = (basicblock **)PyMem_Malloc(mapsize); + if (!label2block) { + PyErr_NoMemory(); + return ERROR; + } + memset(label2block, 0, mapsize); + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + if (b->b_label.id >= 0) { + label2block[b->b_label.id] = b; + } + } + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + assert(instr->i_target == NULL); + if (HAS_TARGET(instr->i_opcode)) { + int lbl = instr->i_oparg; + assert(lbl >= 0 && lbl <= max_label); + instr->i_target = label2block[lbl]; + assert(instr->i_target != NULL); + assert(instr->i_target->b_label.id == lbl); + } + } + } + PyMem_Free(label2block); + return SUCCESS; +} + + +static int +mark_except_handlers(basicblock *entryblock) { +#ifndef NDEBUG + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + assert(!b->b_except_handler); + } +#endif + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int i=0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + if (is_block_push(instr)) { + instr->i_target->b_except_handler = 1; + } + } + } + return SUCCESS; +} + + +typedef _PyCfgExceptStack ExceptStack; + +static basicblock * +push_except_block(ExceptStack *stack, cfg_instr *setup) { + assert(is_block_push(setup)); + int opcode = setup->i_opcode; + basicblock * target = setup->i_target; + if (opcode == SETUP_WITH || opcode == SETUP_CLEANUP) { + target->b_preserve_lasti = 1; + } + stack->handlers[++stack->depth] = target; + return target; +} + +static basicblock * +pop_except_block(ExceptStack *stack) { + assert(stack->depth > 0); + return stack->handlers[--stack->depth]; +} + +static basicblock * +except_stack_top(ExceptStack *stack) { + return stack->handlers[stack->depth]; +} + +static ExceptStack * +make_except_stack(void) { + ExceptStack *new = PyMem_Malloc(sizeof(ExceptStack)); + if (new == NULL) { + PyErr_NoMemory(); + return NULL; + } + new->depth = 0; + new->handlers[0] = NULL; + return new; +} + +static ExceptStack * +copy_except_stack(ExceptStack *stack) { + ExceptStack *copy = PyMem_Malloc(sizeof(ExceptStack)); + if (copy == NULL) { + PyErr_NoMemory(); + return NULL; + } + memcpy(copy, stack, sizeof(ExceptStack)); + return copy; +} + +static basicblock** +make_cfg_traversal_stack(basicblock *entryblock) { + int nblocks = 0; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + b->b_visited = 0; + nblocks++; + } + basicblock **stack = (basicblock **)PyMem_Malloc(sizeof(basicblock *) * nblocks); + if (!stack) { + PyErr_NoMemory(); + } + return stack; +} + +Py_LOCAL_INLINE(void) +stackdepth_push(basicblock ***sp, basicblock *b, int depth) +{ + assert(b->b_startdepth < 0 || b->b_startdepth == depth); + if (b->b_startdepth < depth && b->b_startdepth < 100) { + assert(b->b_startdepth < 0); + b->b_startdepth = depth; + *(*sp)++ = b; + } +} + +/* Find the flow path that needs the largest stack. We assume that + * cycles in the flow graph have no net effect on the stack depth. + */ +int +_PyCfg_Stackdepth(basicblock *entryblock, int code_flags) +{ + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + b->b_startdepth = INT_MIN; + } + basicblock **stack = make_cfg_traversal_stack(entryblock); + if (!stack) { + return ERROR; + } + + int maxdepth = 0; + basicblock **sp = stack; + if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { + stackdepth_push(&sp, entryblock, 1); + } else { + stackdepth_push(&sp, entryblock, 0); + } + + while (sp != stack) { + basicblock *b = *--sp; + int depth = b->b_startdepth; + assert(depth >= 0); + basicblock *next = b->b_next; + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + int effect = PyCompile_OpcodeStackEffectWithJump(instr->i_opcode, instr->i_oparg, 0); + if (effect == PY_INVALID_STACK_EFFECT) { + PyErr_Format(PyExc_SystemError, + "compiler PyCompile_OpcodeStackEffectWithJump(opcode=%d, arg=%i) failed", + instr->i_opcode, instr->i_oparg); + return ERROR; + } + int new_depth = depth + effect; + assert(new_depth >= 0); /* invalid code or bug in stackdepth() */ + if (new_depth > maxdepth) { + maxdepth = new_depth; + } + if (HAS_TARGET(instr->i_opcode)) { + effect = PyCompile_OpcodeStackEffectWithJump(instr->i_opcode, instr->i_oparg, 1); + assert(effect != PY_INVALID_STACK_EFFECT); + int target_depth = depth + effect; + assert(target_depth >= 0); /* invalid code or bug in stackdepth() */ + if (target_depth > maxdepth) { + maxdepth = target_depth; + } + stackdepth_push(&sp, instr->i_target, target_depth); + } + depth = new_depth; + assert(!IS_ASSEMBLER_OPCODE(instr->i_opcode)); + if (IS_UNCONDITIONAL_JUMP_OPCODE(instr->i_opcode) || + IS_SCOPE_EXIT_OPCODE(instr->i_opcode)) + { + /* remaining code is dead */ + next = NULL; + break; + } + } + if (next != NULL) { + assert(BB_HAS_FALLTHROUGH(b)); + stackdepth_push(&sp, next, depth); + } + } + PyMem_Free(stack); + return maxdepth; +} + +static int +label_exception_targets(basicblock *entryblock) { + basicblock **todo_stack = make_cfg_traversal_stack(entryblock); + if (todo_stack == NULL) { + return ERROR; + } + ExceptStack *except_stack = make_except_stack(); + if (except_stack == NULL) { + PyMem_Free(todo_stack); + PyErr_NoMemory(); + return ERROR; + } + except_stack->depth = 0; + todo_stack[0] = entryblock; + entryblock->b_visited = 1; + entryblock->b_exceptstack = except_stack; + basicblock **todo = &todo_stack[1]; + basicblock *handler = NULL; + while (todo > todo_stack) { + todo--; + basicblock *b = todo[0]; + assert(b->b_visited == 1); + except_stack = b->b_exceptstack; + assert(except_stack != NULL); + b->b_exceptstack = NULL; + handler = except_stack_top(except_stack); + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + if (is_block_push(instr)) { + if (!instr->i_target->b_visited) { + ExceptStack *copy = copy_except_stack(except_stack); + if (copy == NULL) { + goto error; + } + instr->i_target->b_exceptstack = copy; + todo[0] = instr->i_target; + instr->i_target->b_visited = 1; + todo++; + } + handler = push_except_block(except_stack, instr); + } + else if (instr->i_opcode == POP_BLOCK) { + handler = pop_except_block(except_stack); + } + else if (is_jump(instr)) { + instr->i_except = handler; + assert(i == b->b_iused -1); + if (!instr->i_target->b_visited) { + if (BB_HAS_FALLTHROUGH(b)) { + ExceptStack *copy = copy_except_stack(except_stack); + if (copy == NULL) { + goto error; + } + instr->i_target->b_exceptstack = copy; + } + else { + instr->i_target->b_exceptstack = except_stack; + except_stack = NULL; + } + todo[0] = instr->i_target; + instr->i_target->b_visited = 1; + todo++; + } + } + else { + if (instr->i_opcode == YIELD_VALUE) { + instr->i_oparg = except_stack->depth; + } + instr->i_except = handler; + } + } + if (BB_HAS_FALLTHROUGH(b) && !b->b_next->b_visited) { + assert(except_stack != NULL); + b->b_next->b_exceptstack = except_stack; + todo[0] = b->b_next; + b->b_next->b_visited = 1; + todo++; + } + else if (except_stack != NULL) { + PyMem_Free(except_stack); + } + } +#ifdef Py_DEBUG + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + assert(b->b_exceptstack == NULL); + } +#endif + PyMem_Free(todo_stack); + return SUCCESS; +error: + PyMem_Free(todo_stack); + PyMem_Free(except_stack); + return ERROR; +} + +/***** CFG optimizations *****/ + +static int +mark_reachable(basicblock *entryblock) { + basicblock **stack = make_cfg_traversal_stack(entryblock); + if (stack == NULL) { + return ERROR; + } + basicblock **sp = stack; + entryblock->b_predecessors = 1; + *sp++ = entryblock; + while (sp > stack) { + basicblock *b = *(--sp); + b->b_visited = 1; + if (b->b_next && BB_HAS_FALLTHROUGH(b)) { + if (!b->b_next->b_visited) { + assert(b->b_next->b_predecessors == 0); + *sp++ = b->b_next; + } + b->b_next->b_predecessors++; + } + for (int i = 0; i < b->b_iused; i++) { + basicblock *target; + cfg_instr *instr = &b->b_instr[i]; + if (is_jump(instr) || is_block_push(instr)) { + target = instr->i_target; + if (!target->b_visited) { + assert(target->b_predecessors == 0 || target == b->b_next); + *sp++ = target; + } + target->b_predecessors++; + } + } + } + PyMem_Free(stack); + return SUCCESS; +} + +static void +eliminate_empty_basic_blocks(cfg_builder *g) { + /* Eliminate empty blocks */ + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + basicblock *next = b->b_next; + while (next && next->b_iused == 0) { + next = next->b_next; + } + b->b_next = next; + } + while(g->g_entryblock && g->g_entryblock->b_iused == 0) { + g->g_entryblock = g->g_entryblock->b_next; + } + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + assert(b->b_iused > 0); + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + if (HAS_TARGET(instr->i_opcode)) { + basicblock *target = instr->i_target; + while (target->b_iused == 0) { + target = target->b_next; + } + instr->i_target = target; + assert(instr->i_target && instr->i_target->b_iused > 0); + } + } + } +} + +static int +remove_redundant_nops(basicblock *bb) { + /* Remove NOPs when legal to do so. */ + int dest = 0; + int prev_lineno = -1; + for (int src = 0; src < bb->b_iused; src++) { + int lineno = bb->b_instr[src].i_loc.lineno; + if (bb->b_instr[src].i_opcode == NOP) { + /* Eliminate no-op if it doesn't have a line number */ + if (lineno < 0) { + continue; + } + /* or, if the previous instruction had the same line number. */ + if (prev_lineno == lineno) { + continue; + } + /* or, if the next instruction has same line number or no line number */ + if (src < bb->b_iused - 1) { + int next_lineno = bb->b_instr[src+1].i_loc.lineno; + if (next_lineno == lineno) { + continue; + } + if (next_lineno < 0) { + bb->b_instr[src+1].i_loc = bb->b_instr[src].i_loc; + continue; + } + } + else { + basicblock* next = bb->b_next; + while (next && next->b_iused == 0) { + next = next->b_next; + } + /* or if last instruction in BB and next BB has same line number */ + if (next) { + if (lineno == next->b_instr[0].i_loc.lineno) { + continue; + } + } + } + + } + if (dest != src) { + bb->b_instr[dest] = bb->b_instr[src]; + } + dest++; + prev_lineno = lineno; + } + assert(dest <= bb->b_iused); + int num_removed = bb->b_iused - dest; + bb->b_iused = dest; + return num_removed; +} + +static int +remove_redundant_nops_and_pairs(basicblock *entryblock) +{ + bool done = false; + + while (! done) { + done = true; + cfg_instr *prev_instr = NULL; + cfg_instr *instr = NULL; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + remove_redundant_nops(b); + if (IS_LABEL(b->b_label)) { + /* this block is a jump target, forget instr */ + instr = NULL; + } + for (int i = 0; i < b->b_iused; i++) { + prev_instr = instr; + instr = &b->b_instr[i]; + int prev_opcode = prev_instr ? prev_instr->i_opcode : 0; + int prev_oparg = prev_instr ? prev_instr->i_oparg : 0; + int opcode = instr->i_opcode; + bool is_redundant_pair = false; + if (opcode == POP_TOP) { + if (prev_opcode == LOAD_CONST) { + is_redundant_pair = true; + } + else if (prev_opcode == COPY && prev_oparg == 1) { + is_redundant_pair = true; + } + } + if (is_redundant_pair) { + INSTR_SET_OP0(prev_instr, NOP); + INSTR_SET_OP0(instr, NOP); + done = false; + } + } + if ((instr && is_jump(instr)) || !BB_HAS_FALLTHROUGH(b)) { + instr = NULL; + } + } + } + return SUCCESS; +} + +static int +remove_redundant_jumps(cfg_builder *g) { + /* If a non-empty block ends with a jump instruction, check if the next + * non-empty block reached through normal flow control is the target + * of that jump. If it is, then the jump instruction is redundant and + * can be deleted. + */ + assert(no_empty_basic_blocks(g)); + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + assert(last != NULL); + assert(!IS_ASSEMBLER_OPCODE(last->i_opcode)); + if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { + if (last->i_target == NULL) { + PyErr_SetString(PyExc_SystemError, "jump with NULL target"); + return ERROR; + } + if (last->i_target == b->b_next) { + assert(b->b_next->b_iused); + INSTR_SET_OP0(last, NOP); + } + } + } + return SUCCESS; +} + +/* Maximum size of basic block that should be copied in optimizer */ +#define MAX_COPY_SIZE 4 + +/* If this block ends with an unconditional jump to a small exit block, then + * remove the jump and extend this block with the target. + * Returns 1 if extended, 0 if no change, and -1 on error. + */ +static int +inline_small_exit_blocks(basicblock *bb) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(bb); + if (last == NULL) { + return 0; + } + if (!IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)) { + return 0; + } + basicblock *target = last->i_target; + if (basicblock_exits_scope(target) && target->b_iused <= MAX_COPY_SIZE) { + INSTR_SET_OP0(last, NOP); + RETURN_IF_ERROR(basicblock_append_instructions(bb, target)); + return 1; + } + return 0; +} + +// Attempt to eliminate jumps to jumps by updating inst to jump to +// target->i_target using the provided opcode. Return whether or not the +// optimization was successful. +static bool +jump_thread(cfg_instr *inst, cfg_instr *target, int opcode) +{ + assert(is_jump(inst)); + assert(is_jump(target)); + // bpo-45773: If inst->i_target == target->i_target, then nothing actually + // changes (and we fall into an infinite loop): + if ((inst->i_loc.lineno == target->i_loc.lineno || target->i_loc.lineno == -1) && + inst->i_target != target->i_target) + { + inst->i_target = target->i_target; + inst->i_opcode = opcode; + return true; + } + return false; +} + +static PyObject* +get_const_value(int opcode, int oparg, PyObject *co_consts) +{ + PyObject *constant = NULL; + assert(HAS_CONST(opcode)); + if (opcode == LOAD_CONST) { + constant = PyList_GET_ITEM(co_consts, oparg); + } + + if (constant == NULL) { + PyErr_SetString(PyExc_SystemError, + "Internal error: failed to get value of a constant"); + return NULL; + } + return Py_NewRef(constant); +} + +/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n + with LOAD_CONST (c1, c2, ... cn). + The consts table must still be in list form so that the + new constant (c1, c2, ... cn) can be appended. + Called with codestr pointing to the first LOAD_CONST. +*/ +static int +fold_tuple_on_constants(PyObject *const_cache, + cfg_instr *inst, + int n, PyObject *consts) +{ + /* Pre-conditions */ + assert(PyDict_CheckExact(const_cache)); + assert(PyList_CheckExact(consts)); + assert(inst[n].i_opcode == BUILD_TUPLE); + assert(inst[n].i_oparg == n); + + for (int i = 0; i < n; i++) { + if (!HAS_CONST(inst[i].i_opcode)) { + return SUCCESS; + } + } + + /* Buildup new tuple of constants */ + PyObject *newconst = PyTuple_New(n); + if (newconst == NULL) { + return ERROR; + } + for (int i = 0; i < n; i++) { + int op = inst[i].i_opcode; + int arg = inst[i].i_oparg; + PyObject *constant = get_const_value(op, arg, consts); + if (constant == NULL) { + return ERROR; + } + PyTuple_SET_ITEM(newconst, i, constant); + } + if (_PyCompile_ConstCacheMergeOne(const_cache, &newconst) < 0) { + Py_DECREF(newconst); + return ERROR; + } + + Py_ssize_t index; + for (index = 0; index < PyList_GET_SIZE(consts); index++) { + if (PyList_GET_ITEM(consts, index) == newconst) { + break; + } + } + if (index == PyList_GET_SIZE(consts)) { + if ((size_t)index >= (size_t)INT_MAX - 1) { + Py_DECREF(newconst); + PyErr_SetString(PyExc_OverflowError, "too many constants"); + return ERROR; + } + if (PyList_Append(consts, newconst)) { + Py_DECREF(newconst); + return ERROR; + } + } + Py_DECREF(newconst); + for (int i = 0; i < n; i++) { + INSTR_SET_OP0(&inst[i], NOP); + } + INSTR_SET_OP1(&inst[n], LOAD_CONST, (int)index); + return SUCCESS; +} + +#define VISITED (-1) + +// Replace an arbitrary run of SWAPs and NOPs with an optimal one that has the +// same effect. +static int +swaptimize(basicblock *block, int *ix) +{ + // NOTE: "./python -m test test_patma" serves as a good, quick stress test + // for this function. Make sure to blow away cached *.pyc files first! + assert(*ix < block->b_iused); + cfg_instr *instructions = &block->b_instr[*ix]; + // Find the length of the current sequence of SWAPs and NOPs, and record the + // maximum depth of the stack manipulations: + assert(instructions[0].i_opcode == SWAP); + int depth = instructions[0].i_oparg; + int len = 0; + int more = false; + int limit = block->b_iused - *ix; + while (++len < limit) { + int opcode = instructions[len].i_opcode; + if (opcode == SWAP) { + depth = Py_MAX(depth, instructions[len].i_oparg); + more = true; + } + else if (opcode != NOP) { + break; + } + } + // It's already optimal if there's only one SWAP: + if (!more) { + return SUCCESS; + } + // Create an array with elements {0, 1, 2, ..., depth - 1}: + int *stack = PyMem_Malloc(depth * sizeof(int)); + if (stack == NULL) { + PyErr_NoMemory(); + return ERROR; + } + for (int i = 0; i < depth; i++) { + stack[i] = i; + } + // Simulate the combined effect of these instructions by "running" them on + // our "stack": + for (int i = 0; i < len; i++) { + if (instructions[i].i_opcode == SWAP) { + int oparg = instructions[i].i_oparg; + int top = stack[0]; + // SWAPs are 1-indexed: + stack[0] = stack[oparg - 1]; + stack[oparg - 1] = top; + } + } + // Now we can begin! Our approach here is based on a solution to a closely + // related problem (https://cs.stackexchange.com/a/13938). It's easiest to + // think of this algorithm as determining the steps needed to efficiently + // "un-shuffle" our stack. By performing the moves in *reverse* order, + // though, we can efficiently *shuffle* it! For this reason, we will be + // replacing instructions starting from the *end* of the run. Since the + // solution is optimal, we don't need to worry about running out of space: + int current = len - 1; + for (int i = 0; i < depth; i++) { + // Skip items that have already been visited, or just happen to be in + // the correct location: + if (stack[i] == VISITED || stack[i] == i) { + continue; + } + // Okay, we've found an item that hasn't been visited. It forms a cycle + // with other items; traversing the cycle and swapping each item with + // the next will put them all in the correct place. The weird + // loop-and-a-half is necessary to insert 0 into every cycle, since we + // can only swap from that position: + int j = i; + while (true) { + // Skip the actual swap if our item is zero, since swapping the top + // item with itself is pointless: + if (j) { + assert(0 <= current); + // SWAPs are 1-indexed: + instructions[current].i_opcode = SWAP; + instructions[current--].i_oparg = j + 1; + } + if (stack[j] == VISITED) { + // Completed the cycle: + assert(j == i); + break; + } + int next_j = stack[j]; + stack[j] = VISITED; + j = next_j; + } + } + // NOP out any unused instructions: + while (0 <= current) { + INSTR_SET_OP0(&instructions[current--], NOP); + } + PyMem_Free(stack); + *ix += len - 1; + return SUCCESS; +} + + +// This list is pretty small, since it's only okay to reorder opcodes that: +// - can't affect control flow (like jumping or raising exceptions) +// - can't invoke arbitrary code (besides finalizers) +// - only touch the TOS (and pop it when finished) +#define SWAPPABLE(opcode) \ + ((opcode) == STORE_FAST || (opcode) == POP_TOP) + +static int +next_swappable_instruction(basicblock *block, int i, int lineno) +{ + while (++i < block->b_iused) { + cfg_instr *instruction = &block->b_instr[i]; + if (0 <= lineno && instruction->i_loc.lineno != lineno) { + // Optimizing across this instruction could cause user-visible + // changes in the names bound between line tracing events! + return -1; + } + if (instruction->i_opcode == NOP) { + continue; + } + if (SWAPPABLE(instruction->i_opcode)) { + return i; + } + return -1; + } + return -1; +} + +// Attempt to apply SWAPs statically by swapping *instructions* rather than +// stack items. For example, we can replace SWAP(2), POP_TOP, STORE_FAST(42) +// with the more efficient NOP, STORE_FAST(42), POP_TOP. +static void +apply_static_swaps(basicblock *block, int i) +{ + // SWAPs are to our left, and potential swaperands are to our right: + for (; 0 <= i; i--) { + assert(i < block->b_iused); + cfg_instr *swap = &block->b_instr[i]; + if (swap->i_opcode != SWAP) { + if (swap->i_opcode == NOP || SWAPPABLE(swap->i_opcode)) { + // Nope, but we know how to handle these. Keep looking: + continue; + } + // We can't reason about what this instruction does. Bail: + return; + } + int j = next_swappable_instruction(block, i, -1); + if (j < 0) { + return; + } + int k = j; + int lineno = block->b_instr[j].i_loc.lineno; + for (int count = swap->i_oparg - 1; 0 < count; count--) { + k = next_swappable_instruction(block, k, lineno); + if (k < 0) { + return; + } + } + // Success! + INSTR_SET_OP0(swap, NOP); + cfg_instr temp = block->b_instr[j]; + block->b_instr[j] = block->b_instr[k]; + block->b_instr[k] = temp; + } +} + +static int +optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) +{ + assert(PyDict_CheckExact(const_cache)); + assert(PyList_CheckExact(consts)); + cfg_instr nop; + INSTR_SET_OP0(&nop, NOP); + cfg_instr *target = &nop; + int opcode = 0; + int oparg = 0; + int nextop = 0; + for (int i = 0; i < bb->b_iused; i++) { + cfg_instr *inst = &bb->b_instr[i]; + bool is_copy_of_load_const = (opcode == LOAD_CONST && + inst->i_opcode == COPY && + inst->i_oparg == 1); + if (! is_copy_of_load_const) { + opcode = inst->i_opcode; + oparg = inst->i_oparg; + if (HAS_TARGET(opcode)) { + assert(inst->i_target->b_iused > 0); + target = &inst->i_target->b_instr[0]; + assert(!IS_ASSEMBLER_OPCODE(target->i_opcode)); + } + else { + target = &nop; + } + } + nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0; + assert(!IS_ASSEMBLER_OPCODE(opcode)); + switch (opcode) { + /* Remove LOAD_CONST const; conditional jump */ + case LOAD_CONST: + { + PyObject* cnt; + int is_true; + int jump_if_true; + switch(nextop) { + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: + cnt = get_const_value(opcode, oparg, consts); + if (cnt == NULL) { + goto error; + } + is_true = PyObject_IsTrue(cnt); + Py_DECREF(cnt); + if (is_true == -1) { + goto error; + } + INSTR_SET_OP0(inst, NOP); + jump_if_true = nextop == POP_JUMP_IF_TRUE; + if (is_true == jump_if_true) { + bb->b_instr[i+1].i_opcode = JUMP; + } + else { + INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); + } + break; + case IS_OP: + cnt = get_const_value(opcode, oparg, consts); + if (cnt == NULL) { + goto error; + } + int jump_op = i+2 < bb->b_iused ? bb->b_instr[i+2].i_opcode : 0; + if (Py_IsNone(cnt) && (jump_op == POP_JUMP_IF_FALSE || jump_op == POP_JUMP_IF_TRUE)) { + unsigned char nextarg = bb->b_instr[i+1].i_oparg; + INSTR_SET_OP0(inst, NOP); + INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); + bb->b_instr[i+2].i_opcode = nextarg ^ (jump_op == POP_JUMP_IF_FALSE) ? + POP_JUMP_IF_NOT_NONE : POP_JUMP_IF_NONE; + } + Py_DECREF(cnt); + break; + case RETURN_VALUE: + INSTR_SET_OP0(inst, NOP); + INSTR_SET_OP1(&bb->b_instr[++i], RETURN_CONST, oparg); + break; + } + break; + } + /* Try to fold tuples of constants. + Skip over BUILD_TUPLE(1) UNPACK_SEQUENCE(1). + Replace BUILD_TUPLE(2) UNPACK_SEQUENCE(2) with SWAP(2). + Replace BUILD_TUPLE(3) UNPACK_SEQUENCE(3) with SWAP(3). */ + case BUILD_TUPLE: + if (nextop == UNPACK_SEQUENCE && oparg == bb->b_instr[i+1].i_oparg) { + switch(oparg) { + case 1: + INSTR_SET_OP0(inst, NOP); + INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); + continue; + case 2: + case 3: + INSTR_SET_OP0(inst, NOP); + bb->b_instr[i+1].i_opcode = SWAP; + continue; + } + } + if (i >= oparg) { + if (fold_tuple_on_constants(const_cache, inst-oparg, oparg, consts)) { + goto error; + } + } + break; + case POP_JUMP_IF_NOT_NONE: + case POP_JUMP_IF_NONE: + switch (target->i_opcode) { + case JUMP: + i -= jump_thread(inst, target, inst->i_opcode); + } + break; + case POP_JUMP_IF_FALSE: + switch (target->i_opcode) { + case JUMP: + i -= jump_thread(inst, target, POP_JUMP_IF_FALSE); + } + break; + case POP_JUMP_IF_TRUE: + switch (target->i_opcode) { + case JUMP: + i -= jump_thread(inst, target, POP_JUMP_IF_TRUE); + } + break; + case JUMP: + switch (target->i_opcode) { + case JUMP: + i -= jump_thread(inst, target, JUMP); + } + break; + case FOR_ITER: + if (target->i_opcode == JUMP) { + /* This will not work now because the jump (at target) could + * be forward or backward and FOR_ITER only jumps forward. We + * can re-enable this if ever we implement a backward version + * of FOR_ITER. + */ + /* + i -= jump_thread(inst, target, FOR_ITER); + */ + } + break; + case SWAP: + if (oparg == 1) { + INSTR_SET_OP0(inst, NOP); + break; + } + if (swaptimize(bb, &i) < 0) { + goto error; + } + apply_static_swaps(bb, i); + break; + case KW_NAMES: + break; + case PUSH_NULL: + if (nextop == LOAD_GLOBAL && (inst[1].i_opcode & 1) == 0) { + INSTR_SET_OP0(inst, NOP); + inst[1].i_oparg |= 1; + } + break; + default: + /* All HAS_CONST opcodes should be handled with LOAD_CONST */ + assert (!HAS_CONST(inst->i_opcode)); + } + } + return SUCCESS; +error: + return ERROR; +} + + +/* Perform optimizations on a control flow graph. + The consts object should still be in list form to allow new constants + to be appended. + + Code trasnformations that reduce code size initially fill the gaps with + NOPs. Later those NOPs are removed. +*/ +static int +optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache) +{ + assert(PyDict_CheckExact(const_cache)); + RETURN_IF_ERROR(check_cfg(g)); + eliminate_empty_basic_blocks(g); + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + RETURN_IF_ERROR(inline_small_exit_blocks(b)); + } + assert(no_empty_basic_blocks(g)); + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts)); + assert(b->b_predecessors == 0); + } + RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock)); + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + RETURN_IF_ERROR(inline_small_exit_blocks(b)); + } + RETURN_IF_ERROR(mark_reachable(g->g_entryblock)); + + /* Delete unreachable instructions */ + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + if (b->b_predecessors == 0) { + b->b_iused = 0; + } + } + for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { + remove_redundant_nops(b); + } + eliminate_empty_basic_blocks(g); + assert(no_redundant_nops(g)); + RETURN_IF_ERROR(remove_redundant_jumps(g)); + return SUCCESS; +} + +// helper functions for add_checks_for_loads_of_unknown_variables +static inline void +maybe_push(basicblock *b, uint64_t unsafe_mask, basicblock ***sp) +{ + // Push b if the unsafe mask is giving us any new information. + // To avoid overflowing the stack, only allow each block once. + // Use b->b_visited=1 to mean that b is currently on the stack. + uint64_t both = b->b_unsafe_locals_mask | unsafe_mask; + if (b->b_unsafe_locals_mask != both) { + b->b_unsafe_locals_mask = both; + // More work left to do. + if (!b->b_visited) { + // not on the stack, so push it. + *(*sp)++ = b; + b->b_visited = 1; + } + } +} + +static void +scan_block_for_locals(basicblock *b, basicblock ***sp) +{ + // bit i is set if local i is potentially uninitialized + uint64_t unsafe_mask = b->b_unsafe_locals_mask; + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + assert(instr->i_opcode != EXTENDED_ARG); + assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); + if (instr->i_except != NULL) { + maybe_push(instr->i_except, unsafe_mask, sp); + } + if (instr->i_oparg >= 64) { + continue; + } + assert(instr->i_oparg >= 0); + uint64_t bit = (uint64_t)1 << instr->i_oparg; + switch (instr->i_opcode) { + case DELETE_FAST: + unsafe_mask |= bit; + break; + case STORE_FAST: + unsafe_mask &= ~bit; + break; + case LOAD_FAST_CHECK: + // If this doesn't raise, then the local is defined. + unsafe_mask &= ~bit; + break; + case LOAD_FAST: + if (unsafe_mask & bit) { + instr->i_opcode = LOAD_FAST_CHECK; + } + unsafe_mask &= ~bit; + break; + } + } + if (b->b_next && BB_HAS_FALLTHROUGH(b)) { + maybe_push(b->b_next, unsafe_mask, sp); + } + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + if (last && is_jump(last)) { + assert(last->i_target != NULL); + maybe_push(last->i_target, unsafe_mask, sp); + } +} + +static int +fast_scan_many_locals(basicblock *entryblock, int nlocals) +{ + assert(nlocals > 64); + Py_ssize_t *states = PyMem_Calloc(nlocals - 64, sizeof(Py_ssize_t)); + if (states == NULL) { + PyErr_NoMemory(); + return ERROR; + } + Py_ssize_t blocknum = 0; + // state[i - 64] == blocknum if local i is guaranteed to + // be initialized, i.e., if it has had a previous LOAD_FAST or + // STORE_FAST within that basicblock (not followed by DELETE_FAST). + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + blocknum++; + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + assert(instr->i_opcode != EXTENDED_ARG); + assert(!IS_SUPERINSTRUCTION_OPCODE(instr->i_opcode)); + int arg = instr->i_oparg; + if (arg < 64) { + continue; + } + assert(arg >= 0); + switch (instr->i_opcode) { + case DELETE_FAST: + states[arg - 64] = blocknum - 1; + break; + case STORE_FAST: + states[arg - 64] = blocknum; + break; + case LOAD_FAST: + if (states[arg - 64] != blocknum) { + instr->i_opcode = LOAD_FAST_CHECK; + } + states[arg - 64] = blocknum; + break; + Py_UNREACHABLE(); + } + } + } + PyMem_Free(states); + return SUCCESS; +} + +static int +remove_unused_consts(basicblock *entryblock, PyObject *consts) +{ + assert(PyList_CheckExact(consts)); + Py_ssize_t nconsts = PyList_GET_SIZE(consts); + if (nconsts == 0) { + return SUCCESS; /* nothing to do */ + } + + Py_ssize_t *index_map = NULL; + Py_ssize_t *reverse_index_map = NULL; + int err = ERROR; + + index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t)); + if (index_map == NULL) { + goto end; + } + for (Py_ssize_t i = 1; i < nconsts; i++) { + index_map[i] = -1; + } + // The first constant may be docstring; keep it always. + index_map[0] = 0; + + /* mark used consts */ + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int i = 0; i < b->b_iused; i++) { + if (HAS_CONST(b->b_instr[i].i_opcode)) { + int index = b->b_instr[i].i_oparg; + index_map[index] = index; + } + } + } + /* now index_map[i] == i if consts[i] is used, -1 otherwise */ + /* condense consts */ + Py_ssize_t n_used_consts = 0; + for (int i = 0; i < nconsts; i++) { + if (index_map[i] != -1) { + assert(index_map[i] == i); + index_map[n_used_consts++] = index_map[i]; + } + } + if (n_used_consts == nconsts) { + /* nothing to do */ + err = SUCCESS; + goto end; + } + + /* move all used consts to the beginning of the consts list */ + assert(n_used_consts < nconsts); + for (Py_ssize_t i = 0; i < n_used_consts; i++) { + Py_ssize_t old_index = index_map[i]; + assert(i <= old_index && old_index < nconsts); + if (i != old_index) { + PyObject *value = PyList_GET_ITEM(consts, index_map[i]); + assert(value != NULL); + PyList_SetItem(consts, i, Py_NewRef(value)); + } + } + + /* truncate the consts list at its new size */ + if (PyList_SetSlice(consts, n_used_consts, nconsts, NULL) < 0) { + goto end; + } + /* adjust const indices in the bytecode */ + reverse_index_map = PyMem_Malloc(nconsts * sizeof(Py_ssize_t)); + if (reverse_index_map == NULL) { + goto end; + } + for (Py_ssize_t i = 0; i < nconsts; i++) { + reverse_index_map[i] = -1; + } + for (Py_ssize_t i = 0; i < n_used_consts; i++) { + assert(index_map[i] != -1); + assert(reverse_index_map[index_map[i]] == -1); + reverse_index_map[index_map[i]] = i; + } + + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int i = 0; i < b->b_iused; i++) { + if (HAS_CONST(b->b_instr[i].i_opcode)) { + int index = b->b_instr[i].i_oparg; + assert(reverse_index_map[index] >= 0); + assert(reverse_index_map[index] < n_used_consts); + b->b_instr[i].i_oparg = (int)reverse_index_map[index]; + } + } + } + + err = SUCCESS; +end: + PyMem_Free(index_map); + PyMem_Free(reverse_index_map); + return err; +} + + + +static int +add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock, + int nlocals, + int nparams) +{ + if (nlocals == 0) { + return SUCCESS; + } + if (nlocals > 64) { + // To avoid O(nlocals**2) compilation, locals beyond the first + // 64 are only analyzed one basicblock at a time: initialization + // info is not passed between basicblocks. + if (fast_scan_many_locals(entryblock, nlocals) < 0) { + return ERROR; + } + nlocals = 64; + } + basicblock **stack = make_cfg_traversal_stack(entryblock); + if (stack == NULL) { + return ERROR; + } + basicblock **sp = stack; + + // First origin of being uninitialized: + // The non-parameter locals in the entry block. + uint64_t start_mask = 0; + for (int i = nparams; i < nlocals; i++) { + start_mask |= (uint64_t)1 << i; + } + maybe_push(entryblock, start_mask, &sp); + + // Second origin of being uninitialized: + // There could be DELETE_FAST somewhere, so + // be sure to scan each basicblock at least once. + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + scan_block_for_locals(b, &sp); + } + // Now propagate the uncertainty from the origins we found: Use + // LOAD_FAST_CHECK for any LOAD_FAST where the local could be undefined. + while (sp > stack) { + basicblock *b = *--sp; + // mark as no longer on stack + b->b_visited = 0; + scan_block_for_locals(b, &sp); + } + PyMem_Free(stack); + return SUCCESS; +} + + +static int +mark_warm(basicblock *entryblock) { + basicblock **stack = make_cfg_traversal_stack(entryblock); + if (stack == NULL) { + return ERROR; + } + basicblock **sp = stack; + + *sp++ = entryblock; + entryblock->b_visited = 1; + while (sp > stack) { + basicblock *b = *(--sp); + assert(!b->b_except_handler); + b->b_warm = 1; + basicblock *next = b->b_next; + if (next && BB_HAS_FALLTHROUGH(b) && !next->b_visited) { + *sp++ = next; + next->b_visited = 1; + } + for (int i=0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + if (is_jump(instr) && !instr->i_target->b_visited) { + *sp++ = instr->i_target; + instr->i_target->b_visited = 1; + } + } + } + PyMem_Free(stack); + return SUCCESS; +} + +static int +mark_cold(basicblock *entryblock) { + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + assert(!b->b_cold && !b->b_warm); + } + if (mark_warm(entryblock) < 0) { + return ERROR; + } + + basicblock **stack = make_cfg_traversal_stack(entryblock); + if (stack == NULL) { + return ERROR; + } + + basicblock **sp = stack; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + if (b->b_except_handler) { + assert(!b->b_warm); + *sp++ = b; + b->b_visited = 1; + } + } + + while (sp > stack) { + basicblock *b = *(--sp); + b->b_cold = 1; + basicblock *next = b->b_next; + if (next && BB_HAS_FALLTHROUGH(b)) { + if (!next->b_warm && !next->b_visited) { + *sp++ = next; + next->b_visited = 1; + } + } + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + if (is_jump(instr)) { + assert(i == b->b_iused - 1); + basicblock *target = b->b_instr[i].i_target; + if (!target->b_warm && !target->b_visited) { + *sp++ = target; + target->b_visited = 1; + } + } + } + } + PyMem_Free(stack); + return SUCCESS; +} + + +static int +push_cold_blocks_to_end(cfg_builder *g, int code_flags) { + basicblock *entryblock = g->g_entryblock; + if (entryblock->b_next == NULL) { + /* single basicblock, no need to reorder */ + return SUCCESS; + } + RETURN_IF_ERROR(mark_cold(entryblock)); + + /* If we have a cold block with fallthrough to a warm block, add */ + /* an explicit jump instead of fallthrough */ + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + if (b->b_cold && BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_next->b_warm) { + basicblock *explicit_jump = cfg_builder_new_block(g); + if (explicit_jump == NULL) { + return ERROR; + } + basicblock_addop(explicit_jump, JUMP, b->b_next->b_label.id, NO_LOCATION); + explicit_jump->b_cold = 1; + explicit_jump->b_next = b->b_next; + b->b_next = explicit_jump; + + /* set target */ + cfg_instr *last = _PyCfg_BasicblockLastInstr(explicit_jump); + last->i_target = explicit_jump->b_next; + } + } + + assert(!entryblock->b_cold); /* First block can't be cold */ + basicblock *cold_blocks = NULL; + basicblock *cold_blocks_tail = NULL; + + basicblock *b = entryblock; + while(b->b_next) { + assert(!b->b_cold); + while (b->b_next && !b->b_next->b_cold) { + b = b->b_next; + } + if (b->b_next == NULL) { + /* no more cold blocks */ + break; + } + + /* b->b_next is the beginning of a cold streak */ + assert(!b->b_cold && b->b_next->b_cold); + + basicblock *b_end = b->b_next; + while (b_end->b_next && b_end->b_next->b_cold) { + b_end = b_end->b_next; + } + + /* b_end is the end of the cold streak */ + assert(b_end && b_end->b_cold); + assert(b_end->b_next == NULL || !b_end->b_next->b_cold); + + if (cold_blocks == NULL) { + cold_blocks = b->b_next; + } + else { + cold_blocks_tail->b_next = b->b_next; + } + cold_blocks_tail = b_end; + b->b_next = b_end->b_next; + b_end->b_next = NULL; + } + assert(b != NULL && b->b_next == NULL); + b->b_next = cold_blocks; + + if (cold_blocks != NULL) { + RETURN_IF_ERROR(remove_redundant_jumps(g)); + } + return SUCCESS; +} + +int +_PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache, + int code_flags, int nlocals, int nparams) +{ + assert(cfg_builder_check(g)); + /** Preprocessing **/ + /* Map labels to targets and mark exception handlers */ + RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock)); + RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock)); + RETURN_IF_ERROR(label_exception_targets(g->g_entryblock)); + + /** Optimization **/ + RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache)); + RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts)); + RETURN_IF_ERROR( + add_checks_for_loads_of_uninitialized_variables( + g->g_entryblock, nlocals, nparams)); + + RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags)); + return SUCCESS; +} + +void +_PyCfg_ConvertExceptionHandlersToNops(basicblock *entryblock) +{ + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int i = 0; i < b->b_iused; i++) { + cfg_instr *instr = &b->b_instr[i]; + if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) { + INSTR_SET_OP0(instr, NOP); + } + } + } + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + remove_redundant_nops(b); + } +} + +static inline bool +is_exit_without_lineno(basicblock *b) { + if (!basicblock_exits_scope(b)) { + return false; + } + for (int i = 0; i < b->b_iused; i++) { + if (b->b_instr[i].i_loc.lineno >= 0) { + return false; + } + } + return true; +} + +/* PEP 626 mandates that the f_lineno of a frame is correct + * after a frame terminates. It would be prohibitively expensive + * to continuously update the f_lineno field at runtime, + * so we make sure that all exiting instruction (raises and returns) + * have a valid line number, allowing us to compute f_lineno lazily. + * We can do this by duplicating the exit blocks without line number + * so that none have more than one predecessor. We can then safely + * copy the line number from the sole predecessor block. + */ +static int +duplicate_exits_without_lineno(cfg_builder *g) +{ + assert(no_empty_basic_blocks(g)); + /* Copy all exit blocks without line number that are targets of a jump. + */ + basicblock *entryblock = g->g_entryblock; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + assert(last != NULL); + if (is_jump(last)) { + basicblock *target = last->i_target; + if (is_exit_without_lineno(target) && target->b_predecessors > 1) { + basicblock *new_target = copy_basicblock(g, target); + if (new_target == NULL) { + return ERROR; + } + new_target->b_instr[0].i_loc = last->i_loc; + last->i_target = new_target; + target->b_predecessors--; + new_target->b_predecessors = 1; + new_target->b_next = target->b_next; + target->b_next = new_target; + } + } + } + + /* Any remaining reachable exit blocks without line number can only be reached by + * fall through, and thus can only have a single predecessor */ + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) { + if (is_exit_without_lineno(b->b_next)) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + assert(last != NULL); + b->b_next->b_instr[0].i_loc = last->i_loc; + } + } + } + return SUCCESS; +} + + +/* If an instruction has no line number, but it's predecessor in the BB does, + * then copy the line number. If a successor block has no line number, and only + * one predecessor, then inherit the line number. + * This ensures that all exit blocks (with one predecessor) receive a line number. + * Also reduces the size of the line number table, + * but has no impact on the generated line number events. + */ +static void +propagate_line_numbers(basicblock *entryblock) { + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + if (last == NULL) { + continue; + } + + location prev_location = NO_LOCATION; + for (int i = 0; i < b->b_iused; i++) { + if (b->b_instr[i].i_loc.lineno < 0) { + b->b_instr[i].i_loc = prev_location; + } + else { + prev_location = b->b_instr[i].i_loc; + } + } + if (BB_HAS_FALLTHROUGH(b) && b->b_next->b_predecessors == 1) { + assert(b->b_next->b_iused); + if (b->b_next->b_instr[0].i_loc.lineno < 0) { + b->b_next->b_instr[0].i_loc = prev_location; + } + } + if (is_jump(last)) { + basicblock *target = last->i_target; + if (target->b_predecessors == 1) { + if (target->b_instr[0].i_loc.lineno < 0) { + target->b_instr[0].i_loc = prev_location; + } + } + } + } +} + +/* Make sure that all returns have a line number, even if early passes + * have failed to propagate a correct line number. + * The resulting line number may not be correct according to PEP 626, + * but should be "good enough", and no worse than in older versions. */ +static void +guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) { + int lineno = firstlineno; + assert(lineno > 0); + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + cfg_instr *last = _PyCfg_BasicblockLastInstr(b); + if (last == NULL) { + continue; + } + if (last->i_loc.lineno < 0) { + if (last->i_opcode == RETURN_VALUE) { + for (int i = 0; i < b->b_iused; i++) { + assert(b->b_instr[i].i_loc.lineno < 0); + + b->b_instr[i].i_loc.lineno = lineno; + } + } + } + else { + lineno = last->i_loc.lineno; + } + } +} + +int +_PyCfg_ResolveLineNumbers(cfg_builder *g, int firstlineno) +{ + RETURN_IF_ERROR(duplicate_exits_without_lineno(g)); + propagate_line_numbers(g->g_entryblock); + guarantee_lineno_for_exits(g->g_entryblock, firstlineno); + return SUCCESS; +} + diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 08032519f383..5c984eb4ae12 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -3,7 +3,7 @@ // Python/bytecodes.c // Do not edit! -#ifndef NEED_OPCODE_TABLES +#ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); #else int @@ -349,7 +349,7 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { } #endif -#ifndef NEED_OPCODE_TABLES +#ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_pushed(int opcode, int oparg, bool jump); #else int @@ -701,7 +701,7 @@ struct opcode_metadata { enum InstructionFormat instr_format; }; -#ifndef NEED_OPCODE_TABLES +#ifndef NEED_OPCODE_METADATA extern const struct opcode_metadata _PyOpcode_opcode_metadata[256]; #else const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 9b2112f7f5f3..614b17df7409 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -60,7 +60,7 @@ def write_int_array_from_ops(name, ops, out): bits = 0 for op in ops: bits |= 1<>= 32 @@ -130,6 +130,8 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna for name, op in specialized_opmap.items(): fobj.write(DEFINE.format(name, op)) + iobj.write("\nextern const uint32_t _PyOpcode_RelativeJump[9];\n") + iobj.write("\nextern const uint32_t _PyOpcode_Jump[9];\n") iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n") iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n") iobj.write("\n#ifdef NEED_OPCODE_TABLES\n") diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index a0bba65545d4..62ddeac0265a 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -930,7 +930,7 @@ def write_function( direction: str, data: list[tuple[AnyInstruction, str]] ) -> None: self.out.emit("") - self.out.emit("#ifndef NEED_OPCODE_TABLES") + self.out.emit("#ifndef NEED_OPCODE_METADATA") self.out.emit(f"extern int _PyOpcode_num_{direction}(int opcode, int oparg, bool jump);") self.out.emit("#else") self.out.emit("int") @@ -999,7 +999,7 @@ def write_metadata(self) -> None: self.out.emit("") # Write metadata array declaration - self.out.emit("#ifndef NEED_OPCODE_TABLES") + self.out.emit("#ifndef NEED_OPCODE_METADATA") self.out.emit("extern const struct opcode_metadata _PyOpcode_opcode_metadata[256];") self.out.emit("#else") self.out.emit("const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {") From webhook-mailer at python.org Fri Mar 31 13:37:32 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 31 Mar 2023 17:37:32 -0000 Subject: [Python-checkins] gh-74690: typing: Don't unnecessarily call `_get_protocol_attrs` twice in `_ProtocolMeta.__instancecheck__` (#103141) Message-ID: https://github.com/python/cpython/commit/9048d73f7a5c58be21988250c381f866586687a0 commit: 9048d73f7a5c58be21988250c381f866586687a0 branch: main author: Alex Waygood committer: AlexWaygood date: 2023-03-31T18:37:24+01:00 summary: gh-74690: typing: Don't unnecessarily call `_get_protocol_attrs` twice in `_ProtocolMeta.__instancecheck__` (#103141) Speed up `isinstance()` calls against runtime-checkable protocols files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index 157a563bbece..3d086dc1cb90 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1931,9 +1931,9 @@ def _get_protocol_attrs(cls): return attrs -def _is_callable_members_only(cls): +def _is_callable_members_only(cls, protocol_attrs): # PEP 544 prohibits using issubclass() with protocols that have non-method members. - return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) + return all(callable(getattr(cls, attr, None)) for attr in protocol_attrs) def _no_init_or_replace_init(self, *args, **kwargs): @@ -2000,24 +2000,32 @@ class _ProtocolMeta(ABCMeta): def __instancecheck__(cls, instance): # We need this method for situations where attributes are # assigned in __init__. + is_protocol_cls = getattr(cls, "_is_protocol", False) if ( - getattr(cls, '_is_protocol', False) and + is_protocol_cls and not getattr(cls, '_is_runtime_protocol', False) and not _allow_reckless_class_checks(depth=2) ): raise TypeError("Instance and class checks can only be used with" " @runtime_checkable protocols") - if ((not getattr(cls, '_is_protocol', False) or - _is_callable_members_only(cls)) and - issubclass(instance.__class__, cls)): + if not is_protocol_cls and issubclass(instance.__class__, cls): return True - if cls._is_protocol: + + protocol_attrs = _get_protocol_attrs(cls) + + if ( + _is_callable_members_only(cls, protocol_attrs) + and issubclass(instance.__class__, cls) + ): + return True + + if is_protocol_cls: if all(hasattr(instance, attr) and # All *methods* can be blocked by setting them to None. (not callable(getattr(cls, attr, None)) or getattr(instance, attr) is not None) - for attr in _get_protocol_attrs(cls)): + for attr in protocol_attrs): return True return super().__instancecheck__(instance) @@ -2074,7 +2082,10 @@ def _proto_hook(other): return NotImplemented raise TypeError("Instance and class checks can only be used with" " @runtime_checkable protocols") - if not _is_callable_members_only(cls): + + protocol_attrs = _get_protocol_attrs(cls) + + if not _is_callable_members_only(cls, protocol_attrs): if _allow_reckless_class_checks(): return NotImplemented raise TypeError("Protocols with non-method members" @@ -2084,7 +2095,7 @@ def _proto_hook(other): raise TypeError('issubclass() arg 1 must be a class') # Second, perform the actual structural compatibility check. - for attr in _get_protocol_attrs(cls): + for attr in protocol_attrs: for base in other.__mro__: # Check if the members appears in the class dictionary... if attr in base.__dict__: From webhook-mailer at python.org Fri Mar 31 14:09:18 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Fri, 31 Mar 2023 18:09:18 -0000 Subject: [Python-checkins] gh-100227: Fix Cleanup of the Extensions Cache (gh-103150) Message-ID: https://github.com/python/cpython/commit/dde028480e57bffa83fb084b15ec22490c42ef93 commit: dde028480e57bffa83fb084b15ec22490c42ef93 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-31T12:09:10-06:00 summary: gh-100227: Fix Cleanup of the Extensions Cache (gh-103150) Decref the key in the right interpreter in _extensions_cache_set(). This is a follow-up to gh-103084. I found the bug while working on gh-101660. files: M Python/import.c diff --git a/Python/import.c b/Python/import.c index a45b3bfaacb2..24249ae4a6ad 100644 --- a/Python/import.c +++ b/Python/import.c @@ -983,13 +983,13 @@ _extensions_cache_set(PyObject *filename, PyObject *name, PyModuleDef *def) res = 0; finally: + Py_XDECREF(key); if (oldts != NULL) { _PyThreadState_Swap(interp->runtime, oldts); _PyThreadState_UnbindDetached(main_tstate); Py_DECREF(name); Py_DECREF(filename); } - Py_XDECREF(key); extensions_lock_release(); return res; } From webhook-mailer at python.org Fri Mar 31 14:18:41 2023 From: webhook-mailer at python.org (ericsnowcurrently) Date: Fri, 31 Mar 2023 18:18:41 -0000 Subject: [Python-checkins] gh-101659: Clean Up the General Import Tests for Subinterpreters (gh-103151) Message-ID: https://github.com/python/cpython/commit/dfc4c95762f417e84dcb21dbbe6399ab7b7cef19 commit: dfc4c95762f417e84dcb21dbbe6399ab7b7cef19 branch: main author: Eric Snow committer: ericsnowcurrently date: 2023-03-31T12:18:33-06:00 summary: gh-101659: Clean Up the General Import Tests for Subinterpreters (gh-103151) This involves 3 changes: some general cleanup, checks to match the kind of module, and switch from testing against sys to _imp. This is a precursor to gh-103150, though the changes are meant to stand on their own. files: M Lib/test/test_import/__init__.py diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 96815b3f758a..3ef07203c46c 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -4,6 +4,9 @@ import glob import importlib.util from importlib._bootstrap_external import _get_sourcefile +from importlib.machinery import ( + BuiltinImporter, ExtensionFileLoader, FrozenImporter, SourceFileLoader, +) import marshal import os import py_compile @@ -44,6 +47,49 @@ sys.dont_write_bytecode, "test meaningful only when writing bytecode") + +def _require_loader(module, loader, skip): + if isinstance(module, str): + module = __import__(module) + + MODULE_KINDS = { + BuiltinImporter: 'built-in', + ExtensionFileLoader: 'extension', + FrozenImporter: 'frozen', + SourceFileLoader: 'pure Python', + } + + expected = loader + assert isinstance(expected, type), expected + expected = MODULE_KINDS[expected] + + actual = module.__spec__.loader + if not isinstance(actual, type): + actual = type(actual) + actual = MODULE_KINDS[actual] + + if actual != expected: + err = f'expected module to be {expected}, got {module.__spec__}' + if skip: + raise unittest.SkipTest(err) + raise Exception(err) + return module + +def require_builtin(module, *, skip=False): + module = _require_loader(module, BuiltinImporter, skip) + assert module.__spec__.origin == 'built-in', module.__spec__ + +def require_extension(module, *, skip=False): + _require_loader(module, ExtensionFileLoader, skip) + +def require_frozen(module, *, skip=True): + module = _require_loader(module, FrozenImporter, skip) + assert module.__spec__.origin == 'frozen', module.__spec__ + +def require_pure_python(module, *, skip=False): + _require_loader(module, SourceFileLoader, skip) + + def remove_files(name): for f in (name + ".py", name + ".pyc", @@ -1437,10 +1483,10 @@ def import_script(self, name, fd, check_override=None): os.write({fd}, text.encode('utf-8')) ''') - def run_shared(self, name, *, - check_singlephase_setting=False, - check_singlephase_override=None, - ): + def run_here(self, name, *, + check_singlephase_setting=False, + check_singlephase_override=None, + ): """ Try importing the named module in a subinterpreter. @@ -1470,27 +1516,35 @@ def run_shared(self, name, *, self.assertEqual(ret, 0) return os.read(r, 100) - def check_compatible_shared(self, name, *, strict=False): + def check_compatible_here(self, name, *, strict=False): # Verify that the named module may be imported in a subinterpreter. - # (See run_shared() for more info.) - out = self.run_shared(name, check_singlephase_setting=strict) + # (See run_here() for more info.) + out = self.run_here(name, + check_singlephase_setting=strict, + ) self.assertEqual(out, b'okay') - def check_incompatible_shared(self, name): - # Differences from check_compatible_shared(): + def check_incompatible_here(self, name): + # Differences from check_compatible_here(): # * verify that import fails # * "strict" is always True - out = self.run_shared(name, check_singlephase_setting=True) + out = self.run_here(name, + check_singlephase_setting=True, + ) self.assertEqual( out.decode('utf-8'), f'ImportError: module {name} does not support loading in subinterpreters', ) - def check_compatible_isolated(self, name, *, strict=False): - # Differences from check_compatible_shared(): + def check_compatible_fresh(self, name, *, strict=False): + # Differences from check_compatible_here(): # * subinterpreter in a new process # * module has never been imported before in that process # * this tests importing the module for the first time + kwargs = dict( + **self.RUN_KWARGS, + check_multi_interp_extensions=strict, + ) _, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f''' import _testcapi, sys assert ( @@ -1499,25 +1553,27 @@ def check_compatible_isolated(self, name, *, strict=False): ), repr({name!r}) ret = _testcapi.run_in_subinterp_with_config( {self.import_script(name, "sys.stdout.fileno()")!r}, - **{self.RUN_KWARGS}, - check_multi_interp_extensions={strict}, + **{kwargs}, ) assert ret == 0, ret ''')) self.assertEqual(err, b'') self.assertEqual(out, b'okay') - def check_incompatible_isolated(self, name): - # Differences from check_compatible_isolated(): + def check_incompatible_fresh(self, name): + # Differences from check_compatible_fresh(): # * verify that import fails # * "strict" is always True + kwargs = dict( + **self.RUN_KWARGS, + check_multi_interp_extensions=True, + ) _, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f''' import _testcapi, sys assert {name!r} not in sys.modules, {name!r} ret = _testcapi.run_in_subinterp_with_config( {self.import_script(name, "sys.stdout.fileno()")!r}, - **{self.RUN_KWARGS}, - check_multi_interp_extensions=True, + **{kwargs}, ) assert ret == 0, ret ''')) @@ -1528,59 +1584,65 @@ def check_incompatible_isolated(self, name): ) def test_builtin_compat(self): - module = 'sys' + # For now we avoid using sys or builtins + # since they still don't implement multi-phase init. + module = '_imp' + require_builtin(module) with self.subTest(f'{module}: not strict'): - self.check_compatible_shared(module, strict=False) - with self.subTest(f'{module}: strict, shared'): - self.check_compatible_shared(module, strict=True) + self.check_compatible_here(module, strict=False) + with self.subTest(f'{module}: strict, not fresh'): + self.check_compatible_here(module, strict=True) @cpython_only def test_frozen_compat(self): module = '_frozen_importlib' + require_frozen(module, skip=True) if __import__(module).__spec__.origin != 'frozen': raise unittest.SkipTest(f'{module} is unexpectedly not frozen') with self.subTest(f'{module}: not strict'): - self.check_compatible_shared(module, strict=False) - with self.subTest(f'{module}: strict, shared'): - self.check_compatible_shared(module, strict=True) + self.check_compatible_here(module, strict=False) + with self.subTest(f'{module}: strict, not fresh'): + self.check_compatible_here(module, strict=True) @unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module") def test_single_init_extension_compat(self): module = '_testsinglephase' + require_extension(module) with self.subTest(f'{module}: not strict'): - self.check_compatible_shared(module, strict=False) - with self.subTest(f'{module}: strict, shared'): - self.check_incompatible_shared(module) - with self.subTest(f'{module}: strict, isolated'): - self.check_incompatible_isolated(module) + self.check_compatible_here(module, strict=False) + with self.subTest(f'{module}: strict, not fresh'): + self.check_incompatible_here(module) + with self.subTest(f'{module}: strict, fresh'): + self.check_incompatible_fresh(module) @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module") def test_multi_init_extension_compat(self): module = '_testmultiphase' + require_extension(module) with self.subTest(f'{module}: not strict'): - self.check_compatible_shared(module, strict=False) - with self.subTest(f'{module}: strict, shared'): - self.check_compatible_shared(module, strict=True) - with self.subTest(f'{module}: strict, isolated'): - self.check_compatible_isolated(module, strict=True) + self.check_compatible_here(module, strict=False) + with self.subTest(f'{module}: strict, not fresh'): + self.check_compatible_here(module, strict=True) + with self.subTest(f'{module}: strict, fresh'): + self.check_compatible_fresh(module, strict=True) def test_python_compat(self): module = 'threading' - if __import__(module).__spec__.origin == 'frozen': - raise unittest.SkipTest(f'{module} is unexpectedly frozen') + require_pure_python(module) with self.subTest(f'{module}: not strict'): - self.check_compatible_shared(module, strict=False) - with self.subTest(f'{module}: strict, shared'): - self.check_compatible_shared(module, strict=True) - with self.subTest(f'{module}: strict, isolated'): - self.check_compatible_isolated(module, strict=True) + self.check_compatible_here(module, strict=False) + with self.subTest(f'{module}: strict, not fresh'): + self.check_compatible_here(module, strict=True) + with self.subTest(f'{module}: strict, fresh'): + self.check_compatible_fresh(module, strict=True) @unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module") def test_singlephase_check_with_setting_and_override(self): module = '_testsinglephase' + require_extension(module) def check_compatible(setting, override): - out = self.run_shared( + out = self.run_here( module, check_singlephase_setting=setting, check_singlephase_override=override, @@ -1588,7 +1650,7 @@ def check_compatible(setting, override): self.assertEqual(out, b'okay') def check_incompatible(setting, override): - out = self.run_shared( + out = self.run_here( module, check_singlephase_setting=setting, check_singlephase_override=override, From webhook-mailer at python.org Fri Mar 31 16:52:58 2023 From: webhook-mailer at python.org (ethanfurman) Date: Fri, 31 Mar 2023 20:52:58 -0000 Subject: [Python-checkins] gh-102549: [Enum] fail enum creation when data type raises in __init__ (GH-103149) Message-ID: https://github.com/python/cpython/commit/2a4d8c0a9e88f45047da640ce5a92b304d2d39b1 commit: 2a4d8c0a9e88f45047da640ce5a92b304d2d39b1 branch: main author: Ethan Furman committer: ethanfurman date: 2023-03-31T13:52:31-07:00 summary: gh-102549: [Enum] fail enum creation when data type raises in __init__ (GH-103149) files: A Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index 8c77117ce6ac..4e231e7e8ea7 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -266,23 +266,20 @@ def __set_name__(self, enum_class, member_name): args = (args, ) # wrap it one more time if not enum_class._use_args_: enum_member = enum_class._new_member_(enum_class) - if not hasattr(enum_member, '_value_'): + else: + enum_member = enum_class._new_member_(enum_class, *args) + if not hasattr(enum_member, '_value_'): + if enum_class._member_type_ is object: + enum_member._value_ = value + else: try: enum_member._value_ = enum_class._member_type_(*args) except Exception as exc: - enum_member._value_ = value - else: - enum_member = enum_class._new_member_(enum_class, *args) - if not hasattr(enum_member, '_value_'): - if enum_class._member_type_ is object: - enum_member._value_ = value - else: - try: - enum_member._value_ = enum_class._member_type_(*args) - except Exception as exc: - raise TypeError( - '_value_ not set in __new__, unable to create it' - ) from None + new_exc = TypeError( + '_value_ not set in __new__, unable to create it' + ) + new_exc.__cause__ = exc + raise new_exc value = enum_member._value_ enum_member._name_ = member_name enum_member.__objclass__ = enum_class diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index bea19542705d..ee5280601be1 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -2916,6 +2916,26 @@ def __new__(cls, c): self.assertEqual(FlagFromChar.a, 158456325028528675187087900672) self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673) + def test_init_exception(self): + class Base: + def __init__(self, x): + raise ValueError("I don't like", x) + with self.assertRaises(TypeError): + class MyEnum(Base, enum.Enum): + A = 'a' + def __init__(self, y): + self.y = y + with self.assertRaises(ValueError): + class MyEnum(Base, enum.Enum): + A = 'a' + def __init__(self, y): + self.y = y + def __new__(cls, value): + member = Base.__new__(cls) + member._value_ = Base(value) + return member + + class TestOrder(unittest.TestCase): "test usage of the `_order_` attribute" diff --git a/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst b/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst new file mode 100644 index 000000000000..e4def038175b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-27-19-21-51.gh-issue-102549.NQ6Nlv.rst @@ -0,0 +1 @@ +Don't ignore exceptions in member type creation. From webhook-mailer at python.org Fri Mar 31 16:54:58 2023 From: webhook-mailer at python.org (AlexWaygood) Date: Fri, 31 Mar 2023 20:54:58 -0000 Subject: [Python-checkins] gh-74690: Micro-optimise `typing._get_protocol_attrs` (#103152) Message-ID: https://github.com/python/cpython/commit/361a3eaf1b6bf3360e34388cc909307ddd20737b commit: 361a3eaf1b6bf3360e34388cc909307ddd20737b branch: main author: Alex Waygood committer: AlexWaygood date: 2023-03-31T21:54:50+01:00 summary: gh-74690: Micro-optimise `typing._get_protocol_attrs` (#103152) Improve performance of `isinstance()` checks against runtime-checkable protocols files: M Lib/typing.py diff --git a/Lib/typing.py b/Lib/typing.py index 3d086dc1cb90..a88542cfbaec 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1903,15 +1903,19 @@ class _TypingEllipsis: """Internal placeholder for ... (ellipsis).""" -_TYPING_INTERNALS = ['__parameters__', '__orig_bases__', '__orig_class__', - '_is_protocol', '_is_runtime_protocol'] +_TYPING_INTERNALS = frozenset({ + '__parameters__', '__orig_bases__', '__orig_class__', + '_is_protocol', '_is_runtime_protocol' +}) -_SPECIAL_NAMES = ['__abstractmethods__', '__annotations__', '__dict__', '__doc__', - '__init__', '__module__', '__new__', '__slots__', - '__subclasshook__', '__weakref__', '__class_getitem__'] +_SPECIAL_NAMES = frozenset({ + '__abstractmethods__', '__annotations__', '__dict__', '__doc__', + '__init__', '__module__', '__new__', '__slots__', + '__subclasshook__', '__weakref__', '__class_getitem__' +}) # These special attributes will be not collected as protocol members. -EXCLUDED_ATTRIBUTES = _TYPING_INTERNALS + _SPECIAL_NAMES + ['_MutableMapping__marker'] +EXCLUDED_ATTRIBUTES = _TYPING_INTERNALS | _SPECIAL_NAMES | {'_MutableMapping__marker'} def _get_protocol_attrs(cls): @@ -1922,10 +1926,10 @@ def _get_protocol_attrs(cls): """ attrs = set() for base in cls.__mro__[:-1]: # without object - if base.__name__ in ('Protocol', 'Generic'): + if base.__name__ in {'Protocol', 'Generic'}: continue annotations = getattr(base, '__annotations__', {}) - for attr in list(base.__dict__.keys()) + list(annotations.keys()): + for attr in (*base.__dict__, *annotations): if not attr.startswith('_abc_') and attr not in EXCLUDED_ATTRIBUTES: attrs.add(attr) return attrs From webhook-mailer at python.org Fri Mar 31 17:24:10 2023 From: webhook-mailer at python.org (brettcannon) Date: Fri, 31 Mar 2023 21:24:10 -0000 Subject: [Python-checkins] Add missing variables to `bytecodes.c` (GH-103153) Message-ID: https://github.com/python/cpython/commit/d97aef8ebfbbb275384b17f06945e583fb3189ea commit: d97aef8ebfbbb275384b17f06945e583fb3189ea branch: main author: Brett Cannon committer: brettcannon date: 2023-03-31T14:23:55-07:00 summary: Add missing variables to `bytecodes.c` (GH-103153) The code works without this change, but it does cause C tooling to complain less about undeclared variables. files: M Python/bytecodes.c M Python/generated_cases.c.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 484f6e6b1a1c..825fa705a4cd 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -74,10 +74,56 @@ dummy_func( PyObject **stack_pointer, PyObject *kwnames, int throwflag, - binaryfunc binary_ops[] + binaryfunc binary_ops[], + PyObject *args[] ) { + // Dummy labels. + pop_1_error: + // Dummy locals. + PyObject *annotations; + PyObject *attrs; + PyObject *bottom; + PyObject *callable; + PyObject *callargs; + PyObject *closure; + PyObject *codeobj; + PyObject *cond; + PyObject *defaults; + PyObject *descr; _PyInterpreterFrame entry_frame; + PyObject *exc; + PyObject *exit; + PyObject *fget; + PyObject *fmt_spec; + PyObject *func; + uint32_t func_version; + PyObject *getattribute; + PyObject *kwargs; + PyObject *kwdefaults; + PyObject *len_o; + PyObject *match; + PyObject *match_type; + PyObject *method; + PyObject *mgr; + Py_ssize_t min_args; + PyObject *names; + PyObject *new_exc; + PyObject *next; + PyObject *none; + PyObject *null; + PyObject *prev_exc; + PyObject *receiver; + PyObject *rest; + int result; + PyObject *self; + PyObject *seq; + PyObject *slice; + PyObject *step; + PyObject *subject; + PyObject *top; + PyObject *type; + int values_or_none; switch (opcode) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d9c66343430f..6bb37d69cc07 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8,7 +8,7 @@ } TARGET(RESUME) { - #line 89 "Python/bytecodes.c" + #line 135 "Python/bytecodes.c" assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { @@ -20,7 +20,7 @@ TARGET(LOAD_CLOSURE) { PyObject *value; - #line 97 "Python/bytecodes.c" + #line 143 "Python/bytecodes.c" /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; @@ -33,7 +33,7 @@ TARGET(LOAD_FAST_CHECK) { PyObject *value; - #line 104 "Python/bytecodes.c" + #line 150 "Python/bytecodes.c" value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); @@ -45,7 +45,7 @@ TARGET(LOAD_FAST) { PyObject *value; - #line 110 "Python/bytecodes.c" + #line 156 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -58,7 +58,7 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; - #line 116 "Python/bytecodes.c" + #line 162 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 65 "Python/generated_cases.c.h" @@ -69,7 +69,7 @@ TARGET(STORE_FAST) { PyObject *value = stack_pointer[-1]; - #line 121 "Python/bytecodes.c" + #line 167 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 75 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -81,7 +81,7 @@ PyObject *_tmp_2; { PyObject *value; - #line 110 "Python/bytecodes.c" + #line 156 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -91,7 +91,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - #line 110 "Python/bytecodes.c" + #line 156 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -109,7 +109,7 @@ PyObject *_tmp_2; { PyObject *value; - #line 110 "Python/bytecodes.c" + #line 156 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -119,7 +119,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - #line 116 "Python/bytecodes.c" + #line 162 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 126 "Python/generated_cases.c.h" @@ -135,14 +135,14 @@ PyObject *_tmp_1 = stack_pointer[-1]; { PyObject *value = _tmp_1; - #line 121 "Python/bytecodes.c" + #line 167 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 141 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value; - #line 110 "Python/bytecodes.c" + #line 156 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -158,14 +158,14 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 121 "Python/bytecodes.c" + #line 167 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 164 "Python/generated_cases.c.h" } oparg = (next_instr++)->op.arg; { PyObject *value = _tmp_2; - #line 121 "Python/bytecodes.c" + #line 167 "Python/bytecodes.c" SETLOCAL(oparg, value); #line 171 "Python/generated_cases.c.h" } @@ -178,7 +178,7 @@ PyObject *_tmp_2; { PyObject *value; - #line 116 "Python/bytecodes.c" + #line 162 "Python/bytecodes.c" value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); #line 185 "Python/generated_cases.c.h" @@ -187,7 +187,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - #line 110 "Python/bytecodes.c" + #line 156 "Python/bytecodes.c" value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); @@ -202,7 +202,7 @@ TARGET(POP_TOP) { PyObject *value = stack_pointer[-1]; - #line 131 "Python/bytecodes.c" + #line 177 "Python/bytecodes.c" #line 207 "Python/generated_cases.c.h" Py_DECREF(value); STACK_SHRINK(1); @@ -211,7 +211,7 @@ TARGET(PUSH_NULL) { PyObject *res; - #line 135 "Python/bytecodes.c" + #line 181 "Python/bytecodes.c" res = NULL; #line 217 "Python/generated_cases.c.h" STACK_GROW(1); @@ -224,13 +224,13 @@ PyObject *_tmp_2 = stack_pointer[-2]; { PyObject *value = _tmp_1; - #line 131 "Python/bytecodes.c" + #line 177 "Python/bytecodes.c" #line 229 "Python/generated_cases.c.h" Py_DECREF(value); } { PyObject *value = _tmp_2; - #line 131 "Python/bytecodes.c" + #line 177 "Python/bytecodes.c" #line 235 "Python/generated_cases.c.h" Py_DECREF(value); } @@ -241,11 +241,11 @@ TARGET(UNARY_NEGATIVE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 141 "Python/bytecodes.c" + #line 187 "Python/bytecodes.c" res = PyNumber_Negative(value); #line 247 "Python/generated_cases.c.h" Py_DECREF(value); - #line 143 "Python/bytecodes.c" + #line 189 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 251 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -255,11 +255,11 @@ TARGET(UNARY_NOT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 147 "Python/bytecodes.c" + #line 193 "Python/bytecodes.c" int err = PyObject_IsTrue(value); #line 261 "Python/generated_cases.c.h" Py_DECREF(value); - #line 149 "Python/bytecodes.c" + #line 195 "Python/bytecodes.c" if (err < 0) goto pop_1_error; if (err == 0) { res = Py_True; @@ -276,11 +276,11 @@ TARGET(UNARY_INVERT) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 160 "Python/bytecodes.c" + #line 206 "Python/bytecodes.c" res = PyNumber_Invert(value); #line 282 "Python/generated_cases.c.h" Py_DECREF(value); - #line 162 "Python/bytecodes.c" + #line 208 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 286 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -291,7 +291,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 179 "Python/bytecodes.c" + #line 225 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -311,7 +311,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *prod; - #line 190 "Python/bytecodes.c" + #line 236 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); @@ -330,7 +330,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 200 "Python/bytecodes.c" + #line 246 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -350,7 +350,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sub; - #line 211 "Python/bytecodes.c" + #line 257 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); @@ -368,7 +368,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 220 "Python/bytecodes.c" + #line 266 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -387,7 +387,7 @@ TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; - #line 237 "Python/bytecodes.c" + #line 283 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -424,7 +424,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 267 "Python/bytecodes.c" + #line 313 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -443,7 +443,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; - #line 277 "Python/bytecodes.c" + #line 323 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -465,7 +465,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; PyObject *res; - #line 296 "Python/bytecodes.c" + #line 342 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -481,7 +481,7 @@ #line 482 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 309 "Python/bytecodes.c" + #line 355 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 487 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -495,7 +495,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *res; - #line 313 "Python/bytecodes.c" + #line 359 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); // Can't use ERROR_IF() here, because we haven't // DECREF'ed container yet, and we still own slice. @@ -519,7 +519,7 @@ PyObject *start = stack_pointer[-2]; PyObject *container = stack_pointer[-3]; PyObject *v = stack_pointer[-4]; - #line 328 "Python/bytecodes.c" + #line 374 "Python/bytecodes.c" PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); int err; if (slice == NULL) { @@ -541,7 +541,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *res; - #line 343 "Python/bytecodes.c" + #line 389 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); @@ -567,7 +567,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *tuple = stack_pointer[-2]; PyObject *res; - #line 360 "Python/bytecodes.c" + #line 406 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); @@ -593,7 +593,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *res; - #line 377 "Python/bytecodes.c" + #line 423 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -605,7 +605,7 @@ #line 606 "Python/generated_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); - #line 386 "Python/bytecodes.c" + #line 432 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -621,7 +621,7 @@ TARGET(BINARY_SUBSCR_GETITEM) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 393 "Python/bytecodes.c" + #line 439 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(container); DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR); PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; @@ -648,7 +648,7 @@ TARGET(LIST_APPEND) { PyObject *v = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 416 "Python/bytecodes.c" + #line 462 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; #line 654 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -659,11 +659,11 @@ TARGET(SET_ADD) { PyObject *v = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 421 "Python/bytecodes.c" + #line 467 "Python/bytecodes.c" int err = PySet_Add(set, v); #line 665 "Python/generated_cases.c.h" Py_DECREF(v); - #line 423 "Python/bytecodes.c" + #line 469 "Python/bytecodes.c" if (err) goto pop_1_error; #line 669 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -678,7 +678,7 @@ PyObject *container = stack_pointer[-2]; PyObject *v = stack_pointer[-3]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 434 "Python/bytecodes.c" + #line 480 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -698,7 +698,7 @@ Py_DECREF(v); Py_DECREF(container); Py_DECREF(sub); - #line 450 "Python/bytecodes.c" + #line 496 "Python/bytecodes.c" if (err) goto pop_3_error; #line 704 "Python/generated_cases.c.h" STACK_SHRINK(3); @@ -710,7 +710,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 454 "Python/bytecodes.c" + #line 500 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -738,7 +738,7 @@ PyObject *sub = stack_pointer[-1]; PyObject *dict = stack_pointer[-2]; PyObject *value = stack_pointer[-3]; - #line 474 "Python/bytecodes.c" + #line 520 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); @@ -754,13 +754,13 @@ TARGET(DELETE_SUBSCR) { PyObject *sub = stack_pointer[-1]; PyObject *container = stack_pointer[-2]; - #line 483 "Python/bytecodes.c" + #line 529 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); #line 761 "Python/generated_cases.c.h" Py_DECREF(container); Py_DECREF(sub); - #line 486 "Python/bytecodes.c" + #line 532 "Python/bytecodes.c" if (err) goto pop_2_error; #line 766 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -770,12 +770,12 @@ TARGET(CALL_INTRINSIC_1) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 490 "Python/bytecodes.c" + #line 536 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); #line 777 "Python/generated_cases.c.h" Py_DECREF(value); - #line 493 "Python/bytecodes.c" + #line 539 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; #line 781 "Python/generated_cases.c.h" stack_pointer[-1] = res; @@ -786,13 +786,13 @@ PyObject *value1 = stack_pointer[-1]; PyObject *value2 = stack_pointer[-2]; PyObject *res; - #line 497 "Python/bytecodes.c" + #line 543 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); #line 793 "Python/generated_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); - #line 500 "Python/bytecodes.c" + #line 546 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 798 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -802,7 +802,7 @@ TARGET(RAISE_VARARGS) { PyObject **args = (stack_pointer - oparg); - #line 504 "Python/bytecodes.c" + #line 550 "Python/bytecodes.c" PyObject *cause = NULL, *exc = NULL; switch (oparg) { case 2: @@ -825,7 +825,7 @@ TARGET(INTERPRETER_EXIT) { PyObject *retval = stack_pointer[-1]; - #line 524 "Python/bytecodes.c" + #line 570 "Python/bytecodes.c" assert(frame == &entry_frame); assert(_PyFrame_IsIncomplete(frame)); STACK_SHRINK(1); // Since we're not going to DISPATCH() @@ -842,7 +842,7 @@ TARGET(RETURN_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 538 "Python/bytecodes.c" + #line 584 "Python/bytecodes.c" STACK_SHRINK(1); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -860,7 +860,7 @@ } TARGET(RETURN_CONST) { - #line 554 "Python/bytecodes.c" + #line 600 "Python/bytecodes.c" PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); @@ -881,7 +881,7 @@ TARGET(GET_AITER) { PyObject *obj = stack_pointer[-1]; PyObject *iter; - #line 571 "Python/bytecodes.c" + #line 617 "Python/bytecodes.c" unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); @@ -896,14 +896,14 @@ type->tp_name); #line 898 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 584 "Python/bytecodes.c" + #line 630 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); #line 905 "Python/generated_cases.c.h" Py_DECREF(obj); - #line 589 "Python/bytecodes.c" + #line 635 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; if (Py_TYPE(iter)->tp_as_async == NULL || @@ -924,7 +924,7 @@ TARGET(GET_ANEXT) { PyObject *aiter = stack_pointer[-1]; PyObject *awaitable; - #line 604 "Python/bytecodes.c" + #line 650 "Python/bytecodes.c" unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -979,7 +979,7 @@ PREDICTED(GET_AWAITABLE); PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 651 "Python/bytecodes.c" + #line 697 "Python/bytecodes.c" iter = _PyCoro_GetAwaitableIter(iterable); if (iter == NULL) { @@ -988,7 +988,7 @@ #line 990 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 658 "Python/bytecodes.c" + #line 704 "Python/bytecodes.c" if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); @@ -1017,7 +1017,7 @@ PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; PyObject *retval; - #line 684 "Python/bytecodes.c" + #line 730 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PySendCache *cache = (_PySendCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1062,7 +1062,7 @@ TARGET(SEND_GEN) { PyObject *v = stack_pointer[-1]; PyObject *receiver = stack_pointer[-2]; - #line 722 "Python/bytecodes.c" + #line 768 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)receiver; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && @@ -1083,7 +1083,7 @@ TARGET(YIELD_VALUE) { PyObject *retval = stack_pointer[-1]; - #line 740 "Python/bytecodes.c" + #line 786 "Python/bytecodes.c" // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1107,7 +1107,7 @@ TARGET(POP_EXCEPT) { PyObject *exc_value = stack_pointer[-1]; - #line 761 "Python/bytecodes.c" + #line 807 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); #line 1114 "Python/generated_cases.c.h" @@ -1118,7 +1118,7 @@ TARGET(RERAISE) { PyObject *exc = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); - #line 766 "Python/bytecodes.c" + #line 812 "Python/bytecodes.c" assert(oparg >= 0 && oparg <= 2); if (oparg) { PyObject *lasti = values[0]; @@ -1142,13 +1142,13 @@ TARGET(END_ASYNC_FOR) { PyObject *exc = stack_pointer[-1]; PyObject *awaitable = stack_pointer[-2]; - #line 786 "Python/bytecodes.c" + #line 832 "Python/bytecodes.c" assert(exc && PyExceptionInstance_Check(exc)); if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) { #line 1149 "Python/generated_cases.c.h" Py_DECREF(awaitable); Py_DECREF(exc); - #line 789 "Python/bytecodes.c" + #line 835 "Python/bytecodes.c" } else { Py_INCREF(exc); @@ -1166,7 +1166,7 @@ PyObject *sub_iter = stack_pointer[-3]; PyObject *none; PyObject *value; - #line 798 "Python/bytecodes.c" + #line 844 "Python/bytecodes.c" assert(throwflag); assert(exc_value && PyExceptionInstance_Check(exc_value)); if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { @@ -1175,7 +1175,7 @@ Py_DECREF(sub_iter); Py_DECREF(last_sent_val); Py_DECREF(exc_value); - #line 803 "Python/bytecodes.c" + #line 849 "Python/bytecodes.c" none = Py_NewRef(Py_None); } else { @@ -1191,7 +1191,7 @@ TARGET(LOAD_ASSERTION_ERROR) { PyObject *value; - #line 812 "Python/bytecodes.c" + #line 858 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); #line 1197 "Python/generated_cases.c.h" STACK_GROW(1); @@ -1201,7 +1201,7 @@ TARGET(LOAD_BUILD_CLASS) { PyObject *bc; - #line 816 "Python/bytecodes.c" + #line 862 "Python/bytecodes.c" if (PyDict_CheckExact(BUILTINS())) { bc = _PyDict_GetItemWithError(BUILTINS(), &_Py_ID(__build_class__)); @@ -1231,7 +1231,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - #line 840 "Python/bytecodes.c" + #line 886 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1240,7 +1240,7 @@ "no locals found when storing %R", name); #line 1242 "Python/generated_cases.c.h" Py_DECREF(v); - #line 847 "Python/bytecodes.c" + #line 893 "Python/bytecodes.c" if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) @@ -1249,7 +1249,7 @@ err = PyObject_SetItem(ns, name, v); #line 1251 "Python/generated_cases.c.h" Py_DECREF(v); - #line 854 "Python/bytecodes.c" + #line 900 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1255 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1257,7 +1257,7 @@ } TARGET(DELETE_NAME) { - #line 858 "Python/bytecodes.c" + #line 904 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; @@ -1282,7 +1282,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; - #line 884 "Python/bytecodes.c" + #line 930 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1298,7 +1298,7 @@ int res = unpack_iterable(tstate, seq, oparg, -1, top); #line 1300 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 898 "Python/bytecodes.c" + #line 944 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1304 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1310,7 +1310,7 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 902 "Python/bytecodes.c" + #line 948 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -1328,7 +1328,7 @@ TARGET(UNPACK_SEQUENCE_TUPLE) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 912 "Python/bytecodes.c" + #line 958 "Python/bytecodes.c" DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1347,7 +1347,7 @@ TARGET(UNPACK_SEQUENCE_LIST) { PyObject *seq = stack_pointer[-1]; PyObject **values = stack_pointer - (1); - #line 923 "Python/bytecodes.c" + #line 969 "Python/bytecodes.c" DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -1365,13 +1365,13 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; - #line 934 "Python/bytecodes.c" + #line 980 "Python/bytecodes.c" int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); #line 1373 "Python/generated_cases.c.h" Py_DECREF(seq); - #line 938 "Python/bytecodes.c" + #line 984 "Python/bytecodes.c" if (res == 0) goto pop_1_error; #line 1377 "Python/generated_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); @@ -1384,7 +1384,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *v = stack_pointer[-2]; uint16_t counter = read_u16(&next_instr[0].cache); - #line 949 "Python/bytecodes.c" + #line 995 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); @@ -1404,7 +1404,7 @@ #line 1405 "Python/generated_cases.c.h" Py_DECREF(v); Py_DECREF(owner); - #line 966 "Python/bytecodes.c" + #line 1012 "Python/bytecodes.c" if (err) goto pop_2_error; #line 1410 "Python/generated_cases.c.h" STACK_SHRINK(2); @@ -1414,12 +1414,12 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - #line 970 "Python/bytecodes.c" + #line 1016 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); #line 1421 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 973 "Python/bytecodes.c" + #line 1019 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1425 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1428,12 +1428,12 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - #line 977 "Python/bytecodes.c" + #line 1023 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); #line 1435 "Python/generated_cases.c.h" Py_DECREF(v); - #line 980 "Python/bytecodes.c" + #line 1026 "Python/bytecodes.c" if (err) goto pop_1_error; #line 1439 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1441,7 +1441,7 @@ } TARGET(DELETE_GLOBAL) { - #line 984 "Python/bytecodes.c" + #line 1030 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); @@ -1459,7 +1459,7 @@ TARGET(LOAD_NAME) { PyObject *v; - #line 998 "Python/bytecodes.c" + #line 1044 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { @@ -1529,7 +1529,7 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *null = NULL; PyObject *v; - #line 1065 "Python/bytecodes.c" + #line 1111 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1596,7 +1596,7 @@ PyObject *res; uint16_t index = read_u16(&next_instr[1].cache); uint16_t version = read_u16(&next_instr[2].cache); - #line 1120 "Python/bytecodes.c" + #line 1166 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); PyDictObject *dict = (PyDictObject *)GLOBALS(); @@ -1623,7 +1623,7 @@ uint16_t index = read_u16(&next_instr[1].cache); uint16_t mod_version = read_u16(&next_instr[2].cache); uint16_t bltn_version = read_u16(&next_instr[3].cache); - #line 1134 "Python/bytecodes.c" + #line 1180 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); @@ -1648,7 +1648,7 @@ } TARGET(DELETE_FAST) { - #line 1151 "Python/bytecodes.c" + #line 1197 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); @@ -1657,7 +1657,7 @@ } TARGET(MAKE_CELL) { - #line 1157 "Python/bytecodes.c" + #line 1203 "Python/bytecodes.c" // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); @@ -1671,7 +1671,7 @@ } TARGET(DELETE_DEREF) { - #line 1168 "Python/bytecodes.c" + #line 1214 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); // Can't use ERROR_IF here. @@ -1688,7 +1688,7 @@ TARGET(LOAD_CLASSDEREF) { PyObject *value; - #line 1181 "Python/bytecodes.c" + #line 1227 "Python/bytecodes.c" PyObject *name, *locals = LOCALS(); assert(locals); assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); @@ -1728,7 +1728,7 @@ TARGET(LOAD_DEREF) { PyObject *value; - #line 1215 "Python/bytecodes.c" + #line 1261 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); value = PyCell_GET(cell); if (value == NULL) { @@ -1744,7 +1744,7 @@ TARGET(STORE_DEREF) { PyObject *v = stack_pointer[-1]; - #line 1225 "Python/bytecodes.c" + #line 1271 "Python/bytecodes.c" PyObject *cell = GETLOCAL(oparg); PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); @@ -1755,7 +1755,7 @@ } TARGET(COPY_FREE_VARS) { - #line 1232 "Python/bytecodes.c" + #line 1278 "Python/bytecodes.c" /* Copy closure variables to free variables */ PyCodeObject *co = frame->f_code; assert(PyFunction_Check(frame->f_funcobj)); @@ -1773,13 +1773,13 @@ TARGET(BUILD_STRING) { PyObject **pieces = (stack_pointer - oparg); PyObject *str; - #line 1245 "Python/bytecodes.c" + #line 1291 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); #line 1779 "Python/generated_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - #line 1247 "Python/bytecodes.c" + #line 1293 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } #line 1785 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -1791,7 +1791,7 @@ TARGET(BUILD_TUPLE) { PyObject **values = (stack_pointer - oparg); PyObject *tup; - #line 1251 "Python/bytecodes.c" + #line 1297 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } #line 1798 "Python/generated_cases.c.h" @@ -1804,7 +1804,7 @@ TARGET(BUILD_LIST) { PyObject **values = (stack_pointer - oparg); PyObject *list; - #line 1256 "Python/bytecodes.c" + #line 1302 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } #line 1811 "Python/generated_cases.c.h" @@ -1817,7 +1817,7 @@ TARGET(LIST_EXTEND) { PyObject *iterable = stack_pointer[-1]; PyObject *list = stack_pointer[-(2 + (oparg-1))]; - #line 1261 "Python/bytecodes.c" + #line 1307 "Python/bytecodes.c" PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1830,7 +1830,7 @@ } #line 1832 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1272 "Python/bytecodes.c" + #line 1318 "Python/bytecodes.c" if (true) goto pop_1_error; } Py_DECREF(none_val); @@ -1843,11 +1843,11 @@ TARGET(SET_UPDATE) { PyObject *iterable = stack_pointer[-1]; PyObject *set = stack_pointer[-(2 + (oparg-1))]; - #line 1279 "Python/bytecodes.c" + #line 1325 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); #line 1849 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1281 "Python/bytecodes.c" + #line 1327 "Python/bytecodes.c" if (err < 0) goto pop_1_error; #line 1853 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -1857,7 +1857,7 @@ TARGET(BUILD_SET) { PyObject **values = (stack_pointer - oparg); PyObject *set; - #line 1285 "Python/bytecodes.c" + #line 1331 "Python/bytecodes.c" set = PySet_New(NULL); if (set == NULL) goto error; @@ -1882,7 +1882,7 @@ TARGET(BUILD_MAP) { PyObject **values = (stack_pointer - oparg*2); PyObject *map; - #line 1302 "Python/bytecodes.c" + #line 1348 "Python/bytecodes.c" map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1894,7 +1894,7 @@ for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - #line 1310 "Python/bytecodes.c" + #line 1356 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } #line 1900 "Python/generated_cases.c.h" STACK_SHRINK(oparg*2); @@ -1904,7 +1904,7 @@ } TARGET(SETUP_ANNOTATIONS) { - #line 1314 "Python/bytecodes.c" + #line 1360 "Python/bytecodes.c" int err; PyObject *ann_dict; if (LOCALS() == NULL) { @@ -1952,7 +1952,7 @@ PyObject *keys = stack_pointer[-1]; PyObject **values = (stack_pointer - (1 + oparg)); PyObject *map; - #line 1356 "Python/bytecodes.c" + #line 1402 "Python/bytecodes.c" if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1967,7 +1967,7 @@ Py_DECREF(values[_i]); } Py_DECREF(keys); - #line 1366 "Python/bytecodes.c" + #line 1412 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } #line 1973 "Python/generated_cases.c.h" STACK_SHRINK(oparg); @@ -1977,7 +1977,7 @@ TARGET(DICT_UPDATE) { PyObject *update = stack_pointer[-1]; - #line 1370 "Python/bytecodes.c" + #line 1416 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { @@ -1987,7 +1987,7 @@ } #line 1989 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1378 "Python/bytecodes.c" + #line 1424 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 1994 "Python/generated_cases.c.h" @@ -1998,14 +1998,14 @@ TARGET(DICT_MERGE) { PyObject *update = stack_pointer[-1]; - #line 1384 "Python/bytecodes.c" + #line 1430 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 1); // update is still on the stack if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); #line 2007 "Python/generated_cases.c.h" Py_DECREF(update); - #line 1389 "Python/bytecodes.c" + #line 1435 "Python/bytecodes.c" if (true) goto pop_1_error; } #line 2012 "Python/generated_cases.c.h" @@ -2018,7 +2018,7 @@ TARGET(MAP_ADD) { PyObject *value = stack_pointer[-1]; PyObject *key = stack_pointer[-2]; - #line 1396 "Python/bytecodes.c" + #line 1442 "Python/bytecodes.c" PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack assert(PyDict_CheckExact(dict)); /* dict[key] = value */ @@ -2036,7 +2036,7 @@ PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; - #line 1419 "Python/bytecodes.c" + #line 1465 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2073,7 +2073,7 @@ */ #line 2075 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1454 "Python/bytecodes.c" + #line 1500 "Python/bytecodes.c" if (meth == NULL) goto pop_1_error; res2 = NULL; res = meth; @@ -2084,7 +2084,7 @@ res = PyObject_GetAttr(owner, name); #line 2086 "Python/generated_cases.c.h" Py_DECREF(owner); - #line 1463 "Python/bytecodes.c" + #line 1509 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; } #line 2091 "Python/generated_cases.c.h" @@ -2101,7 +2101,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1468 "Python/bytecodes.c" + #line 1514 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2130,7 +2130,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1485 "Python/bytecodes.c" + #line 1531 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; @@ -2159,7 +2159,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1502 "Python/bytecodes.c" + #line 1548 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2202,7 +2202,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1533 "Python/bytecodes.c" + #line 1579 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2228,7 +2228,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1547 "Python/bytecodes.c" + #line 1593 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); @@ -2255,7 +2255,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1563 "Python/bytecodes.c" + #line 1609 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); @@ -2287,7 +2287,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1589 "Python/bytecodes.c" + #line 1635 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2321,7 +2321,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1617 "Python/bytecodes.c" + #line 1663 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2351,7 +2351,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1638 "Python/bytecodes.c" + #line 1684 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2402,7 +2402,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1680 "Python/bytecodes.c" + #line 1726 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); @@ -2425,7 +2425,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1700 "Python/bytecodes.c" + #line 1746 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2442,7 +2442,7 @@ #line 2443 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1714 "Python/bytecodes.c" + #line 1760 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2448 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2455,7 +2455,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1718 "Python/bytecodes.c" + #line 1764 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); @@ -2479,7 +2479,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1734 "Python/bytecodes.c" + #line 1780 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); @@ -2507,7 +2507,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 1754 "Python/bytecodes.c" + #line 1800 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); @@ -2532,12 +2532,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1770 "Python/bytecodes.c" + #line 1816 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; #line 2538 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1772 "Python/bytecodes.c" + #line 1818 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); #line 2543 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2549,12 +2549,12 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1776 "Python/bytecodes.c" + #line 1822 "Python/bytecodes.c" int res = PySequence_Contains(right, left); #line 2555 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 1778 "Python/bytecodes.c" + #line 1824 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = Py_NewRef((res^oparg) ? Py_True : Py_False); #line 2561 "Python/generated_cases.c.h" @@ -2568,12 +2568,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 1783 "Python/bytecodes.c" + #line 1829 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { #line 2574 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1785 "Python/bytecodes.c" + #line 1831 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2584,7 +2584,7 @@ #line 2585 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 1793 "Python/bytecodes.c" + #line 1839 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2603,19 +2603,19 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 1804 "Python/bytecodes.c" + #line 1850 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { #line 2610 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1807 "Python/bytecodes.c" + #line 1853 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); #line 2617 "Python/generated_cases.c.h" Py_DECREF(right); - #line 1812 "Python/bytecodes.c" + #line 1858 "Python/bytecodes.c" b = Py_NewRef(res ? Py_True : Py_False); #line 2621 "Python/generated_cases.c.h" stack_pointer[-1] = b; @@ -2626,13 +2626,13 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 1816 "Python/bytecodes.c" + #line 1862 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); #line 2633 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 1819 "Python/bytecodes.c" + #line 1865 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 2638 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2643,7 +2643,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 1823 "Python/bytecodes.c" + #line 1869 "Python/bytecodes.c" PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; @@ -2654,7 +2654,7 @@ } TARGET(JUMP_FORWARD) { - #line 1829 "Python/bytecodes.c" + #line 1875 "Python/bytecodes.c" JUMPBY(oparg); #line 2660 "Python/generated_cases.c.h" DISPATCH(); @@ -2662,7 +2662,7 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - #line 1833 "Python/bytecodes.c" + #line 1879 "Python/bytecodes.c" assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); #line 2669 "Python/generated_cases.c.h" @@ -2673,7 +2673,7 @@ TARGET(POP_JUMP_IF_FALSE) { PREDICTED(POP_JUMP_IF_FALSE); PyObject *cond = stack_pointer[-1]; - #line 1839 "Python/bytecodes.c" + #line 1885 "Python/bytecodes.c" if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2685,7 +2685,7 @@ int err = PyObject_IsTrue(cond); #line 2687 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1849 "Python/bytecodes.c" + #line 1895 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -2700,7 +2700,7 @@ TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 1859 "Python/bytecodes.c" + #line 1905 "Python/bytecodes.c" if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); } @@ -2712,7 +2712,7 @@ int err = PyObject_IsTrue(cond); #line 2714 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 1869 "Python/bytecodes.c" + #line 1915 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -2727,11 +2727,11 @@ TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 1879 "Python/bytecodes.c" + #line 1925 "Python/bytecodes.c" if (!Py_IsNone(value)) { #line 2733 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1881 "Python/bytecodes.c" + #line 1927 "Python/bytecodes.c" JUMPBY(oparg); } else { @@ -2744,7 +2744,7 @@ TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 1889 "Python/bytecodes.c" + #line 1935 "Python/bytecodes.c" if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); JUMPBY(oparg); @@ -2752,7 +2752,7 @@ else { #line 2754 "Python/generated_cases.c.h" Py_DECREF(value); - #line 1895 "Python/bytecodes.c" + #line 1941 "Python/bytecodes.c" } #line 2758 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -2760,7 +2760,7 @@ } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 1899 "Python/bytecodes.c" + #line 1945 "Python/bytecodes.c" /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost * generator or coroutine, so we deliberately do not check it here. @@ -2774,7 +2774,7 @@ TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 1908 "Python/bytecodes.c" + #line 1954 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; @@ -2791,7 +2791,7 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 1916 "Python/bytecodes.c" + #line 1962 "Python/bytecodes.c" // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or // None on failure. assert(PyTuple_CheckExact(names)); @@ -2800,7 +2800,7 @@ Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 1921 "Python/bytecodes.c" + #line 1967 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -2817,7 +2817,7 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1931 "Python/bytecodes.c" + #line 1977 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); #line 2824 "Python/generated_cases.c.h" @@ -2830,7 +2830,7 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 1937 "Python/bytecodes.c" + #line 1983 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); #line 2837 "Python/generated_cases.c.h" @@ -2844,7 +2844,7 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 1943 "Python/bytecodes.c" + #line 1989 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; @@ -2857,12 +2857,12 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 1949 "Python/bytecodes.c" + #line 1995 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); #line 2864 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1952 "Python/bytecodes.c" + #line 1998 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; #line 2868 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -2872,7 +2872,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 1956 "Python/bytecodes.c" + #line 2002 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -2897,7 +2897,7 @@ } #line 2899 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 1979 "Python/bytecodes.c" + #line 2025 "Python/bytecodes.c" } #line 2903 "Python/generated_cases.c.h" stack_pointer[-1] = iter; @@ -2910,7 +2910,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 1998 "Python/bytecodes.c" + #line 2044 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2953,7 +2953,7 @@ TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2033 "Python/bytecodes.c" + #line 2079 "Python/bytecodes.c" assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -2984,7 +2984,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2056 "Python/bytecodes.c" + #line 2102 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -3015,7 +3015,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2079 "Python/bytecodes.c" + #line 2125 "Python/bytecodes.c" assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -3043,7 +3043,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2100 "Python/bytecodes.c" + #line 2146 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3065,7 +3065,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2117 "Python/bytecodes.c" + #line 2163 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3090,7 +3090,7 @@ } #line 3092 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2140 "Python/bytecodes.c" + #line 2186 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3109,7 +3109,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2150 "Python/bytecodes.c" + #line 2196 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3137,7 +3137,7 @@ } #line 3139 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2176 "Python/bytecodes.c" + #line 2222 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3156,7 +3156,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2185 "Python/bytecodes.c" + #line 2231 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3186,7 +3186,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2208 "Python/bytecodes.c" + #line 2254 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3210,7 +3210,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2220 "Python/bytecodes.c" + #line 2266 "Python/bytecodes.c" /* Cached method object */ assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); @@ -3242,7 +3242,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2240 "Python/bytecodes.c" + #line 2286 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3267,7 +3267,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2253 "Python/bytecodes.c" + #line 2299 "Python/bytecodes.c" assert(cframe.use_tracing == 0); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3291,7 +3291,7 @@ } TARGET(KW_NAMES) { - #line 2270 "Python/bytecodes.c" + #line 2316 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); kwnames = GETITEM(frame->f_code->co_consts, oparg); @@ -3306,7 +3306,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2306 "Python/bytecodes.c" + #line 2352 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3390,7 +3390,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2384 "Python/bytecodes.c" + #line 2430 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3409,7 +3409,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2396 "Python/bytecodes.c" + #line 2442 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3443,7 +3443,7 @@ PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); uint16_t min_args = read_u16(&next_instr[3].cache); - #line 2423 "Python/bytecodes.c" + #line 2469 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3481,7 +3481,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2455 "Python/bytecodes.c" + #line 2501 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3505,7 +3505,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2468 "Python/bytecodes.c" + #line 2514 "Python/bytecodes.c" assert(kwnames == NULL); assert(cframe.use_tracing == 0); assert(oparg == 1); @@ -3531,7 +3531,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2483 "Python/bytecodes.c" + #line 2529 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3556,7 +3556,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2497 "Python/bytecodes.c" + #line 2543 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3592,7 +3592,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2522 "Python/bytecodes.c" + #line 2568 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_O functions */ assert(kwnames == NULL); @@ -3635,7 +3635,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2554 "Python/bytecodes.c" + #line 2600 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); @@ -3682,7 +3682,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2590 "Python/bytecodes.c" + #line 2636 "Python/bytecodes.c" assert(cframe.use_tracing == 0); /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; @@ -3729,7 +3729,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2626 "Python/bytecodes.c" + #line 2672 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* len(o) */ @@ -3768,7 +3768,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2654 "Python/bytecodes.c" + #line 2700 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); /* isinstance(o, o2) */ @@ -3808,7 +3808,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2685 "Python/bytecodes.c" + #line 2731 "Python/bytecodes.c" assert(cframe.use_tracing == 0); assert(kwnames == NULL); assert(oparg == 1); @@ -3834,7 +3834,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2706 "Python/bytecodes.c" + #line 2752 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -3878,7 +3878,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2740 "Python/bytecodes.c" + #line 2786 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3920,7 +3920,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2772 "Python/bytecodes.c" + #line 2818 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -3962,7 +3962,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2804 "Python/bytecodes.c" + #line 2850 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4005,7 +4005,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 2835 "Python/bytecodes.c" + #line 2881 "Python/bytecodes.c" if (oparg & 1) { // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. @@ -4028,7 +4028,7 @@ Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 2854 "Python/bytecodes.c" + #line 2900 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } @@ -4047,7 +4047,7 @@ PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL; PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL; PyObject *func; - #line 2865 "Python/bytecodes.c" + #line 2911 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4083,7 +4083,7 @@ } TARGET(RETURN_GENERATOR) { - #line 2896 "Python/bytecodes.c" + #line 2942 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4112,13 +4112,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 2919 "Python/bytecodes.c" + #line 2965 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 4118 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 2921 "Python/bytecodes.c" + #line 2967 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 4124 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -4131,7 +4131,7 @@ PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL; PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))]; PyObject *result; - #line 2925 "Python/bytecodes.c" + #line 2971 "Python/bytecodes.c" /* Handles f-string value formatting. */ PyObject *(*conv_fn)(PyObject *); int which_conversion = oparg & FVC_MASK; @@ -4175,7 +4175,7 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 2962 "Python/bytecodes.c" + #line 3008 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 4182 "Python/generated_cases.c.h" @@ -4190,7 +4190,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 2967 "Python/bytecodes.c" + #line 3013 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4209,7 +4209,7 @@ #line 4210 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 2983 "Python/bytecodes.c" + #line 3029 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 4215 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -4221,7 +4221,7 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 2988 "Python/bytecodes.c" + #line 3034 "Python/bytecodes.c" assert(oparg >= 2); #line 4227 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; @@ -4230,7 +4230,7 @@ } TARGET(EXTENDED_ARG) { - #line 2992 "Python/bytecodes.c" + #line 3038 "Python/bytecodes.c" assert(oparg); assert(cframe.use_tracing == 0); opcode = next_instr->op.code; @@ -4241,7 +4241,7 @@ } TARGET(CACHE) { - #line 3001 "Python/bytecodes.c" + #line 3047 "Python/bytecodes.c" Py_UNREACHABLE(); #line 4247 "Python/generated_cases.c.h" }