From a9073564ee50bc610e1fd36e45b0a5204618883a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 1 Dec 2023 16:54:40 +0100 Subject: [PATCH 01/87] gh-110481: Fix typo in Py_SET_REFCNT() (#112595) --- Include/object.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Include/object.h b/Include/object.h index 86fcba21caa9c8a..81f777ad21f2f9f 100644 --- a/Include/object.h +++ b/Include/object.h @@ -357,9 +357,9 @@ static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) { if (_Py_IsOwnedByCurrentThread(ob)) { if ((size_t)refcnt > (size_t)UINT32_MAX) { // On overflow, make the object immortal - op->ob_tid = _Py_UNOWNED_TID; - op->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL; - op->ob_ref_shared = 0; + ob->ob_tid = _Py_UNOWNED_TID; + ob->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL; + ob->ob_ref_shared = 0; } else { // Set local refcount to desired refcount and shared refcount From 05a370abd6cdfe4b54be60b3b911f3a441026bb2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 1 Dec 2023 17:05:56 +0100 Subject: [PATCH 02/87] gh-112567: Add _Py_GetTicksPerSecond() function (#112587) * Move _PyRuntimeState.time to _posixstate.ticks_per_second and time_module_state.ticks_per_second. * Add time_module_state.clocks_per_second. * Rename _PyTime_GetClockWithInfo() to py_clock(). * Rename _PyTime_GetProcessTimeWithInfo() to py_process_time(). * Add process_time_times() helper function, called by py_process_time(). * os.times() is now always built: no longer rely on HAVE_TIMES. --- Include/internal/pycore_fileutils.h | 4 + Include/internal/pycore_pylifecycle.h | 1 - Include/internal/pycore_runtime.h | 2 - Include/internal/pycore_time.h | 10 -- Modules/clinic/posixmodule.c.h | 10 +- Modules/posixmodule.c | 53 +++++---- Modules/timemodule.c | 158 ++++++++++++++------------ Python/fileutils.c | 24 ++++ Python/pylifecycle.c | 5 - 9 files changed, 142 insertions(+), 125 deletions(-) diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h index 2f89da2c6ecd916..5c55282fa39e6f6 100644 --- a/Include/internal/pycore_fileutils.h +++ b/Include/internal/pycore_fileutils.h @@ -320,6 +320,10 @@ PyAPI_FUNC(char*) _Py_UniversalNewlineFgetsWithSize(char *, int, FILE*, PyObject extern int _PyFile_Flush(PyObject *); +#ifndef MS_WINDOWS +extern int _Py_GetTicksPerSecond(long *ticks_per_second); +#endif + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index 61e0150e89009ce..daf7cb77dcc63ae 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -40,7 +40,6 @@ extern void _PySys_FiniTypes(PyInterpreterState *interp); extern int _PyBuiltins_AddExceptions(PyObject * bltinmod); extern PyStatus _Py_HashRandomization_Init(const PyConfig *); -extern PyStatus _PyTime_Init(void); extern PyStatus _PyGC_Init(PyInterpreterState *interp); extern PyStatus _PyAtExit_Init(PyInterpreterState *interp); extern int _Py_Deepfreeze_Init(void); diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index e6efe8b646e86f8..36743723f8afd88 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -21,7 +21,6 @@ extern "C" { #include "pycore_pymem.h" // struct _pymem_allocators #include "pycore_pythread.h" // struct _pythread_runtime_state #include "pycore_signal.h" // struct _signals_runtime_state -#include "pycore_time.h" // struct _time_runtime_state #include "pycore_tracemalloc.h" // struct _tracemalloc_runtime_state #include "pycore_typeobject.h" // struct _types_runtime_state #include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_state @@ -205,7 +204,6 @@ typedef struct pyruntimestate { struct _pymem_allocators allocators; struct _obmalloc_global_state obmalloc; struct pyhash_runtime_state pyhash_state; - struct _time_runtime_state time; struct _pythread_runtime_state threads; struct _signals_runtime_state signals; diff --git a/Include/internal/pycore_time.h b/Include/internal/pycore_time.h index 46713f91d190ffc..7ea3485107572e1 100644 --- a/Include/internal/pycore_time.h +++ b/Include/internal/pycore_time.h @@ -52,16 +52,6 @@ extern "C" { #endif -struct _time_runtime_state { -#ifdef HAVE_TIMES - int ticks_per_second_initialized; - long ticks_per_second; -#else - int _not_used; -#endif -}; - - #ifdef __clang__ struct timeval; #endif diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 9c54935bafa617a..a6c76370f241be1 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -5997,8 +5997,6 @@ os_symlink(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject * #endif /* defined(HAVE_SYMLINK) */ -#if defined(HAVE_TIMES) - PyDoc_STRVAR(os_times__doc__, "times($module, /)\n" "--\n" @@ -6021,8 +6019,6 @@ os_times(PyObject *module, PyObject *Py_UNUSED(ignored)) return os_times_impl(module); } -#endif /* defined(HAVE_TIMES) */ - #if defined(HAVE_TIMERFD_CREATE) PyDoc_STRVAR(os_timerfd_create__doc__, @@ -12116,10 +12112,6 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #define OS_SYMLINK_METHODDEF #endif /* !defined(OS_SYMLINK_METHODDEF) */ -#ifndef OS_TIMES_METHODDEF - #define OS_TIMES_METHODDEF -#endif /* !defined(OS_TIMES_METHODDEF) */ - #ifndef OS_TIMERFD_CREATE_METHODDEF #define OS_TIMERFD_CREATE_METHODDEF #endif /* !defined(OS_TIMERFD_CREATE_METHODDEF) */ @@ -12403,4 +12395,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=0f216bf44ea358f9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2900675ac5219924 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d99b5335b6989ae..70d107a297f315d 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1030,6 +1030,10 @@ typedef struct { PyObject *struct_rusage; #endif PyObject *st_mode; +#ifndef MS_WINDOWS + // times() clock frequency in hertz; used by os.times() + long ticks_per_second; +#endif } _posixstate; @@ -9986,8 +9990,6 @@ os_symlink_impl(PyObject *module, path_t *src, path_t *dst, #endif /* HAVE_SYMLINK */ - - static PyStructSequence_Field times_result_fields[] = { {"user", "user time"}, {"system", "system time"}, @@ -10013,12 +10015,6 @@ static PyStructSequence_Desc times_result_desc = { 5 }; -#ifdef MS_WINDOWS -#define HAVE_TIMES /* mandatory, for the method table */ -#endif - -#ifdef HAVE_TIMES - static PyObject * build_times_result(PyObject *module, double user, double system, double children_user, double children_system, @@ -10064,8 +10060,8 @@ All fields are floating point numbers. static PyObject * os_times_impl(PyObject *module) /*[clinic end generated code: output=35f640503557d32a input=2bf9df3d6ab2e48b]*/ -#ifdef MS_WINDOWS { +#ifdef MS_WINDOWS FILETIME create, exit, kernel, user; HANDLE hProc; hProc = GetCurrentProcess(); @@ -10083,28 +10079,26 @@ os_times_impl(PyObject *module) (double)0, (double)0, (double)0); -} #else /* MS_WINDOWS */ -{ - struct tms t; - clock_t c; + _posixstate *state = get_posix_state(module); + long ticks_per_second = state->ticks_per_second; + + struct tms process; + clock_t elapsed; errno = 0; - c = times(&t); - if (c == (clock_t) -1) { + elapsed = times(&process); + if (elapsed == (clock_t) -1) { return posix_error(); } - assert(_PyRuntime.time.ticks_per_second_initialized); -#define ticks_per_second _PyRuntime.time.ticks_per_second + return build_times_result(module, - (double)t.tms_utime / ticks_per_second, - (double)t.tms_stime / ticks_per_second, - (double)t.tms_cutime / ticks_per_second, - (double)t.tms_cstime / ticks_per_second, - (double)c / ticks_per_second); -#undef ticks_per_second -} + (double)process.tms_utime / ticks_per_second, + (double)process.tms_stime / ticks_per_second, + (double)process.tms_cutime / ticks_per_second, + (double)process.tms_cstime / ticks_per_second, + (double)elapsed / ticks_per_second); #endif /* MS_WINDOWS */ -#endif /* HAVE_TIMES */ +} #if defined(HAVE_TIMERFD_CREATE) @@ -17279,6 +17273,15 @@ posixmodule_exec(PyObject *m) Py_DECREF(unicode); } +#ifndef MS_WINDOWS + if (_Py_GetTicksPerSecond(&state->ticks_per_second) < 0) { + PyErr_SetString(PyExc_RuntimeError, + "cannot read ticks_per_second"); + return -1; + } + assert(state->ticks_per_second >= 1); +#endif + return PyModule_Add(m, "_have_functions", list); } diff --git a/Modules/timemodule.c b/Modules/timemodule.c index bc3901e0d7a6212..aa0cdc5f026e7c7 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -73,51 +73,20 @@ module time static int check_ticks_per_second(long tps, const char *context) { - /* Effectively, check that _PyTime_MulDiv(t, SEC_TO_NS, ticks_per_second) + /* Effectively, check that _PyTime_MulDiv(t, SEC_TO_NS, tps) cannot overflow. */ if (tps >= 0 && (_PyTime_t)tps > _PyTime_MAX / SEC_TO_NS) { PyErr_Format(PyExc_OverflowError, "%s is too large", context); return -1; } + if (tps < 1) { + PyErr_Format(PyExc_RuntimeError, "invalid %s", context); + return -1; + } return 0; } #endif /* HAVE_TIMES || HAVE_CLOCK */ -#ifdef HAVE_TIMES - -# define ticks_per_second _PyRuntime.time.ticks_per_second - -static void -ensure_ticks_per_second(void) -{ - if (_PyRuntime.time.ticks_per_second_initialized) { - return; - } - _PyRuntime.time.ticks_per_second_initialized = 1; -# if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) - ticks_per_second = sysconf(_SC_CLK_TCK); - if (ticks_per_second < 1) { - ticks_per_second = -1; - } -# elif defined(HZ) - ticks_per_second = HZ; -# else - ticks_per_second = 60; /* magic fallback value; may be bogus */ -# endif -} - -#endif /* HAVE_TIMES */ - - -PyStatus -_PyTime_Init(void) -{ -#ifdef HAVE_TIMES - ensure_ticks_per_second(); -#endif - return PyStatus_Ok(); -} - /* Forward declarations */ static int pysleep(_PyTime_t timeout); @@ -125,6 +94,14 @@ static int pysleep(_PyTime_t timeout); typedef struct { PyTypeObject *struct_time_type; +#ifdef HAVE_TIMES + // times() clock frequency in hertz + long ticks_per_second; +#endif +#ifdef HAVE_CLOCK + // clock() frequency in hertz + long clocks_per_second; +#endif } time_module_state; static inline time_module_state* @@ -184,7 +161,7 @@ PyDoc_STRVAR(time_ns_doc, \n\ Return the current time in nanoseconds since the Epoch."); -#if defined(HAVE_CLOCK) +#ifdef HAVE_CLOCK #ifndef CLOCKS_PER_SEC # ifdef CLK_TCK @@ -195,15 +172,12 @@ Return the current time in nanoseconds since the Epoch."); #endif static int -_PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) +py_clock(time_module_state *state, _PyTime_t *tp, _Py_clock_info_t *info) { - if (check_ticks_per_second(CLOCKS_PER_SEC, "CLOCKS_PER_SEC") < 0) { - return -1; - } - + long clocks_per_second = state->clocks_per_second; if (info) { info->implementation = "clock()"; - info->resolution = 1.0 / (double)CLOCKS_PER_SEC; + info->resolution = 1.0 / (double)clocks_per_second; info->monotonic = 1; info->adjustable = 0; } @@ -215,7 +189,7 @@ _PyTime_GetClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) "or its value cannot be represented"); return -1; } - _PyTime_t ns = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)CLOCKS_PER_SEC); + _PyTime_t ns = _PyTime_MulDiv(ticks, SEC_TO_NS, clocks_per_second); *tp = _PyTime_FromNanoseconds(ns); return 0; } @@ -1277,8 +1251,38 @@ PyDoc_STRVAR(perf_counter_ns_doc, \n\ Performance counter for benchmarking as nanoseconds."); + +#ifdef HAVE_TIMES static int -_PyTime_GetProcessTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) +process_time_times(time_module_state *state, _PyTime_t *tp, + _Py_clock_info_t *info) +{ + long ticks_per_second = state->ticks_per_second; + + struct tms process; + if (times(&process) == (clock_t)-1) { + return 0; + } + + if (info) { + info->implementation = "times()"; + info->monotonic = 1; + info->adjustable = 0; + info->resolution = 1.0 / (double)ticks_per_second; + } + + _PyTime_t ns; + ns = _PyTime_MulDiv(process.tms_utime, SEC_TO_NS, ticks_per_second); + ns += _PyTime_MulDiv(process.tms_stime, SEC_TO_NS, ticks_per_second); + *tp = _PyTime_FromNanoseconds(ns); + return 1; +} +#endif + + +static int +py_process_time(time_module_state *state, _PyTime_t *tp, + _Py_clock_info_t *info) { #if defined(MS_WINDOWS) HANDLE process; @@ -1381,41 +1385,28 @@ _PyTime_GetProcessTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) /* times() */ #ifdef HAVE_TIMES - struct tms t; - - if (times(&t) != (clock_t)-1) { - assert(_PyRuntime.time.ticks_per_second_initialized); - if (check_ticks_per_second(ticks_per_second, "_SC_CLK_TCK") < 0) { - return -1; - } - if (ticks_per_second != -1) { - if (info) { - info->implementation = "times()"; - info->monotonic = 1; - info->adjustable = 0; - info->resolution = 1.0 / (double)ticks_per_second; - } - - _PyTime_t ns; - ns = _PyTime_MulDiv(t.tms_utime, SEC_TO_NS, ticks_per_second); - ns += _PyTime_MulDiv(t.tms_stime, SEC_TO_NS, ticks_per_second); - *tp = _PyTime_FromNanoseconds(ns); - return 0; - } + int res = process_time_times(state, tp, info); + if (res < 0) { + return -1; } + if (res == 1) { + return 0; + } + // times() failed, ignore failure #endif /* clock */ /* Currently, Python 3 requires clock() to build: see issue #22624 */ - return _PyTime_GetClockWithInfo(tp, info); + return py_clock(state, tp, info); #endif } static PyObject * -time_process_time(PyObject *self, PyObject *unused) +time_process_time(PyObject *module, PyObject *unused) { + time_module_state *state = get_time_state(module); _PyTime_t t; - if (_PyTime_GetProcessTimeWithInfo(&t, NULL) < 0) { + if (py_process_time(state, &t, NULL) < 0) { return NULL; } return _PyFloat_FromPyTime(t); @@ -1427,10 +1418,11 @@ PyDoc_STRVAR(process_time_doc, Process time for profiling: sum of the kernel and user-space CPU time."); static PyObject * -time_process_time_ns(PyObject *self, PyObject *unused) +time_process_time_ns(PyObject *module, PyObject *unused) { + time_module_state *state = get_time_state(module); _PyTime_t t; - if (_PyTime_GetProcessTimeWithInfo(&t, NULL) < 0) { + if (py_process_time(state, &t, NULL) < 0) { return NULL; } return _PyTime_AsNanosecondsObject(t); @@ -1617,7 +1609,7 @@ sum of the kernel and user-space CPU time."); static PyObject * -time_get_clock_info(PyObject *self, PyObject *args) +time_get_clock_info(PyObject *module, PyObject *args) { char *name; _Py_clock_info_t info; @@ -1656,7 +1648,8 @@ time_get_clock_info(PyObject *self, PyObject *args) } } else if (strcmp(name, "process_time") == 0) { - if (_PyTime_GetProcessTimeWithInfo(&t, &info) < 0) { + time_module_state *state = get_time_state(module); + if (py_process_time(state, &t, &info) < 0) { return NULL; } } @@ -2116,6 +2109,25 @@ time_exec(PyObject *module) } #endif +#ifdef HAVE_TIMES + if (_Py_GetTicksPerSecond(&state->ticks_per_second) < 0) { + PyErr_SetString(PyExc_RuntimeError, + "cannot read ticks_per_second"); + return -1; + } + + if (check_ticks_per_second(state->ticks_per_second, "_SC_CLK_TCK") < 0) { + return -1; + } +#endif + +#ifdef HAVE_CLOCK + state->clocks_per_second = CLOCKS_PER_SEC; + if (check_ticks_per_second(state->clocks_per_second, "CLOCKS_PER_SEC") < 0) { + return -1; + } +#endif + return 0; } diff --git a/Python/fileutils.c b/Python/fileutils.c index 649b188b5167d03..9d12bc89c95436a 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -2943,3 +2943,27 @@ _Py_closerange(int first, int last) #endif /* USE_FDWALK */ _Py_END_SUPPRESS_IPH } + + +#ifndef MS_WINDOWS +// Ticks per second used by clock() and times() functions. +// See os.times() and time.process_time() implementations. +int +_Py_GetTicksPerSecond(long *ticks_per_second) +{ +#if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) + long value = sysconf(_SC_CLK_TCK); + if (value < 1) { + return -1; + } + *ticks_per_second = value; +#elif defined(HZ) + assert(HZ >= 1); + *ticks_per_second = HZ; +#else + // Magic fallback value; may be bogus + *ticks_per_second = 60; +#endif + return 0; +} +#endif diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index aff67d7a835e898..95a72eb47048f25 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -528,11 +528,6 @@ pycore_init_runtime(_PyRuntimeState *runtime, return status; } - status = _PyTime_Init(); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - status = _PyImport_Init(); if (_PyStatus_EXCEPTION(status)) { return status; From 5c5022b8625e34f0035ad5a23bc4c2f16649d134 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 1 Dec 2023 19:50:10 +0100 Subject: [PATCH 03/87] gh-112567: Add _PyTimeFraction C API (#112568) Use a fraction internally in the _PyTime API to reduce the risk of integer overflow: simplify the fraction using Greatest Common Divisor (GCD). The fraction API is used by time functions: perf_counter(), monotonic() and process_time(). For example, QueryPerformanceFrequency() usually returns 10 MHz on Windows 10 and newer. The fraction SEC_TO_NS / frequency = 1_000_000_000 / 10_000_000 can be simplified to 100 / 1. * Add _PyTimeFraction type. * Add functions: * _PyTimeFraction_Set() * _PyTimeFraction_Mul() * _PyTimeFraction_Resolution() * No longer check "numer * denom <= _PyTime_MAX" in _PyTimeFraction_Set(). _PyTimeFraction_Mul() uses _PyTime_Mul() which handles integer overflow. --- Include/internal/pycore_time.h | 33 ++++++-- Modules/timemodule.c | 54 +++++------- Python/pytime.c | 150 +++++++++++++++++++-------------- 3 files changed, 130 insertions(+), 107 deletions(-) diff --git a/Include/internal/pycore_time.h b/Include/internal/pycore_time.h index 7ea3485107572e1..dabbd7b41556cdf 100644 --- a/Include/internal/pycore_time.h +++ b/Include/internal/pycore_time.h @@ -253,13 +253,6 @@ PyAPI_FUNC(void) _PyTime_AsTimespec_clamp(_PyTime_t t, struct timespec *ts); // Compute t1 + t2. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. extern _PyTime_t _PyTime_Add(_PyTime_t t1, _PyTime_t t2); -// Compute ticks * mul / div. -// Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. -// The caller must ensure that ((div - 1) * mul) cannot overflow. -extern _PyTime_t _PyTime_MulDiv(_PyTime_t ticks, - _PyTime_t mul, - _PyTime_t div); - // Structure used by time.get_clock_info() typedef struct { const char *implementation; @@ -355,6 +348,32 @@ PyAPI_FUNC(_PyTime_t) _PyDeadline_Init(_PyTime_t timeout); PyAPI_FUNC(_PyTime_t) _PyDeadline_Get(_PyTime_t deadline); +// --- _PyTimeFraction ------------------------------------------------------- + +typedef struct { + _PyTime_t numer; + _PyTime_t denom; +} _PyTimeFraction; + +// Set a fraction. +// Return 0 on success. +// Return -1 if the fraction is invalid. +extern int _PyTimeFraction_Set( + _PyTimeFraction *frac, + _PyTime_t numer, + _PyTime_t denom); + +// Compute ticks * frac.numer / frac.denom. +// Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. +extern _PyTime_t _PyTimeFraction_Mul( + _PyTime_t ticks, + const _PyTimeFraction *frac); + +// Compute a clock resolution: frac.numer / frac.denom / 1e9. +extern double _PyTimeFraction_Resolution( + const _PyTimeFraction *frac); + + #ifdef __cplusplus } #endif diff --git a/Modules/timemodule.c b/Modules/timemodule.c index aa0cdc5f026e7c7..b3fe175d9b184a7 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -69,25 +69,6 @@ module time /*[clinic end generated code: output=da39a3ee5e6b4b0d input=a668a08771581f36]*/ -#if defined(HAVE_TIMES) || defined(HAVE_CLOCK) -static int -check_ticks_per_second(long tps, const char *context) -{ - /* Effectively, check that _PyTime_MulDiv(t, SEC_TO_NS, tps) - cannot overflow. */ - if (tps >= 0 && (_PyTime_t)tps > _PyTime_MAX / SEC_TO_NS) { - PyErr_Format(PyExc_OverflowError, "%s is too large", context); - return -1; - } - if (tps < 1) { - PyErr_Format(PyExc_RuntimeError, "invalid %s", context); - return -1; - } - return 0; -} -#endif /* HAVE_TIMES || HAVE_CLOCK */ - - /* Forward declarations */ static int pysleep(_PyTime_t timeout); @@ -96,11 +77,11 @@ typedef struct { PyTypeObject *struct_time_type; #ifdef HAVE_TIMES // times() clock frequency in hertz - long ticks_per_second; + _PyTimeFraction times_base; #endif #ifdef HAVE_CLOCK // clock() frequency in hertz - long clocks_per_second; + _PyTimeFraction clock_base; #endif } time_module_state; @@ -174,10 +155,11 @@ Return the current time in nanoseconds since the Epoch."); static int py_clock(time_module_state *state, _PyTime_t *tp, _Py_clock_info_t *info) { - long clocks_per_second = state->clocks_per_second; + _PyTimeFraction *base = &state->clock_base; + if (info) { info->implementation = "clock()"; - info->resolution = 1.0 / (double)clocks_per_second; + info->resolution = _PyTimeFraction_Resolution(base); info->monotonic = 1; info->adjustable = 0; } @@ -189,7 +171,7 @@ py_clock(time_module_state *state, _PyTime_t *tp, _Py_clock_info_t *info) "or its value cannot be represented"); return -1; } - _PyTime_t ns = _PyTime_MulDiv(ticks, SEC_TO_NS, clocks_per_second); + _PyTime_t ns = _PyTimeFraction_Mul(ticks, base); *tp = _PyTime_FromNanoseconds(ns); return 0; } @@ -1257,7 +1239,7 @@ static int process_time_times(time_module_state *state, _PyTime_t *tp, _Py_clock_info_t *info) { - long ticks_per_second = state->ticks_per_second; + _PyTimeFraction *base = &state->times_base; struct tms process; if (times(&process) == (clock_t)-1) { @@ -1266,14 +1248,14 @@ process_time_times(time_module_state *state, _PyTime_t *tp, if (info) { info->implementation = "times()"; + info->resolution = _PyTimeFraction_Resolution(base); info->monotonic = 1; info->adjustable = 0; - info->resolution = 1.0 / (double)ticks_per_second; } _PyTime_t ns; - ns = _PyTime_MulDiv(process.tms_utime, SEC_TO_NS, ticks_per_second); - ns += _PyTime_MulDiv(process.tms_stime, SEC_TO_NS, ticks_per_second); + ns = _PyTimeFraction_Mul(process.tms_utime, base); + ns += _PyTimeFraction_Mul(process.tms_stime, base); *tp = _PyTime_FromNanoseconds(ns); return 1; } @@ -1395,8 +1377,7 @@ py_process_time(time_module_state *state, _PyTime_t *tp, // times() failed, ignore failure #endif - /* clock */ - /* Currently, Python 3 requires clock() to build: see issue #22624 */ + /* clock(). Python 3 requires clock() to build (see gh-66814) */ return py_clock(state, tp, info); #endif } @@ -2110,20 +2091,23 @@ time_exec(PyObject *module) #endif #ifdef HAVE_TIMES - if (_Py_GetTicksPerSecond(&state->ticks_per_second) < 0) { + long ticks_per_second; + if (_Py_GetTicksPerSecond(&ticks_per_second) < 0) { PyErr_SetString(PyExc_RuntimeError, "cannot read ticks_per_second"); return -1; } - - if (check_ticks_per_second(state->ticks_per_second, "_SC_CLK_TCK") < 0) { + if (_PyTimeFraction_Set(&state->times_base, SEC_TO_NS, + ticks_per_second) < 0) { + PyErr_Format(PyExc_OverflowError, "ticks_per_second is too large"); return -1; } #endif #ifdef HAVE_CLOCK - state->clocks_per_second = CLOCKS_PER_SEC; - if (check_ticks_per_second(state->clocks_per_second, "CLOCKS_PER_SEC") < 0) { + if (_PyTimeFraction_Set(&state->clock_base, SEC_TO_NS, + CLOCKS_PER_SEC) < 0) { + PyErr_Format(PyExc_OverflowError, "CLOCKS_PER_SEC is too large"); return -1; } #endif diff --git a/Python/pytime.c b/Python/pytime.c index e4813d4a9c2a2ad..77cb95f8feb179f 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -55,6 +55,43 @@ #endif +static _PyTime_t +_PyTime_GCD(_PyTime_t x, _PyTime_t y) +{ + // Euclidean algorithm + assert(x >= 1); + assert(y >= 1); + while (y != 0) { + _PyTime_t tmp = y; + y = x % y; + x = tmp; + } + assert(x >= 1); + return x; +} + + +int +_PyTimeFraction_Set(_PyTimeFraction *frac, _PyTime_t numer, _PyTime_t denom) +{ + if (numer < 1 || denom < 1) { + return -1; + } + + _PyTime_t gcd = _PyTime_GCD(numer, denom); + frac->numer = numer / gcd; + frac->denom = denom / gcd; + return 0; +} + + +double +_PyTimeFraction_Resolution(const _PyTimeFraction *frac) +{ + return (double)frac->numer / (double)frac->denom / 1e9; +} + + static void pytime_time_t_overflow(void) { @@ -152,11 +189,17 @@ _PyTime_Mul(_PyTime_t t, _PyTime_t k) } - - _PyTime_t -_PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div) +_PyTimeFraction_Mul(_PyTime_t ticks, const _PyTimeFraction *frac) { + const _PyTime_t mul = frac->numer; + const _PyTime_t div = frac->denom; + + if (div == 1) { + // Fast-path taken by mach_absolute_time() with 1/1 time base. + return _PyTime_Mul(ticks, mul); + } + /* Compute (ticks * mul / div) in two parts to reduce the risk of integer overflow: compute the integer part, and then the remaining part. @@ -1016,51 +1059,34 @@ _PyTime_GetSystemClockWithInfo(_PyTime_t *t, _Py_clock_info_t *info) #ifdef __APPLE__ static int -py_mach_timebase_info(_PyTime_t *pnumer, _PyTime_t *pdenom, int raise) +py_mach_timebase_info(_PyTimeFraction *base, int raise) { - static mach_timebase_info_data_t timebase; - /* According to the Technical Q&A QA1398, mach_timebase_info() cannot - fail: https://developer.apple.com/library/mac/#qa/qa1398/ */ + mach_timebase_info_data_t timebase; + // According to the Technical Q&A QA1398, mach_timebase_info() cannot + // fail: https://developer.apple.com/library/mac/#qa/qa1398/ (void)mach_timebase_info(&timebase); - /* Sanity check: should never occur in practice */ - if (timebase.numer < 1 || timebase.denom < 1) { + // Check that timebase.numer and timebase.denom can be casted to + // _PyTime_t. In practice, timebase uses uint32_t, so casting cannot + // overflow. At the end, only make sure that the type is uint32_t + // (_PyTime_t is 64-bit long). + Py_BUILD_ASSERT(sizeof(timebase.numer) <= sizeof(_PyTime_t)); + Py_BUILD_ASSERT(sizeof(timebase.denom) <= sizeof(_PyTime_t)); + _PyTime_t numer = (_PyTime_t)timebase.numer; + _PyTime_t denom = (_PyTime_t)timebase.denom; + + // Known time bases: + // + // * (1, 1) on Intel: 1 ns + // * (1000000000, 33333335) on PowerPC: ~30 ns + // * (1000000000, 25000000) on PowerPC: 40 ns + if (_PyTimeFraction_Set(base, numer, denom) < 0) { if (raise) { PyErr_SetString(PyExc_RuntimeError, "invalid mach_timebase_info"); } return -1; } - - /* Check that timebase.numer and timebase.denom can be casted to - _PyTime_t. In practice, timebase uses uint32_t, so casting cannot - overflow. At the end, only make sure that the type is uint32_t - (_PyTime_t is 64-bit long). */ - static_assert(sizeof(timebase.numer) <= sizeof(_PyTime_t), - "timebase.numer is larger than _PyTime_t"); - static_assert(sizeof(timebase.denom) <= sizeof(_PyTime_t), - "timebase.denom is larger than _PyTime_t"); - - /* Make sure that _PyTime_MulDiv(ticks, timebase_numer, timebase_denom) - cannot overflow. - - Known time bases: - - * (1, 1) on Intel - * (1000000000, 33333335) or (1000000000, 25000000) on PowerPC - - None of these time bases can overflow with 64-bit _PyTime_t, but - check for overflow, just in case. */ - if ((_PyTime_t)timebase.numer > _PyTime_MAX / (_PyTime_t)timebase.denom) { - if (raise) { - PyErr_SetString(PyExc_OverflowError, - "mach_timebase_info is too large"); - } - return -1; - } - - *pnumer = (_PyTime_t)timebase.numer; - *pdenom = (_PyTime_t)timebase.denom; return 0; } #endif @@ -1109,17 +1135,16 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) } #elif defined(__APPLE__) - static _PyTime_t timebase_numer = 0; - static _PyTime_t timebase_denom = 0; - if (timebase_denom == 0) { - if (py_mach_timebase_info(&timebase_numer, &timebase_denom, raise_exc) < 0) { + static _PyTimeFraction base = {0, 0}; + if (base.denom == 0) { + if (py_mach_timebase_info(&base, raise_exc) < 0) { return -1; } } if (info) { info->implementation = "mach_absolute_time()"; - info->resolution = (double)timebase_numer / (double)timebase_denom * 1e-9; + info->resolution = _PyTimeFraction_Resolution(&base); info->monotonic = 1; info->adjustable = 0; } @@ -1129,7 +1154,7 @@ py_get_monotonic_clock(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) assert(uticks <= (uint64_t)_PyTime_MAX); _PyTime_t ticks = (_PyTime_t)uticks; - _PyTime_t ns = _PyTime_MulDiv(ticks, timebase_numer, timebase_denom); + _PyTime_t ns = _PyTimeFraction_Mul(ticks, &base); *tp = pytime_from_nanoseconds(ns); #elif defined(__hpux) @@ -1213,7 +1238,7 @@ _PyTime_GetMonotonicClockWithInfo(_PyTime_t *tp, _Py_clock_info_t *info) #ifdef MS_WINDOWS static int -py_win_perf_counter_frequency(LONGLONG *pfrequency, int raise) +py_win_perf_counter_frequency(_PyTimeFraction *base, int raise) { LONGLONG frequency; @@ -1225,25 +1250,20 @@ py_win_perf_counter_frequency(LONGLONG *pfrequency, int raise) // Since Windows XP, frequency cannot be zero. assert(frequency >= 1); - /* Make also sure that (ticks * SEC_TO_NS) cannot overflow in - _PyTime_MulDiv(), with ticks < frequency. + Py_BUILD_ASSERT(sizeof(_PyTime_t) == sizeof(frequency)); + _PyTime_t denom = (_PyTime_t)frequency; - Known QueryPerformanceFrequency() values: - - * 10,000,000 (10 MHz): 100 ns resolution - * 3,579,545 Hz (3.6 MHz): 279 ns resolution - - None of these frequencies can overflow with 64-bit _PyTime_t, but - check for integer overflow just in case. */ - if (frequency > _PyTime_MAX / SEC_TO_NS) { + // Known QueryPerformanceFrequency() values: + // + // * 10,000,000 (10 MHz): 100 ns resolution + // * 3,579,545 Hz (3.6 MHz): 279 ns resolution + if (_PyTimeFraction_Set(base, SEC_TO_NS, denom) < 0) { if (raise) { - PyErr_SetString(PyExc_OverflowError, - "QueryPerformanceFrequency is too large"); + PyErr_SetString(PyExc_RuntimeError, + "invalid QueryPerformanceFrequency"); } return -1; } - - *pfrequency = frequency; return 0; } @@ -1253,16 +1273,16 @@ py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) { assert(info == NULL || raise_exc); - static LONGLONG frequency = 0; - if (frequency == 0) { - if (py_win_perf_counter_frequency(&frequency, raise_exc) < 0) { + static _PyTimeFraction base = {0, 0}; + if (base.denom == 0) { + if (py_win_perf_counter_frequency(&base, raise_exc) < 0) { return -1; } } if (info) { info->implementation = "QueryPerformanceCounter()"; - info->resolution = 1.0 / (double)frequency; + info->resolution = _PyTimeFraction_Resolution(&base); info->monotonic = 1; info->adjustable = 0; } @@ -1278,7 +1298,7 @@ py_get_win_perf_counter(_PyTime_t *tp, _Py_clock_info_t *info, int raise_exc) "LONGLONG is larger than _PyTime_t"); ticks = (_PyTime_t)ticksll; - _PyTime_t ns = _PyTime_MulDiv(ticks, SEC_TO_NS, (_PyTime_t)frequency); + _PyTime_t ns = _PyTimeFraction_Mul(ticks, &base); *tp = pytime_from_nanoseconds(ns); return 0; } From 939fc6d6eab9b7ea8c244d513610dbdd556503a7 Mon Sep 17 00:00:00 2001 From: William Wen Date: Fri, 1 Dec 2023 14:18:16 -0800 Subject: [PATCH 04/87] gh-106922: Support multi-line error locations in traceback (attempt 2) (#112097) --- Doc/library/traceback.rst | 13 +- Lib/test/test_doctest.py | 3 + Lib/test/test_exceptions.py | 3 +- Lib/test/test_repl.py | 3 +- Lib/test/test_sys.py | 6 +- Lib/test/test_traceback.py | 435 ++++++++++++++++-- Lib/test/test_warnings/__init__.py | 4 +- Lib/traceback.py | 368 +++++++++++---- ...-11-15-01-36-04.gh-issue-106922.qslOVH.rst | 1 + 9 files changed, 709 insertions(+), 127 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-15-01-36-04.gh-issue-106922.qslOVH.rst diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 80dda5ec520d7a9..2d5ea19b2cb892f 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -523,27 +523,32 @@ The output for the example would look similar to this: *** print_tb: File "", line 10, in lumberjack() + ~~~~~~~~~~^^ *** print_exception: Traceback (most recent call last): File "", line 10, in lumberjack() + ~~~~~~~~~~^^ File "", line 4, in lumberjack bright_side_of_life() + ~~~~~~~~~~~~~~~~~~~^^ IndexError: tuple index out of range *** print_exc: Traceback (most recent call last): File "", line 10, in lumberjack() + ~~~~~~~~~~^^ File "", line 4, in lumberjack bright_side_of_life() + ~~~~~~~~~~~~~~~~~~~^^ IndexError: tuple index out of range *** format_exc, first and last line: Traceback (most recent call last): IndexError: tuple index out of range *** format_exception: ['Traceback (most recent call last):\n', - ' File "", line 10, in \n lumberjack()\n', - ' File "", line 4, in lumberjack\n bright_side_of_life()\n', + ' File "", line 10, in \n lumberjack()\n ~~~~~~~~~~^^\n', + ' File "", line 4, in lumberjack\n bright_side_of_life()\n ~~~~~~~~~~~~~~~~~~~^^\n', ' File "", line 7, in bright_side_of_life\n return tuple()[0]\n ~~~~~~~^^^\n', 'IndexError: tuple index out of range\n'] *** extract_tb: @@ -551,8 +556,8 @@ The output for the example would look similar to this: , line 4 in lumberjack>, , line 7 in bright_side_of_life>] *** format_tb: - [' File "", line 10, in \n lumberjack()\n', - ' File "", line 4, in lumberjack\n bright_side_of_life()\n', + [' File "", line 10, in \n lumberjack()\n ~~~~~~~~~~^^\n', + ' File "", line 4, in lumberjack\n bright_side_of_life()\n ~~~~~~~~~~~~~~~~~~~^^\n', ' File "", line 7, in bright_side_of_life\n return tuple()[0]\n ~~~~~~~^^^\n'] *** tb_lineno: 10 diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 772dbd1d0213053..36328f8086c7ad2 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -2922,6 +2922,9 @@ def test_unicode(): """ Traceback (most recent call last): File ... exec(compile(example.source, filename, "single", + ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + compileflags, True), test.globs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "", line 1, in raise Exception('clé') Exception: clé diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 8ccf08703e5389f..c57488e44aecc64 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -2080,6 +2080,7 @@ def test_multiline_not_highlighted(self): """, [ ' 1 < 2 and', + ' 3 > 4', 'AssertionError', ], ), @@ -2087,7 +2088,7 @@ def test_multiline_not_highlighted(self): for source, expected in cases: with self.subTest(source): result = self.write_source(source) - self.assertEqual(result[-2:], expected) + self.assertEqual(result[-len(expected):], expected) class SyntaxErrorTests(unittest.TestCase): diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 7533376e015e731..a28d1595f445331 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -161,10 +161,11 @@ def foo(x): output = kill_python(p) self.assertEqual(p.returncode, 0) - traceback_lines = output.splitlines()[-7:-1] + traceback_lines = output.splitlines()[-8:-1] expected_lines = [ ' File "", line 1, in ', ' foo(0)', + ' ~~~^^^', ' File "", line 2, in foo', ' 1 / x', ' ~~^~~', diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 7f49fb004272bba..0028281596fa4be 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1115,8 +1115,10 @@ def check(tracebacklimit, expected): b'Traceback (most recent call last):', b' File "", line 8, in ', b' f2()', + b' ~~^^', b' File "", line 6, in f2', b' f1()', + b' ~~^^', b' File "", line 4, in f1', b' 1 / 0', b' ~~^~~', @@ -1124,8 +1126,8 @@ def check(tracebacklimit, expected): ] check(10, traceback) check(3, traceback) - check(2, traceback[:1] + traceback[3:]) - check(1, traceback[:1] + traceback[5:]) + check(2, traceback[:1] + traceback[4:]) + check(1, traceback[:1] + traceback[7:]) check(0, [traceback[-1]]) check(-1, [traceback[-1]]) check(1<<1000, traceback) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index c58d979bdd01153..b60e06ff37f494a 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -578,6 +578,7 @@ def f(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+1}, in f\n' ' if True: raise ValueError("basic caret tests")\n' ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' @@ -596,6 +597,7 @@ def f_with_unicode(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+1}, in f_with_unicode\n' ' if True: raise ValueError("Ĥellö Wörld")\n' ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' @@ -613,6 +615,7 @@ def foo(a: THIS_DOES_NOT_EXIST ) -> int: 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+1}, in f_with_type\n' ' def foo(a: THIS_DOES_NOT_EXIST ) -> int:\n' ' ^^^^^^^^^^^^^^^^^^^\n' @@ -633,9 +636,14 @@ def f_with_multiline(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+1}, in f_with_multiline\n' ' if True: raise ValueError(\n' - ' ^^^^^^^^^^^^^^^^^' + ' ^^^^^^^^^^^^^^^^^\n' + ' "error over multiple lines"\n' + ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' + ' )\n' + ' ^' ) result_lines = self.get_exception(f_with_multiline) self.assertEqual(result_lines, expected_f.splitlines()) @@ -664,9 +672,10 @@ def f_with_multiline(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+2}, in f_with_multiline\n' ' return compile(code, "?", "exec")\n' - ' ^^^^^^^^^^^^^^^^^^^^^^^^^^\n' + ' ~~~~~~~^^^^^^^^^^^^^^^^^^^\n' ' File "?", line 7\n' ' foo(a, z\n' ' ^' @@ -689,9 +698,12 @@ def f_with_multiline(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+2}, in f_with_multiline\n' ' 2 + 1 /\n' - ' ^^^' + ' ~~^\n' + ' 0\n' + ' ~' ) result_lines = self.get_exception(f_with_multiline) self.assertEqual(result_lines, expected_f.splitlines()) @@ -706,6 +718,7 @@ def f_with_binary_operator(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+2}, in f_with_binary_operator\n' ' return 10 + divisor / 0 + 30\n' ' ~~~~~~~~^~~\n' @@ -723,6 +736,7 @@ def f_with_binary_operator(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+2}, in f_with_binary_operator\n' ' return 10 + áóí / 0 + 30\n' ' ~~~~^~~\n' @@ -740,6 +754,7 @@ def f_with_binary_operator(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+2}, in f_with_binary_operator\n' ' return 10 + divisor // 0 + 30\n' ' ~~~~~~~~^^~~\n' @@ -751,16 +766,102 @@ def test_caret_for_binary_operators_with_spaces_and_parenthesis(self): def f_with_binary_operator(): a = 1 b = "" - return ( a ) + b + return ( a ) +b lineno_f = f_with_binary_operator.__code__.co_firstlineno expected_error = ( 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n' - ' return ( a ) + b\n' - ' ~~~~~~~~~~^~~\n' + ' return ( a ) +b\n' + ' ~~~~~~~~~~^~\n' + ) + result_lines = self.get_exception(f_with_binary_operator) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_caret_for_binary_operators_multiline(self): + def f_with_binary_operator(): + b = 1 + c = "" + a = b \ + +\ + c # test + return a + + lineno_f = f_with_binary_operator.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n' + ' a = b \\\n' + ' ~~~~~~\n' + ' +\\\n' + ' ^~\n' + ' c # test\n' + ' ~\n' + ) + result_lines = self.get_exception(f_with_binary_operator) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_caret_for_binary_operators_multiline_two_char(self): + def f_with_binary_operator(): + b = 1 + c = "" + a = ( + (b # test + + ) \ + # + + << (c # test + \ + ) # test + ) + return a + + lineno_f = f_with_binary_operator.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+4}, in f_with_binary_operator\n' + ' (b # test +\n' + ' ~~~~~~~~~~~~\n' + ' ) \\\n' + ' ~~~~\n' + ' # +\n' + ' ~~~\n' + ' << (c # test\n' + ' ^^~~~~~~~~~~~\n' + ' \\\n' + ' ~\n' + ' ) # test\n' + ' ~\n' + ) + result_lines = self.get_exception(f_with_binary_operator) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_caret_for_binary_operators_multiline_with_unicode(self): + def f_with_binary_operator(): + b = 1 + a = ("ááá" + + "áá") + b + return a + + lineno_f = f_with_binary_operator.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+2}, in f_with_binary_operator\n' + ' a = ("ááá" +\n' + ' ~~~~~~~~\n' + ' "áá") + b\n' + ' ~~~~~~^~~\n' ) result_lines = self.get_exception(f_with_binary_operator) self.assertEqual(result_lines, expected_error.splitlines()) @@ -775,6 +876,7 @@ def f_with_subscript(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+2}, in f_with_subscript\n' " return some_dict['x']['y']['z']\n" ' ~~~~~~~~~~~~~~~~~~~^^^^^\n' @@ -792,6 +894,7 @@ def f_with_subscript(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+2}, in f_with_subscript\n' " return some_dict['ó']['á']['í']['beta']\n" ' ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^\n' @@ -810,6 +913,7 @@ def f_with_binary_operator(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n' ' return b [ a ] + c\n' ' ~~~~~~^^^^^^^^^\n' @@ -817,6 +921,226 @@ def f_with_binary_operator(): result_lines = self.get_exception(f_with_binary_operator) self.assertEqual(result_lines, expected_error.splitlines()) + def test_caret_for_subscript_multiline(self): + def f_with_subscript(): + bbbbb = {} + ccc = 1 + ddd = 2 + b = bbbbb \ + [ ccc # test + + + ddd \ + + ] # test + return b + + lineno_f = f_with_subscript.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+4}, in f_with_subscript\n' + ' b = bbbbb \\\n' + ' ~~~~~~~\n' + ' [ ccc # test\n' + ' ^^^^^^^^^^^^^\n' + ' \n' + ' \n' + ' + ddd \\\n' + ' ^^^^^^^^\n' + ' \n' + ' \n' + ' ] # test\n' + ' ^\n' + ) + result_lines = self.get_exception(f_with_subscript) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_caret_for_call(self): + def f_with_call(): + def f1(a): + def f2(b): + raise RuntimeError("fail") + return f2 + return f1("x")("y") + + lineno_f = f_with_call.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+5}, in f_with_call\n' + ' return f1("x")("y")\n' + ' ~~~~~~~^^^^^\n' + f' File "{__file__}", line {lineno_f+3}, in f2\n' + ' raise RuntimeError("fail")\n' + ) + result_lines = self.get_exception(f_with_call) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_caret_for_call_unicode(self): + def f_with_call(): + def f1(a): + def f2(b): + raise RuntimeError("fail") + return f2 + return f1("ó")("á") + + lineno_f = f_with_call.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+5}, in f_with_call\n' + ' return f1("ó")("á")\n' + ' ~~~~~~~^^^^^\n' + f' File "{__file__}", line {lineno_f+3}, in f2\n' + ' raise RuntimeError("fail")\n' + ) + result_lines = self.get_exception(f_with_call) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_caret_for_call_with_spaces_and_parenthesis(self): + def f_with_binary_operator(): + def f(a): + raise RuntimeError("fail") + return f ( "x" ) + 2 + + lineno_f = f_with_binary_operator.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n' + ' return f ( "x" ) + 2\n' + ' ~~~~~~^^^^^^^^^^^\n' + f' File "{__file__}", line {lineno_f+2}, in f\n' + ' raise RuntimeError("fail")\n' + ) + result_lines = self.get_exception(f_with_binary_operator) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_caret_for_call_multiline(self): + def f_with_call(): + class C: + def y(self, a): + def f(b): + raise RuntimeError("fail") + return f + def g(x): + return C() + a = (g(1).y)( + 2 + )(3)(4) + return a + + lineno_f = f_with_call.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+8}, in f_with_call\n' + ' a = (g(1).y)(\n' + ' ~~~~~~~~~\n' + ' 2\n' + ' ~\n' + ' )(3)(4)\n' + ' ~^^^\n' + f' File "{__file__}", line {lineno_f+4}, in f\n' + ' raise RuntimeError("fail")\n' + ) + result_lines = self.get_exception(f_with_call) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_many_lines(self): + def f(): + x = 1 + if True: x += ( + "a" + + "a" + ) # test + + lineno_f = f.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+2}, in f\n' + ' if True: x += (\n' + ' ^^^^^^\n' + ' ...<2 lines>...\n' + ' ) # test\n' + ' ^\n' + ) + result_lines = self.get_exception(f) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_many_lines_no_caret(self): + def f(): + x = 1 + x += ( + "a" + + "a" + ) + + lineno_f = f.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+2}, in f\n' + ' x += (\n' + ' ...<2 lines>...\n' + ' )\n' + ) + result_lines = self.get_exception(f) + self.assertEqual(result_lines, expected_error.splitlines()) + + def test_many_lines_binary_op(self): + def f_with_binary_operator(): + b = 1 + c = "a" + a = ( + b + + b + ) + ( + c + + c + + c + ) + return a + + lineno_f = f_with_binary_operator.__code__.co_firstlineno + expected_error = ( + 'Traceback (most recent call last):\n' + f' File "{__file__}", line {self.callable_line}, in get_exception\n' + ' callable()\n' + ' ~~~~~~~~^^\n' + f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n' + ' a = (\n' + ' ~\n' + ' b +\n' + ' ~~~\n' + ' b\n' + ' ~\n' + ' ) + (\n' + ' ~~^~~\n' + ' c +\n' + ' ~~~\n' + ' ...<2 lines>...\n' + ' )\n' + ' ~\n' + ) + result_lines = self.get_exception(f_with_binary_operator) + self.assertEqual(result_lines, expected_error.splitlines()) + def test_traceback_specialization_with_syntax_error(self): bytecode = compile("1 / 0 / 1 / 2\n", TESTFN, "exec") @@ -833,6 +1157,7 @@ def test_traceback_specialization_with_syntax_error(self): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{TESTFN}", line {lineno_f}, in \n' " 1 $ 0 / 1 / 2\n" ' ^^^^^\n' @@ -855,6 +1180,7 @@ def test_traceback_very_long_line(self): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{TESTFN}", line {lineno_f}, in \n' f' {source}\n' f' {" "*len("if True: ") + "^"*256}\n' @@ -872,6 +1198,7 @@ def f_with_subscript(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_f+2}, in f_with_subscript\n' " some_dict['x']['y']['z']\n" ' ~~~~~~~~~~~~~~~~~~~^^^^^\n' @@ -891,6 +1218,7 @@ def exc(): f' + Exception Group Traceback (most recent call last):\n' f' | File "{__file__}", line {self.callable_line}, in get_exception\n' f' | callable()\n' + f' | ~~~~~~~~^^\n' f' | File "{__file__}", line {exc.__code__.co_firstlineno + 1}, in exc\n' f' | if True: raise ExceptionGroup("eg", [ValueError(1), TypeError(2)])\n' f' | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' @@ -956,6 +1284,7 @@ def g(): pass 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_applydescs + 1}, in applydecs\n' ' @dec_error\n' ' ^^^^^^^^^\n' @@ -974,6 +1303,7 @@ class A: pass 'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' ' callable()\n' + ' ~~~~~~~~^^\n' f' File "{__file__}", line {lineno_applydescs_class + 1}, in applydecs_class\n' ' @dec_error\n' ' ^^^^^^^^^\n' @@ -992,6 +1322,7 @@ def f(): "Traceback (most recent call last):", f" File \"{__file__}\", line {self.callable_line}, in get_exception", " callable()", + " ~~~~~~~~^^", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f", " .method", " ^^^^^^", @@ -1008,6 +1339,7 @@ def f(): "Traceback (most recent call last):", f" File \"{__file__}\", line {self.callable_line}, in get_exception", " callable()", + " ~~~~~~~~^^", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f", " method", ] @@ -1023,6 +1355,7 @@ def f(): "Traceback (most recent call last):", f" File \"{__file__}\", line {self.callable_line}, in get_exception", " callable()", + " ~~~~~~~~^^", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f", " . method", " ^^^^^^", @@ -1038,6 +1371,7 @@ def f(): "Traceback (most recent call last):", f" File \"{__file__}\", line {self.callable_line}, in get_exception", " callable()", + " ~~~~~~~~^^", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f", " width", ] @@ -1054,6 +1388,7 @@ def f(): "Traceback (most recent call last):", f" File \"{__file__}\", line {self.callable_line}, in get_exception", " callable()", + " ~~~~~~~~^^", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f", " raise ValueError(width)", ] @@ -1072,9 +1407,12 @@ def f(): "Traceback (most recent call last):", f" File \"{__file__}\", line {self.callable_line}, in get_exception", " callable()", + " ~~~~~~~~^^", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 4}, in f", f" print(1, www(", - f" ^^^^^^^", + f" ~~~~~~^", + f" th))", + f" ^^^^^", ] self.assertEqual(actual, expected) @@ -1089,6 +1427,7 @@ def f(): f"Traceback (most recent call last):", f" File \"{__file__}\", line {self.callable_line}, in get_exception", f" callable()", + f" ~~~~~~~~^^", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 3}, in f", f" return 说明说明 / şçöğıĤellö", f" ~~~~~~~~~^~~~~~~~~~~~", @@ -1105,6 +1444,7 @@ def f(): f"Traceback (most recent call last):", f" File \"{__file__}\", line {self.callable_line}, in get_exception", f" callable()", + f" ~~~~~~~~^^", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f", f' return "✨🐍" + func_说明说明("📗🚛",', f" ^^^^^^^^^^^^^", @@ -1127,6 +1467,7 @@ def f(): f"Traceback (most recent call last):", f" File \"{__file__}\", line {self.callable_line}, in get_exception", f" callable()", + f" ~~~~~~~~^^", f" File \"{__file__}\", line {f.__code__.co_firstlineno + 8}, in f", f' return my_dct["✨🚛✨"]["说明"]["🐍"]["说明"]["🐍🐍"]', f" ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^", @@ -1141,6 +1482,7 @@ def f(): expected = ['Traceback (most recent call last):', f' File "{__file__}", line {self.callable_line}, in get_exception', ' callable()', + ' ~~~~~~~~^^', f' File "{__file__}", line {f.__code__.co_firstlineno + 1}, in f', ' raise MemoryError()'] self.assertEqual(actual, expected) @@ -1187,6 +1529,14 @@ class TracebackFormatMixin: def some_exception(self): raise KeyError('blah') + def _filter_debug_ranges(self, expected): + return [line for line in expected if not set(line.strip()) <= set("^~")] + + def _maybe_filter_debug_ranges(self, expected): + if not self.DEBUG_RANGES: + return self._filter_debug_ranges(expected) + return expected + @cpython_only def check_traceback_format(self, cleanup_func=None): from _testcapi import traceback_print @@ -1199,6 +1549,11 @@ def check_traceback_format(self, cleanup_func=None): cleanup_func(tb.tb_next) traceback_fmt = 'Traceback (most recent call last):\n' + \ ''.join(traceback.format_tb(tb)) + # clear caret lines from traceback_fmt since internal API does + # not emit them + traceback_fmt = "\n".join( + self._filter_debug_ranges(traceback_fmt.splitlines()) + ) + "\n" file_ = StringIO() traceback_print(tb, file_) python_fmt = file_.getvalue() @@ -1291,12 +1646,16 @@ def f(): 'Traceback (most recent call last):\n' f' File "{__file__}", line {lineno_f+5}, in _check_recursive_traceback_display\n' ' f()\n' + ' ~^^\n' f' File "{__file__}", line {lineno_f+1}, in f\n' ' f()\n' + ' ~^^\n' f' File "{__file__}", line {lineno_f+1}, in f\n' ' f()\n' + ' ~^^\n' f' File "{__file__}", line {lineno_f+1}, in f\n' ' f()\n' + ' ~^^\n' # XXX: The following line changes depending on whether the tests # are run through the interactive interpreter or with -m # It also varies depending on the platform (stack size) @@ -1305,7 +1664,7 @@ def f(): 'RecursionError: maximum recursion depth exceeded\n' ) - expected = result_f.splitlines() + expected = self._maybe_filter_debug_ranges(result_f.splitlines()) actual = stderr_f.getvalue().splitlines() # Check the output text matches expectations @@ -1337,13 +1696,13 @@ def g(count=10): result_g = ( f' File "{__file__}", line {lineno_g+2}, in g\n' ' return g(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' f' File "{__file__}", line {lineno_g+2}, in g\n' ' return g(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' f' File "{__file__}", line {lineno_g+2}, in g\n' ' return g(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' ' [Previous line repeated 7 more times]\n' f' File "{__file__}", line {lineno_g+3}, in g\n' ' raise ValueError\n' @@ -1353,11 +1712,10 @@ def g(count=10): 'Traceback (most recent call last):\n' f' File "{__file__}", line {lineno_g+7}, in _check_recursive_traceback_display\n' ' g()\n' + ' ~^^\n' ) - expected = (tb_line + result_g).splitlines() + expected = self._maybe_filter_debug_ranges((tb_line + result_g).splitlines()) actual = stderr_g.getvalue().splitlines() - if not self.DEBUG_RANGES: - expected = [line for line in expected if not set(line.strip()) == {"^"}] self.assertEqual(actual, expected) # Check 2 different repetitive sections @@ -1379,23 +1737,23 @@ def h(count=10): 'Traceback (most recent call last):\n' f' File "{__file__}", line {lineno_h+7}, in _check_recursive_traceback_display\n' ' h()\n' + ' ~^^\n' f' File "{__file__}", line {lineno_h+2}, in h\n' ' return h(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' f' File "{__file__}", line {lineno_h+2}, in h\n' ' return h(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' f' File "{__file__}", line {lineno_h+2}, in h\n' ' return h(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' ' [Previous line repeated 7 more times]\n' f' File "{__file__}", line {lineno_h+3}, in h\n' ' g()\n' + ' ~^^\n' ) - expected = (result_h + result_g).splitlines() + expected = self._maybe_filter_debug_ranges((result_h + result_g).splitlines()) actual = stderr_h.getvalue().splitlines() - if not self.DEBUG_RANGES: - expected = [line for line in expected if not set(line.strip()) == {"^"}] self.assertEqual(actual, expected) # Check the boundary conditions. First, test just below the cutoff. @@ -1409,26 +1767,25 @@ def h(count=10): result_g = ( f' File "{__file__}", line {lineno_g+2}, in g\n' ' return g(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' f' File "{__file__}", line {lineno_g+2}, in g\n' ' return g(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' f' File "{__file__}", line {lineno_g+2}, in g\n' ' return g(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' f' File "{__file__}", line {lineno_g+3}, in g\n' ' raise ValueError\n' 'ValueError\n' ) tb_line = ( 'Traceback (most recent call last):\n' - f' File "{__file__}", line {lineno_g+81}, in _check_recursive_traceback_display\n' + f' File "{__file__}", line {lineno_g+80}, in _check_recursive_traceback_display\n' ' g(traceback._RECURSIVE_CUTOFF)\n' + ' ~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' ) - expected = (tb_line + result_g).splitlines() + expected = self._maybe_filter_debug_ranges((tb_line + result_g).splitlines()) actual = stderr_g.getvalue().splitlines() - if not self.DEBUG_RANGES: - expected = [line for line in expected if not set(line.strip()) == {"^"}] self.assertEqual(actual, expected) # Second, test just above the cutoff. @@ -1442,13 +1799,13 @@ def h(count=10): result_g = ( f' File "{__file__}", line {lineno_g+2}, in g\n' ' return g(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' f' File "{__file__}", line {lineno_g+2}, in g\n' ' return g(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' f' File "{__file__}", line {lineno_g+2}, in g\n' ' return g(count-1)\n' - ' ^^^^^^^^^^\n' + ' ~^^^^^^^^^\n' ' [Previous line repeated 1 more time]\n' f' File "{__file__}", line {lineno_g+3}, in g\n' ' raise ValueError\n' @@ -1456,13 +1813,12 @@ def h(count=10): ) tb_line = ( 'Traceback (most recent call last):\n' - f' File "{__file__}", line {lineno_g+114}, in _check_recursive_traceback_display\n' + f' File "{__file__}", line {lineno_g+112}, in _check_recursive_traceback_display\n' ' g(traceback._RECURSIVE_CUTOFF + 1)\n' + ' ~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n' ) - expected = (tb_line + result_g).splitlines() + expected = self._maybe_filter_debug_ranges((tb_line + result_g).splitlines()) actual = stderr_g.getvalue().splitlines() - if not self.DEBUG_RANGES: - expected = [line for line in expected if not set(line.strip()) == {"^"}] self.assertEqual(actual, expected) @requires_debug_ranges() @@ -1942,6 +2298,7 @@ def exc(): f' + Exception Group Traceback (most recent call last):\n' f' | File "{__file__}", line {self.callable_line}, in get_exception\n' f' | exception_or_callable()\n' + f' | ~~~~~~~~~~~~~~~~~~~~~^^\n' f' | File "{__file__}", line {exc.__code__.co_firstlineno + 1}, in exc\n' f' | raise ExceptionGroup("eg", [ValueError(1), TypeError(2)])\n' f' | ExceptionGroup: eg (2 sub-exceptions)\n' @@ -1977,6 +2334,7 @@ def exc(): f' + Exception Group Traceback (most recent call last):\n' f' | File "{__file__}", line {self.callable_line}, in get_exception\n' f' | exception_or_callable()\n' + f' | ~~~~~~~~~~~~~~~~~~~~~^^\n' f' | File "{__file__}", line {exc.__code__.co_firstlineno + 5}, in exc\n' f' | raise EG("eg2", [ValueError(3), TypeError(4)]) from e\n' f' | ExceptionGroup: eg2 (2 sub-exceptions)\n' @@ -2028,6 +2386,7 @@ def exc(): f'Traceback (most recent call last):\n' f' File "{__file__}", line {self.callable_line}, in get_exception\n' f' exception_or_callable()\n' + f' ~~~~~~~~~~~~~~~~~~~~~^^\n' f' File "{__file__}", line {exc.__code__.co_firstlineno + 8}, in exc\n' f' raise ImportError(5)\n' f'ImportError: 5\n') @@ -2074,6 +2433,7 @@ def exc(): f' + Exception Group Traceback (most recent call last):\n' f' | File "{__file__}", line {self.callable_line}, in get_exception\n' f' | exception_or_callable()\n' + f' | ~~~~~~~~~~~~~~~~~~~~~^^\n' f' | File "{__file__}", line {exc.__code__.co_firstlineno + 11}, in exc\n' f' | raise EG("top", [VE(5)])\n' f' | ExceptionGroup: top (1 sub-exception)\n' @@ -2233,6 +2593,7 @@ def exc(): expected = (f' + Exception Group Traceback (most recent call last):\n' f' | File "{__file__}", line {self.callable_line}, in get_exception\n' f' | exception_or_callable()\n' + f' | ~~~~~~~~~~~~~~~~~~~~~^^\n' f' | File "{__file__}", line {exc.__code__.co_firstlineno + 9}, in exc\n' f' | raise ExceptionGroup("nested", excs)\n' f' | ExceptionGroup: nested (2 sub-exceptions)\n' @@ -2284,6 +2645,7 @@ def exc(): expected = (f' + Exception Group Traceback (most recent call last):\n' f' | File "{__file__}", line {self.callable_line}, in get_exception\n' f' | exception_or_callable()\n' + f' | ~~~~~~~~~~~~~~~~~~~~~^^\n' f' | File "{__file__}", line {exc.__code__.co_firstlineno + 10}, in exc\n' f' | raise ExceptionGroup("nested", excs)\n' f' | ExceptionGroup: nested (2 sub-exceptions)\n' @@ -2552,7 +2914,7 @@ def test_basics(self): def test_lazy_lines(self): linecache.clearcache() f = traceback.FrameSummary("f", 1, "dummy", lookup_line=False) - self.assertEqual(None, f._line) + self.assertEqual(None, f._lines) linecache.lazycache("f", globals()) self.assertEqual( '"""Test cases for traceback module"""', @@ -3143,6 +3505,7 @@ def test_exception_group_format(self): f' | Traceback (most recent call last):', f' | File "{__file__}", line {lno_g+9}, in _get_exception_group', f' | f()', + f' | ~^^', f' | File "{__file__}", line {lno_f+1}, in f', f' | 1/0', f' | ~^~', @@ -3151,6 +3514,7 @@ def test_exception_group_format(self): f' | Traceback (most recent call last):', f' | File "{__file__}", line {lno_g+13}, in _get_exception_group', f' | g(42)', + f' | ~^^^^', f' | File "{__file__}", line {lno_g+1}, in g', f' | raise ValueError(v)', f' | ValueError: 42', @@ -3159,6 +3523,7 @@ def test_exception_group_format(self): f' | Traceback (most recent call last):', f' | File "{__file__}", line {lno_g+20}, in _get_exception_group', f' | g(24)', + f' | ~^^^^', f' | File "{__file__}", line {lno_g+1}, in g', f' | raise ValueError(v)', f' | ValueError: 24', diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 232480c46e0a002..50b0f3fff04c57b 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1260,8 +1260,8 @@ def test_conflicting_envvar_and_command_line(self): b" File \"\", line 1, in ", b' import sys, warnings; sys.stdout.write(str(sys.warnoptions)); warnings.w' b"arn('Message', DeprecationWarning)", - b' ^^^^^^^^^^' - b'^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^', + b' ~~~~~~~~~~' + b'~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^', b"DeprecationWarning: Message"]) def test_default_filter_configuration(self): diff --git a/Lib/traceback.py b/Lib/traceback.py index 5d83f85ac3edb0a..a0485a7023d07d7 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -274,7 +274,7 @@ class FrameSummary: """ __slots__ = ('filename', 'lineno', 'end_lineno', 'colno', 'end_colno', - 'name', '_line', 'locals') + 'name', '_lines', '_lines_dedented', 'locals') def __init__(self, filename, lineno, name, *, lookup_line=True, locals=None, line=None, @@ -290,15 +290,16 @@ def __init__(self, filename, lineno, name, *, lookup_line=True, """ self.filename = filename self.lineno = lineno + self.end_lineno = lineno if end_lineno is None else end_lineno + self.colno = colno + self.end_colno = end_colno self.name = name - self._line = line + self._lines = line + self._lines_dedented = None if lookup_line: self.line self.locals = {k: _safe_string(v, 'local', func=repr) for k, v in locals.items()} if locals else None - self.end_lineno = end_lineno - self.colno = colno - self.end_colno = end_colno def __eq__(self, other): if isinstance(other, FrameSummary): @@ -323,19 +324,39 @@ def __repr__(self): def __len__(self): return 4 + def _set_lines(self): + if ( + self._lines is None + and self.lineno is not None + and self.end_lineno is not None + ): + lines = [] + for lineno in range(self.lineno, self.end_lineno + 1): + # treat errors (empty string) and empty lines (newline) as the same + lines.append(linecache.getline(self.filename, lineno).rstrip()) + self._lines = "\n".join(lines) + "\n" + @property - def _original_line(self): + def _original_lines(self): # Returns the line as-is from the source, without modifying whitespace. - self.line - return self._line + self._set_lines() + return self._lines + + @property + def _dedented_lines(self): + # Returns _original_lines, but dedented + self._set_lines() + if self._lines_dedented is None and self._lines is not None: + self._lines_dedented = textwrap.dedent(self._lines) + return self._lines_dedented @property def line(self): - if self._line is None: - if self.lineno is None: - return None - self._line = linecache.getline(self.filename, self.lineno) - return self._line.strip() + self._set_lines() + if self._lines is None: + return None + # return only the first line, stripped + return self._lines.partition("\n")[0].strip() def walk_stack(f): @@ -487,56 +508,135 @@ def format_frame_summary(self, frame_summary): filename = "" row.append(' File "{}", line {}, in {}\n'.format( filename, frame_summary.lineno, frame_summary.name)) - if frame_summary.line: - stripped_line = frame_summary.line.strip() - row.append(' {}\n'.format(stripped_line)) - - line = frame_summary._original_line - orig_line_len = len(line) - frame_line_len = len(frame_summary.line.lstrip()) - stripped_characters = orig_line_len - frame_line_len + if frame_summary._dedented_lines and frame_summary._dedented_lines.strip(): if ( - frame_summary.colno is not None - and frame_summary.end_colno is not None + frame_summary.colno is None or + frame_summary.end_colno is None ): - start_offset = _byte_offset_to_character_offset( - line, frame_summary.colno) - end_offset = _byte_offset_to_character_offset( - line, frame_summary.end_colno) - code_segment = line[start_offset:end_offset] + # only output first line if column information is missing + row.append(textwrap.indent(frame_summary.line, ' ') + "\n") + else: + # get first and last line + all_lines_original = frame_summary._original_lines.splitlines() + first_line = all_lines_original[0] + # assume all_lines_original has enough lines (since we constructed it) + last_line = all_lines_original[frame_summary.end_lineno - frame_summary.lineno] + + # character index of the start/end of the instruction + start_offset = _byte_offset_to_character_offset(first_line, frame_summary.colno) + end_offset = _byte_offset_to_character_offset(last_line, frame_summary.end_colno) + + all_lines = frame_summary._dedented_lines.splitlines()[ + :frame_summary.end_lineno - frame_summary.lineno + 1 + ] + # adjust start/end offset based on dedent + dedent_characters = len(first_line) - len(all_lines[0]) + start_offset = max(0, start_offset - dedent_characters) + end_offset = max(0, end_offset - dedent_characters) + + # When showing this on a terminal, some of the non-ASCII characters + # might be rendered as double-width characters, so we need to take + # that into account when calculating the length of the line. + dp_start_offset = _display_width(all_lines[0], offset=start_offset) + dp_end_offset = _display_width(all_lines[-1], offset=end_offset) + + # get exact code segment corresponding to the instruction + segment = "\n".join(all_lines) + segment = segment[start_offset:len(segment) - (len(all_lines[-1]) - end_offset)] + + # attempt to parse for anchors anchors = None - if frame_summary.lineno == frame_summary.end_lineno: - with suppress(Exception): - anchors = _extract_caret_anchors_from_line_segment(code_segment) - else: - # Don't count the newline since the anchors only need to - # go up until the last character of the line. - end_offset = len(line.rstrip()) - - # show indicators if primary char doesn't span the frame line - if end_offset - start_offset < len(stripped_line) or ( - anchors and anchors.right_start_offset - anchors.left_end_offset > 0): - # When showing this on a terminal, some of the non-ASCII characters - # might be rendered as double-width characters, so we need to take - # that into account when calculating the length of the line. - dp_start_offset = _display_width(line, start_offset) + 1 - dp_end_offset = _display_width(line, end_offset) + 1 - - row.append(' ') - row.append(' ' * (dp_start_offset - stripped_characters)) - - if anchors: - dp_left_end_offset = _display_width(code_segment, anchors.left_end_offset) - dp_right_start_offset = _display_width(code_segment, anchors.right_start_offset) - row.append(anchors.primary_char * dp_left_end_offset) - row.append(anchors.secondary_char * (dp_right_start_offset - dp_left_end_offset)) - row.append(anchors.primary_char * (dp_end_offset - dp_start_offset - dp_right_start_offset)) - else: - row.append('^' * (dp_end_offset - dp_start_offset)) + with suppress(Exception): + anchors = _extract_caret_anchors_from_line_segment(segment) + + # only use carets if there are anchors or the carets do not span all lines + show_carets = False + if anchors or all_lines[0][:start_offset].lstrip() or all_lines[-1][end_offset:].rstrip(): + show_carets = True + + result = [] + + # only display first line, last line, and lines around anchor start/end + significant_lines = {0, len(all_lines) - 1} + + anchors_left_end_offset = 0 + anchors_right_start_offset = 0 + primary_char = "^" + secondary_char = "^" + if anchors: + anchors_left_end_offset = anchors.left_end_offset + anchors_right_start_offset = anchors.right_start_offset + # computed anchor positions do not take start_offset into account, + # so account for it here + if anchors.left_end_lineno == 0: + anchors_left_end_offset += start_offset + if anchors.right_start_lineno == 0: + anchors_right_start_offset += start_offset + + # account for display width + anchors_left_end_offset = _display_width( + all_lines[anchors.left_end_lineno], offset=anchors_left_end_offset + ) + anchors_right_start_offset = _display_width( + all_lines[anchors.right_start_lineno], offset=anchors_right_start_offset + ) - row.append('\n') + primary_char = anchors.primary_char + secondary_char = anchors.secondary_char + significant_lines.update( + range(anchors.left_end_lineno - 1, anchors.left_end_lineno + 2) + ) + significant_lines.update( + range(anchors.right_start_lineno - 1, anchors.right_start_lineno + 2) + ) + # remove bad line numbers + significant_lines.discard(-1) + significant_lines.discard(len(all_lines)) + + def output_line(lineno): + """output all_lines[lineno] along with carets""" + result.append(all_lines[lineno] + "\n") + if not show_carets: + return + num_spaces = len(all_lines[lineno]) - len(all_lines[lineno].lstrip()) + carets = [] + num_carets = dp_end_offset if lineno == len(all_lines) - 1 else _display_width(all_lines[lineno]) + # compute caret character for each position + for col in range(num_carets): + if col < num_spaces or (lineno == 0 and col < dp_start_offset): + # before first non-ws char of the line, or before start of instruction + carets.append(' ') + elif anchors and ( + lineno > anchors.left_end_lineno or + (lineno == anchors.left_end_lineno and col >= anchors_left_end_offset) + ) and ( + lineno < anchors.right_start_lineno or + (lineno == anchors.right_start_lineno and col < anchors_right_start_offset) + ): + # within anchors + carets.append(secondary_char) + else: + carets.append(primary_char) + result.append("".join(carets) + "\n") + + # display significant lines + sig_lines_list = sorted(significant_lines) + for i, lineno in enumerate(sig_lines_list): + if i: + linediff = lineno - sig_lines_list[i - 1] + if linediff == 2: + # 1 line in between - just output it + output_line(lineno - 1) + elif linediff > 2: + # > 1 line in between - abbreviate + result.append(f"...<{linediff - 1} lines>...\n") + output_line(lineno) + + row.append( + textwrap.indent(textwrap.dedent("".join(result)), ' ', lambda line: True) + ) if frame_summary.locals: for name, value in sorted(frame_summary.locals.items()): row.append(' {name} = {value}\n'.format(name=name, value=value)) @@ -599,7 +699,9 @@ def _byte_offset_to_character_offset(str, offset): _Anchors = collections.namedtuple( "_Anchors", [ + "left_end_lineno", "left_end_offset", + "right_start_lineno", "right_start_offset", "primary_char", "secondary_char", @@ -608,59 +710,161 @@ def _byte_offset_to_character_offset(str, offset): ) def _extract_caret_anchors_from_line_segment(segment): + """ + Given source code `segment` corresponding to a FrameSummary, determine: + - for binary ops, the location of the binary op + - for indexing and function calls, the location of the brackets. + `segment` is expected to be a valid Python expression. + """ import ast try: - tree = ast.parse(segment) + # Without parentheses, `segment` is parsed as a statement. + # Binary ops, subscripts, and calls are expressions, so + # we can wrap them with parentheses to parse them as + # (possibly multi-line) expressions. + # e.g. if we try to highlight the addition in + # x = ( + # a + + # b + # ) + # then we would ast.parse + # a + + # b + # which is not a valid statement because of the newline. + # Adding brackets makes it a valid expression. + # ( + # a + + # b + # ) + # Line locations will be different than the original, + # which is taken into account later on. + tree = ast.parse(f"(\n{segment}\n)") except SyntaxError: return None if len(tree.body) != 1: return None - normalize = lambda offset: _byte_offset_to_character_offset(segment, offset) + lines = segment.splitlines() + + def normalize(lineno, offset): + """Get character index given byte offset""" + return _byte_offset_to_character_offset(lines[lineno], offset) + + def next_valid_char(lineno, col): + """Gets the next valid character index in `lines`, if + the current location is not valid. Handles empty lines. + """ + while lineno < len(lines) and col >= len(lines[lineno]): + col = 0 + lineno += 1 + assert lineno < len(lines) and col < len(lines[lineno]) + return lineno, col + + def increment(lineno, col): + """Get the next valid character index in `lines`.""" + col += 1 + lineno, col = next_valid_char(lineno, col) + return lineno, col + + def nextline(lineno, col): + """Get the next valid character at least on the next line""" + col = 0 + lineno += 1 + lineno, col = next_valid_char(lineno, col) + return lineno, col + + def increment_until(lineno, col, stop): + """Get the next valid non-"\\#" character that satisfies the `stop` predicate""" + while True: + ch = lines[lineno][col] + if ch in "\\#": + lineno, col = nextline(lineno, col) + elif not stop(ch): + lineno, col = increment(lineno, col) + else: + break + return lineno, col + + def setup_positions(expr, force_valid=True): + """Get the lineno/col position of the end of `expr`. If `force_valid` is True, + forces the position to be a valid character (e.g. if the position is beyond the + end of the line, move to the next line) + """ + # -2 since end_lineno is 1-indexed and because we added an extra + # bracket + newline to `segment` when calling ast.parse + lineno = expr.end_lineno - 2 + col = normalize(lineno, expr.end_col_offset) + return next_valid_char(lineno, col) if force_valid else (lineno, col) + statement = tree.body[0] match statement: case ast.Expr(expr): match expr: case ast.BinOp(): - operator_start = normalize(expr.left.end_col_offset) - operator_end = normalize(expr.right.col_offset) - operator_str = segment[operator_start:operator_end] - operator_offset = len(operator_str) - len(operator_str.lstrip()) + # ast gives these locations for BinOp subexpressions + # ( left_expr ) + ( right_expr ) + # left^^^^^ right^^^^^ + lineno, col = setup_positions(expr.left) - left_anchor = expr.left.end_col_offset + operator_offset - right_anchor = left_anchor + 1 + # First operator character is the first non-space/')' character + lineno, col = increment_until(lineno, col, lambda x: not x.isspace() and x != ')') + + # binary op is 1 or 2 characters long, on the same line, + # before the right subexpression + right_col = col + 1 if ( - operator_offset + 1 < len(operator_str) - and not operator_str[operator_offset + 1].isspace() + right_col < len(lines[lineno]) + and ( + # operator char should not be in the right subexpression + expr.right.lineno - 2 > lineno or + right_col < normalize(expr.right.lineno - 2, expr.right.col_offset) + ) + and not (ch := lines[lineno][right_col]).isspace() + and ch not in "\\#" ): - right_anchor += 1 + right_col += 1 - while left_anchor < len(segment) and ((ch := segment[left_anchor]).isspace() or ch in ")#"): - left_anchor += 1 - right_anchor += 1 - return _Anchors(normalize(left_anchor), normalize(right_anchor)) + # right_col can be invalid since it is exclusive + return _Anchors(lineno, col, lineno, right_col) case ast.Subscript(): - left_anchor = normalize(expr.value.end_col_offset) - right_anchor = normalize(expr.slice.end_col_offset + 1) - while left_anchor < len(segment) and ((ch := segment[left_anchor]).isspace() or ch != "["): - left_anchor += 1 - while right_anchor < len(segment) and ((ch := segment[right_anchor]).isspace() or ch != "]"): - right_anchor += 1 - if right_anchor < len(segment): - right_anchor += 1 - return _Anchors(left_anchor, right_anchor) + # ast gives these locations for value and slice subexpressions + # ( value_expr ) [ slice_expr ] + # value^^^^^ slice^^^^^ + # subscript^^^^^^^^^^^^^^^^^^^^ + + # find left bracket + left_lineno, left_col = setup_positions(expr.value) + left_lineno, left_col = increment_until(left_lineno, left_col, lambda x: x == '[') + # find right bracket (final character of expression) + right_lineno, right_col = setup_positions(expr, force_valid=False) + return _Anchors(left_lineno, left_col, right_lineno, right_col) + case ast.Call(): + # ast gives these locations for function call expressions + # ( func_expr ) (args, kwargs) + # func^^^^^ + # call^^^^^^^^^^^^^^^^^^^^^^^^ + + # find left bracket + left_lineno, left_col = setup_positions(expr.func) + left_lineno, left_col = increment_until(left_lineno, left_col, lambda x: x == '(') + # find right bracket (final character of expression) + right_lineno, right_col = setup_positions(expr, force_valid=False) + return _Anchors(left_lineno, left_col, right_lineno, right_col) return None _WIDE_CHAR_SPECIFIERS = "WF" -def _display_width(line, offset): +def _display_width(line, offset=None): """Calculate the extra amount of width space the given source code segment might take if it were to be displayed on a fixed width output device. Supports wide unicode characters and emojis.""" + if offset is None: + offset = len(line) + # Fast track for ASCII-only strings if line.isascii(): return offset diff --git a/Misc/NEWS.d/next/Library/2023-11-15-01-36-04.gh-issue-106922.qslOVH.rst b/Misc/NEWS.d/next/Library/2023-11-15-01-36-04.gh-issue-106922.qslOVH.rst new file mode 100644 index 000000000000000..b68e75ab87cd0b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-15-01-36-04.gh-issue-106922.qslOVH.rst @@ -0,0 +1 @@ +Display multiple lines with ``traceback`` when errors span multiple lines. From a74daba7ca8b68f47284d82d4604721b8748bbde Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sat, 2 Dec 2023 16:13:44 +0300 Subject: [PATCH 05/87] gh-112316: Improve docs of `inspect.signature` and `Signature.from_callable` (#112317) Co-authored-by: Alex Waygood --- Doc/library/inspect.rst | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index b463c0b6d0e4020..94c5d1c8979afd7 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -620,7 +620,7 @@ function. .. function:: signature(callable, *, follow_wrapped=True, globals=None, locals=None, eval_str=False) - Return a :class:`Signature` object for the given ``callable``:: + Return a :class:`Signature` object for the given *callable*:: >>> from inspect import signature >>> def foo(a, *, b:int, **kwargs): @@ -646,29 +646,30 @@ function. For objects defined in modules using stringized annotations (``from __future__ import annotations``), :func:`signature` will attempt to automatically un-stringize the annotations using - :func:`inspect.get_annotations()`. The - ``global``, ``locals``, and ``eval_str`` parameters are passed - into :func:`inspect.get_annotations()` when resolving the - annotations; see the documentation for :func:`inspect.get_annotations()` + :func:`get_annotations`. The + *global*, *locals*, and *eval_str* parameters are passed + into :func:`get_annotations` when resolving the + annotations; see the documentation for :func:`get_annotations` for instructions on how to use these parameters. Raises :exc:`ValueError` if no signature can be provided, and :exc:`TypeError` if that type of object is not supported. Also, - if the annotations are stringized, and ``eval_str`` is not false, - the ``eval()`` call(s) to un-stringize the annotations could - potentially raise any kind of exception. + if the annotations are stringized, and *eval_str* is not false, + the ``eval()`` call(s) to un-stringize the annotations in :func:`get_annotations` + could potentially raise any kind of exception. A slash(/) in the signature of a function denotes that the parameters prior to it are positional-only. For more info, see :ref:`the FAQ entry on positional-only parameters `. - .. versionadded:: 3.5 - ``follow_wrapped`` parameter. Pass ``False`` to get a signature of - ``callable`` specifically (``callable.__wrapped__`` will not be used to + .. versionchanged:: 3.5 + The *follow_wrapped* parameter was added. + Pass ``False`` to get a signature of + *callable* specifically (``callable.__wrapped__`` will not be used to unwrap decorated callables.) - .. versionadded:: 3.10 - ``globals``, ``locals``, and ``eval_str`` parameters. + .. versionchanged:: 3.10 + The *globals*, *locals*, and *eval_str* parameters were added. .. note:: @@ -752,12 +753,10 @@ function. Signature objects are also supported by generic function :func:`copy.replace`. - .. classmethod:: Signature.from_callable(obj, *, follow_wrapped=True, globalns=None, localns=None) + .. classmethod:: Signature.from_callable(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=False) Return a :class:`Signature` (or its subclass) object for a given callable - ``obj``. Pass ``follow_wrapped=False`` to get a signature of ``obj`` - without unwrapping its ``__wrapped__`` chain. ``globalns`` and - ``localns`` will be used as the namespaces when resolving annotations. + *obj*. This method simplifies subclassing of :class:`Signature`:: @@ -770,8 +769,8 @@ function. .. versionadded:: 3.5 - .. versionadded:: 3.10 - ``globalns`` and ``localns`` parameters. + .. versionchanged:: 3.10 + The *globals*, *locals*, and *eval_str* parameters were added. .. class:: Parameter(name, kind, *, default=Parameter.empty, annotation=Parameter.empty) From a35a30509820f956d6feeaa0dbf42e9ca82c12bb Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sat, 2 Dec 2023 19:10:19 +0300 Subject: [PATCH 06/87] gh-112618: Make `Annotated` cache typed (#112619) Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 34 +++++++++++++++++++ Lib/typing.py | 11 +++--- ...-12-02-12-55-17.gh-issue-112618.7_FT8-.rst | 2 ++ 3 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-02-12-55-17.gh-issue-112618.7_FT8-.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 4fbb410f26ab8d3..3572df7737f6526 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -8675,6 +8675,40 @@ class X(Annotated[int, (1, 10)]): ... self.assertEqual(X.__mro__, (X, int, object), "Annotated should be transparent.") + def test_annotated_cached_with_types(self): + class A(str): ... + class B(str): ... + + field_a1 = Annotated[str, A("X")] + field_a2 = Annotated[str, B("X")] + a1_metadata = field_a1.__metadata__[0] + a2_metadata = field_a2.__metadata__[0] + + self.assertIs(type(a1_metadata), A) + self.assertEqual(a1_metadata, A("X")) + self.assertIs(type(a2_metadata), B) + self.assertEqual(a2_metadata, B("X")) + self.assertIsNot(type(a1_metadata), type(a2_metadata)) + + field_b1 = Annotated[str, A("Y")] + field_b2 = Annotated[str, B("Y")] + b1_metadata = field_b1.__metadata__[0] + b2_metadata = field_b2.__metadata__[0] + + self.assertIs(type(b1_metadata), A) + self.assertEqual(b1_metadata, A("Y")) + self.assertIs(type(b2_metadata), B) + self.assertEqual(b2_metadata, B("Y")) + self.assertIsNot(type(b1_metadata), type(b2_metadata)) + + field_c1 = Annotated[int, 1] + field_c2 = Annotated[int, 1.0] + field_c3 = Annotated[int, True] + + self.assertIs(type(field_c1.__metadata__[0]), int) + self.assertIs(type(field_c2.__metadata__[0]), float) + self.assertIs(type(field_c3.__metadata__[0]), bool) + class TypeAliasTests(BaseTestCase): def test_canonical_usage_with_variable_annotation(self): diff --git a/Lib/typing.py b/Lib/typing.py index b3af701f8d54373..4c19aadabe3b87f 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -490,7 +490,7 @@ def __getitem__(self, parameters): return self._getitem(self, parameters) -class _LiteralSpecialForm(_SpecialForm, _root=True): +class _TypedCacheSpecialForm(_SpecialForm, _root=True): def __getitem__(self, parameters): if not isinstance(parameters, tuple): parameters = (parameters,) @@ -723,7 +723,7 @@ def Optional(self, parameters): arg = _type_check(parameters, f"{self} requires a single type.") return Union[arg, type(None)] -@_LiteralSpecialForm +@_TypedCacheSpecialForm @_tp_cache(typed=True) def Literal(self, *parameters): """Special typing form to define literal types (a.k.a. value types). @@ -2005,8 +2005,9 @@ def __mro_entries__(self, bases): return (self.__origin__,) -@_SpecialForm -def Annotated(self, params): +@_TypedCacheSpecialForm +@_tp_cache(typed=True) +def Annotated(self, *params): """Add context-specific metadata to a type. Example: Annotated[int, runtime_check.Unsigned] indicates to the @@ -2053,7 +2054,7 @@ def Annotated(self, params): where T1, T2 etc. are TypeVars, which would be invalid, because only one type should be passed to Annotated. """ - if not isinstance(params, tuple) or len(params) < 2: + if len(params) < 2: raise TypeError("Annotated[...] should be used " "with at least two arguments (a type and an " "annotation).") diff --git a/Misc/NEWS.d/next/Library/2023-12-02-12-55-17.gh-issue-112618.7_FT8-.rst b/Misc/NEWS.d/next/Library/2023-12-02-12-55-17.gh-issue-112618.7_FT8-.rst new file mode 100644 index 000000000000000..c732de15609c96e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-02-12-55-17.gh-issue-112618.7_FT8-.rst @@ -0,0 +1,2 @@ +Fix a caching bug relating to :data:`typing.Annotated`. +``Annotated[str, True]`` is no longer identical to ``Annotated[str, 1]``. From 0229d2a9b1d6ce6daa6a773f92e3754e7dc86d50 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 2 Dec 2023 19:41:40 +0200 Subject: [PATCH 07/87] Docs: Use sphinx-notfound-page to show a nicer 404 page (#111084) --- Doc/conf.py | 8 +++++++- Doc/requirements.txt | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Doc/conf.py b/Doc/conf.py index f1b411126c4e871..be2a86e12fa2e4f 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -24,7 +24,13 @@ 'sphinx.ext.doctest', ] -# Skip if downstream redistributors haven't installed it +# Skip if downstream redistributors haven't installed them +try: + import notfound.extension +except ImportError: + pass +else: + extensions.append('notfound.extension') try: import sphinxext.opengraph except ImportError: diff --git a/Doc/requirements.txt b/Doc/requirements.txt index ce87be2d3928245..04334fd5a464d4d 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -13,6 +13,7 @@ blurb sphinx-autobuild sphinxext-opengraph==0.7.5 +sphinx-notfound-page==1.0.0 # The theme used by the documentation is stored separately, so we need # to install that as well. From a9574c68f04695eecd19866faaf4cdee5965bc70 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sun, 3 Dec 2023 02:39:43 +0300 Subject: [PATCH 08/87] gh-112139: Add `inspect.Signature.format` and use it in `pydoc` (#112143) Co-authored-by: Jelle Zijlstra --- Doc/library/inspect.rst | 11 +++ Lib/inspect.py | 12 +++ Lib/pydoc.py | 5 +- Lib/test/test_inspect/test_inspect.py | 96 +++++++++++++++++-- Lib/test/test_pydoc.py | 89 +++++++++++++++++ ...-11-16-10-42-15.gh-issue-112139.WpHosf.rst | 3 + 6 files changed, 205 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-16-10-42-15.gh-issue-112139.WpHosf.rst diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 94c5d1c8979afd7..08522510f9ab444 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -753,6 +753,17 @@ function. Signature objects are also supported by generic function :func:`copy.replace`. + .. method:: format(*, max_width=None) + + Convert signature object to string. + + If *max_width* is passed, the method will attempt to fit + the signature into lines of at most *max_width* characters. + If the signature is longer than *max_width*, + all parameters will be on separate lines. + + .. versionadded:: 3.13 + .. classmethod:: Signature.from_callable(obj, *, follow_wrapped=True, globals=None, locals=None, eval_str=False) Return a :class:`Signature` (or its subclass) object for a given callable diff --git a/Lib/inspect.py b/Lib/inspect.py index aaa22bef8966028..079385abbc7bb23 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -3316,6 +3316,16 @@ def __repr__(self): return '<{} {}>'.format(self.__class__.__name__, self) def __str__(self): + return self.format() + + def format(self, *, max_width=None): + """Convert signature object to string. + + If *max_width* integer is passed, + signature will try to fit into the *max_width*. + If signature is longer than *max_width*, + all parameters will be on separate lines. + """ result = [] render_pos_only_separator = False render_kw_only_separator = True @@ -3353,6 +3363,8 @@ def __str__(self): result.append('/') rendered = '({})'.format(', '.join(result)) + if max_width is not None and len(rendered) > max_width: + rendered = '(\n {}\n)'.format(',\n '.join(result)) if self.return_annotation is not _empty: anno = formatannotation(self.return_annotation) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index be41592cc64bad5..83c74a75cd1c004 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -201,7 +201,10 @@ def _getargspec(object): try: signature = inspect.signature(object) if signature: - return str(signature) + name = getattr(object, '__name__', '') + # function are always single-line and should not be formatted + max_width = (80 - len(name)) if name != '' else None + return signature.format(max_width=max_width) except (ValueError, TypeError): argspec = getattr(object, '__text_signature__', None) if argspec: diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index e75682f881ab346..09d50859970c99d 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -3796,26 +3796,36 @@ def foo(a:int=1, *, b, c=None, **kwargs) -> 42: pass self.assertEqual(str(inspect.signature(foo)), '(a: int = 1, *, b, c=None, **kwargs) -> 42') + self.assertEqual(str(inspect.signature(foo)), + inspect.signature(foo).format()) def foo(a:int=1, *args, b, c=None, **kwargs) -> 42: pass self.assertEqual(str(inspect.signature(foo)), '(a: int = 1, *args, b, c=None, **kwargs) -> 42') + self.assertEqual(str(inspect.signature(foo)), + inspect.signature(foo).format()) def foo(): pass self.assertEqual(str(inspect.signature(foo)), '()') + self.assertEqual(str(inspect.signature(foo)), + inspect.signature(foo).format()) def foo(a: list[str]) -> tuple[str, float]: pass self.assertEqual(str(inspect.signature(foo)), '(a: list[str]) -> tuple[str, float]') + self.assertEqual(str(inspect.signature(foo)), + inspect.signature(foo).format()) from typing import Tuple def foo(a: list[str]) -> Tuple[str, float]: pass self.assertEqual(str(inspect.signature(foo)), '(a: list[str]) -> Tuple[str, float]') + self.assertEqual(str(inspect.signature(foo)), + inspect.signature(foo).format()) def test_signature_str_positional_only(self): P = inspect.Parameter @@ -3826,19 +3836,85 @@ def test(a_po, /, *, b, **kwargs): self.assertEqual(str(inspect.signature(test)), '(a_po, /, *, b, **kwargs)') + self.assertEqual(str(inspect.signature(test)), + inspect.signature(test).format()) + + test = S(parameters=[P('foo', P.POSITIONAL_ONLY)]) + self.assertEqual(str(test), '(foo, /)') + self.assertEqual(str(test), test.format()) - self.assertEqual(str(S(parameters=[P('foo', P.POSITIONAL_ONLY)])), - '(foo, /)') + test = S(parameters=[P('foo', P.POSITIONAL_ONLY), + P('bar', P.VAR_KEYWORD)]) + self.assertEqual(str(test), '(foo, /, **bar)') + self.assertEqual(str(test), test.format()) - self.assertEqual(str(S(parameters=[ - P('foo', P.POSITIONAL_ONLY), - P('bar', P.VAR_KEYWORD)])), - '(foo, /, **bar)') + test = S(parameters=[P('foo', P.POSITIONAL_ONLY), + P('bar', P.VAR_POSITIONAL)]) + self.assertEqual(str(test), '(foo, /, *bar)') + self.assertEqual(str(test), test.format()) - self.assertEqual(str(S(parameters=[ - P('foo', P.POSITIONAL_ONLY), - P('bar', P.VAR_POSITIONAL)])), - '(foo, /, *bar)') + def test_signature_format(self): + from typing import Annotated, Literal + + def func(x: Annotated[int, 'meta'], y: Literal['a', 'b'], z: 'LiteralString'): + pass + + expected_singleline = "(x: Annotated[int, 'meta'], y: Literal['a', 'b'], z: 'LiteralString')" + expected_multiline = """( + x: Annotated[int, 'meta'], + y: Literal['a', 'b'], + z: 'LiteralString' +)""" + self.assertEqual( + inspect.signature(func).format(), + expected_singleline, + ) + self.assertEqual( + inspect.signature(func).format(max_width=None), + expected_singleline, + ) + self.assertEqual( + inspect.signature(func).format(max_width=len(expected_singleline)), + expected_singleline, + ) + self.assertEqual( + inspect.signature(func).format(max_width=len(expected_singleline) - 1), + expected_multiline, + ) + self.assertEqual( + inspect.signature(func).format(max_width=0), + expected_multiline, + ) + self.assertEqual( + inspect.signature(func).format(max_width=-1), + expected_multiline, + ) + + def test_signature_format_all_arg_types(self): + from typing import Annotated, Literal + + def func( + x: Annotated[int, 'meta'], + /, + y: Literal['a', 'b'], + *, + z: 'LiteralString', + **kwargs: object, + ) -> None: + pass + + expected_multiline = """( + x: Annotated[int, 'meta'], + /, + y: Literal['a', 'b'], + *, + z: 'LiteralString', + **kwargs: object +) -> None""" + self.assertEqual( + inspect.signature(func).format(max_width=-1), + expected_multiline, + ) def test_signature_replace_parameters(self): def test(a, b) -> 42: diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 745717f492e07a7..eb50510e12b7b64 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -870,6 +870,95 @@ class B(A) for expected_line in expected_lines: self.assertIn(expected_line, as_text) + def test_long_signatures(self): + from collections.abc import Callable + from typing import Literal, Annotated + + class A: + def __init__(self, + arg1: Callable[[int, int, int], str], + arg2: Literal['some value', 'other value'], + arg3: Annotated[int, 'some docs about this type'], + ) -> None: + ... + + doc = pydoc.render_doc(A) + # clean up the extra text formatting that pydoc performs + doc = re.sub('\b.', '', doc) + self.assertEqual(doc, '''Python Library Documentation: class A in module %s + +class A(builtins.object) + | A( + | arg1: collections.abc.Callable[[int, int, int], str], + | arg2: Literal['some value', 'other value'], + | arg3: Annotated[int, 'some docs about this type'] + | ) -> None + | + | Methods defined here: + | + | __init__( + | self, + | arg1: collections.abc.Callable[[int, int, int], str], + | arg2: Literal['some value', 'other value'], + | arg3: Annotated[int, 'some docs about this type'] + | ) -> None + | + | ---------------------------------------------------------------------- + | Data descriptors defined here: + | + | __dict__ + | dictionary for instance variables + | + | __weakref__ + | list of weak references to the object +''' % __name__) + + def func( + arg1: Callable[[Annotated[int, 'Some doc']], str], + arg2: Literal[1, 2, 3, 4, 5, 6, 7, 8], + ) -> Annotated[int, 'Some other']: + ... + + doc = pydoc.render_doc(func) + # clean up the extra text formatting that pydoc performs + doc = re.sub('\b.', '', doc) + self.assertEqual(doc, '''Python Library Documentation: function func in module %s + +func( + arg1: collections.abc.Callable[[typing.Annotated[int, 'Some doc']], str], + arg2: Literal[1, 2, 3, 4, 5, 6, 7, 8] +) -> Annotated[int, 'Some other'] +''' % __name__) + + def function_with_really_long_name_so_annotations_can_be_rather_small( + arg1: int, + arg2: str, + ): + ... + + doc = pydoc.render_doc(function_with_really_long_name_so_annotations_can_be_rather_small) + # clean up the extra text formatting that pydoc performs + doc = re.sub('\b.', '', doc) + self.assertEqual(doc, '''Python Library Documentation: function function_with_really_long_name_so_annotations_can_be_rather_small in module %s + +function_with_really_long_name_so_annotations_can_be_rather_small( + arg1: int, + arg2: str +) +''' % __name__) + + does_not_have_name = lambda \ + very_long_parameter_name_that_should_not_fit_into_a_single_line, \ + second_very_long_parameter_name: ... + + doc = pydoc.render_doc(does_not_have_name) + # clean up the extra text formatting that pydoc performs + doc = re.sub('\b.', '', doc) + self.assertEqual(doc, '''Python Library Documentation: function in module %s + + lambda very_long_parameter_name_that_should_not_fit_into_a_single_line, second_very_long_parameter_name +''' % __name__) + def test__future__imports(self): # __future__ features are excluded from module help, # except when it's the __future__ module itself diff --git a/Misc/NEWS.d/next/Library/2023-11-16-10-42-15.gh-issue-112139.WpHosf.rst b/Misc/NEWS.d/next/Library/2023-11-16-10-42-15.gh-issue-112139.WpHosf.rst new file mode 100644 index 000000000000000..090dc8847d95569 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-16-10-42-15.gh-issue-112139.WpHosf.rst @@ -0,0 +1,3 @@ +Add :meth:`Signature.format` to format signatures to string with extra options. +And use it in :mod:`pydoc` to render more readable signatures that have new +lines between parameters. From 3855b45874d5f8eb92a4957fb9de6fdce63eb760 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 3 Dec 2023 04:28:37 -0500 Subject: [PATCH 09/87] gh-66819: More IDLE htest updates(2) (#112642) Examine and update spec -- callable pairs. Revise run method. --- Lib/idlelib/browser.py | 1 + Lib/idlelib/debugobj.py | 4 +- Lib/idlelib/idle_test/htest.py | 108 ++++++++++++++++----------------- Lib/idlelib/iomenu.py | 9 +-- Lib/idlelib/multicall.py | 2 + Lib/idlelib/pathbrowser.py | 6 +- Lib/idlelib/query.py | 2 +- Lib/idlelib/sidebar.py | 6 +- Lib/idlelib/statusbar.py | 1 + 9 files changed, 70 insertions(+), 69 deletions(-) diff --git a/Lib/idlelib/browser.py b/Lib/idlelib/browser.py index 4fe64dced60acab..672e229ffbca94a 100644 --- a/Lib/idlelib/browser.py +++ b/Lib/idlelib/browser.py @@ -254,5 +254,6 @@ class Nested_in_closure: pass if len(sys.argv) == 1: # If pass file on command line, unittest fails. from unittest import main main('idlelib.idle_test.test_browser', verbosity=2, exit=False) + from idlelib.idle_test.htest import run run(_module_browser) diff --git a/Lib/idlelib/debugobj.py b/Lib/idlelib/debugobj.py index 032b686f379378b..0bf2cb1d5bbfe26 100644 --- a/Lib/idlelib/debugobj.py +++ b/Lib/idlelib/debugobj.py @@ -120,7 +120,7 @@ def make_objecttreeitem(labeltext, object, setfunction=None): return c(labeltext, object, setfunction) -def _object_browser(parent): # htest # +def _debug_object_browser(parent): # htest # import sys from tkinter import Toplevel top = Toplevel(parent) @@ -140,4 +140,4 @@ def _object_browser(parent): # htest # main('idlelib.idle_test.test_debugobj', verbosity=2, exit=False) from idlelib.idle_test.htest import run - run(_object_browser) + run(_debug_object_browser) diff --git a/Lib/idlelib/idle_test/htest.py b/Lib/idlelib/idle_test/htest.py index e21ab98d8aab898..a59b474fba47d8f 100644 --- a/Lib/idlelib/idle_test/htest.py +++ b/Lib/idlelib/idle_test/htest.py @@ -8,14 +8,15 @@ In a tested module, let X be a global name bound to a callable (class or function) whose .__name__ attribute is also X (the usual situation). The -first parameter of X must be 'parent'. When called, the parent argument -will be the root window. X must create a child Toplevel(parent) window -(or subclass thereof). The Toplevel may be a test widget or dialog, in -which case the callable is the corresponding class. Or the Toplevel may -contain the widget to be tested or set up a context in which a test -widget is invoked. In this latter case, the callable is a wrapper -function that sets up the Toplevel and other objects. Wrapper function -names, such as _editor_window', should start with '_' and be lowercase. +first parameter of X must be 'parent' or 'master'. When called, the +first argument will be the root window. X must create a child +Toplevel(parent/master) (or subclass thereof). The Toplevel may be a +test widget or dialog, in which case the callable is the corresponding +class. Or the Toplevel may contain the widget to be tested or set up a +context in which a test widget is invoked. In this latter case, the +callable is a wrapper function that sets up the Toplevel and other +objects. Wrapper function names, such as _editor_window', should start +with '_' and be lowercase. End the module with @@ -117,12 +118,20 @@ 'file': 'query', 'kwds': {'title': 'Customize query.py Run', '_htest': True}, - 'msg': "Enter with or [Run]. Print valid entry to Shell\n" + 'msg': "Enter with or [OK]. Print valid entry to Shell\n" "Arguments are parsed into a list\n" "Mode is currently restart True or False\n" "Close dialog with valid entry, , [Cancel], [X]" } +_debug_object_browser_spec = { + 'file': 'debugobj', + 'kwds': {}, + 'msg': "Double click on items up to the lowest level.\n" + "Attributes of the objects and related information " + "will be displayed side-by-side at each level." + } + # TODO Improve message _dyn_option_menu_spec = { 'file': 'dynoption', @@ -178,7 +187,7 @@ "Any url ('www...', 'http...') is accepted.\n" "Test Browse with and without path, as cannot unittest.\n" "[Ok] or prints valid entry to shell\n" - "[Cancel] or prints None to shell" + ", [Cancel], or [X] prints None to shell" } _io_binding_spec = { @@ -199,17 +208,17 @@ 'kwds': {}, 'msg': textwrap.dedent("""\ 1. Click on the line numbers and drag down below the edge of the - window, moving the mouse a bit and then leaving it there for a while. - The text and line numbers should gradually scroll down, with the - selection updated continuously. + window, moving the mouse a bit and then leaving it there for a + while. The text and line numbers should gradually scroll down, + with the selection updated continuously. - 2. With the lines still selected, click on a line number above the - selected lines. Only the line whose number was clicked should be - selected. + 2. With the lines still selected, click on a line number above + or below the selected lines. Only the line whose number was + clicked should be selected. - 3. Repeat step #1, dragging to above the window. The text and line - numbers should gradually scroll up, with the selection updated - continuously. + 3. Repeat step #1, dragging to above the window. The text and + line numbers should gradually scroll up, with the selection + updated continuously. 4. Repeat step #2, clicking a line number below the selection."""), } @@ -217,42 +226,33 @@ _multi_call_spec = { 'file': 'multicall', 'kwds': {}, - 'msg': "The following actions should trigger a print to console or IDLE" - " Shell.\nEntering and leaving the text area, key entry, " - ",\n, , " - ", \n, and " - "focusing out of the window\nare sequences to be tested." + 'msg': "The following should trigger a print to console or IDLE Shell.\n" + "Entering and leaving the text area, key entry, ,\n" + ", , , \n" + ", and focusing elsewhere." } _module_browser_spec = { 'file': 'browser', 'kwds': {}, - 'msg': "Inspect names of module, class(with superclass if " - "applicable), methods and functions.\nToggle nested items.\n" - "Double clicking on items prints a traceback for an exception " - "that is ignored." + 'msg': textwrap.dedent(""" + "Inspect names of module, class(with superclass if applicable), + "methods and functions. Toggle nested items. Double clicking + "on items prints a traceback for an exception that is ignored.""") } _multistatus_bar_spec = { 'file': 'statusbar', 'kwds': {}, 'msg': "Ensure presence of multi-status bar below text area.\n" - "Click 'Update Status' to change the multi-status text" - } - -_object_browser_spec = { - 'file': 'debugobj', - 'kwds': {}, - 'msg': "Double click on items up to the lowest level.\n" - "Attributes of the objects and related information " - "will be displayed side-by-side at each level." + "Click 'Update Status' to change the status text" } -_path_browser_spec = { +PathBrowser_spec = { 'file': 'pathbrowser', - 'kwds': {}, + 'kwds': {'_htest': True}, 'msg': "Test for correct display of all paths in sys.path.\n" - "Toggle nested items up to the lowest level.\n" + "Toggle nested items out to the lowest level.\n" "Double clicking on an item prints a traceback\n" "for an exception that is ignored." } @@ -367,11 +367,12 @@ } def run(*tests): + "Run callables in tests." root = tk.Tk() root.title('IDLE htest') root.resizable(0, 0) - # a scrollable Label like constant width text widget. + # A scrollable Label-like constant width text widget. frameLabel = tk.Frame(root, padx=10) frameLabel.pack() text = tk.Text(frameLabel, wrap='word') @@ -381,45 +382,44 @@ def run(*tests): scrollbar.pack(side='right', fill='y', expand=False) text.pack(side='left', fill='both', expand=True) - test_list = [] # List of tuples of the form (spec, callable widget) + test_list = [] # Make list of (spec, callable) tuples. if tests: for test in tests: test_spec = globals()[test.__name__ + '_spec'] test_spec['name'] = test.__name__ test_list.append((test_spec, test)) else: - for k, d in globals().items(): - if k.endswith('_spec'): - test_name = k[:-5] - test_spec = d + for key, dic in globals().items(): + if key.endswith('_spec'): + test_name = key[:-5] + test_spec = dic test_spec['name'] = test_name mod = import_module('idlelib.' + test_spec['file']) test = getattr(mod, test_name) test_list.append((test_spec, test)) + test_list.reverse() # So can pop in proper order in next_test. test_name = tk.StringVar(root) callable_object = None test_kwds = None def next_test(): - nonlocal test_name, callable_object, test_kwds if len(test_list) == 1: next_button.pack_forget() test_spec, callable_object = test_list.pop() test_kwds = test_spec['kwds'] - test_kwds['parent'] = root test_name.set('Test ' + test_spec['name']) - text.configure(state='normal') # enable text editing - text.delete('1.0','end') - text.insert("1.0",test_spec['msg']) - text.configure(state='disabled') # preserve read-only property + text['state'] = 'normal' # Enable text replacement. + text.delete('1.0', 'end') + text.insert("1.0", test_spec['msg']) + text['state'] = 'disabled' # Restore read-only property. def run_test(_=None): - widget = callable_object(**test_kwds) + widget = callable_object(root, **test_kwds) try: - print(widget.result) + print(widget.result) # Only true for query classes(?). except AttributeError: pass diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index af8159c2b33f51c..7629101635b8bbe 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -396,10 +396,11 @@ def updaterecentfileslist(self,filename): def _io_binding(parent): # htest # from tkinter import Toplevel, Text - root = Toplevel(parent) - root.title("Test IOBinding") + top = Toplevel(parent) + top.title("Test IOBinding") x, y = map(int, parent.geometry().split('+')[1:]) - root.geometry("+%d+%d" % (x, y + 175)) + top.geometry("+%d+%d" % (x, y + 175)) + class MyEditWin: def __init__(self, text): self.text = text @@ -423,7 +424,7 @@ def saveas(self, event): def savecopy(self, event): self.text.event_generate("<>") - text = Text(root) + text = Text(top) text.pack() text.focus_set() editwin = MyEditWin(text) diff --git a/Lib/idlelib/multicall.py b/Lib/idlelib/multicall.py index 0200f445cc9340b..2aa4a54125156f7 100644 --- a/Lib/idlelib/multicall.py +++ b/Lib/idlelib/multicall.py @@ -421,6 +421,8 @@ def _multi_call(parent): # htest # top.geometry("+%d+%d" % (x, y + 175)) text = MultiCallCreator(tkinter.Text)(top) text.pack() + text.focus_set() + def bindseq(seq, n=[0]): def handler(event): print(seq) diff --git a/Lib/idlelib/pathbrowser.py b/Lib/idlelib/pathbrowser.py index 6de242d0000bedd..48a77875ba5801c 100644 --- a/Lib/idlelib/pathbrowser.py +++ b/Lib/idlelib/pathbrowser.py @@ -99,13 +99,9 @@ def listmodules(self, allnames): return sorted -def _path_browser(parent): # htest # - PathBrowser(parent, _htest=True) - parent.mainloop() - if __name__ == "__main__": from unittest import main main('idlelib.idle_test.test_pathbrowser', verbosity=2, exit=False) from idlelib.idle_test.htest import run - run(_path_browser) + run(PathBrowser) diff --git a/Lib/idlelib/query.py b/Lib/idlelib/query.py index df02f2123ab02f3..57230e2aaca66da 100644 --- a/Lib/idlelib/query.py +++ b/Lib/idlelib/query.py @@ -368,7 +368,7 @@ def create_extra(self): sticky='we') def cli_args_ok(self): - "Validity check and parsing for command line arguments." + "Return command line arg list or None if error." cli_string = self.entry.get().strip() try: cli_args = shlex.split(cli_string, posix=True) diff --git a/Lib/idlelib/sidebar.py b/Lib/idlelib/sidebar.py index 166c04342907f99..8e7eae5037c90c7 100644 --- a/Lib/idlelib/sidebar.py +++ b/Lib/idlelib/sidebar.py @@ -516,13 +516,13 @@ def update_colors(self): def _linenumbers_drag_scrolling(parent): # htest # from idlelib.idle_test.test_sidebar import Dummy_editwin - toplevel = tk.Toplevel(parent) - text_frame = tk.Frame(toplevel) + top = tk.Toplevel(parent) + text_frame = tk.Frame(top) text_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) text_frame.rowconfigure(1, weight=1) text_frame.columnconfigure(1, weight=1) - font = idleConf.GetFont(toplevel, 'main', 'EditorWindow') + font = idleConf.GetFont(top, 'main', 'EditorWindow') text = tk.Text(text_frame, width=80, height=24, wrap=tk.NONE, font=font) text.grid(row=1, column=1, sticky=tk.NSEW) diff --git a/Lib/idlelib/statusbar.py b/Lib/idlelib/statusbar.py index 755fafb0ac64388..7048bd64b98753f 100644 --- a/Lib/idlelib/statusbar.py +++ b/Lib/idlelib/statusbar.py @@ -26,6 +26,7 @@ def _multistatus_bar(parent): # htest # x, y = map(int, parent.geometry().split('+')[1:]) top.geometry("+%d+%d" %(x, y + 175)) top.title("Test multistatus bar") + frame = Frame(top) text = Text(frame, height=5, width=40) text.pack() From fc9e24b01fb7da4160b82cef26981d72bb678c13 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sun, 3 Dec 2023 09:37:34 +0000 Subject: [PATCH 10/87] gh-112316: improve docs for `inspect.signature` and `inspect.Signature` (#112631) --- Doc/library/inspect.rst | 91 +++++++++++++++++++++++++---------------- Lib/inspect.py | 2 +- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 08522510f9ab444..71e7cb433cb1a80 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1,6 +1,11 @@ :mod:`inspect` --- Inspect live objects ======================================= +.. testsetup:: * + + import inspect + from inspect import * + .. module:: inspect :synopsis: Extract information and source code from live objects. @@ -614,13 +619,16 @@ Introspecting callables with the Signature object .. versionadded:: 3.3 -The Signature object represents the call signature of a callable object and its -return annotation. To retrieve a Signature object, use the :func:`signature` +The :class:`Signature` object represents the call signature of a callable object +and its return annotation. To retrieve a :class:`!Signature` object, +use the :func:`!signature` function. .. function:: signature(callable, *, follow_wrapped=True, globals=None, locals=None, eval_str=False) - Return a :class:`Signature` object for the given *callable*:: + Return a :class:`Signature` object for the given *callable*: + + .. doctest:: >>> from inspect import signature >>> def foo(a, *, b:int, **kwargs): @@ -629,10 +637,10 @@ function. >>> sig = signature(foo) >>> str(sig) - '(a, *, b:int, **kwargs)' + '(a, *, b: int, **kwargs)' >>> str(sig.parameters['b']) - 'b:int' + 'b: int' >>> sig.parameters['b'].annotation @@ -647,7 +655,7 @@ function. (``from __future__ import annotations``), :func:`signature` will attempt to automatically un-stringize the annotations using :func:`get_annotations`. The - *global*, *locals*, and *eval_str* parameters are passed + *globals*, *locals*, and *eval_str* parameters are passed into :func:`get_annotations` when resolving the annotations; see the documentation for :func:`get_annotations` for instructions on how to use these parameters. @@ -680,7 +688,8 @@ function. .. class:: Signature(parameters=None, *, return_annotation=Signature.empty) - A Signature object represents the call signature of a function and its return + A :class:`!Signature` object represents the call signature of a function + and its return annotation. For each parameter accepted by the function it stores a :class:`Parameter` object in its :attr:`parameters` collection. @@ -690,14 +699,14 @@ function. positional-only first, then positional-or-keyword, and that parameters with defaults follow parameters without defaults. - The optional *return_annotation* argument, can be an arbitrary Python object, - is the "return" annotation of the callable. + The optional *return_annotation* argument can be an arbitrary Python object. + It represents the "return" annotation of the callable. - Signature objects are *immutable*. Use :meth:`Signature.replace` or + :class:`!Signature` objects are *immutable*. Use :meth:`Signature.replace` or :func:`copy.replace` to make a modified copy. .. versionchanged:: 3.5 - Signature objects are picklable and :term:`hashable`. + :class:`!Signature` objects are now picklable and :term:`hashable`. .. attribute:: Signature.empty @@ -734,13 +743,15 @@ function. .. method:: Signature.replace(*[, parameters][, return_annotation]) - Create a new Signature instance based on the instance :meth:`replace` was invoked - on. It is possible to pass different ``parameters`` and/or - ``return_annotation`` to override the corresponding properties of the base - signature. To remove return_annotation from the copied Signature, pass in + Create a new :class:`Signature` instance based on the instance + :meth:`replace` was invoked on. + It is possible to pass different *parameters* and/or + *return_annotation* to override the corresponding properties of the base + signature. To remove ``return_annotation`` from the copied + :class:`!Signature`, pass in :attr:`Signature.empty`. - :: + .. doctest:: >>> def test(a, b): ... pass @@ -750,12 +761,12 @@ function. >>> str(new_sig) "(a, b) -> 'new return anno'" - Signature objects are also supported by generic function + :class:`Signature` objects are also supported by the generic function :func:`copy.replace`. .. method:: format(*, max_width=None) - Convert signature object to string. + Create a string representation of the :class:`Signature` object. If *max_width* is passed, the method will attempt to fit the signature into lines of at most *max_width* characters. @@ -769,12 +780,14 @@ function. Return a :class:`Signature` (or its subclass) object for a given callable *obj*. - This method simplifies subclassing of :class:`Signature`:: + This method simplifies subclassing of :class:`Signature`: + + .. testcode:: - class MySignature(Signature): - pass - sig = MySignature.from_callable(min) - assert isinstance(sig, MySignature) + class MySignature(Signature): + pass + sig = MySignature.from_callable(sum) + assert isinstance(sig, MySignature) Its behavior is otherwise identical to that of :func:`signature`. @@ -786,11 +799,12 @@ function. .. class:: Parameter(name, kind, *, default=Parameter.empty, annotation=Parameter.empty) - Parameter objects are *immutable*. Instead of modifying a Parameter object, + :class:`!Parameter` objects are *immutable*. + Instead of modifying a :class:`!Parameter` object, you can use :meth:`Parameter.replace` or :func:`copy.replace` to create a modified copy. .. versionchanged:: 3.5 - Parameter objects are picklable and :term:`hashable`. + Parameter objects are now picklable and :term:`hashable`. .. attribute:: Parameter.empty @@ -809,7 +823,7 @@ function. expressions. .. versionchanged:: 3.6 - These parameter names are exposed by this module as names like + These parameter names are now exposed by this module as names like ``implicit0``. .. attribute:: Parameter.default @@ -859,7 +873,9 @@ function. | | definition. | +------------------------+----------------------------------------------+ - Example: print all keyword-only arguments without default values:: + Example: print all keyword-only arguments without default values: + + .. doctest:: >>> def foo(a, b, *, c, d=10): ... pass @@ -873,11 +889,13 @@ function. .. attribute:: Parameter.kind.description - Describes a enum value of Parameter.kind. + Describes a enum value of :attr:`Parameter.kind`. .. versionadded:: 3.8 - Example: print all descriptions of arguments:: + Example: print all descriptions of arguments: + + .. doctest:: >>> def foo(a, b, *, c, d=10): ... pass @@ -892,12 +910,12 @@ function. .. method:: Parameter.replace(*[, name][, kind][, default][, annotation]) - Create a new Parameter instance based on the instance replaced was invoked - on. To override a :class:`Parameter` attribute, pass the corresponding + Create a new :class:`Parameter` instance based on the instance replaced was invoked + on. To override a :class:`!Parameter` attribute, pass the corresponding argument. To remove a default value or/and an annotation from a - Parameter, pass :attr:`Parameter.empty`. + :class:`!Parameter`, pass :attr:`Parameter.empty`. - :: + .. doctest:: >>> from inspect import Parameter >>> param = Parameter('foo', Parameter.KEYWORD_ONLY, default=42) @@ -908,12 +926,13 @@ function. 'foo=42' >>> str(param.replace(default=Parameter.empty, annotation='spam')) - "foo:'spam'" + "foo: 'spam'" - Parameter objects are also supported by generic function :func:`copy.replace`. + :class:`Parameter` objects are also supported by the generic function + :func:`copy.replace`. .. versionchanged:: 3.4 - In Python 3.3 Parameter objects were allowed to have ``name`` set + In Python 3.3 :class:`Parameter` objects were allowed to have ``name`` set to ``None`` if their ``kind`` was set to ``POSITIONAL_ONLY``. This is no longer permitted. diff --git a/Lib/inspect.py b/Lib/inspect.py index 079385abbc7bb23..f0b72662a9a0b21 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -3319,7 +3319,7 @@ def __str__(self): return self.format() def format(self, *, max_width=None): - """Convert signature object to string. + """Create a string representation of the Signature object. If *max_width* integer is passed, signature will try to fit into the *max_width*. From 29e6c7b68acac628b084a82670708008be262379 Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Sun, 3 Dec 2023 03:09:29 -0800 Subject: [PATCH 11/87] gh-112578: Fix RuntimeWarning when running zipfile (GH-112579) --- Lib/zipfile/__init__.py | 73 +++++++++++++++++- Lib/zipfile/__main__.py | 75 +------------------ ...-12-01-08-28-09.gh-issue-112578.bfNbfi.rst | 1 + 3 files changed, 72 insertions(+), 77 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-01-08-28-09.gh-issue-112578.bfNbfi.rst diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py index 2b28a079dbaa95b..fe629ed1cf2fc5c 100644 --- a/Lib/zipfile/__init__.py +++ b/Lib/zipfile/__init__.py @@ -2227,12 +2227,79 @@ def _compile(file, optimize=-1): return (fname, archivename) +def main(args=None): + import argparse + + description = 'A simple command-line interface for zipfile module.' + parser = argparse.ArgumentParser(description=description) + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('-l', '--list', metavar='', + help='Show listing of a zipfile') + group.add_argument('-e', '--extract', nargs=2, + metavar=('', ''), + help='Extract zipfile into target dir') + group.add_argument('-c', '--create', nargs='+', + metavar=('', ''), + help='Create zipfile from sources') + group.add_argument('-t', '--test', metavar='', + help='Test if a zipfile is valid') + parser.add_argument('--metadata-encoding', metavar='', + help='Specify encoding of member names for -l, -e and -t') + args = parser.parse_args(args) + + encoding = args.metadata_encoding + + if args.test is not None: + src = args.test + with ZipFile(src, 'r', metadata_encoding=encoding) as zf: + badfile = zf.testzip() + if badfile: + print("The following enclosed file is corrupted: {!r}".format(badfile)) + print("Done testing") + + elif args.list is not None: + src = args.list + with ZipFile(src, 'r', metadata_encoding=encoding) as zf: + zf.printdir() + + elif args.extract is not None: + src, curdir = args.extract + with ZipFile(src, 'r', metadata_encoding=encoding) as zf: + zf.extractall(curdir) + + elif args.create is not None: + if encoding: + print("Non-conforming encodings not supported with -c.", + file=sys.stderr) + sys.exit(1) + + zip_name = args.create.pop(0) + files = args.create + + def addToZip(zf, path, zippath): + if os.path.isfile(path): + zf.write(path, zippath, ZIP_DEFLATED) + elif os.path.isdir(path): + if zippath: + zf.write(path, zippath) + for nm in sorted(os.listdir(path)): + addToZip(zf, + os.path.join(path, nm), os.path.join(zippath, nm)) + # else: ignore + + with ZipFile(zip_name, 'w') as zf: + for path in files: + zippath = os.path.basename(path) + if not zippath: + zippath = os.path.basename(os.path.dirname(path)) + if zippath in ('', os.curdir, os.pardir): + zippath = '' + addToZip(zf, path, zippath) + + from ._path import ( # noqa: E402 Path, # used privately for tests CompleteDirs, # noqa: F401 ) - -# used privately for tests -from .__main__ import main # noqa: F401, E402 diff --git a/Lib/zipfile/__main__.py b/Lib/zipfile/__main__.py index a9e5fb1b8d72c43..868d99efc3c4a31 100644 --- a/Lib/zipfile/__main__.py +++ b/Lib/zipfile/__main__.py @@ -1,77 +1,4 @@ -import sys -import os -from . import ZipFile, ZIP_DEFLATED - - -def main(args=None): - import argparse - - description = 'A simple command-line interface for zipfile module.' - parser = argparse.ArgumentParser(description=description) - group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-l', '--list', metavar='', - help='Show listing of a zipfile') - group.add_argument('-e', '--extract', nargs=2, - metavar=('', ''), - help='Extract zipfile into target dir') - group.add_argument('-c', '--create', nargs='+', - metavar=('', ''), - help='Create zipfile from sources') - group.add_argument('-t', '--test', metavar='', - help='Test if a zipfile is valid') - parser.add_argument('--metadata-encoding', metavar='', - help='Specify encoding of member names for -l, -e and -t') - args = parser.parse_args(args) - - encoding = args.metadata_encoding - - if args.test is not None: - src = args.test - with ZipFile(src, 'r', metadata_encoding=encoding) as zf: - badfile = zf.testzip() - if badfile: - print("The following enclosed file is corrupted: {!r}".format(badfile)) - print("Done testing") - - elif args.list is not None: - src = args.list - with ZipFile(src, 'r', metadata_encoding=encoding) as zf: - zf.printdir() - - elif args.extract is not None: - src, curdir = args.extract - with ZipFile(src, 'r', metadata_encoding=encoding) as zf: - zf.extractall(curdir) - - elif args.create is not None: - if encoding: - print("Non-conforming encodings not supported with -c.", - file=sys.stderr) - sys.exit(1) - - zip_name = args.create.pop(0) - files = args.create - - def addToZip(zf, path, zippath): - if os.path.isfile(path): - zf.write(path, zippath, ZIP_DEFLATED) - elif os.path.isdir(path): - if zippath: - zf.write(path, zippath) - for nm in sorted(os.listdir(path)): - addToZip(zf, - os.path.join(path, nm), os.path.join(zippath, nm)) - # else: ignore - - with ZipFile(zip_name, 'w') as zf: - for path in files: - zippath = os.path.basename(path) - if not zippath: - zippath = os.path.basename(os.path.dirname(path)) - if zippath in ('', os.curdir, os.pardir): - zippath = '' - addToZip(zf, path, zippath) - +from . import main if __name__ == "__main__": main() diff --git a/Misc/NEWS.d/next/Library/2023-12-01-08-28-09.gh-issue-112578.bfNbfi.rst b/Misc/NEWS.d/next/Library/2023-12-01-08-28-09.gh-issue-112578.bfNbfi.rst new file mode 100644 index 000000000000000..1de5b1fe26ce6d9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-01-08-28-09.gh-issue-112578.bfNbfi.rst @@ -0,0 +1 @@ +Fix a spurious :exc:`RuntimeWarning` when executing the :mod:`zipfile` module. From 1f2a676785d48ed9ac01e60cc56a82e44b725474 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 3 Dec 2023 12:16:31 +0100 Subject: [PATCH 12/87] gh-106560: Fix redundant declarations in Include/ (#112611) Don't declare PyBool_Type, PyLong_Type and PySys_Audit() twice, but only once. Compiler warnings seen by building Python with gcc -Wredundant-decls. --- Include/boolobject.h | 2 +- Include/cpython/sysmodule.h | 4 ---- Include/longobject.h | 2 +- .../next/C API/2023-12-02-02-08-11.gh-issue-106560.THvuji.rst | 2 ++ 4 files changed, 4 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-12-02-02-08-11.gh-issue-106560.THvuji.rst diff --git a/Include/boolobject.h b/Include/boolobject.h index 976fa35201d035d..19aef5b1b87c6ae 100644 --- a/Include/boolobject.h +++ b/Include/boolobject.h @@ -7,7 +7,7 @@ extern "C" { #endif -PyAPI_DATA(PyTypeObject) PyBool_Type; +// PyBool_Type is declared by object.h #define PyBool_Check(x) Py_IS_TYPE((x), &PyBool_Type) diff --git a/Include/cpython/sysmodule.h b/Include/cpython/sysmodule.h index 9fd7cc0cb439311..a3ac07f538a94f3 100644 --- a/Include/cpython/sysmodule.h +++ b/Include/cpython/sysmodule.h @@ -4,10 +4,6 @@ typedef int(*Py_AuditHookFunction)(const char *, PyObject *, void *); -PyAPI_FUNC(int) PySys_Audit( - const char *event, - const char *format, - ...); PyAPI_FUNC(int) PySys_AddAuditHook(Py_AuditHookFunction, void*); typedef struct { diff --git a/Include/longobject.h b/Include/longobject.h index 7393254cd24a9bf..51005efff636fac 100644 --- a/Include/longobject.h +++ b/Include/longobject.h @@ -7,7 +7,7 @@ extern "C" { /* Long (arbitrary precision) integer object interface */ -PyAPI_DATA(PyTypeObject) PyLong_Type; +// PyLong_Type is declared by object.h #define PyLong_Check(op) \ PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_LONG_SUBCLASS) diff --git a/Misc/NEWS.d/next/C API/2023-12-02-02-08-11.gh-issue-106560.THvuji.rst b/Misc/NEWS.d/next/C API/2023-12-02-02-08-11.gh-issue-106560.THvuji.rst new file mode 100644 index 000000000000000..59b461ec47ad649 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-12-02-02-08-11.gh-issue-106560.THvuji.rst @@ -0,0 +1,2 @@ +Fix redundant declarations in the public C API. Declare PyBool_Type, +PyLong_Type and PySys_Audit() only once. Patch by Victor Stinner. From d9e444dbb86e173ee5b8491e3facbd447b91eaed Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 3 Dec 2023 12:18:24 +0100 Subject: [PATCH 13/87] gh-106560: Fix redundant declarations in Python/frozen.c (#112612) Avoid duplicated declarations of "extern" functions in Python/frozen.c. Compiler warnings seen by building Python with gcc -Wredundant-decls. --- Python/frozen.c | 6 ------ Tools/build/freeze_modules.py | 13 ++++++++++++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Python/frozen.c b/Python/frozen.c index 0fb38a11902f35e..77f51a7f750965b 100644 --- a/Python/frozen.c +++ b/Python/frozen.c @@ -80,7 +80,6 @@ extern PyObject *_Py_get__sitebuiltins_toplevel(void); extern PyObject *_Py_get_genericpath_toplevel(void); extern PyObject *_Py_get_ntpath_toplevel(void); extern PyObject *_Py_get_posixpath_toplevel(void); -extern PyObject *_Py_get_posixpath_toplevel(void); extern PyObject *_Py_get_os_toplevel(void); extern PyObject *_Py_get_site_toplevel(void); extern PyObject *_Py_get_stat_toplevel(void); @@ -88,13 +87,8 @@ extern PyObject *_Py_get_importlib_util_toplevel(void); extern PyObject *_Py_get_importlib_machinery_toplevel(void); extern PyObject *_Py_get_runpy_toplevel(void); extern PyObject *_Py_get___hello___toplevel(void); -extern PyObject *_Py_get___hello___toplevel(void); -extern PyObject *_Py_get___hello___toplevel(void); -extern PyObject *_Py_get___hello___toplevel(void); -extern PyObject *_Py_get___phello___toplevel(void); extern PyObject *_Py_get___phello___toplevel(void); extern PyObject *_Py_get___phello___ham_toplevel(void); -extern PyObject *_Py_get___phello___ham_toplevel(void); extern PyObject *_Py_get___phello___ham_eggs_toplevel(void); extern PyObject *_Py_get___phello___spam_toplevel(void); extern PyObject *_Py_get_frozen_only_toplevel(void); diff --git a/Tools/build/freeze_modules.py b/Tools/build/freeze_modules.py index c5a397129201b67..6a54f45bac3a86a 100644 --- a/Tools/build/freeze_modules.py +++ b/Tools/build/freeze_modules.py @@ -468,6 +468,17 @@ def replace_block(lines, start_marker, end_marker, replacements, file): return lines[:start_pos + 1] + replacements + lines[end_pos:] +class UniqueList(list): + def __init__(self): + self._seen = set() + + def append(self, item): + if item in self._seen: + return + super().append(item) + self._seen.add(item) + + def regen_frozen(modules): headerlines = [] parentdir = os.path.dirname(FROZEN_FILE) @@ -477,7 +488,7 @@ def regen_frozen(modules): header = relpath_for_posix_display(src.frozenfile, parentdir) headerlines.append(f'#include "{header}"') - externlines = [] + externlines = UniqueList() bootstraplines = [] stdliblines = [] testlines = [] From a971574b73140b6badf9442a5b954eab766a082c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 3 Dec 2023 12:21:48 +0100 Subject: [PATCH 14/87] gh-111545: Mention PEP 456 in PyHash_GetFuncDef() doc (#112647) --- Doc/c-api/hash.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/c-api/hash.rst b/Doc/c-api/hash.rst index 4dc121d7fbaa9b4..3bfaf8b9f54c14f 100644 --- a/Doc/c-api/hash.rst +++ b/Doc/c-api/hash.rst @@ -45,4 +45,7 @@ See also the :c:member:`PyTypeObject.tp_hash` member. Get the hash function definition. + .. seealso:: + :pep:`456` "Secure and interchangeable hash algorithm". + .. versionadded:: 3.4 From 4ed46d224401243399b41c7ceef4532bd249da27 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sun, 3 Dec 2023 11:50:22 +0000 Subject: [PATCH 15/87] Run more `inspect.rst` code snippets in CI (#112654) --- Doc/library/inspect.rst | 66 ++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 71e7cb433cb1a80..815bd54107a987e 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -392,7 +392,11 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Return ``True`` if the object can be used in :keyword:`await` expression. Can also be used to distinguish generator-based coroutines from regular - generators:: + generators: + + .. testcode:: + + import types def gen(): yield @@ -409,13 +413,15 @@ attributes (see :ref:`import-mod-attrs` for module attributes): .. function:: isasyncgenfunction(object) Return ``True`` if the object is an :term:`asynchronous generator` function, - for example:: + for example: - >>> async def agen(): - ... yield 1 - ... - >>> inspect.isasyncgenfunction(agen) - True + .. doctest:: + + >>> async def agen(): + ... yield 1 + ... + >>> inspect.isasyncgenfunction(agen) + True .. versionadded:: 3.6 @@ -985,18 +991,20 @@ function. For variable-keyword arguments (``**kwargs``) the default is an empty dict. - :: + .. doctest:: - >>> def foo(a, b='ham', *args): pass - >>> ba = inspect.signature(foo).bind('spam') - >>> ba.apply_defaults() - >>> ba.arguments - {'a': 'spam', 'b': 'ham', 'args': ()} + >>> def foo(a, b='ham', *args): pass + >>> ba = inspect.signature(foo).bind('spam') + >>> ba.apply_defaults() + >>> ba.arguments + {'a': 'spam', 'b': 'ham', 'args': ()} .. versionadded:: 3.5 The :attr:`args` and :attr:`kwargs` properties can be used to invoke - functions:: + functions: + + .. testcode:: def test(a, *, b): ... @@ -1115,20 +1123,22 @@ Classes and functions ``**`` arguments, if any) to their values from *args* and *kwds*. In case of invoking *func* incorrectly, i.e. whenever ``func(*args, **kwds)`` would raise an exception because of incompatible signature, an exception of the same type - and the same or similar message is raised. For example:: - - >>> from inspect import getcallargs - >>> def f(a, b=1, *pos, **named): - ... pass - ... - >>> getcallargs(f, 1, 2, 3) == {'a': 1, 'named': {}, 'b': 2, 'pos': (3,)} - True - >>> getcallargs(f, a=2, x=4) == {'a': 2, 'named': {'x': 4}, 'b': 1, 'pos': ()} - True - >>> getcallargs(f) - Traceback (most recent call last): - ... - TypeError: f() missing 1 required positional argument: 'a' + and the same or similar message is raised. For example: + + .. doctest:: + + >>> from inspect import getcallargs + >>> def f(a, b=1, *pos, **named): + ... pass + ... + >>> getcallargs(f, 1, 2, 3) == {'a': 1, 'named': {}, 'b': 2, 'pos': (3,)} + True + >>> getcallargs(f, a=2, x=4) == {'a': 2, 'named': {'x': 4}, 'b': 1, 'pos': ()} + True + >>> getcallargs(f) + Traceback (most recent call last): + ... + TypeError: f() missing 1 required positional argument: 'a' .. versionadded:: 3.2 From 162d3d428a836850ba29c58bbf37c931843d9e37 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sun, 3 Dec 2023 12:12:49 +0000 Subject: [PATCH 16/87] gh-112620: Fix dis error on show_cache with labels (#112621) --- Lib/dis.py | 17 +++++++++++------ Lib/test/test_dis.py | 12 ++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Lib/dis.py b/Lib/dis.py index e08e9a940576893..8d3885d2526b70e 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -412,7 +412,6 @@ def _create(cls, op, arg, offset, start_offset, starts_line, line_number, co_consts=None, varname_from_oparg=None, names=None, labels_map=None, exceptions_map=None): - label_width = 4 + len(str(len(labels_map))) argval, argrepr = cls._get_argval_argrepr( op, arg, offset, co_consts, names, varname_from_oparg, labels_map) @@ -420,7 +419,7 @@ def _create(cls, op, arg, offset, start_offset, starts_line, line_number, instr = Instruction(_all_opname[op], op, arg, argval, argrepr, offset, start_offset, starts_line, line_number, label, positions) - instr.label_width = label_width + instr.label_width = 4 + len(str(len(labels_map))) instr.exc_handler = exceptions_map.get(offset, None) return instr @@ -468,12 +467,14 @@ def is_jump_target(self): """True if other code jumps to here, otherwise False""" return self.label is not None - def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=0): + def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=0, + label_width=0): """Format instruction details for inclusion in disassembly output. *lineno_width* sets the width of the line number field (0 omits it) *mark_as_current* inserts a '-->' marker arrow as part of the line *offset_width* sets the width of the instruction offset field + *label_width* sets the width of the label field """ fields = [] # Column: Source code line number @@ -488,9 +489,9 @@ def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=0): # Column: Label if self.label is not None: lbl = f"L{self.label}:" - fields.append(f"{lbl:>{self.label_width}}") + fields.append(f"{lbl:>{label_width}}") else: - fields.append(' ' * self.label_width) + fields.append(' ' * label_width) # Column: Instruction offset from start of code sequence if offset_width > 0: fields.append(f"{repr(self.offset):>{offset_width}} ") @@ -648,6 +649,7 @@ def make_labels_map(original_code, exception_entries): return labels_map labels_map = make_labels_map(original_code, exception_entries) + label_width = 4 + len(str(len(labels_map))) exceptions_map = {} for start, end, target, _, _ in exception_entries: @@ -756,6 +758,7 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None, else: offset_width = 0 + label_width = -1 for instr in _get_instructions_bytes(code, varname_from_oparg, names, co_consts, linestarts, line_offset=line_offset, @@ -774,7 +777,9 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None, # Each CACHE takes 2 bytes is_current_instr = instr.offset <= lasti \ <= instr.offset + 2 * _get_cache_size(_all_opname[_deoptop(instr.opcode)]) - print(instr._disassemble(lineno_width, is_current_instr, offset_width), + label_width = getattr(instr, 'label_width', label_width) + assert label_width >= 0 + print(instr._disassemble(lineno_width, is_current_instr, offset_width, label_width), file=file) if exception_entries: print("ExceptionTable:", file=file) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 805cd4e4c309652..349790ecd7d0758 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1896,6 +1896,18 @@ def test_oparg_alias(self): positions=None) self.assertEqual(instruction.arg, instruction.oparg) + def test_show_caches_with_label(self): + def f(x, y, z): + if x: + res = y + else: + res = z + return res + + output = io.StringIO() + dis.dis(f.__code__, file=output, show_caches=True) + self.assertIn("L1:", output.getvalue()) + def test_baseopname_and_baseopcode(self): # Standard instructions for name, code in dis.opmap.items(): From 97857ac0580057c3a4f75d34209841c81ee11a96 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sun, 3 Dec 2023 14:02:37 +0000 Subject: [PATCH 17/87] gh-112645: remove deprecation warning for use of onerror in shutil.rmtree (#112659) --- Doc/whatsnew/3.12.rst | 7 +++---- Lib/shutil.py | 5 ----- Lib/test/test_shutil.py | 15 +++++---------- ...2023-12-03-12-41-48.gh-issue-112645.blMsKf.rst | 1 + 4 files changed, 9 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-03-12-41-48.gh-issue-112645.blMsKf.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 96893527cc91ed2..fc17c86665335c5 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -838,8 +838,7 @@ 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 and - will be removed in Python 3.14. + rather than a *(typ, val, tb)* triplet. *onerror* is deprecated. (Contributed by Irit Katriel in :gh:`102828`.) * :func:`shutil.which` now consults the *PATHEXT* environment variable to @@ -1261,8 +1260,8 @@ Deprecated :mod:`concurrent.futures` the fix is to use a different :mod:`multiprocessing` start method such as ``"spawn"`` or ``"forkserver"``. -* :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` is deprecated and will be removed - in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.) +* :mod:`shutil`: The *onerror* argument of :func:`shutil.rmtree` is deprecated; + use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.) * :mod:`sqlite3`: diff --git a/Lib/shutil.py b/Lib/shutil.py index 0fed0117a63234b..dd93872e83c9e2c 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -721,11 +721,6 @@ def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None): If both onerror and onexc are set, onerror is ignored and onexc is used. """ - if onerror is not None: - import warnings - warnings.warn("onerror argument is deprecated, use onexc instead", - DeprecationWarning, stacklevel=2) - sys.audit("shutil.rmtree", path, dir_fd) if ignore_errors: def onexc(*args): diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index d231e66b7b889f6..ae6c6814fcc3eca 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -208,8 +208,7 @@ def test_rmtree_fails_on_symlink_onerror(self): errors = [] def onerror(*args): errors.append(args) - with self.assertWarns(DeprecationWarning): - shutil.rmtree(link, onerror=onerror) + shutil.rmtree(link, onerror=onerror) self.assertEqual(len(errors), 1) self.assertIs(errors[0][0], os.path.islink) self.assertEqual(errors[0][1], link) @@ -270,8 +269,7 @@ def test_rmtree_fails_on_junctions_onerror(self): errors = [] def onerror(*args): errors.append(args) - with self.assertWarns(DeprecationWarning): - shutil.rmtree(link, onerror=onerror) + shutil.rmtree(link, onerror=onerror) self.assertEqual(len(errors), 1) self.assertIs(errors[0][0], os.path.islink) self.assertEqual(errors[0][1], link) @@ -340,8 +338,7 @@ def test_rmtree_errors_onerror(self): errors = [] def onerror(*args): errors.append(args) - with self.assertWarns(DeprecationWarning): - shutil.rmtree(filename, onerror=onerror) + shutil.rmtree(filename, onerror=onerror) self.assertEqual(len(errors), 2) self.assertIs(errors[0][0], os.scandir) self.assertEqual(errors[0][1], filename) @@ -410,8 +407,7 @@ 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) - with self.assertWarns(DeprecationWarning): - shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) + 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.") @@ -537,8 +533,7 @@ 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) - with self.assertWarns(DeprecationWarning): - shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc) + shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc) self.assertTrue(onexc_called) self.assertFalse(onerror_called) diff --git a/Misc/NEWS.d/next/Library/2023-12-03-12-41-48.gh-issue-112645.blMsKf.rst b/Misc/NEWS.d/next/Library/2023-12-03-12-41-48.gh-issue-112645.blMsKf.rst new file mode 100644 index 000000000000000..4e8f6ebdb882e03 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-03-12-41-48.gh-issue-112645.blMsKf.rst @@ -0,0 +1 @@ +Remove deprecation error on passing ``onerror`` to :func:`shutil.rmtree`. From c27b09c81368bc3b756e94a79a39307ce44a4a2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20A=2E=20Barbosa?= Date: Sun, 3 Dec 2023 12:14:14 -0300 Subject: [PATCH 18/87] Fix link to 'The Perils of Floating Point', on the tutorial (GH-112499) Use author link to 'The Perils of Floating Point'. --- Doc/tutorial/floatingpoint.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tutorial/floatingpoint.rst b/Doc/tutorial/floatingpoint.rst index 30f3dfb6b238b4a..0795e2fef98830b 100644 --- a/Doc/tutorial/floatingpoint.rst +++ b/Doc/tutorial/floatingpoint.rst @@ -150,7 +150,7 @@ section. See `Examples of Floating Point Problems `_ for a pleasant summary of how binary floating-point works and the kinds of problems commonly encountered in practice. Also see -`The Perils of Floating Point `_ +`The Perils of Floating Point `_ for a more complete account of other common surprises. As that says near the end, "there are no easy answers." Still, don't be unduly From 45650d1c479a8b0370f126d821718dd3c502f333 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sun, 3 Dec 2023 17:32:49 +0000 Subject: [PATCH 19/87] gh-101100: Fix most Sphinx nitpicks in `inspect.rst` (#112662) --- Doc/conf.py | 3 +++ Doc/library/inspect.rst | 15 +++++++++------ Doc/reference/datamodel.rst | 2 ++ Doc/whatsnew/2.6.rst | 5 +++-- Doc/whatsnew/2.7.rst | 3 ++- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Doc/conf.py b/Doc/conf.py index be2a86e12fa2e4f..323d443588ceb63 100644 --- a/Doc/conf.py +++ b/Doc/conf.py @@ -163,6 +163,9 @@ ('envvar', 'USER'), ('envvar', 'USERNAME'), ('envvar', 'USERPROFILE'), + # Deprecated function that was never documented: + ('py:func', 'getargspec'), + ('py:func', 'inspect.getargspec'), ] # Temporary undocumented names. diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 815bd54107a987e..6fd0d32afe7415c 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -273,7 +273,7 @@ attributes (see :ref:`import-mod-attrs` for module attributes): :func:`getmembers` will only return class attributes defined in the metaclass when the argument is a class and those attributes have been - listed in the metaclass' custom :meth:`__dir__`. + listed in the metaclass' custom :meth:`~object.__dir__`. .. function:: getmembers_static(object[, predicate]) @@ -487,12 +487,13 @@ attributes (see :ref:`import-mod-attrs` for module attributes): has a :meth:`~object.__get__` method but not a :meth:`~object.__set__` method, but beyond that the set of attributes varies. A :attr:`~definition.__name__` attribute is usually - sensible, and :attr:`__doc__` often is. + sensible, and :attr:`!__doc__` often is. Methods implemented via descriptors that also pass one of the other tests return ``False`` from the :func:`ismethoddescriptor` test, simply because the other tests promise more -- you can, e.g., count on having the - :attr:`__func__` attribute (etc) when an object passes :func:`ismethod`. + :ref:`__func__ ` attribute (etc) when an object passes + :func:`ismethod`. .. function:: isdatadescriptor(object) @@ -503,7 +504,7 @@ attributes (see :ref:`import-mod-attrs` for module attributes): Examples are properties (defined in Python), getsets, and members. The latter two are defined in C and there are more specific tests available for those types, which is robust across Python implementations. Typically, data - descriptors will also have :attr:`~definition.__name__` and :attr:`__doc__` attributes + descriptors will also have :attr:`~definition.__name__` and :attr:`!__doc__` attributes (properties, getsets, and members have both of these attributes), but this is not guaranteed. @@ -1440,7 +1441,8 @@ Fetching attributes statically Both :func:`getattr` and :func:`hasattr` can trigger code execution when fetching or checking for the existence of attributes. Descriptors, like -properties, will be invoked and :meth:`__getattr__` and :meth:`__getattribute__` +properties, will be invoked and :meth:`~object.__getattr__` and +:meth:`~object.__getattribute__` may be called. For cases where you want passive introspection, like documentation tools, this @@ -1450,7 +1452,8 @@ but avoids executing code when it fetches attributes. .. function:: getattr_static(obj, attr, default=None) Retrieve attributes without triggering dynamic lookup via the - descriptor protocol, :meth:`__getattr__` or :meth:`__getattribute__`. + descriptor protocol, :meth:`~object.__getattr__` + or :meth:`~object.__getattribute__`. Note: this function may not be able to retrieve all attributes that getattr can fetch (like dynamically created attributes) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index f7d3d2d0bbec23a..29298b79ef06dd9 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -634,6 +634,8 @@ code object; see the description of internal types below. The module. +.. _instance-methods: + Instance methods ^^^^^^^^^^^^^^^^ diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 016de153f3dd6ac..8bdbb0fa352ed1e 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -1677,8 +1677,9 @@ Some smaller changes made to the core Python language are: (:issue:`1591665`) * Instance method objects have new attributes for the object and function - comprising the method; the new synonym for :attr:`im_self` is - :attr:`__self__`, and :attr:`im_func` is also available as :attr:`__func__`. + comprising the method; the new synonym for :attr:`!im_self` is + :ref:`__self__ `, and :attr:`!im_func` is also available as + :ref:`__func__ `. The old names are still supported in Python 2.6, but are gone in 3.0. * An obscure change: when you use the :func:`locals` function inside a diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index da66dd731831bcf..4072e040dc9130d 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -860,7 +860,8 @@ Some smaller changes made to the core Python language are: * When using ``@classmethod`` and ``@staticmethod`` to wrap methods as class or static methods, the wrapper object now - exposes the wrapped function as their :attr:`__func__` attribute. + exposes the wrapped function as their :ref:`__func__ ` + attribute. (Contributed by Amaury Forgeot d'Arc, after a suggestion by George Sakkis; :issue:`5982`.) From 489aeac3a2d3b347ff033334688e2f44eec7944a Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 3 Dec 2023 22:23:09 +0200 Subject: [PATCH 20/87] gh-101100: Fix Sphinx warning in `library/gettext.rst` (#112668) Co-authored-by: Alex Waygood --- Doc/library/gettext.rst | 14 +++++++------- Doc/tools/.nitignore | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst index dc6cf5533fccbe5..41beac3e0c73966 100644 --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -257,7 +257,7 @@ are the methods of :class:`!NullTranslations`: .. method:: info() - Return the "protected" :attr:`_info` variable, a dictionary containing + Return a dictionary containing the metadata found in the message catalog file. @@ -296,9 +296,9 @@ are the methods of :class:`!NullTranslations`: The :class:`GNUTranslations` class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The :mod:`gettext` module provides one additional class derived from +The :mod:`!gettext` module provides one additional class derived from :class:`NullTranslations`: :class:`GNUTranslations`. This class overrides -:meth:`_parse` to enable reading GNU :program:`gettext` format :file:`.mo` files +:meth:`!_parse` to enable reading GNU :program:`gettext` format :file:`.mo` files in both big-endian and little-endian format. :class:`GNUTranslations` parses optional metadata out of the translation @@ -306,7 +306,7 @@ catalog. It is convention with GNU :program:`gettext` to include metadata as the translation for the empty string. This metadata is in :rfc:`822`\ -style ``key: value`` pairs, and should contain the ``Project-Id-Version`` key. If the key ``Content-Type`` is found, then the ``charset`` property is used to -initialize the "protected" :attr:`_charset` instance variable, defaulting to +initialize the "protected" :attr:`!_charset` instance variable, defaulting to ``None`` if not found. If the charset encoding is specified, then all message ids and message strings read from the catalog are converted to Unicode using this encoding, else ASCII is assumed. @@ -315,7 +315,7 @@ Since message ids are read as Unicode strings too, all ``*gettext()`` methods will assume message ids as Unicode strings, not byte strings. The entire set of key/value pairs are placed into a dictionary and set as the -"protected" :attr:`_info` instance variable. +"protected" :attr:`!_info` instance variable. If the :file:`.mo` file's magic number is invalid, the major version number is unexpected, or if other problems occur while reading the file, instantiating a @@ -636,9 +636,9 @@ implementations, and valuable experience to the creation of this module: .. rubric:: Footnotes -.. [#] The default locale directory is system dependent; for example, on RedHat Linux +.. [#] The default locale directory is system dependent; for example, on Red Hat Linux it is :file:`/usr/share/locale`, but on Solaris it is :file:`/usr/lib/locale`. - The :mod:`gettext` module does not try to support these system dependent + The :mod:`!gettext` module does not try to support these system dependent defaults; instead its default is :file:`{sys.base_prefix}/share/locale` (see :data:`sys.base_prefix`). For this reason, it is always best to call :func:`bindtextdomain` with an explicit absolute path at the start of your diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 1e3e367460147ad..8d79a848b7cc7b3 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -58,7 +58,6 @@ Doc/library/fcntl.rst Doc/library/ftplib.rst Doc/library/functions.rst Doc/library/functools.rst -Doc/library/gettext.rst Doc/library/http.client.rst Doc/library/http.cookiejar.rst Doc/library/http.cookies.rst From 09505c5c26d6a4c81b54786eb4196379e9cb223c Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Sun, 3 Dec 2023 20:35:10 +0000 Subject: [PATCH 21/87] GH-106747: Improve `Path.glob()` expectations in pathlib tests (#112365) Add trailing slashes to expected `Path.glob()` results wherever a pattern has a trailing slash. This matches what `glob.glob()` produces. Due to another bug (GH-65238) pathlib strips all trailing slashes, so this change is academic for now. --- Lib/test/test_pathlib.py | 66 ++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 427e082f3e16cb0..ccaef070974ffdc 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1968,9 +1968,9 @@ def _check(glob, expected): _check(p.glob("brokenLink"), ['brokenLink']) if not self.can_symlink: - _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE"]) + _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/"]) else: - _check(p.glob("*/"), ["dirA", "dirB", "dirC", "dirE", "linkB"]) + _check(p.glob("*/"), ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"]) def test_glob_empty_pattern(self): p = self.cls() @@ -2003,17 +2003,17 @@ def _check(path, glob, expected): _check(p, "*A", ["dirA", "fileA", "linkA"]) _check(p, "*B/*", ["dirB/fileB", "dirB/linkD", "linkB/fileB", "linkB/linkD"]) _check(p, "*/fileB", ["dirB/fileB", "linkB/fileB"]) - _check(p, "*/", ["dirA", "dirB", "dirC", "dirE", "linkB"]) + _check(p, "*/", ["dirA/", "dirB/", "dirC/", "dirE/", "linkB/"]) _check(p, "dir*/*/..", ["dirC/dirD/..", "dirA/linkC/.."]) - _check(p, "dir*/**/", ["dirA", "dirA/linkC", "dirA/linkC/linkD", "dirB", "dirB/linkD", - "dirC", "dirC/dirD", "dirE"]) + _check(p, "dir*/**/", ["dirA/", "dirA/linkC/", "dirA/linkC/linkD/", "dirB/", "dirB/linkD/", + "dirC/", "dirC/dirD/", "dirE/"]) _check(p, "dir*/**/..", ["dirA/..", "dirA/linkC/..", "dirB/..", "dirC/..", "dirC/dirD/..", "dirE/.."]) - _check(p, "dir*/*/**/", ["dirA/linkC", "dirA/linkC/linkD", "dirB/linkD", "dirC/dirD"]) + _check(p, "dir*/*/**/", ["dirA/linkC/", "dirA/linkC/linkD/", "dirB/linkD/", "dirC/dirD/"]) _check(p, "dir*/*/**/..", ["dirA/linkC/..", "dirC/dirD/.."]) _check(p, "dir*/**/fileC", ["dirC/fileC"]) - _check(p, "dir*/*/../dirD/**/", ["dirC/dirD/../dirD"]) - _check(p, "*/dirD/**/", ["dirC/dirD"]) + _check(p, "dir*/*/../dirD/**/", ["dirC/dirD/../dirD/"]) + _check(p, "*/dirD/**/", ["dirC/dirD/"]) def test_glob_no_follow_symlinks_common(self): if not self.can_symlink: @@ -2028,15 +2028,15 @@ def _check(path, glob, expected): _check(p, "*A", ["dirA", "fileA", "linkA"]) _check(p, "*B/*", ["dirB/fileB", "dirB/linkD"]) _check(p, "*/fileB", ["dirB/fileB"]) - _check(p, "*/", ["dirA", "dirB", "dirC", "dirE"]) + _check(p, "*/", ["dirA/", "dirB/", "dirC/", "dirE/"]) _check(p, "dir*/*/..", ["dirC/dirD/.."]) - _check(p, "dir*/**/", ["dirA", "dirB", "dirC", "dirC/dirD", "dirE"]) + _check(p, "dir*/**/", ["dirA/", "dirB/", "dirC/", "dirC/dirD/", "dirE/"]) _check(p, "dir*/**/..", ["dirA/..", "dirB/..", "dirC/..", "dirC/dirD/..", "dirE/.."]) - _check(p, "dir*/*/**/", ["dirC/dirD"]) + _check(p, "dir*/*/**/", ["dirC/dirD/"]) _check(p, "dir*/*/**/..", ["dirC/dirD/.."]) _check(p, "dir*/**/fileC", ["dirC/fileC"]) - _check(p, "dir*/*/../dirD/**/", ["dirC/dirD/../dirD"]) - _check(p, "*/dirD/**/", ["dirC/dirD"]) + _check(p, "dir*/*/../dirD/**/", ["dirC/dirD/../dirD/"]) + _check(p, "*/dirD/**/", ["dirC/dirD/"]) def test_rglob_common(self): def _check(glob, expected): @@ -2058,25 +2058,25 @@ def _check(glob, expected): "dirC/fileC", "dirC/dirD/fileD"]) if not self.can_symlink: _check(p.rglob("*/"), [ - "dirA", "dirB", "dirC", "dirC/dirD", "dirE", + "dirA/", "dirB/", "dirC/", "dirC/dirD/", "dirE/", ]) else: _check(p.rglob("*/"), [ - "dirA", "dirA/linkC", "dirB", "dirB/linkD", "dirC", - "dirC/dirD", "dirE", "linkB", + "dirA/", "dirA/linkC/", "dirB/", "dirB/linkD/", "dirC/", + "dirC/dirD/", "dirE/", "linkB/", ]) - _check(p.rglob(""), ["", "dirA", "dirB", "dirC", "dirE", "dirC/dirD"]) + _check(p.rglob(""), ["./", "dirA/", "dirB/", "dirC/", "dirE/", "dirC/dirD/"]) p = P(BASE, "dirC") _check(p.rglob("*"), ["dirC/fileC", "dirC/novel.txt", "dirC/dirD", "dirC/dirD/fileD"]) _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"]) _check(p.rglob("**/file*"), ["dirC/fileC", "dirC/dirD/fileD"]) - _check(p.rglob("dir*/**/"), ["dirC/dirD"]) + _check(p.rglob("dir*/**/"), ["dirC/dirD/"]) _check(p.rglob("*/*"), ["dirC/dirD/fileD"]) - _check(p.rglob("*/"), ["dirC/dirD"]) - _check(p.rglob(""), ["dirC", "dirC/dirD"]) - _check(p.rglob("**/"), ["dirC", "dirC/dirD"]) + _check(p.rglob("*/"), ["dirC/dirD/"]) + _check(p.rglob(""), ["dirC/", "dirC/dirD/"]) + _check(p.rglob("**/"), ["dirC/", "dirC/dirD/"]) # gh-91616, a re module regression _check(p.rglob("*.txt"), ["dirC/novel.txt"]) _check(p.rglob("*.*"), ["dirC/novel.txt"]) @@ -2095,18 +2095,18 @@ def _check(path, glob, expected): _check(p, "*/fileB", ["dirB/fileB", "dirA/linkC/fileB", "linkB/fileB"]) _check(p, "file*", ["fileA", "dirA/linkC/fileB", "dirB/fileB", "dirC/fileC", "dirC/dirD/fileD", "linkB/fileB"]) - _check(p, "*/", ["dirA", "dirA/linkC", "dirA/linkC/linkD", "dirB", "dirB/linkD", - "dirC", "dirC/dirD", "dirE", "linkB", "linkB/linkD"]) - _check(p, "", ["", "dirA", "dirA/linkC", "dirA/linkC/linkD", "dirB", "dirB/linkD", - "dirC", "dirE", "dirC/dirD", "linkB", "linkB/linkD"]) + _check(p, "*/", ["dirA/", "dirA/linkC/", "dirA/linkC/linkD/", "dirB/", "dirB/linkD/", + "dirC/", "dirC/dirD/", "dirE/", "linkB/", "linkB/linkD/"]) + _check(p, "", ["./", "dirA/", "dirA/linkC/", "dirA/linkC/linkD/", "dirB/", "dirB/linkD/", + "dirC/", "dirE/", "dirC/dirD/", "linkB/", "linkB/linkD/"]) p = P(BASE, "dirC") _check(p, "*", ["dirC/fileC", "dirC/novel.txt", "dirC/dirD", "dirC/dirD/fileD"]) _check(p, "file*", ["dirC/fileC", "dirC/dirD/fileD"]) _check(p, "*/*", ["dirC/dirD/fileD"]) - _check(p, "*/", ["dirC/dirD"]) - _check(p, "", ["dirC", "dirC/dirD"]) + _check(p, "*/", ["dirC/dirD/"]) + _check(p, "", ["dirC/", "dirC/dirD/"]) # gh-91616, a re module regression _check(p, "*.txt", ["dirC/novel.txt"]) _check(p, "*.*", ["dirC/novel.txt"]) @@ -2123,16 +2123,16 @@ def _check(path, glob, expected): _check(p, "*/fileA", []) _check(p, "*/fileB", ["dirB/fileB"]) _check(p, "file*", ["fileA", "dirB/fileB", "dirC/fileC", "dirC/dirD/fileD", ]) - _check(p, "*/", ["dirA", "dirB", "dirC", "dirC/dirD", "dirE"]) - _check(p, "", ["", "dirA", "dirB", "dirC", "dirE", "dirC/dirD"]) + _check(p, "*/", ["dirA/", "dirB/", "dirC/", "dirC/dirD/", "dirE/"]) + _check(p, "", ["./", "dirA/", "dirB/", "dirC/", "dirE/", "dirC/dirD/"]) p = P(BASE, "dirC") _check(p, "*", ["dirC/fileC", "dirC/novel.txt", "dirC/dirD", "dirC/dirD/fileD"]) _check(p, "file*", ["dirC/fileC", "dirC/dirD/fileD"]) _check(p, "*/*", ["dirC/dirD/fileD"]) - _check(p, "*/", ["dirC/dirD"]) - _check(p, "", ["dirC", "dirC/dirD"]) + _check(p, "*/", ["dirC/dirD/"]) + _check(p, "", ["dirC/", "dirC/dirD/"]) # gh-91616, a re module regression _check(p, "*.txt", ["dirC/novel.txt"]) _check(p, "*.*", ["dirC/novel.txt"]) @@ -3642,7 +3642,7 @@ def test_glob(self): P = self.cls p = P(BASE) self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") }) - self.assertEqual(set(p.glob("*a\\")), { P(BASE, "dirA") }) + self.assertEqual(set(p.glob("*a\\")), { P(BASE, "dirA/") }) self.assertEqual(set(p.glob("F*a")), { P(BASE, "fileA") }) self.assertEqual(set(map(str, p.glob("FILEa"))), {f"{p}\\fileA"}) self.assertEqual(set(map(str, p.glob("F*a"))), {f"{p}\\fileA"}) @@ -3651,7 +3651,7 @@ def test_rglob(self): P = self.cls p = P(BASE, "dirC") self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") }) - self.assertEqual(set(p.rglob("*\\")), { P(BASE, "dirC/dirD") }) + self.assertEqual(set(p.rglob("*\\")), { P(BASE, "dirC/dirD/") }) self.assertEqual(set(map(str, p.rglob("FILEd"))), {f"{p}\\dirD\\fileD"}) def test_expanduser(self): From 5a1b5316af648ae79bb91f28253b6272bbbd2886 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Sun, 3 Dec 2023 23:45:56 -0500 Subject: [PATCH 22/87] gh-66819: More IDLE htest updates(3) (#112683) Revise spec-callable pairs from percolator to end. --- Lib/idlelib/help.py | 4 ++-- Lib/idlelib/idle_test/htest.py | 16 ++++++++-------- Lib/idlelib/percolator.py | 12 ++++++------ Lib/idlelib/scrolledlist.py | 3 ++- Lib/idlelib/stackviewer.py | 4 ++-- Lib/idlelib/undo.py | 14 +++++++------- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/Lib/idlelib/help.py b/Lib/idlelib/help.py index cc027b9cef4f5b3..580a327f620a792 100644 --- a/Lib/idlelib/help.py +++ b/Lib/idlelib/help.py @@ -278,7 +278,7 @@ def copy_strip(): out.write(line.rstrip() + b'\n') print(f'{src} copied to {dst}') -def show_idlehelp(parent): +def _helpwindow(parent): "Create HelpWindow; called from Idle Help event handler." filename = join(abspath(dirname(__file__)), 'help.html') if not isfile(filename): @@ -291,4 +291,4 @@ def show_idlehelp(parent): main('idlelib.idle_test.test_help', verbosity=2, exit=False) from idlelib.idle_test.htest import run - run(show_idlehelp) + run(_helpwindow) diff --git a/Lib/idlelib/idle_test/htest.py b/Lib/idlelib/idle_test/htest.py index a59b474fba47d8f..4042106bf44a9f7 100644 --- a/Lib/idlelib/idle_test/htest.py +++ b/Lib/idlelib/idle_test/htest.py @@ -190,6 +190,13 @@ ", [Cancel], or [X] prints None to shell" } +_helpwindow_spec = { + 'file': 'help', + 'kwds': {}, + 'msg': "If the help text displays, this works.\n" + "Text is selectable. Window is scrollable." + } + _io_binding_spec = { 'file': 'iomenu', 'kwds': {}, @@ -312,14 +319,7 @@ "Right clicking an item will display a popup." } -show_idlehelp_spec = { - 'file': 'help', - 'kwds': {}, - 'msg': "If the help text displays, this works.\n" - "Text is selectable. Window is scrollable." - } - -_stack_viewer_spec = { +_stackbrowser_spec = { 'file': 'stackviewer', 'kwds': {}, 'msg': "A stacktrace for a NameError exception.\n" diff --git a/Lib/idlelib/percolator.py b/Lib/idlelib/percolator.py index 1fe34d29f54eb28..91ad7272f4ae560 100644 --- a/Lib/idlelib/percolator.py +++ b/Lib/idlelib/percolator.py @@ -86,11 +86,11 @@ def delete(self, *args): print(self.name, ": delete", args) self.delegate.delete(*args) - box = tk.Toplevel(parent) - box.title("Test Percolator") + top = tk.Toplevel(parent) + top.title("Test Percolator") x, y = map(int, parent.geometry().split('+')[1:]) - box.geometry("+%d+%d" % (x, y + 175)) - text = tk.Text(box) + top.geometry("+%d+%d" % (x, y + 175)) + text = tk.Text(top) p = Percolator(text) pin = p.insertfilter pout = p.removefilter @@ -104,10 +104,10 @@ def toggle2(): text.pack() var1 = tk.IntVar(parent) - cb1 = tk.Checkbutton(box, text="Tracer1", command=toggle1, variable=var1) + cb1 = tk.Checkbutton(top, text="Tracer1", command=toggle1, variable=var1) cb1.pack() var2 = tk.IntVar(parent) - cb2 = tk.Checkbutton(box, text="Tracer2", command=toggle2, variable=var2) + cb2 = tk.Checkbutton(top, text="Tracer2", command=toggle2, variable=var2) cb2.pack() if __name__ == "__main__": diff --git a/Lib/idlelib/scrolledlist.py b/Lib/idlelib/scrolledlist.py index 71fd18ab19ec8ae..4f1241a576fca1c 100644 --- a/Lib/idlelib/scrolledlist.py +++ b/Lib/idlelib/scrolledlist.py @@ -132,6 +132,7 @@ def _scrolled_list(parent): # htest # top = Toplevel(parent) x, y = map(int, parent.geometry().split('+')[1:]) top.geometry("+%d+%d" % (x+200, y + 175)) + class MyScrolledList(ScrolledList): def fill_menu(self): self.menu.add_command(label="right click") def on_select(self, index): print("select", self.get(index)) @@ -143,7 +144,7 @@ def on_double(self, index): print("double", self.get(index)) if __name__ == '__main__': from unittest import main - main('idlelib.idle_test.test_scrolledlist', verbosity=2,) + main('idlelib.idle_test.test_scrolledlist', verbosity=2, exit=False) from idlelib.idle_test.htest import run run(_scrolled_list) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index f8e60fd9b6d818a..977c56ef15f2ae4 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -113,7 +113,7 @@ def setfunction(value, key=key, object=self.object): return sublist -def _stack_viewer(parent): # htest # +def _stackbrowser(parent): # htest # from idlelib.pyshell import PyShellFileList top = tk.Toplevel(parent) top.title("Test StackViewer") @@ -131,4 +131,4 @@ def _stack_viewer(parent): # htest # main('idlelib.idle_test.test_stackviewer', verbosity=2, exit=False) from idlelib.idle_test.htest import run - run(_stack_viewer) + run(_stackbrowser) diff --git a/Lib/idlelib/undo.py b/Lib/idlelib/undo.py index 5f10c0f05c1acbf..f1d03f4c9ed5ef9 100644 --- a/Lib/idlelib/undo.py +++ b/Lib/idlelib/undo.py @@ -339,23 +339,23 @@ def bump_depth(self, incr=1): def _undo_delegator(parent): # htest # from tkinter import Toplevel, Text, Button from idlelib.percolator import Percolator - undowin = Toplevel(parent) - undowin.title("Test UndoDelegator") + top = Toplevel(parent) + top.title("Test UndoDelegator") x, y = map(int, parent.geometry().split('+')[1:]) - undowin.geometry("+%d+%d" % (x, y + 175)) + top.geometry("+%d+%d" % (x, y + 175)) - text = Text(undowin, height=10) + text = Text(top, height=10) text.pack() text.focus_set() p = Percolator(text) d = UndoDelegator() p.insertfilter(d) - undo = Button(undowin, text="Undo", command=lambda:d.undo_event(None)) + undo = Button(top, text="Undo", command=lambda:d.undo_event(None)) undo.pack(side='left') - redo = Button(undowin, text="Redo", command=lambda:d.redo_event(None)) + redo = Button(top, text="Redo", command=lambda:d.redo_event(None)) redo.pack(side='left') - dump = Button(undowin, text="Dump", command=lambda:d.dump_event(None)) + dump = Button(top, text="Dump", command=lambda:d.dump_event(None)) dump.pack(side='left') if __name__ == "__main__": From e5b0db0315941b968ebcc2414bfcdd2da44fd3c2 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Mon, 4 Dec 2023 01:36:40 -0500 Subject: [PATCH 23/87] gh-66819: More IDLE htest updates(4) (#112686) Mostly double spacing before 'if __name__...'. --- Lib/idlelib/browser.py | 1 + Lib/idlelib/calltip_w.py | 1 + Lib/idlelib/config.py | 1 + Lib/idlelib/debugobj.py | 1 + Lib/idlelib/delegator.py | 1 + Lib/idlelib/dynoption.py | 2 ++ Lib/idlelib/editor.py | 1 + Lib/idlelib/filelist.py | 1 + Lib/idlelib/grep.py | 6 ++-- Lib/idlelib/help.py | 2 ++ Lib/idlelib/idle_test/htest.py | 60 +++++++++++++++++----------------- Lib/idlelib/iomenu.py | 2 ++ Lib/idlelib/multicall.py | 1 + Lib/idlelib/outwin.py | 1 + Lib/idlelib/percolator.py | 2 ++ Lib/idlelib/pyshell.py | 1 + Lib/idlelib/redirector.py | 1 + Lib/idlelib/replace.py | 1 + Lib/idlelib/scrolledlist.py | 1 + Lib/idlelib/search.py | 1 + Lib/idlelib/sidebar.py | 4 +-- Lib/idlelib/statusbar.py | 1 + Lib/idlelib/tree.py | 1 + Lib/idlelib/undo.py | 1 + Lib/idlelib/util.py | 1 + 25 files changed, 62 insertions(+), 34 deletions(-) diff --git a/Lib/idlelib/browser.py b/Lib/idlelib/browser.py index 672e229ffbca94a..8b9060e57072ea0 100644 --- a/Lib/idlelib/browser.py +++ b/Lib/idlelib/browser.py @@ -250,6 +250,7 @@ def closure(): class Nested_in_closure: pass ModuleBrowser(parent, file, _htest=True) + if __name__ == "__main__": if len(sys.argv) == 1: # If pass file on command line, unittest fails. from unittest import main diff --git a/Lib/idlelib/calltip_w.py b/Lib/idlelib/calltip_w.py index 278546064adde29..9386376058c7916 100644 --- a/Lib/idlelib/calltip_w.py +++ b/Lib/idlelib/calltip_w.py @@ -193,6 +193,7 @@ def calltip_hide(event): text.focus_set() + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_calltip_w', verbosity=2, exit=False) diff --git a/Lib/idlelib/config.py b/Lib/idlelib/config.py index 898efeb4dd15508..92992fd9cce9cd6 100644 --- a/Lib/idlelib/config.py +++ b/Lib/idlelib/config.py @@ -906,6 +906,7 @@ def dumpCfg(cfg): dumpCfg(idleConf.userCfg) print('\nlines = ', line, ', crc = ', crc, sep='') + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_config', verbosity=2, exit=False) diff --git a/Lib/idlelib/debugobj.py b/Lib/idlelib/debugobj.py index 0bf2cb1d5bbfe26..156377f8ed26ac2 100644 --- a/Lib/idlelib/debugobj.py +++ b/Lib/idlelib/debugobj.py @@ -135,6 +135,7 @@ def _debug_object_browser(parent): # htest # node = TreeNode(sc.canvas, None, item) node.update() + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_debugobj', verbosity=2, exit=False) diff --git a/Lib/idlelib/delegator.py b/Lib/idlelib/delegator.py index 55c95da8532f472..93ae8bbd43ff440 100644 --- a/Lib/idlelib/delegator.py +++ b/Lib/idlelib/delegator.py @@ -28,6 +28,7 @@ def setdelegate(self, delegate): self.resetcache() self.delegate = delegate + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_delegator', verbosity=2) diff --git a/Lib/idlelib/dynoption.py b/Lib/idlelib/dynoption.py index d5dfc3eda13f60a..b8937f7106ca75b 100644 --- a/Lib/idlelib/dynoption.py +++ b/Lib/idlelib/dynoption.py @@ -29,6 +29,7 @@ def SetMenu(self,valueList,value=None): if value: self.variable.set(value) + def _dyn_option_menu(parent): # htest # from tkinter import Toplevel # + StringVar, Button @@ -49,6 +50,7 @@ def update(): button = Button(top, text="Change option set", command=update) button.pack() + if __name__ == '__main__': # Only module without unittests because of intention to replace. from idlelib.idle_test.htest import run diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 69b27d0683a1045..6ad383f460c7ee2 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1748,6 +1748,7 @@ def _editor_window(parent): # htest # # Does not stop error, neither does following # edit.text.bind("<>", edit.close_event) + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_editor', verbosity=2, exit=False) diff --git a/Lib/idlelib/filelist.py b/Lib/idlelib/filelist.py index f87781d2570fe06..e27e5d32a0ff633 100644 --- a/Lib/idlelib/filelist.py +++ b/Lib/idlelib/filelist.py @@ -124,6 +124,7 @@ def _test(): # TODO check and convert to htest if flist.inversedict: root.mainloop() + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_filelist', verbosity=2) diff --git a/Lib/idlelib/grep.py b/Lib/idlelib/grep.py index 12513594b76f8fd..ef14349960bfa2c 100644 --- a/Lib/idlelib/grep.py +++ b/Lib/idlelib/grep.py @@ -204,15 +204,17 @@ def _grep_dialog(parent): # htest # frame.pack() text = Text(frame, height=5) text.pack() + text.insert('1.0', 'import grep') def show_grep_dialog(): - text.tag_add(SEL, "1.0", END) + text.tag_add(SEL, "1.0", '1.end') grep(text, flist=flist) - text.tag_remove(SEL, "1.0", END) + text.tag_remove(SEL, "1.0", '1.end') button = Button(frame, text="Show GrepDialog", command=show_grep_dialog) button.pack() + if __name__ == "__main__": from unittest import main main('idlelib.idle_test.test_grep', verbosity=2, exit=False) diff --git a/Lib/idlelib/help.py b/Lib/idlelib/help.py index 580a327f620a792..3cc7e36e35555b0 100644 --- a/Lib/idlelib/help.py +++ b/Lib/idlelib/help.py @@ -278,6 +278,7 @@ def copy_strip(): out.write(line.rstrip() + b'\n') print(f'{src} copied to {dst}') + def _helpwindow(parent): "Create HelpWindow; called from Idle Help event handler." filename = join(abspath(dirname(__file__)), 'help.html') @@ -286,6 +287,7 @@ def _helpwindow(parent): return HelpWindow(parent, filename, 'IDLE Help (%s)' % python_version()) + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_help', verbosity=2, exit=False) diff --git a/Lib/idlelib/idle_test/htest.py b/Lib/idlelib/idle_test/htest.py index 4042106bf44a9f7..997f85ff5a78b21 100644 --- a/Lib/idlelib/idle_test/htest.py +++ b/Lib/idlelib/idle_test/htest.py @@ -170,8 +170,8 @@ 'msg': "Click the 'Show GrepDialog' button.\n" "Test the various 'Find-in-files' functions.\n" "The results should be displayed in a new '*Output*' window.\n" - "'Right-click'->'Go to file/line' anywhere in the search results " - "should open that file \nin a new EditorWindow." + "'Right-click'->'Go to file/line' in the search results\n " + "should open that file in a new EditorWindow." } HelpSource_spec = { @@ -210,26 +210,6 @@ "Check that changes were saved by opening the file elsewhere." } -_linenumbers_drag_scrolling_spec = { - 'file': 'sidebar', - 'kwds': {}, - 'msg': textwrap.dedent("""\ - 1. Click on the line numbers and drag down below the edge of the - window, moving the mouse a bit and then leaving it there for a - while. The text and line numbers should gradually scroll down, - with the selection updated continuously. - - 2. With the lines still selected, click on a line number above - or below the selected lines. Only the line whose number was - clicked should be selected. - - 3. Repeat step #1, dragging to above the window. The text and - line numbers should gradually scroll up, with the selection - updated continuously. - - 4. Repeat step #2, clicking a line number below the selection."""), - } - _multi_call_spec = { 'file': 'multicall', 'kwds': {}, @@ -295,6 +275,15 @@ "Click [Close] or [X] to close the 'Replace Dialog'." } +_scrolled_list_spec = { + 'file': 'scrolledlist', + 'kwds': {}, + 'msg': "You should see a scrollable list of items\n" + "Selecting (clicking) or double clicking an item " + "prints the name to the console or Idle shell.\n" + "Right clicking an item will display a popup." + } + _search_dialog_spec = { 'file': 'search', 'kwds': {}, @@ -310,21 +299,31 @@ "Its only action is to close." } -_scrolled_list_spec = { - 'file': 'scrolledlist', +_sidebar_number_scrolling_spec = { + 'file': 'sidebar', 'kwds': {}, - 'msg': "You should see a scrollable list of items\n" - "Selecting (clicking) or double clicking an item " - "prints the name to the console or Idle shell.\n" - "Right clicking an item will display a popup." + 'msg': textwrap.dedent("""\ + 1. Click on the line numbers and drag down below the edge of the + window, moving the mouse a bit and then leaving it there for a + while. The text and line numbers should gradually scroll down, + with the selection updated continuously. + + 2. With the lines still selected, click on a line number above + or below the selected lines. Only the line whose number was + clicked should be selected. + + 3. Repeat step #1, dragging to above the window. The text and + line numbers should gradually scroll up, with the selection + updated continuously. + + 4. Repeat step #2, clicking a line number below the selection."""), } _stackbrowser_spec = { 'file': 'stackviewer', 'kwds': {}, 'msg': "A stacktrace for a NameError exception.\n" - "Expand 'idlelib ...' and ''.\n" - "Check that exc_value, exc_tb, and exc_type are correct.\n" + "Should have NameError and 1 traceback line." } _tooltip_spec = { @@ -438,5 +437,6 @@ def close(_=None): next_test() root.mainloop() + if __name__ == '__main__': run() diff --git a/Lib/idlelib/iomenu.py b/Lib/idlelib/iomenu.py index 7629101635b8bbe..667623ec71ac982 100644 --- a/Lib/idlelib/iomenu.py +++ b/Lib/idlelib/iomenu.py @@ -393,6 +393,7 @@ def updaterecentfileslist(self,filename): if self.editwin.flist: self.editwin.update_recent_files_list(filename) + def _io_binding(parent): # htest # from tkinter import Toplevel, Text @@ -430,6 +431,7 @@ def savecopy(self, event): editwin = MyEditWin(text) IOBinding(editwin) + if __name__ == "__main__": from unittest import main main('idlelib.idle_test.test_iomenu', verbosity=2, exit=False) diff --git a/Lib/idlelib/multicall.py b/Lib/idlelib/multicall.py index 2aa4a54125156f7..41f818131130621 100644 --- a/Lib/idlelib/multicall.py +++ b/Lib/idlelib/multicall.py @@ -442,6 +442,7 @@ def handler(event): bindseq("") bindseq("") + if __name__ == "__main__": from unittest import main main('idlelib.idle_test.test_mainmenu', verbosity=2, exit=False) diff --git a/Lib/idlelib/outwin.py b/Lib/idlelib/outwin.py index 610031e26f1dffe..5ed3f35a7af6558 100644 --- a/Lib/idlelib/outwin.py +++ b/Lib/idlelib/outwin.py @@ -182,6 +182,7 @@ def setup(self): text.tag_raise('sel') self.write = self.owin.write + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_outwin', verbosity=2, exit=False) diff --git a/Lib/idlelib/percolator.py b/Lib/idlelib/percolator.py index 91ad7272f4ae560..aa73427c4915c8c 100644 --- a/Lib/idlelib/percolator.py +++ b/Lib/idlelib/percolator.py @@ -103,6 +103,7 @@ def toggle2(): (pin if var2.get() else pout)(t2) text.pack() + text.focus_set() var1 = tk.IntVar(parent) cb1 = tk.Checkbutton(top, text="Tracer1", command=toggle1, variable=var1) cb1.pack() @@ -110,6 +111,7 @@ def toggle2(): cb2 = tk.Checkbutton(top, text="Tracer2", command=toggle2, variable=var2) cb2.pack() + if __name__ == "__main__": from unittest import main main('idlelib.idle_test.test_percolator', verbosity=2, exit=False) diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index 00b3732a7bc4eb4..1524fccd5d20f8e 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1694,6 +1694,7 @@ def main(): root.destroy() capture_warnings(False) + if __name__ == "__main__": main() diff --git a/Lib/idlelib/redirector.py b/Lib/idlelib/redirector.py index 4928340e98df686..08728956abd9008 100644 --- a/Lib/idlelib/redirector.py +++ b/Lib/idlelib/redirector.py @@ -164,6 +164,7 @@ def my_insert(*args): original_insert(*args) original_insert = redir.register("insert", my_insert) + if __name__ == "__main__": from unittest import main main('idlelib.idle_test.test_redirector', verbosity=2, exit=False) diff --git a/Lib/idlelib/replace.py b/Lib/idlelib/replace.py index ca83173877ad1d9..a29ca5914274915 100644 --- a/Lib/idlelib/replace.py +++ b/Lib/idlelib/replace.py @@ -299,6 +299,7 @@ def show_replace(): button = Button(frame, text="Replace", command=show_replace) button.pack() + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_replace', verbosity=2, exit=False) diff --git a/Lib/idlelib/scrolledlist.py b/Lib/idlelib/scrolledlist.py index 4f1241a576fca1c..4fb418db3262556 100644 --- a/Lib/idlelib/scrolledlist.py +++ b/Lib/idlelib/scrolledlist.py @@ -142,6 +142,7 @@ def on_double(self, index): print("double", self.get(index)) for i in range(30): scrolled_list.append("Item %02d" % i) + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_scrolledlist', verbosity=2, exit=False) diff --git a/Lib/idlelib/search.py b/Lib/idlelib/search.py index b35f3b59c3d2e8f..935a4832257fa4a 100644 --- a/Lib/idlelib/search.py +++ b/Lib/idlelib/search.py @@ -156,6 +156,7 @@ def show_find(): button = Button(frame, text="Search (selection ignored)", command=show_find) button.pack() + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_search', verbosity=2, exit=False) diff --git a/Lib/idlelib/sidebar.py b/Lib/idlelib/sidebar.py index 8e7eae5037c90c7..ff77b568a786e0f 100644 --- a/Lib/idlelib/sidebar.py +++ b/Lib/idlelib/sidebar.py @@ -513,7 +513,7 @@ def update_colors(self): self.change_callback() -def _linenumbers_drag_scrolling(parent): # htest # +def _sidebar_number_scrolling(parent): # htest # from idlelib.idle_test.test_sidebar import Dummy_editwin top = tk.Toplevel(parent) @@ -540,4 +540,4 @@ def _linenumbers_drag_scrolling(parent): # htest # main('idlelib.idle_test.test_sidebar', verbosity=2, exit=False) from idlelib.idle_test.htest import run - run(_linenumbers_drag_scrolling) + run(_sidebar_number_scrolling) diff --git a/Lib/idlelib/statusbar.py b/Lib/idlelib/statusbar.py index 7048bd64b98753f..8445d4cc8dfdb9e 100644 --- a/Lib/idlelib/statusbar.py +++ b/Lib/idlelib/statusbar.py @@ -43,6 +43,7 @@ def change(): button.pack(side='bottom') frame.pack() + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_statusbar', verbosity=2, exit=False) diff --git a/Lib/idlelib/tree.py b/Lib/idlelib/tree.py index 5f30f0f6092bfa5..9c2eb47b24aec94 100644 --- a/Lib/idlelib/tree.py +++ b/Lib/idlelib/tree.py @@ -492,6 +492,7 @@ def _tree_widget(parent): # htest # node = TreeNode(sc.canvas, None, item) node.expand() + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_tree', verbosity=2, exit=False) diff --git a/Lib/idlelib/undo.py b/Lib/idlelib/undo.py index f1d03f4c9ed5ef9..f52446d5fcdcf84 100644 --- a/Lib/idlelib/undo.py +++ b/Lib/idlelib/undo.py @@ -358,6 +358,7 @@ def _undo_delegator(parent): # htest # dump = Button(top, text="Dump", command=lambda:d.dump_event(None)) dump.pack(side='left') + if __name__ == "__main__": from unittest import main main('idlelib.idle_test.test_undo', verbosity=2, exit=False) diff --git a/Lib/idlelib/util.py b/Lib/idlelib/util.py index ede670a4db55360..5ac69a7b94cb56d 100644 --- a/Lib/idlelib/util.py +++ b/Lib/idlelib/util.py @@ -16,6 +16,7 @@ # .pyw is for Windows; .pyi is for stub files. py_extensions = ('.py', '.pyw', '.pyi') # Order needed for open/save dialogs. + if __name__ == '__main__': from unittest import main main('idlelib.idle_test.test_util', verbosity=2) From 23e001fa9f1897ba3384c02bbbe634313358a549 Mon Sep 17 00:00:00 2001 From: Christopher Chavez Date: Mon, 4 Dec 2023 02:00:27 -0600 Subject: [PATCH 24/87] gh-112678: Declare `Tkapp_CallDeallocArgs()` as `static` (GH-112679) --- Modules/_tkinter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index f9a18644945c653..64e752c305aae16 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -1202,7 +1202,7 @@ typedef struct Tkapp_CallEvent { Tcl_Condition *done; } Tkapp_CallEvent; -void +static void Tkapp_CallDeallocArgs(Tcl_Obj** objv, Tcl_Obj** objStore, int objc) { int i; From 0e732d0997cff08855d98c17af4dd5527f10e419 Mon Sep 17 00:00:00 2001 From: chilaxan Date: Mon, 4 Dec 2023 03:15:43 -0500 Subject: [PATCH 25/87] gh-112625: Protect bytearray from being freed by misbehaving iterator inside bytearray.join (GH-112626) --- Lib/test/test_builtin.py | 17 +++++++++++++++++ ...23-12-03-19-34-51.gh-issue-112625.QWTlwS.rst | 1 + Objects/bytearrayobject.c | 5 ++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-12-03-19-34-51.gh-issue-112625.QWTlwS.rst diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index b7966f8f03875b3..535856adaea4d35 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -2039,6 +2039,23 @@ def test_bytearray_extend_error(self): bad_iter = map(int, "X") self.assertRaises(ValueError, array.extend, bad_iter) + def test_bytearray_join_with_misbehaving_iterator(self): + # Issue #112625 + array = bytearray(b',') + def iterator(): + array.clear() + yield b'A' + yield b'B' + self.assertRaises(BufferError, array.join, iterator()) + + def test_bytearray_join_with_custom_iterator(self): + # Issue #112625 + array = bytearray(b',') + def iterator(): + yield b'A' + yield b'B' + self.assertEqual(bytearray(b'A,B'), array.join(iterator())) + def test_construct_singletons(self): for const in None, Ellipsis, NotImplemented: tp = type(const) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-03-19-34-51.gh-issue-112625.QWTlwS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-03-19-34-51.gh-issue-112625.QWTlwS.rst new file mode 100644 index 000000000000000..4970e10f3f4dcb1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-12-03-19-34-51.gh-issue-112625.QWTlwS.rst @@ -0,0 +1 @@ +Fixes a bug where a bytearray object could be cleared while iterating over an argument in the ``bytearray.join()`` method that could result in reading memory after it was freed. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 67073190cc889d1..659de7d3dd5a994 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -2007,7 +2007,10 @@ static PyObject * bytearray_join(PyByteArrayObject *self, PyObject *iterable_of_bytes) /*[clinic end generated code: output=a8516370bf68ae08 input=aba6b1f9b30fcb8e]*/ { - return stringlib_bytes_join((PyObject*)self, iterable_of_bytes); + self->ob_exports++; // this protects `self` from being cleared/resized if `iterable_of_bytes` is a custom iterator + PyObject* ret = stringlib_bytes_join((PyObject*)self, iterable_of_bytes); + self->ob_exports--; // unexport `self` + return ret; } /*[clinic input] From dee7beeb4f9d28fec945c8c495027cc22a512328 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 4 Dec 2023 11:09:06 +0200 Subject: [PATCH 26/87] bpo-34392: Add sys. _is_interned() (GH-8755) --- Doc/library/sys.rst | 12 +++++++ Doc/whatsnew/3.13.rst | 7 ++++ Lib/test/test_sys.py | 14 ++++++++ .../2018-08-13-13-25-15.bpo-34392.9kIlMF.rst | 1 + Python/clinic/sysmodule.c.h | 36 ++++++++++++++++++- Python/sysmodule.c | 18 ++++++++++ 6 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2018-08-13-13-25-15.bpo-34392.9kIlMF.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index bf9aaca2a696ded..7f359819e6847ee 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1205,6 +1205,18 @@ always available. .. versionadded:: 3.12 +.. function:: _is_interned(string) + + Return :const:`True` if the given string is "interned", :const:`False` + otherwise. + + .. versionadded:: 3.13 + + .. impl-detail:: + + It is not guaranteed to exist in all implementations of Python. + + .. data:: last_type last_value last_traceback diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 372e4a45468e68b..676305c6e1d06a8 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -297,6 +297,13 @@ sqlite3 object is not :meth:`closed ` explicitly. (Contributed by Erlend E. Aasland in :gh:`105539`.) +sys +--- + +* Add the :func:`sys._is_interned` function to test if the string was interned. + This function is not guaranteed to exist in all implementations of Python. + (Contributed by Serhiy Storchaka in :gh:`78573`.) + tkinter ------- diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 0028281596fa4be..8c2c1a40f74bf24 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -691,11 +691,23 @@ def test_43581(self): self.assertEqual(sys.__stdout__.encoding, sys.__stderr__.encoding) def test_intern(self): + has_is_interned = (test.support.check_impl_detail(cpython=True) + or hasattr(sys, '_is_interned')) self.assertRaises(TypeError, sys.intern) + self.assertRaises(TypeError, sys.intern, b'abc') + if has_is_interned: + self.assertRaises(TypeError, sys._is_interned) + self.assertRaises(TypeError, sys._is_interned, b'abc') s = "never interned before" + str(random.randrange(0, 10**9)) self.assertTrue(sys.intern(s) is s) + if has_is_interned: + self.assertIs(sys._is_interned(s), True) s2 = s.swapcase().swapcase() + if has_is_interned: + self.assertIs(sys._is_interned(s2), False) self.assertTrue(sys.intern(s2) is s) + if has_is_interned: + self.assertIs(sys._is_interned(s2), False) # Subclasses of string can't be interned, because they # provide too much opportunity for insane things to happen. @@ -707,6 +719,8 @@ def __hash__(self): return 123 self.assertRaises(TypeError, sys.intern, S("abc")) + if has_is_interned: + self.assertIs(sys._is_interned(S("abc")), False) @requires_subinterpreters def test_subinterp_intern_dynamically_allocated(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-08-13-13-25-15.bpo-34392.9kIlMF.rst b/Misc/NEWS.d/next/Core and Builtins/2018-08-13-13-25-15.bpo-34392.9kIlMF.rst new file mode 100644 index 000000000000000..bc4fd1ad1f5c7ca --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-08-13-13-25-15.bpo-34392.9kIlMF.rst @@ -0,0 +1 @@ +Added :func:`sys._is_interned`. diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 98717ecc875b8bc..93b8385a5b4097c 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -289,6 +289,40 @@ sys_intern(PyObject *module, PyObject *arg) return return_value; } +PyDoc_STRVAR(sys__is_interned__doc__, +"_is_interned($module, string, /)\n" +"--\n" +"\n" +"Return True if the given string is \"interned\"."); + +#define SYS__IS_INTERNED_METHODDEF \ + {"_is_interned", (PyCFunction)sys__is_interned, METH_O, sys__is_interned__doc__}, + +static int +sys__is_interned_impl(PyObject *module, PyObject *string); + +static PyObject * +sys__is_interned(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *string; + int _return_value; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("_is_interned", "argument", "str", arg); + goto exit; + } + string = arg; + _return_value = sys__is_interned_impl(module, string); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyBool_FromLong((long)_return_value); + +exit: + return return_value; +} + PyDoc_STRVAR(sys__settraceallthreads__doc__, "_settraceallthreads($module, arg, /)\n" "--\n" @@ -1452,4 +1486,4 @@ sys__get_cpu_count_config(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=f36d45c829250775 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3dc3b2cb0ce38ebb input=a9049054013a1b77]*/ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index c17de44731b7030..46878c7c9687f5c 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -989,6 +989,23 @@ sys_intern_impl(PyObject *module, PyObject *s) } +/*[clinic input] +sys._is_interned -> bool + + string: unicode + / + +Return True if the given string is "interned". +[clinic start generated code]*/ + +static int +sys__is_interned_impl(PyObject *module, PyObject *string) +/*[clinic end generated code: output=c3678267b4e9d7ed input=039843e17883b606]*/ +{ + return PyUnicode_CHECK_INTERNED(string); +} + + /* * Cached interned string objects used for calling the profile and * trace functions. @@ -2462,6 +2479,7 @@ static PyMethodDef sys_methods[] = { SYS_GETWINDOWSVERSION_METHODDEF SYS__ENABLELEGACYWINDOWSFSENCODING_METHODDEF SYS_INTERN_METHODDEF + SYS__IS_INTERNED_METHODDEF SYS_IS_FINALIZING_METHODDEF SYS_MDEBUG_METHODDEF SYS_SETSWITCHINTERVAL_METHODDEF From a74902a14cdc0952abf7bfabcf529c9b132c5cce Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 Dec 2023 11:42:58 +0100 Subject: [PATCH 27/87] gh-106550: Fix sign conversion in pycore_code.h (#112613) Fix sign conversion in pycore_code.h: use unsigned integers and cast explicitly when needed. --- Include/internal/pycore_code.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index eaf84a9c94fc9be..73df6c3568ffe0c 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -394,27 +394,29 @@ write_varint(uint8_t *ptr, unsigned int val) val >>= 6; written++; } - *ptr = val; + *ptr = (uint8_t)val; return written; } static inline int write_signed_varint(uint8_t *ptr, int val) { + unsigned int uval; if (val < 0) { - val = ((-val)<<1) | 1; + // (unsigned int)(-val) has an undefined behavior for INT_MIN + uval = ((0 - (unsigned int)val) << 1) | 1; } else { - val = val << 1; + uval = (unsigned int)val << 1; } - return write_varint(ptr, val); + return write_varint(ptr, uval); } static inline int write_location_entry_start(uint8_t *ptr, int code, int length) { assert((code & 15) == code); - *ptr = 128 | (code << 3) | (length - 1); + *ptr = 128 | (uint8_t)(code << 3) | (uint8_t)(length - 1); return 1; } @@ -454,9 +456,9 @@ write_location_entry_start(uint8_t *ptr, int code, int length) static inline uint16_t -adaptive_counter_bits(int value, int backoff) { - return (value << ADAPTIVE_BACKOFF_BITS) | - (backoff & ((1< MAX_BACKOFF_VALUE) { backoff = MAX_BACKOFF_VALUE; } - unsigned int value = (1 << backoff) - 1; + uint16_t value = (uint16_t)(1 << backoff) - 1; return adaptive_counter_bits(value, backoff); } From cda737924fd616c4e08027888258f97e81f34447 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 4 Dec 2023 11:05:20 +0000 Subject: [PATCH 28/87] gh-101100: Fix Sphinx nitpicks in `library/functions.rst` (#112669) --- Doc/library/functions.rst | 113 ++++++++++++++++++++++---------------- Doc/tools/.nitignore | 1 - 2 files changed, 67 insertions(+), 47 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index b2dd32f925ef4df..c731b6fd3332753 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -57,7 +57,8 @@ are always available. They are listed here in alphabetical order. .. function:: abs(x) Return the absolute value of a number. The argument may be an - integer, a floating point number, or an object implementing :meth:`__abs__`. + integer, a floating point number, or an object implementing + :meth:`~object.__abs__`. If the argument is a complex number, its magnitude is returned. @@ -235,7 +236,7 @@ are always available. They are listed here in alphabetical order. :const:`False` if not. If this returns ``True``, it is still possible that a call fails, but if it is ``False``, calling *object* will never succeed. Note that classes are callable (calling a class returns a new instance); - instances are callable if their class has a :meth:`__call__` method. + instances are callable if their class has a :meth:`~object.__call__` method. .. versionadded:: 3.2 This function was first removed in Python 3.0 and then brought back @@ -432,15 +433,18 @@ are always available. They are listed here in alphabetical order. Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object. - If the object has a method named :meth:`__dir__`, this method will be called and + If the object has a method named :meth:`~object.__dir__`, + this method will be called and must return the list of attributes. This allows objects that implement a custom - :func:`__getattr__` or :func:`__getattribute__` function to customize the way + :func:`~object.__getattr__` or :func:`~object.__getattribute__` function + to customize the way :func:`dir` reports their attributes. - If the object does not provide :meth:`__dir__`, the function tries its best to - gather information from the object's :attr:`~object.__dict__` attribute, if defined, and + If the object does not provide :meth:`~object.__dir__`, + the function tries its best to gather information from the object's + :attr:`~object.__dict__` attribute, if defined, and from its type object. The resulting list is not necessarily complete and may - be inaccurate when the object has a custom :func:`__getattr__`. + be inaccurate when the object has a custom :func:`~object.__getattr__`. The default :func:`dir` mechanism behaves differently with different types of objects, as it attempts to produce the most relevant, rather than complete, @@ -664,7 +668,7 @@ are always available. They are listed here in alphabetical order. sign: "+" | "-" infinity: "Infinity" | "inf" nan: "nan" - digitpart: `digit` (["_"] `digit`)* + digitpart: `!digit` (["_"] `!digit`)* number: [`digitpart`] "." `digitpart` | `digitpart` ["."] exponent: ("e" | "E") ["+" | "-"] `digitpart` floatnumber: number [`exponent`] @@ -727,8 +731,8 @@ are always available. They are listed here in alphabetical order. A call to ``format(value, format_spec)`` is translated to ``type(value).__format__(value, format_spec)`` which bypasses the instance - dictionary when searching for the value's :meth:`__format__` method. A - :exc:`TypeError` exception is raised if the method search reaches + dictionary when searching for the value's :meth:`~object.__format__` method. + A :exc:`TypeError` exception is raised if the method search reaches :mod:`object` and the *format_spec* is non-empty, or if either the *format_spec* or the return value are not strings. @@ -792,9 +796,9 @@ are always available. They are listed here in alphabetical order. .. note:: - For objects with custom :meth:`__hash__` methods, note that :func:`hash` + For objects with custom :meth:`~object.__hash__` methods, + note that :func:`hash` truncates the return value based on the bit width of the host machine. - See :meth:`__hash__ ` for details. .. function:: help() help(request) @@ -982,7 +986,8 @@ are always available. They are listed here in alphabetical order. Return an :term:`iterator` object. The first argument is interpreted very differently depending on the presence of the second argument. Without a second argument, *object* must be a collection object which supports the - :term:`iterable` protocol (the :meth:`__iter__` method), or it must support + :term:`iterable` protocol (the :meth:`~object.__iter__` method), + or it must support the sequence protocol (the :meth:`~object.__getitem__` method with integer arguments starting at ``0``). If it does not support either of those protocols, :exc:`TypeError` is raised. If the second argument, *sentinel*, is given, @@ -1500,38 +1505,44 @@ are always available. They are listed here in alphabetical order. """Get the current voltage.""" return self._voltage - The ``@property`` decorator turns the :meth:`voltage` method into a "getter" + The ``@property`` decorator turns the :meth:`!voltage` method into a "getter" for a read-only attribute with the same name, and it sets the docstring for *voltage* to "Get the current voltage." - A property object has :attr:`~property.getter`, :attr:`~property.setter`, - and :attr:`~property.deleter` methods usable as decorators that create a - copy of the property with the corresponding accessor function set to the - decorated function. This is best explained with an example:: + .. decorator:: property.getter + .. decorator:: property.setter + .. decorator:: property.deleter - class C: - def __init__(self): - self._x = None + A property object has ``getter``, ``setter``, + and ``deleter`` methods usable as decorators that create a + copy of the property with the corresponding accessor function set to the + decorated function. This is best explained with an example: - @property - def x(self): - """I'm the 'x' property.""" - return self._x + .. testcode:: - @x.setter - def x(self, value): - self._x = value + class C: + def __init__(self): + self._x = None - @x.deleter - def x(self): - del self._x + @property + def x(self): + """I'm the 'x' property.""" + return self._x - This code is exactly equivalent to the first example. Be sure to give the - additional functions the same name as the original property (``x`` in this - case.) + @x.setter + def x(self, value): + self._x = value - The returned property object also has the attributes ``fget``, ``fset``, and - ``fdel`` corresponding to the constructor arguments. + @x.deleter + def x(self): + del self._x + + This code is exactly equivalent to the first example. Be sure to give the + additional functions the same name as the original property (``x`` in this + case.) + + The returned property object also has the attributes ``fget``, ``fset``, and + ``fdel`` corresponding to the constructor arguments. .. versionchanged:: 3.5 The docstrings of property objects are now writeable. @@ -1554,7 +1565,8 @@ are always available. They are listed here in alphabetical order. representation is a string enclosed in angle brackets that contains the name of the type of the object together with additional information often including the name and address of the object. A class can control what this - function returns for its instances by defining a :meth:`__repr__` method. + function returns for its instances + by defining a :meth:`~object.__repr__` method. If :func:`sys.displayhook` is not accessible, this function will raise :exc:`RuntimeError`. @@ -1562,9 +1574,9 @@ are always available. They are listed here in alphabetical order. .. function:: reversed(seq) Return a reverse :term:`iterator`. *seq* must be an object which has - a :meth:`__reversed__` method or supports the sequence protocol (the - :meth:`__len__` method and the :meth:`~object.__getitem__` method with integer - arguments starting at ``0``). + a :meth:`~object.__reversed__` method or supports the sequence protocol (the + :meth:`~object.__len__` method and the :meth:`~object.__getitem__` method + with integer arguments starting at ``0``). .. function:: round(number, ndigits=None) @@ -1635,13 +1647,21 @@ are always available. They are listed here in alphabetical order. Return a :term:`slice` object representing the set of indices specified by ``range(start, stop, step)``. The *start* and *step* arguments default to - ``None``. Slice objects have read-only data attributes :attr:`~slice.start`, - :attr:`~slice.stop`, and :attr:`~slice.step` which merely return the argument - values (or their default). They have no other explicit functionality; - however, they are used by NumPy and other third-party packages. + ``None``. + + .. attribute:: slice.start + .. attribute:: slice.stop + .. attribute:: slice.step + + Slice objects have read-only data attributes :attr:`!start`, + :attr:`!stop`, and :attr:`!step` which merely return the argument + values (or their default). They have no other explicit functionality; + however, they are used by NumPy and other third-party packages. + Slice objects are also generated when extended indexing syntax is used. For example: ``a[start:stop:step]`` or ``a[start:stop, i]``. See - :func:`itertools.islice` for an alternate version that returns an iterator. + :func:`itertools.islice` for an alternate version that returns an + :term:`iterator`. .. versionchanged:: 3.12 Slice objects are now :term:`hashable` (provided :attr:`~slice.start`, @@ -1808,7 +1828,8 @@ are always available. They are listed here in alphabetical order. Note that :func:`super` is implemented as part of the binding process for explicit dotted attribute lookups such as ``super().__getitem__(name)``. - It does so by implementing its own :meth:`__getattribute__` method for searching + It does so by implementing its own :meth:`~object.__getattribute__` method + for searching classes in a predictable order that supports cooperative multiple inheritance. Accordingly, :func:`super` is undefined for implicit lookups using statements or operators such as ``super()[name]``. diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 8d79a848b7cc7b3..e79b4c3bdecb671 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -56,7 +56,6 @@ Doc/library/exceptions.rst Doc/library/faulthandler.rst Doc/library/fcntl.rst Doc/library/ftplib.rst -Doc/library/functions.rst Doc/library/functools.rst Doc/library/http.client.rst Doc/library/http.cookiejar.rst From da6760bdf5ed8ede203618d5118f4ceb2cb1652d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 4 Dec 2023 13:14:56 +0200 Subject: [PATCH 29/87] gh-65210: Add const qualifiers in PyArg_VaParseTupleAndKeywords() (GH-105958) Change the declaration of the keywords parameter in functions PyArg_ParseTupleAndKeywords() and PyArg_VaParseTupleAndKeywords() from `char **` to `char * const *` in C and `const char * const *` in C++. It makes these functions compatible with argument of type `const char * const *`, `const char **` or `char * const *` in C++ and `char * const *` in C without explicit type cast. Co-authored-by: C.A.M. Gerlach --- Doc/c-api/arg.rst | 26 +++++++++++++++++-- Doc/extending/extending.rst | 2 +- Doc/whatsnew/3.13.rst | 10 +++++++ Include/modsupport.h | 4 +-- Include/pyport.h | 8 ++++++ ...3-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst | 3 +++ Python/getargs.c | 17 ++++++------ 7 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index 62d87d898e682c5..834aae9372fe3bd 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -413,7 +413,7 @@ API Functions than a variable number of arguments. -.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], ...) +.. c:function:: int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char * const *keywords, ...) Parse the parameters of a function that takes both positional and keyword parameters into local variables. @@ -424,15 +424,24 @@ API Functions Returns true on success; on failure, it returns false and raises the appropriate exception. + .. note:: + + The *keywords* parameter declaration is :c:expr:`char * const *` in C and + :c:expr:`const char * const *` in C++. + This can be overridden with the :c:macro:`PY_CXX_CONST` macro. + .. versionchanged:: 3.6 Added support for :ref:`positional-only parameters `. .. versionchanged:: 3.13 + The *keywords* parameter has now type :c:expr:`char * const *` in C and + :c:expr:`const char * const *` in C++, instead of :c:expr:`char **`. Added support for non-ASCII keyword parameter names. -.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], va_list vargs) + +.. c:function:: int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char * const *keywords, va_list vargs) Identical to :c:func:`PyArg_ParseTupleAndKeywords`, except that it accepts a va_list rather than a variable number of arguments. @@ -505,6 +514,19 @@ API Functions PyArg_ParseTuple(args, "O|O:ref", &object, &callback) +.. c:macro:: PY_CXX_CONST + + The value to be inserted, if any, before :c:expr:`char * const *` + in the *keywords* parameter declaration of + :c:func:`PyArg_ParseTupleAndKeywords` and + :c:func:`PyArg_VaParseTupleAndKeywords`. + Default empty for C and ``const`` for C++ + (:c:expr:`const char * const *`). + To override, define it to the desired value before including + :file:`Python.h`. + + .. versionadded:: 3.13 + --------------- Building values diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index 1ee7f28b2ba2206..745fc10a22d1612 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -735,7 +735,7 @@ Keyword Parameters for Extension Functions The :c:func:`PyArg_ParseTupleAndKeywords` function is declared as follows:: int PyArg_ParseTupleAndKeywords(PyObject *arg, PyObject *kwdict, - const char *format, char *kwlist[], ...); + const char *format, char * const *kwlist, ...); The *arg* and *format* parameters are identical to those of the :c:func:`PyArg_ParseTuple` function. The *kwdict* parameter is the dictionary of diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 676305c6e1d06a8..be890ff314dfa44 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -1111,6 +1111,16 @@ New Features APIs accepting the format codes always use ``Py_ssize_t`` for ``#`` formats. (Contributed by Inada Naoki in :gh:`104922`.) +* The *keywords* parameter of :c:func:`PyArg_ParseTupleAndKeywords` and + :c:func:`PyArg_VaParseTupleAndKeywords` has now type :c:expr:`char * const *` + in C and :c:expr:`const char * const *` in C++, instead of :c:expr:`char **`. + It makes these functions compatible with arguments of type + :c:expr:`const char * const *`, :c:expr:`const char **` or + :c:expr:`char * const *` in C++ and :c:expr:`char * const *` in C + without an explicit type cast. + This can be overridden with the :c:macro:`PY_CXX_CONST` macro. + (Contributed by Serhiy Storchaka in :gh:`65210`.) + * Add :c:func:`PyImport_AddModuleRef`: similar to :c:func:`PyImport_AddModule`, but return a :term:`strong reference` instead of a :term:`borrowed reference`. diff --git a/Include/modsupport.h b/Include/modsupport.h index 450cc99c404c170..ea4c0fce9f4562c 100644 --- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -9,10 +9,10 @@ extern "C" { PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...); PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...); PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, ...); + const char *, PY_CXX_CONST char * const *, ...); PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list); PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, va_list); + const char *, PY_CXX_CONST char * const *, va_list); PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *); PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...); diff --git a/Include/pyport.h b/Include/pyport.h index abb526d503fddd7..328471085f959da 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -586,6 +586,14 @@ extern "C" { # define ALIGNOF_MAX_ALIGN_T _Alignof(long double) #endif +#ifndef PY_CXX_CONST +# ifdef __cplusplus +# define PY_CXX_CONST const +# else +# define PY_CXX_CONST +# endif +#endif + #if defined(__sgi) && !defined(_SGI_MP_SOURCE) # define _SGI_MP_SOURCE #endif diff --git a/Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst b/Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst new file mode 100644 index 000000000000000..a15646f4dad1272 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-06-21-11-53-09.gh-issue-65210.PhFRBJ.rst @@ -0,0 +1,3 @@ +Change the declaration of the *keywords* parameter of +:c:func:`PyArg_ParseTupleAndKeywords` and +:c:func:`PyArg_VaParseTupleAndKeywords` for better compatibility with C++. diff --git a/Python/getargs.c b/Python/getargs.c index 5ff8f7473609f5e..0c4ce282f487648 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1,6 +1,7 @@ /* New getargs implementation */ +#define PY_CXX_CONST const #include "Python.h" #include "pycore_abstract.h" // _PyNumber_Index() #include "pycore_dict.h" // _PyDict_HasOnlyStringKeys() @@ -12,10 +13,10 @@ PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *, - const char *, char **, ...); + const char *, const char * const *, ...); PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, const char *, va_list); PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *, - const char *, char **, va_list); + const char *, const char * const *, va_list); #define FLAG_COMPAT 1 @@ -54,7 +55,7 @@ static Py_ssize_t convertbuffer(PyObject *, const void **p, const char **); static int getbuffer(PyObject *, Py_buffer *, const char**); static int vgetargskeywords(PyObject *, PyObject *, - const char *, char **, va_list *, int); + const char *, const char * const *, va_list *, int); static int vgetargskeywordsfast(PyObject *, PyObject *, struct _PyArg_Parser *, va_list *, int); static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, @@ -1247,7 +1248,7 @@ int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, ...) + const char * const *kwlist, ...) { int retval; va_list va; @@ -1271,7 +1272,7 @@ int _PyArg_ParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, ...) + const char * const *kwlist, ...) { int retval; va_list va; @@ -1297,7 +1298,7 @@ int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, va_list va) + const char * const *kwlist, va_list va) { int retval; va_list lva; @@ -1322,7 +1323,7 @@ int _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, va_list va) + const char * const *kwlist, va_list va) { int retval; va_list lva; @@ -1460,7 +1461,7 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs) static int vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, - char **kwlist, va_list *p_va, int flags) + const char * const *kwlist, va_list *p_va, int flags) { char msgbuf[512]; int levels[32]; From c74e9fb18917ceb287c3ed5be5d0c2a16a646a99 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 4 Dec 2023 13:30:32 +0200 Subject: [PATCH 30/87] gh-110275: Named tuple's __replace__() now raises TypeError for invalid arguments (GH-110299) --- Doc/library/collections.rst | 4 ++++ Lib/collections/__init__.py | 2 +- Lib/test/test_collections.py | 6 +----- Lib/test/test_copy.py | 2 +- .../Library/2023-11-08-16-11-04.gh-issue-110275.Bm6GwR.rst | 2 ++ 5 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-08-16-11-04.gh-issue-110275.Bm6GwR.rst diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 17dd6da7479e504..233b2c6a771f4a1 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -981,6 +981,10 @@ field names, the method and attribute names start with an underscore. Named tuples are also supported by generic function :func:`copy.replace`. + .. versionchanged:: 3.13 + Raise :exc:`TypeError` instead of :exc:`ValueError` for invalid + keyword arguments. + .. attribute:: somenamedtuple._fields Tuple of strings listing the field names. Useful for introspection diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index a461550ea40da74..2e527dfd810c43b 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -457,7 +457,7 @@ def _make(cls, iterable): def _replace(self, /, **kwds): result = self._make(_map(kwds.pop, field_names, self)) if kwds: - raise ValueError(f'Got unexpected field names: {list(kwds)!r}') + raise TypeError(f'Got unexpected field names: {list(kwds)!r}') return result _replace.__doc__ = (f'Return a new {typename} object replacing specified ' diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index bb8b352518ef3ec..7e6f811e17cfa2d 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -488,12 +488,8 @@ def test_instance(self): self.assertEqual(p._replace(x=1), (1, 22)) # test _replace method self.assertEqual(p._asdict(), dict(x=11, y=22)) # test _asdict method - try: + with self.assertRaises(TypeError): p._replace(x=1, error=2) - except ValueError: - pass - else: - self._fail('Did not detect an incorrect fieldname') # verify that field string can have commas Point = namedtuple('Point', 'x, y') diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py index 60735ba89a80eef..89102373759ca0e 100644 --- a/Lib/test/test_copy.py +++ b/Lib/test/test_copy.py @@ -952,7 +952,7 @@ class PointFromClass(NamedTuple): self.assertEqual(copy.replace(p, x=1), (1, 22)) self.assertEqual(copy.replace(p, y=2), (11, 2)) self.assertEqual(copy.replace(p, x=1, y=2), (1, 2)) - with self.assertRaisesRegex(ValueError, 'unexpected field name'): + with self.assertRaisesRegex(TypeError, 'unexpected field name'): copy.replace(p, x=1, error=2) def test_dataclass(self): diff --git a/Misc/NEWS.d/next/Library/2023-11-08-16-11-04.gh-issue-110275.Bm6GwR.rst b/Misc/NEWS.d/next/Library/2023-11-08-16-11-04.gh-issue-110275.Bm6GwR.rst new file mode 100644 index 000000000000000..194dd5cb623f0f9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-08-16-11-04.gh-issue-110275.Bm6GwR.rst @@ -0,0 +1,2 @@ +Named tuple's methods ``_replace()`` and ``__replace__()`` now raise +TypeError instead of ValueError for invalid keyword arguments. From 6ca9d3e0173c38e2eac50367b187d4c1d43f9892 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 4 Dec 2023 13:47:55 +0200 Subject: [PATCH 31/87] gh-109786: Fix leaks and crash when re-enter itertools.pairwise.__next__() (GH-109788) --- Lib/test/test_itertools.py | 72 +++++++++++++++++++ ...-09-23-14-40-51.gh-issue-109786.UX3pKv.rst | 2 + Modules/itertoolsmodule.c | 13 +++- 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-09-23-14-40-51.gh-issue-109786.UX3pKv.rst diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 512745e45350d10..705e880d98685e5 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -1152,6 +1152,78 @@ def test_pairwise(self): with self.assertRaises(TypeError): pairwise(None) # non-iterable argument + def test_pairwise_reenter(self): + def check(reenter_at, expected): + class I: + count = 0 + def __iter__(self): + return self + def __next__(self): + self.count +=1 + if self.count in reenter_at: + return next(it) + return [self.count] # new object + + it = pairwise(I()) + for item in expected: + self.assertEqual(next(it), item) + + check({1}, [ + (([2], [3]), [4]), + ([4], [5]), + ]) + check({2}, [ + ([1], ([1], [3])), + (([1], [3]), [4]), + ([4], [5]), + ]) + check({3}, [ + ([1], [2]), + ([2], ([2], [4])), + (([2], [4]), [5]), + ([5], [6]), + ]) + check({1, 2}, [ + ((([3], [4]), [5]), [6]), + ([6], [7]), + ]) + check({1, 3}, [ + (([2], ([2], [4])), [5]), + ([5], [6]), + ]) + check({1, 4}, [ + (([2], [3]), (([2], [3]), [5])), + ((([2], [3]), [5]), [6]), + ([6], [7]), + ]) + check({2, 3}, [ + ([1], ([1], ([1], [4]))), + (([1], ([1], [4])), [5]), + ([5], [6]), + ]) + + def test_pairwise_reenter2(self): + def check(maxcount, expected): + class I: + count = 0 + def __iter__(self): + return self + def __next__(self): + if self.count >= maxcount: + raise StopIteration + self.count +=1 + if self.count == 1: + return next(it, None) + return [self.count] # new object + + it = pairwise(I()) + self.assertEqual(list(it), expected) + + check(1, []) + check(2, []) + check(3, []) + check(4, [(([2], [3]), [4])]) + def test_product(self): for args, result in [ ([], [()]), # zero iterables diff --git a/Misc/NEWS.d/next/Library/2023-09-23-14-40-51.gh-issue-109786.UX3pKv.rst b/Misc/NEWS.d/next/Library/2023-09-23-14-40-51.gh-issue-109786.UX3pKv.rst new file mode 100644 index 000000000000000..07222fa339d7034 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-23-14-40-51.gh-issue-109786.UX3pKv.rst @@ -0,0 +1,2 @@ +Fix possible reference leaks and crash when re-enter the ``__next__()`` method of +:class:`itertools.pairwise`. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 4ed34aa5bde827b..ab99fa4d873bf51 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -330,21 +330,30 @@ pairwise_next(pairwiseobject *po) return NULL; } if (old == NULL) { - po->old = old = (*Py_TYPE(it)->tp_iternext)(it); + old = (*Py_TYPE(it)->tp_iternext)(it); + Py_XSETREF(po->old, old); if (old == NULL) { Py_CLEAR(po->it); return NULL; } + it = po->it; + if (it == NULL) { + Py_CLEAR(po->old); + return NULL; + } } + Py_INCREF(old); new = (*Py_TYPE(it)->tp_iternext)(it); if (new == NULL) { Py_CLEAR(po->it); Py_CLEAR(po->old); + Py_DECREF(old); return NULL; } /* Future optimization: Reuse the result tuple as we do in enumerate() */ result = PyTuple_Pack(2, old, new); - Py_SETREF(po->old, new); + Py_XSETREF(po->old, new); + Py_DECREF(old); return result; } From 9560e0d6d7a316341939b4016e47e03bd5bf17c3 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 4 Dec 2023 12:42:24 +0000 Subject: [PATCH 32/87] gh-101100: Fix Sphinx nitpicks in `library/abc.rst` (#112703) --- Doc/library/abc.rst | 42 +++++++++++++++++++++--------------------- Doc/tools/.nitignore | 1 - 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Doc/library/abc.rst b/Doc/library/abc.rst index fb4f9da169c5abf..c073ea955abaa40 100644 --- a/Doc/library/abc.rst +++ b/Doc/library/abc.rst @@ -21,7 +21,7 @@ The :mod:`collections` module has some concrete classes that derive from ABCs; these can, of course, be further derived. In addition, the :mod:`collections.abc` submodule has some ABCs that can be used to test whether a class or instance provides a particular interface, for example, if it is -:term:`hashable` or if it is a mapping. +:term:`hashable` or if it is a :term:`mapping`. This module provides the metaclass :class:`ABCMeta` for defining ABCs and @@ -30,7 +30,7 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: .. class:: ABC A helper class that has :class:`ABCMeta` as its metaclass. With this class, - an abstract base class can be created by simply deriving from :class:`ABC` + an abstract base class can be created by simply deriving from :class:`!ABC` avoiding sometimes confusing metaclass usage, for example:: from abc import ABC @@ -38,11 +38,11 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: class MyABC(ABC): pass - Note that the type of :class:`ABC` is still :class:`ABCMeta`, therefore - inheriting from :class:`ABC` requires the usual precautions regarding + Note that the type of :class:`!ABC` is still :class:`ABCMeta`, therefore + inheriting from :class:`!ABC` requires the usual precautions regarding metaclass usage, as multiple inheritance may lead to metaclass conflicts. One may also define an abstract base class by passing the metaclass - keyword and using :class:`ABCMeta` directly, for example:: + keyword and using :class:`!ABCMeta` directly, for example:: from abc import ABCMeta @@ -65,7 +65,7 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: implementations defined by the registering ABC be callable (not even via :func:`super`). [#]_ - Classes created with a metaclass of :class:`ABCMeta` have the following method: + Classes created with a metaclass of :class:`!ABCMeta` have the following method: .. method:: register(subclass) @@ -86,7 +86,7 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: Returns the registered subclass, to allow usage as a class decorator. .. versionchanged:: 3.4 - To detect calls to :meth:`register`, you can use the + To detect calls to :meth:`!register`, you can use the :func:`get_cache_token` function. You can also override this method in an abstract base class: @@ -96,10 +96,10 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: (Must be defined as a class method.) Check whether *subclass* is considered a subclass of this ABC. This means - that you can customize the behavior of ``issubclass`` further without the + that you can customize the behavior of :func:`issubclass` further without the need to call :meth:`register` on every class you want to consider a subclass of the ABC. (This class method is called from the - :meth:`__subclasscheck__` method of the ABC.) + :meth:`~class.__subclasscheck__` method of the ABC.) This method should return ``True``, ``False`` or ``NotImplemented``. If it returns ``True``, the *subclass* is considered a subclass of this ABC. @@ -142,7 +142,7 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: The ABC ``MyIterable`` defines the standard iterable method, :meth:`~iterator.__iter__`, as an abstract method. The implementation given - here can still be called from subclasses. The :meth:`get_iterator` method + here can still be called from subclasses. The :meth:`!get_iterator` method is also part of the ``MyIterable`` abstract base class, but it does not have to be overridden in non-abstract derived classes. @@ -153,14 +153,14 @@ a helper class :class:`ABC` to alternatively define ABCs through inheritance: Finally, the last line makes ``Foo`` a virtual subclass of ``MyIterable``, even though it does not define an :meth:`~iterator.__iter__` method (it uses - the old-style iterable protocol, defined in terms of :meth:`__len__` and + the old-style iterable protocol, defined in terms of :meth:`~object.__len__` and :meth:`~object.__getitem__`). Note that this will not make ``get_iterator`` available as a method of ``Foo``, so it is provided separately. -The :mod:`abc` module also provides the following decorator: +The :mod:`!abc` module also provides the following decorator: .. decorator:: abstractmethod @@ -168,19 +168,19 @@ The :mod:`abc` module also provides the following decorator: Using this decorator requires that the class's metaclass is :class:`ABCMeta` or is derived from it. A class that has a metaclass derived from - :class:`ABCMeta` cannot be instantiated unless all of its abstract methods + :class:`!ABCMeta` cannot be instantiated unless all of its abstract methods and properties are overridden. The abstract methods can be called using any - of the normal 'super' call mechanisms. :func:`abstractmethod` may be used + of the normal 'super' call mechanisms. :func:`!abstractmethod` may be used to declare abstract methods for properties and descriptors. Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are only supported using the :func:`update_abstractmethods` function. The - :func:`abstractmethod` only affects subclasses derived using regular - inheritance; "virtual subclasses" registered with the ABC's :meth:`register` - method are not affected. + :func:`!abstractmethod` only affects subclasses derived using regular + inheritance; "virtual subclasses" registered with the ABC's + :meth:`~ABCMeta.register` method are not affected. - When :func:`abstractmethod` is applied in combination with other method + When :func:`!abstractmethod` is applied in combination with other method descriptors, it should be applied as the innermost decorator, as shown in the following usage examples:: @@ -216,7 +216,7 @@ The :mod:`abc` module also provides the following decorator: In order to correctly interoperate with the abstract base class machinery, the descriptor must identify itself as abstract using - :attr:`__isabstractmethod__`. In general, this attribute should be ``True`` + :attr:`!__isabstractmethod__`. In general, this attribute should be ``True`` if any of the methods used to compose the descriptor are abstract. For example, Python's built-in :class:`property` does the equivalent of:: @@ -236,7 +236,7 @@ The :mod:`abc` module also provides the following decorator: super-call in a framework that uses cooperative multiple-inheritance. -The :mod:`abc` module also supports the following legacy decorators: +The :mod:`!abc` module also supports the following legacy decorators: .. decorator:: abstractclassmethod @@ -323,7 +323,7 @@ The :mod:`abc` module also supports the following legacy decorators: ... -The :mod:`abc` module also provides the following functions: +The :mod:`!abc` module also provides the following functions: .. function:: get_cache_token() diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index e79b4c3bdecb671..50f04d72c0dee01 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -26,7 +26,6 @@ Doc/howto/enum.rst Doc/howto/isolating-extensions.rst Doc/howto/logging.rst Doc/howto/urllib2.rst -Doc/library/abc.rst Doc/library/ast.rst Doc/library/asyncio-extending.rst Doc/library/asyncio-policy.rst From c718ab92a584fa658b6a626a744f5a71a048b47c Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 4 Dec 2023 15:41:41 +0000 Subject: [PATCH 33/87] gh-74690: Optimise `isinstance()` and `issubclass()` calls against runtime-checkable protocols by avoiding costly `super()` calls (#112708) --- Lib/typing.py | 14 +++++++++++--- .../2023-12-04-14-05-24.gh-issue-74690.eODKRm.rst | 5 +++++ 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-04-14-05-24.gh-issue-74690.eODKRm.rst diff --git a/Lib/typing.py b/Lib/typing.py index 4c19aadabe3b87f..aa64ed93f76fbfd 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1782,6 +1782,14 @@ def _pickle_pskwargs(pskwargs): del _pickle_psargs, _pickle_pskwargs +# Preload these once, as globals, as a micro-optimisation. +# This makes a significant difference to the time it takes +# to do `isinstance()`/`issubclass()` checks +# against runtime-checkable protocols with only one callable member. +_abc_instancecheck = ABCMeta.__instancecheck__ +_abc_subclasscheck = ABCMeta.__subclasscheck__ + + class _ProtocolMeta(ABCMeta): # This metaclass is somewhat unfortunate, # but is necessary for several reasons... @@ -1841,7 +1849,7 @@ def __subclasscheck__(cls, other): "Instance and class checks can only be used with " "@runtime_checkable protocols" ) - return super().__subclasscheck__(other) + return _abc_subclasscheck(cls, other) def __instancecheck__(cls, instance): # We need this method for situations where attributes are @@ -1850,7 +1858,7 @@ def __instancecheck__(cls, instance): return type.__instancecheck__(cls, instance) if not getattr(cls, "_is_protocol", False): # i.e., it's a concrete subclass of a protocol - return super().__instancecheck__(instance) + return _abc_instancecheck(cls, instance) if ( not getattr(cls, '_is_runtime_protocol', False) and @@ -1859,7 +1867,7 @@ def __instancecheck__(cls, instance): raise TypeError("Instance and class checks can only be used with" " @runtime_checkable protocols") - if super().__instancecheck__(instance): + if _abc_instancecheck(cls, instance): return True getattr_static = _lazy_load_getattr_static() diff --git a/Misc/NEWS.d/next/Library/2023-12-04-14-05-24.gh-issue-74690.eODKRm.rst b/Misc/NEWS.d/next/Library/2023-12-04-14-05-24.gh-issue-74690.eODKRm.rst new file mode 100644 index 000000000000000..36d793f787302ea --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-04-14-05-24.gh-issue-74690.eODKRm.rst @@ -0,0 +1,5 @@ +Speedup :func:`isinstance` checks by roughly 20% for +:func:`runtime-checkable protocols ` +that only have one callable member. +Speedup :func:`issubclass` checks for these protocols by roughly 10%. +Patch by Alex Waygood. From e08b70fab1fbc45fa498020aac522ae1d5da6136 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 4 Dec 2023 17:43:27 +0200 Subject: [PATCH 34/87] gh-108927: Fix removing testing modules from sys.modules (GH-108952) It breaks import machinery if the test module has submodules used in other tests. --- Lib/test/libregrtest/main.py | 18 +++++++++++++----- Lib/test/libregrtest/single.py | 4 ---- .../import_from_tests/test_regrtest_a.py | 11 +++++++++++ .../test_regrtest_b/__init__.py | 9 +++++++++ .../import_from_tests/test_regrtest_b/util.py | 0 .../import_from_tests/test_regrtest_c.py | 11 +++++++++++ Lib/test/test_regrtest.py | 19 +++++++++++++++++++ ...-09-05-20-46-35.gh-issue-108927.TpwWav.rst | 4 ++++ 8 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 Lib/test/regrtestdata/import_from_tests/test_regrtest_a.py create mode 100644 Lib/test/regrtestdata/import_from_tests/test_regrtest_b/__init__.py create mode 100644 Lib/test/regrtestdata/import_from_tests/test_regrtest_b/util.py create mode 100644 Lib/test/regrtestdata/import_from_tests/test_regrtest_c.py create mode 100644 Misc/NEWS.d/next/Tests/2023-09-05-20-46-35.gh-issue-108927.TpwWav.rst diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py index 16f6974ae324653..7ca1b1cb65ae40e 100644 --- a/Lib/test/libregrtest/main.py +++ b/Lib/test/libregrtest/main.py @@ -311,7 +311,7 @@ def run_tests_sequentially(self, runtests) -> None: else: tracer = None - save_modules = sys.modules.keys() + save_modules = set(sys.modules) jobs = runtests.get_jobs() if jobs is not None: @@ -335,10 +335,18 @@ def run_tests_sequentially(self, runtests) -> None: result = self.run_test(test_name, runtests, tracer) - # Unload the newly imported modules (best effort finalization) - for module in sys.modules.keys(): - if module not in save_modules and module.startswith("test."): - support.unload(module) + # Unload the newly imported test modules (best effort finalization) + new_modules = [module for module in sys.modules + if module not in save_modules and + module.startswith(("test.", "test_"))] + for module in new_modules: + sys.modules.pop(module, None) + # Remove the attribute of the parent module. + parent, _, name = module.rpartition('.') + try: + delattr(sys.modules[parent], name) + except (KeyError, AttributeError): + pass if result.must_stop(self.fail_fast, self.fail_env_changed): break diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py index eafeb5fe26f3f3a..235029d8620ff5b 100644 --- a/Lib/test/libregrtest/single.py +++ b/Lib/test/libregrtest/single.py @@ -122,10 +122,6 @@ def _load_run_test(result: TestResult, runtests: RunTests) -> None: # Load the test module and run the tests. test_name = result.test_name module_name = abs_module_name(test_name, runtests.test_dir) - - # Remove the module from sys.module to reload it if it was already imported - sys.modules.pop(module_name, None) - test_mod = importlib.import_module(module_name) if hasattr(test_mod, "test_main"): diff --git a/Lib/test/regrtestdata/import_from_tests/test_regrtest_a.py b/Lib/test/regrtestdata/import_from_tests/test_regrtest_a.py new file mode 100644 index 000000000000000..9c3d0c7cf4bfaa0 --- /dev/null +++ b/Lib/test/regrtestdata/import_from_tests/test_regrtest_a.py @@ -0,0 +1,11 @@ +import sys +import unittest +import test_regrtest_b.util + +class Test(unittest.TestCase): + def test(self): + test_regrtest_b.util # does not fail + self.assertIn('test_regrtest_a', sys.modules) + self.assertIs(sys.modules['test_regrtest_b'], test_regrtest_b) + self.assertIs(sys.modules['test_regrtest_b.util'], test_regrtest_b.util) + self.assertNotIn('test_regrtest_c', sys.modules) diff --git a/Lib/test/regrtestdata/import_from_tests/test_regrtest_b/__init__.py b/Lib/test/regrtestdata/import_from_tests/test_regrtest_b/__init__.py new file mode 100644 index 000000000000000..3dfba253455ad2a --- /dev/null +++ b/Lib/test/regrtestdata/import_from_tests/test_regrtest_b/__init__.py @@ -0,0 +1,9 @@ +import sys +import unittest + +class Test(unittest.TestCase): + def test(self): + self.assertNotIn('test_regrtest_a', sys.modules) + self.assertIn('test_regrtest_b', sys.modules) + self.assertNotIn('test_regrtest_b.util', sys.modules) + self.assertNotIn('test_regrtest_c', sys.modules) diff --git a/Lib/test/regrtestdata/import_from_tests/test_regrtest_b/util.py b/Lib/test/regrtestdata/import_from_tests/test_regrtest_b/util.py new file mode 100644 index 000000000000000..e69de29bb2d1d64 diff --git a/Lib/test/regrtestdata/import_from_tests/test_regrtest_c.py b/Lib/test/regrtestdata/import_from_tests/test_regrtest_c.py new file mode 100644 index 000000000000000..de80769118d7099 --- /dev/null +++ b/Lib/test/regrtestdata/import_from_tests/test_regrtest_c.py @@ -0,0 +1,11 @@ +import sys +import unittest +import test_regrtest_b.util + +class Test(unittest.TestCase): + def test(self): + test_regrtest_b.util # does not fail + self.assertNotIn('test_regrtest_a', sys.modules) + self.assertIs(sys.modules['test_regrtest_b'], test_regrtest_b) + self.assertIs(sys.modules['test_regrtest_b.util'], test_regrtest_b.util) + self.assertIn('test_regrtest_c', sys.modules) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index d7b9f8010924984..e828941f6c779df 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -2031,6 +2031,25 @@ def test_dev_mode(self): self.check_executed_tests(output, tests, stats=len(tests), parallel=True) + def test_unload_tests(self): + # Test that unloading test modules does not break tests + # that import from other tests. + # The test execution order matters for this test. + # Both test_regrtest_a and test_regrtest_c which are executed before + # and after test_regrtest_b import a submodule from the test_regrtest_b + # package and use it in testing. test_regrtest_b itself does not import + # that submodule. + # Previously test_regrtest_c failed because test_regrtest_b.util in + # sys.modules was left after test_regrtest_a (making the import + # statement no-op), but new test_regrtest_b without the util attribute + # was imported for test_regrtest_b. + testdir = os.path.join(os.path.dirname(__file__), + 'regrtestdata', 'import_from_tests') + tests = [f'test_regrtest_{name}' for name in ('a', 'b', 'c')] + args = ['-Wd', '-E', '-bb', '-m', 'test', '--testdir=%s' % testdir, *tests] + output = self.run_python(args) + self.check_executed_tests(output, tests, stats=3) + def check_add_python_opts(self, option): # --fast-ci and --slow-ci add "-u -W default -bb -E" options to Python code = textwrap.dedent(r""" diff --git a/Misc/NEWS.d/next/Tests/2023-09-05-20-46-35.gh-issue-108927.TpwWav.rst b/Misc/NEWS.d/next/Tests/2023-09-05-20-46-35.gh-issue-108927.TpwWav.rst new file mode 100644 index 000000000000000..b1a78370afedb27 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-09-05-20-46-35.gh-issue-108927.TpwWav.rst @@ -0,0 +1,4 @@ +Fixed order dependence in running tests in the same process +when a test that has submodules (e.g. test_importlib) follows a test that +imports its submodule (e.g. test_importlib.util) and precedes a test +(e.g. test_unittest or test_compileall) that uses that submodule. From 1e4680ce52ab6c065f5e0bb27e0b156b897aff67 Mon Sep 17 00:00:00 2001 From: Thomas Bininda Date: Mon, 4 Dec 2023 18:27:57 +0100 Subject: [PATCH 35/87] gh-112516: Update bundled pip version to 23.3.1 (gh-112517) --- Lib/ensurepip/__init__.py | 2 +- ...ne-any.whl => pip-23.3.1-py3-none-any.whl} | Bin 2086091 -> 2107242 bytes ...-11-29-10-51-41.gh-issue-112516.rFKUKN.rst | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) rename Lib/ensurepip/_bundled/{pip-23.2.1-py3-none-any.whl => pip-23.3.1-py3-none-any.whl} (80%) create mode 100644 Misc/NEWS.d/next/Library/2023-11-29-10-51-41.gh-issue-112516.rFKUKN.rst diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 1fb1d505cfd0c53..21e4ad99a396287 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -10,7 +10,7 @@ __all__ = ["version", "bootstrap"] _PACKAGE_NAMES = ('pip',) -_PIP_VERSION = "23.2.1" +_PIP_VERSION = "23.3.1" _PROJECTS = [ ("pip", _PIP_VERSION, "py3"), ] diff --git a/Lib/ensurepip/_bundled/pip-23.2.1-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-23.3.1-py3-none-any.whl similarity index 80% rename from Lib/ensurepip/_bundled/pip-23.2.1-py3-none-any.whl rename to Lib/ensurepip/_bundled/pip-23.3.1-py3-none-any.whl index ba28ef02e265f032560e28e40b2be0bd6e2e964f..a4faf716b663e61faf22bb58fa57d3b2b0e00299 100644 GIT binary patch delta 397715 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

dIF8*FnUbd0S#cy5H)2HTWG_fy6K@XIvE2B zDFA@}(>gX}6NzN}^h0GAR&sa8Pr~7Gn40kP4+r z$M`R~id`RD#fnH^#{lBkSbnff>k>!41H8Wp(8@3e+Hh3bGZJuw7iA3HU2di>+AizZ z<5akAhB%rB^|U-)Ti-xK4qJ9%J?OS+(yOQTCu9T3Py){;fnt}yW zNYJq`0eEo1C>GfzV4u$Z zGq~oc+jR(5?_H(q<}p3Fw)ryw$h4Y#U>8(1q1QE1!8Dh3y@?BK#rYOH=APe~x9eaG z$LzMQ$VAn!s`i%L5C-VNqu`CE04IOM&#Fh#9jg~E%G@*^wg-qD2@O;58icl7>QOcR zGl;5m9I`ju=x!3CZjX1oj)Slfpe(bJq6)m7l32o3-xlH&?%!!6-Ex_fyj0RG&ziU4 zp@1xyrx!y}JykKl2=|lCb)M80T7UVETt|n(Y8>`r*35|Yh_~b{bNzGkfWxe8ThLF@r=q5_cU(j-qG?(XhQc)I& zgS802FQ~b{ZBlC)f#@aZ-HJOTgsz{DT+?5R1Escw#GLSJtSduYrv z3VSQV32d>D7;yzr&{XOG`B-9id=PPs19s6Nqp!%I;_9dDNHd&Wwaf-q2Pg4Z%3|gf zx8O(w?k5?;Y-Hu752DTn^_Bjc5Dky$;Z`o{5(-UTK#pO5W_LCG5U9i?r&rZvY+GIz zPp?om@1$0Ej?+~X*>3GVuL3^!bxg5h&?Z;1H|k!Ck*img70@36G3kprhTiK!56Xv! zZC)xzT=aEv9=>5f>d7s4*iUzC?-4#ucb@E4Xil`q>d1X2K(%M~X$T+Ig74sI!DMy) z*cBoQC z7)6=QXG@=hZdfY-s&Xa}ek01huu(oc#{5iOn=AnSDxO)I?Bh&g@dx-y3mtalT;;nS z1XhAM@{^>M0a!sO785b3WP5ziAU4pRcH($7Orm+pXDJ2Lo+mT4V0)6wdb@3r?>eK> zyL0l*;-&_%Q+Wl|4(OU}Ef+A6nF4g$aF@ovj++tCE`Jn$hL|7oq#kban9S zuLdiVo-thxThk>v{CSyYj|&4`*?T8F=K z!O63Fxd)q9bcRf!uzu{WL_dMUI1sp?hXf3oJ-T_bMj={Rq;3mTp)g3m zpT9H}rIfmsFzAC#8V1Q2!IJOPe7&dgK#!E#bP($RaJE*|5FJ+5Ew(5Z%@l2&0R~S| zY~R4PD~RVDJLk1A!&R`E3lak{P8b)d_Ep|1ajge8QAWqHzE5mxCA^Xf2t_%bvPg7F z1j!eia4WejoTIObti1-R8coq5Rxcj5wXykqRF?8ZdH9zV;!XC5EB$lxWM3r5%%XYfK8js5wx=3!bkcX-&m3)) zmrS=N_Rl#LNxm}p*ncr*EO#p7dE&(Np`*)_S7b@nhFQc|sJ`4aAsc?1R%z)o0UGHj0V?^x3s(;}xhWIf?TjyD#Z63g~fmi}_ zLNZe%*(p${;*{|~-}jGI6q?CKoK|?M5FKdI3G~qQd~OtZcssvsp8Av+n>qRavKq+W9Y?F$6gZ0#vn3$Xh%hraPFL3mQTEe8r)W=$^Z{FsuL!w z!%Opy<}@%>`@>`d$$y4b(#M&4dePj_L1AwKF{ zlhioDfVECP(xE@jT;_Y#1ORQVt#Q{QI2e|hx>T1sR!*Mm7^7{vkJv|V99FqNEb%^1#08#;w#kGlzSc< z`tZ=|SJpvJ0&UE@qz~4lcGrG+Mh~XoQ9x@&IM=%H>_GVXl&u2YYXBxWgSgJq6h50E zB*-#&bv>mnVgeMFKFTegq{6E#{%k?3HRvIxy}lpp1@uK%+Bg*r-6t7J}z|j zc6+VCz0v!+KjngAQv%S)CwRgaIM0R>L0aMsd-i=%vEn`EB<-U+zVgWpR{rw>ANVy0 z6^y^WI6v4wNVxy0W&rm25Nb-yEz{E6(c24!fb=={jq(hiKD~m{2A;3SH6F)So?Mt^ zk`7N)rE479#b-_J!OO|v{Dp!9`R{JFaE(bR0rtA!vzmJ&Stcg9n$RmttCf^1(x{Lz zrAh*zKSrG2AuzVmez0+w6(2z=BxyLRnfshEW?+443bYNey_^D+%;Mt%o{I8mj8j#(CEpKXS8 zYT@X7{*{p=7)(op2aZA5l>ro@NEDY1XS-w{TWO0p1X%g014N>~t9ty4D8^+k>CAgM zltFUuPO|NGj8zehAn~T(zxxO0adOp({>{MGN2itB7`~#eA^raR+-d zG8xilM?ejyCGA_zj%RP^i*Z3ok`$zn=Tvz(Md+VF3;8WEK#z(C#` z&CKuY!Q!{%h1{Rr-EF+ol;NWQ8T)zZCc`zLPg)TzVuG!)TeqQCT~H$>JEsp)2mEYE z$NkqnPZd|$0)>m==*!EmVyeLY%3I;ht%}Ti4Zxm<9tV?4R*N0cKyw7tWd$x9f&u8d zlfGU8hr>2O8*T?iGD&Q?i2c9#U8<6L5|yu0Y)ZNE$3jjX@tnN*Vqn2d9`B^R-okbF z1efho<)x$Ge(c}Xx<78h92nxi?{)Ax!7b6FgDmRrg7d+UWCiA#;|G+kUSQ6>7gOU~ z`2etjbci!bJQlvR<5HJ0AK3d4Q$DjyiWCb|9JN6A-yUrMQS?2TbbVwGLtrQA3>1Gxl zL!#YxK!h5?8=fG0V{gaSY9m&PMI+Hd{Lu0La>@w0)6sp*1chxpclvlMIxVod-8h^B zOLbTOWrGw|Xul;3I)LI?j!}jhzIggE3N74@8?BKbUG^Ysk)jN|kNOC^B-R#ajtfu{ zI>ggINS4_DDU^*oOgU4oHM)r|$dq)BrooG;&Me@3DhJ#oxzG}7(;S`d=EcBb>63rX zQ4E82Mc`R=?Moofl^w{x{;F$l2Z3KaRUSb*abC4&IFK_qU~Jto@-DW{rqcPl(d_&P z(xoPC*3tw17+_ED@$$N4)QQEiJqAc$<2k8He8r9vuz#IrgB87ajL4JH%n5%7pq~DM z8p#awx1tY`3_^I$tmP)0tjnxd_CDtVwX&tV7S>g~w`D>?u+Cyy}9 zDH#?8EQ}l*6K0q75Qb)4Y1MMoi^!BTy3XE81XXcVOdYw)an6>9(Tlhrjh_D6-BLt6 zfa=~+B;8q&2@_gX)76i;F2Gs`;;bf4B{Ql-P1gGMbwJ?e?PTYXVB~rWVaB%|J5MR= zln#i;miJi;%2!lMl!c)cI1q?_ZY5=N2gJ%T2w*X0V>Pz>4 z?4vz{8czq)L(Z;Sl7C6NoZF~q{rqt!Db9du_F6rGBmtHh9ljdc{sSixt$#K-Xb5yh z&wa`6W!0dLmn!J7cGEU>nE=)tYg1p8gte{9rCq@w#WxQ1w{l1T{i9D4aa>#6RWSt>>4XPK~Z2u{V+ zXsm2pmElb?^GeL>a!moLRlg=Hw}zuPw`)vDUNC+VZcl*k9mGf1Fs?bA#pqoa;aI*Z zFB@pJJC)uCX_ur$Coq^gn?Y4QtstW z+GL~r@4Bh^uPVTHS*M0DnWKR}L>{__R-dD#S2Br3C*3*6q!V!tOXXgc zHw({y$ueeIwp6E09bKOV)pjimnF1~$*KFlA2d(rkLRT`L;LDePB2J$k7lXg=P{{qc zGKRft1@w7>Tv_V_De_|42r;3PcTM(BP*PbQ<{bAinpQ`;LW5-}utK<10$2(QvJa)q z+n-_9B9Z{7PVy(491wije4o5CqCJRfUt{6QiY(OfmqamX=7TnyEQQtbp}ffyRN6(V z*oRSko(#H?5UZfeNcsu9e+J|`Af{_r`UPYNwa9YOclq5vyza)h=)*--Mv2@m{J9inK>Elpmx4Q0F2}{0Gv~>S@0v8Gn_;Av*GOVTk#n2PlsFJ z{oSFJggpP{YUPkNB*uHlm!I;4o%Jhs{bs~ygGJGiqT!8Q9w*#Z>T;|*<75;nP|^Lp z!)|V}e2ZHuplBqtV&Bm7!qth})@8Z67hv?Bt3?Ms3!kB>C){424HN80fFNI0g?T;5jpj&^T+5hrD5fS z+k*Z%t><6E8|JK5Wzvz2V77w2tcoIoDu!y6<;waKR5O%Nm$CxyS3Jr2cKru)1=2Ou zkz0nVsXK0Pe{YX>ng^59z^+#J`~HF^JyK1?W5%(eX?ZVDr_N07-}fYaqx4FPcBY_= zEIEbmZ3{E#6YAuU;O{O*)SQ~7$in@() z!Su1BUx~qbHi*T_nWl$_&rBU(%Zo#2iyWA>Uk^bQmzMaf>bn&hs4&Yn3B`sII_ zJlooOdY^>S;jqvfl;`K2X^bB{6+$Ejl935k@n1V56p0cEPDU$Q`DFhNdknNFMxnA{ zpk^T;jHNKT!pLoj(Xpi}bu3D*O7$|$9NsH=9hkVOwRainPjt#N^)OEj`j#MJy*~T5 z&?NbR-)^K#FD~qSU71h-ZEG+&f~P}Fu-m-Py4Er!61GObAD`VHfX&Yf6+c7BxOm?>XEAPHYDny@G zCI#Okrb-f_r|${yHFVu@t*jb!)tLO2t!e-8l>{*>Li~%^ora_UuWL{kD6OiTarqOSZ9tyTVn>`2L0Qbl8x(#zBBa#CB#<({N)oB&m7~^gam3#kogQ7+6t=Sa zPaWuDCea^BRDc^qH8yL7>NIqiB8a#3R%#4$w?x8khSD#h+F;=IU9jR*27_$ujs!i{ zqjrs3*eRb9U|Q0U#x~#mTjq3h^|FdaWHYH!P_`6Y%Bs;V_~XgF&;Cr_B)7f1wS3=6 zZ&O@;l6tUTvjY8a=T36~rf=1wZ+=?=qO0QTM)y(+xqyLR%68-6vQUJPHuteWBu><> zMfn!BJP}4c)}4QI6?OqKsRSN|04B+>Umyp0v}v*&fJTl29;M_2G&$|+tew_W8;tG= ziD&k#WvelOPnbfjc20Te%h_0RHy=~#Pg!AmDOZUY*jSubyPLy%c2P7FvFd?Yx+g>| zIkBZcsB5nCBMn2TE1~g5_eXkr% z2`2{wj30l<$ul$#pqVx3jXhmwI`lTP2F3OuOXcN)FgpQSgb{wk+ul zR%HDEMF^Z02< z$;j?(xcwtCgoN|)Uy<3Uu3aLm^8AfQouPcNFoATT18t#@DJsZl_M+GHM)W)97 zdbG370PTaF`|YTuuqXLLx{)pvr8+}|sde}?->T}FY*8T2g0&kat{tN7tHh>ew|P4} z$;~q&2;DH8&g$OGt!ZaGuH{8snVgs9}*W(5$NY9aIV9__ zL^WP=GZkJg`79}NTvbWyi;#j) zj1z_bpDL8zIFzzEneZB5wlYJiO%pfhQ(~&}NXYI%LfL5Qo}smcWMB0CK8$VklJ4Aw z&2F`vnqO!!Bw)Q%wRWn2(^6Q`V!`)l+f~|Tki`0drTXb2vSqDdboQ4q3eRYbg8uhi zfnCp!zrG);#%9S7@N6B&%T8#yK;1zZDV^tKd5UxZm1rP&`ahC!GJWK>ko{QAl6 z`$cy6YGoJMjK+osbZbWKsUH8d@crF~CBcdnd9CblJ%9+u6i3F}D}7SalGYq-hxPmq zKQ)*43;2ZjT z80)U}VR*Xb6m!+Z`4naQ%PvP%ugytoX(J6EC-IMz?-bSwbC z&Sa!|cBz(7f^NLkmBq_^hBfIF2L8dotsRxffB(LPW!aJC_CMJ&Y}Wzc@(L9CNje2` zvwgzYuAe}|K(LwxeBaSoulbP&8OI@3WGqKOL_vSX1w?PIb?7X$X>wmc2mt0G$^1nh zD?=rKR;R~1smZKeD=W#*Y5uBSM5NE%ZiWstQ~Y}{l2PnKc+{HcpD;h*D=CYn`X0B+ z`ZHFoWl{^0z@wkfJaG-^4#5l@sRGy0!JlHk7^Izf_w3GFT8RdYo(DGQ4UUOy+1TCE z^gY8pM;<{t2GW~yY;{S+d0fKJ>sT(+a}RvKiTrhM!gwhM#jm^FI&)QEJZ! zI4mGKW(uaC5h>`}BZ91JtpJ=M01_Z@BCrrhh$7hD1Z#uBF7R;Kgn`x<*s__vX-Dq= z>FOc9ys*>%$~9jc1KBwQeK0VKr78^pGu5XNA6CRiKbi-hW-HkkPc4|!J87k4lwl@B zMD0rFewW@}K!YwB-<_7AlL?`>V?o-{ETfUF$1$LS69% z;+nHu464|9o)TQ?_ZWu;0{>UkMby6*?#Tb37FlRUDl&iIh?7+RQE+yEmfZ$BhHtK3 zUkm}Y$;e-hO;=!04ePxXox&K3x-R=bLZshwvtjiiXyW7hRCoJc2ojq|dk^{d%qR@U zZ?{~boQ7@$+uy$4RMfxK9z`QfEUtG~bLy8%zdzD-%;W2=YN8Vo3&-O1yy=+ZAYy7A z<5bZ=9Wh+E!^O%eTKPrk(*5dVG8*9`?-fzo z*0X+1M=l*~kaK89>`ieKu1A)iXLvI&S7%3;m!$)5AKsOh_-K+Hw7*l83qfxnJSOr% zg78y;@z4PDW)Txbi~?xnQtx1zU8hZjitsd#3k0z%Q+-YlO(yppu+_;|%LMiB7zvfb z>Zwwt%_8QoQ&Cb+$*O5$3M{&Ncp6f^dBNG-f@+xS^|4?K{glL)#f8j+bi04(`LdE6DUOWMS43dLht=iYnk8eB3EO9drQUUM*^t7X}6{- zAgY)Wp3vL2(@EZzA}zSFjos1~TbN(UnYo2=97ThNlhMXU550(gU!m4w=n*vtL75~o zhvfmdujuj^i7?I3XT{FWDDg)S_cX+7-8r+jlCzYFqSfm98?MI*e_2jpjHgts59PFC zgt;Z|kY5Loyef+u%(I>?;FLvZJg2}$hfqgF6@Gk;QWfA-O~V#bM_rTE!oig&*r?&z zzbR*bIeK!Ubg+G1@3Q(6y7=ZQsD%6*xO)JA1A7aF1NOf@=+*pAn*NPaX8TKe_JL*I zzD+;*Jl5AnuTMY{Z$C_|t@4AY$&OXm5SSe`7p_dZFeV)Nz5-%PURpZ3I54KN zUZt%g(#a;QH;)<`t5f1Z9%j{-^?fZz72*YPsDU-HuVaWr5ZBhi)U5K1*ZY3GIA&ma zhkU=#>$xD>%UEZAtq4MtKupB;Is`-5YX-yJdxFa3wXWfTf0!MKwYHin_S*-fyf8*q zF%i~4h;_$Evn_!|*eYB(N-%a)qE=kY0-gF}oy=@edX?j(U+0I`+wBI|1 zuJ|Ymj)`5Fu`7^YVLTnz)_GkR^_NjHv3boB18~X&puH3k-kbTFt9Ahi*c(XKW4xp$|9Ln z;uyRZfGk(2Xfyaw-)fT54BgLk#CSG!VXvS%6I|BeEE9<-EaQ0N`Np{SZFlL>HG6;W zXmdhHo06Ywy&3}DfZza(L)M{VI5fNx%l-L6unfcoQtK#yM$f3mHZcRP_6PI|+}tL` z7akbl8-vXv&%VhawvR_AMJ^dRzC`3)%hQkcdtk*GCOw7rZh*^YRV-B`$7I6;i1EyO z@OIUY{O1fzH&*ob?0inz5r2Of1sRQj6VE*|u)cn;pAT{!bLNR?8$`RMTCT?TtY3S4 zhav~f+D4r$jj(;w(Tg~Z8DBeSjcEBp|LZ`pu#~1$sdrVF7-E&ytg-@6682#6&W{92x)aZ ze{X(IcT4Y{Uxr@a$4c(^vwM}QTD1@0AKLpqy}{FFQ}1eW+Q~4>lrX($CYy6l*HW_< zSq9UGx<%72|K`IqleoNqh$z^a11uRR_^q)nA&VQ)N+>S9kcJB+lae;|@fPX*BlPCg z2xN+Rie|3lJ-ZsY{Hv}_kC|I*%j;4k%2wdcucSdSzEji~lC|hCOS3H%8(9}mTJg*2 z4(!E31A*qyYb>=+zo$55YeYp#98wjd7=1~*kvSrQ__6F9yACo@Z0g@T4VNEEmh=Ra(-*j) zHA&(P(Q1_>lpDxASRUdOp|NW5VyPiUy|;8Hff!`~P_Dk2)l2<@TOi+{>tVtzp=7vb zU>X>1EzSB=zoIyn^9IzX1+W14gMFt)gGF7Z1>_`^)0ugx_I+PmrP{BUkJS|15swZ( zz_3YRI8*6wNy)VUyVWCaoHr)J?g`8WBc`_AS)|}wB#dCPY=5$d)EgEyHz|*TNJUK$5EVcPC9B6f)%xaY}sVHj@GA_6QOaIrmo> zw{bVTYEYv4W3c7v-RI5KQupW`1{`2w4-(y!F_Cs#A0SZWXHD89 zf)6s(lY;B(M*5$QqJdV(U4@@%Soi1o>H16Ev?d_bV;k>-@gsx-n(5GEa>a;uIax>* z79S-R(2*|RW(bDgFophSoRwknbqz;(FNBQ?S^aQvNz#sjC=veWR{bd`}V|L(N-bN^`AGLggGX2Nzu#GRU5nuC0 z-RP2ho8J^M;dxpud?C9?(0gd$eFvqBN?4nDWW`Splz_%Zl-jTau?|b0cB#|D^(wan zTO=`}T$;OhTy5e5m?SSJ##T0l>hJ9tGaX;CKA8f@bt<#&=ml$-_QByxU!$Mbb>IZv zkgPDgzzz>4nwf)?aLMd*km9Lh;8mP5nsXpi;B&*h7E!J>l(Z4qaLr@IzHk{Svd?-#QusE}9D(c`Y&d=78)Aql z@s94w8@1yuFjvJ8TajH8f^f56uF2T6oG+c}3mEriuFXY!*ZNL2JocrnOY8|KC4f9m zb`zRP9zVaDmCI)jZ&yorRVXPgsQd7y5MnTrLFk~wG1fJE{tAjE<=;7X@+VRgKFum2 zq4`2`=ABZ-NDt$&RHfJxVOu_)l`?g?OUSZH4k_dxKYs)7Hi9IKxsD<=upXL2x;XRn z0Ce9ok|G`iZOxs&Vr_qvxla$eNW2bwM}z$UCHe|$&=12wqP?b zwaUeqRN95c z$~8R93`pLj>D0NAo#M&0SGriyij4bu+@KV7#{6aj4N%ARIda^%w4_{4AUhR?uW7`l zw>q(}Z3||ft%?@YV9$%V{;W7YEsP=?LQUnm^afYWkyXK#ApQdH6t;^@vw3s4{)FH) zjD(YmpVpRDOVq&+E@caaLzW}ew#*AboaxgBF z40707{ISgEOaw<%UK9qL9Q0dM*WH&f$oxp9r&V}GY4HTR!A~0zv1rjaY+4*-4?ZdC=GKh+uXrE531YqxbVM3WbsI>dvXzBM=*z|aJ?0&i26wN$y`8v49HIRA zB;$^Vc4n%^%fgva5B$6PAUZ&{^ZrX-sdMZ>IB4C=lmW|7+d_<<)G4S|1BeB26MXTp zPb&v?Nr3Dx4&irt)wYOL=W72sBXIsOOUv@*Lin>EZj69^iWq>a#`1osupK?HAuO9p z`NrWqVY7*DpP8GOp?5V&oi@S~sfWr!rRO-I&W?aN3&X!aR-U zTcp)gFB37f2Y_Dpxv2m^SoP)I8_9zw;YT7uMiL?n>!pMlh?koJcT?+yTElY+cg}3m z1dJwD6UX^!%>vSUp9+B5$X4?I8L?AutxYmtOnBcPsX^KN@j_dLJz2%5wpkK*C6CU! zcI~pVhN`|s`X)EkitTf2%7xm3xv^To5YrMR9d5y9wY>HpaGT&q+e*OE3IN>@{2j5j zw%t-7+TBzb=vAwmVoOmU5_@3Fob}~1$!_b6{au1g$_2QdRUyih@7r~%&LiM#_t&9? zqV+ZX=zmVLK7ab_Yu>Ii=6z#?20j|FHKN!m!2pO&>OLem(Qq?Y)-smg)`4%-YmxDL zlnQ+9;lbT0&AV!7c+G6Jc}H5Uby$C=mHbm&sF{=Jr0Y;^6?bhUdKS7MzNcGlZx`SB zT*;H46$&UUL$D+vq}AuOQXjDbd84$tdN{IIvHWx9GDO^TJKDeZei(vpp_MFpd$#fi zLtFRden-!P*cZrOD6O8pDby$z83S(XiuGW>fQKOcu{;#kdiPhIS#`mqKR+7gA8N%~ zl`Hf{@r^c95c^1r+T8_8MxwD>?59~86#Dac8fCy|lb1oNxMW=29|pwetqV7Kc8$CKlg_OU|`*hL!c4xY@uD=Ad2XqYy&#G!kXGEh8diaork zr#{qiT5pi_f?G?zhI-UTJJ~Wa*1eTi;4{8(TS;iw=k>#bpRk5ZB^lhhZJazW(U zSpmROEWe;+7BI$h0pUbSStFO*uH?}WJgn~tdTnWThoBTVA_YfX(^{z8z#a{bz98ii zHy4%P64Q`h_USwclsX)z@|Dfe>zBJYkAhE&YfFgZxDPqCtwr02mSNfR-cdi=-y-iY zI_Nk&)4HgdWrgjS!7$pCvpBj(*q~MkPF_F*fApL0g{>+5a6!?uvcCV*%*Iy0=U)*D zNNOE-csNC7N-8OzOj3=)zEW7ju0!rc@bjgi3FlOrL|=Nw7fU8#R2muD8(}B{?x)lJA zWG|b`9Ovx2h;H}N zxQn8@3BKoy5qY-qFR+DaGFhJcCDMXh>i?<**Fr1b*=6dc^9U++uxkhwka2sT7yUlS1`Vt@bDeFKbB#sv9L zVXRP4<{m@COoo)09USRy5!&|#D})zn?iZc&%n0^m1cjm2k|JqLc|t0Nn%>1;SJmjm z+7msWB3bCXs`LiWrsq3^%}%#d7IeS*`9MV!YntbnTlS?Ug9+|#cIUE0>_|4UYqe-F zSLcbwhAKYo#$#4t9&;HW=>zT+-%h+0#x_-x>JWek45o=Sw zWrJS5=MF{e;dFdO7yW&}^YEfAOm(Z4A21N$cpv@y34n#p8Mxt?V6;psA|-JoOt3e(n0NJD0jteWmsTF|b8x+3CqQWo66KEn|qW72=f z{=GO6_-J8`{YEos_^sW4JCN}@aPPpt{Moo0iM-U*@rl#=c|YKr(E92+%CH%WCW1sM zs)!WT2PRM@j2;@!76S;B#~P8qgFt?nfBT6K>XH~i(&`z)u{Ib~#n%KSja%b{YtTt| zpti(~}I^UoX(kK%R_^%wom1~m29Rb$n7M4WI8j9>i1kd}cT_50Ad*suFNd+76lxyyp z42+|a-^cpfyj7+7#_IKEtl3iQOz^fCQYJxL=pDV#&AkA`Yr~sTy{NukqHZd~z}1wR zo9KPV!2FWrr|tme+IvRqenu?x+syk-{9ADrtBujC7E9snu9d${4o2@ANQo0`k=Ld% zU=HW2YpB2p>;xcZ#|SbOjh*;pbRpM}An}rsnAvT)>#oPc$XAU3+~bzwy(n_zCFSc6 zp01C7w_DIsc}!ym!L~bNJQaz22aD9b28x4aG&2d4Cf9@*2|Iq1Vj*L}{rBWt-GqmF z&qpV`g+n?Te=8Fqh8^tMdcn-qYUKCZA23>hu6&I{YOSQ+&v zg->%yy*0IgS`UUP%1K@KpbV5e*E{oaowp@fvfB!YNH>8}xRLocc>xoN;O@}Ey)Q*Z z3jA6T>u`&Z*L43o?iE=*2o${|Nx7J(O1r}{XkwSF{M?Yya<_5t1x zSiSsj7X^SoTbBs@3pLh%0a!q%zZ)RyQFoEI#4gbaNKwx!iLbBJG8{7+JwTJEWe&=s zo#3_7>+#(d>gKRaThR{iO?fbo5rLN1-#^OJyhfYOFIqRh>CXUu4M)uC1Pf!wA9F0V zkq39oQ_Wr@vTLY}572K3!h`N)S}PcvXBEt@pkXa%oZnt?<^vWU>RYx7gz4Ua@ zN{_I1t1u75JiKYHkkaEVoX}3F$re)3TGBaPqBeY$WsQ7x_UIv zp-PFN$TW6KR`MyBgDJvB3qa(}@JYlVUp2cs2Zob}f1Z3TiYLcEXrb0&_qR^iI%b!u z6r#iQD7(=BS)%$ECd?n`^n*;zzeB=*c;L@i`2Cz4*IOPJ(WObopM7f_|6JK;fVxw`kCj{=wXWRGsu~_^5%Z!% z0jirUNZpuPvd@}NMwu9>Aa(wtDwhX!zcBUvEKK)A4rr)g7}n21bY;s?{~WuJe-bCs1l|P^sjRW=!#Frv0p&gwRob&K9Re7H z#l4-**9(JGcUOTfx6w@xB<86Pg)NJi?;Ax$OZDh6SMYMaRY=c$mz)77pa{Evq&f5N zdMQp6&u9vh*H;b(QH*{qLn%GlWoTCtXMUBO*-S|%;1tofj`c+u{#kP-`Etj7e=+0y z5XXgdX}ytN0iq0>jX7%%;u=+%Oi?A?`uAr1K>xl0gQ>)#r1Qwi+zCQp>Hd-?Pz78o z;D~og&W15Y&D9Y^)*3n|x$^kI2s)fRMC{cA8J#d5%E|P&UWWX-=PxyOIovJ=Ac2(; zjwWfck==?@Ok6FIW3t7)U*bL#f30Q7o%oR4Sgtoji^O}VOazj`&gfY8l-2?=2DThj z_D4QF3{O_SV#e|0Qe1Sg;1C?o47#-Rm_cZ4aZh)63d#{f*gzlgP)g}I0IoWZpB$E7 zo-$U5a(vg)iygo3o+sP{_kPgLyoN4*pdaCk{8JnMZOate?jvU$;AqoD6z&-^`9N&5kS4^dLPeXM7A;veBx0xd2 zyN*q?3BSZU$gTUt={6Qm{0=bJ1K?yEAXwo#|7btV{}Ulwet(7ZY-hF*w8_(KTru9- zI0$ODY1$htH;(~oJBr+u>_BXzozS{Yyc-_;t#=bIZH#F8Rsb-ae~w>2eWgL^VGXHJ zh_2)2{9F0BUz`Je@ga2n&W8}#4}5E%`w*6zWrCFMfY$j}A3|lJn{VF0QmvmIm*Snz z#K3>jf%!HvFz+^tYe))wnHkt*Yvz@kuK&51?lh4mi_B-%k>8vn8Etot1pdxClAnII zj{NEz$-f280iiQsfAN2^j=X8C`?W@q{qPxlI>`)tljiwlz~Hau3qYP#uZUXJ)`$RZ z!p9zM2O!=arz|>MoR@SUUh+~PmAa5(GqTr{$A*vRKy+Rf3Fk;nTvN6+{=&zOl7yY4Os!JFd|P;8+#}pRf+!Y;GE=bxj~S}r3Vgh`ZTka zG-7aueVHX=u{--Hax>%+eHvG#8^xF4aaV({&i9M0aLwJq2O2tw%iX>l0M0qwr1;^i zpM~1%_rWkIf6rx2A#@{0=gDUkAtJ=`A=nWo#uwfUqDxrNh5Q5Lodh$0+sTt3>d;c( zoso?7CQ^SfJW_qbSKsyI>9|GT9k!QaOwya)-}vjlNWC-4$21?wo7K7}hZn&4MB`;u zcBy1d#+4j5INlT9K2^uCUVbFMsr|0Acu}bcMRlqOAc~#CYMQwJ4FuKmtLTTPTnI5v==Qo z0@gd#f4V^yo8sofNA!5+Lk5AWt5=YuLGnqxTtY)Q4a86lYQ-20=YtAEshN0-$U;Ve zMe*$V$gHt;o5*6$6Jx7-umsk(kUFEb?!|eBMT?gE{Xix{`Z@=8hmbmxe^u`*-;EU`Xci%5Di#FJbud=e4us~v z7~}hboIK0^&$0X8FY*h1|HT47VmJz61PPM}i4!1+;}nb|k85EZ)*7a(P*~S@HhGM^oxrlm~ZQ? ze^|T{(|A`sUuiFyZ3*Q~4-WZ#0(gbntxykdO`9uqh0tx#fFd@Kj?!%y0p4YCklk7+ z-&eX!Czf8qP13E;ng?=9u_&2CNp4&Q~tDkF5n0F`VK1L4k|#BTPKPw&F2}HB@sQwEIG1X6ZhVrYS`^MEwFO% zyMZ87hk3Qtjyk{0jzdY5gf`QXw-C9TZk{)qC8yZU$^JoA8Tg^B{PV3k>D{K(Kvz6X zOnRK%XC$Nh`H5Efk?=%;u1|+Mf7b%JS&3qoQR1mwMms(Q^qekzn=jCG)(r6=aMGQw zXqQqn(vFfP>lx7^^lD{HvGYhrK;$yoJrb#G&`?{&)_W2$?75`mkxW&t^F6AyjWqZd zPv`AnSlps*nyb9FbN9Rszdn0E-{sqr^~=jYaUgPIKOjsIC=5~v4nsRzfBCas_Rbkr zQnJ#9t(dhNEI_+TM@nvbAuzs4cVWA!S^l{z+U60F{Rcueu@Ds7#j??jp+M0#`-OvF znv<}P#&>kf(yfc_9&Ep}i9ogo;8viEx24lv(PSlNB)UB(*GK5q6%TKM+zGKY#zVVz z?fOtf<1JOV4Ov55j&c+Kf84v>*Xzo$trsg=&o%wq4B>st5ccf%F7-2!pc8+d-Rk&h zmpW(u+NB=a>wUeY{y!|>>4uNi*gf+pFuG`O-uX~k*gVqNuQ5A}m0Klj4Kr!vi%KS> zIohOqdnxSKZIk{>CCqB%H@`je`Yo>e|fyz;`U#; zJaBS!mK5k2ExP2kMM(@#mAGFFz9lR{3NrDUGa(9?tW*aI7R}KC(U`mc$tY|KpBeWQFy1Pkyh&2f6#UJ{{-Zl6&zq6>&WQ|D>Nrd?5$ZY0W2Vg<~Pj?$Z;fro#}1pMa45(oZ9R zlaJDWv9nkjClmhhHs0=H;J>|%i=w8F&!qxr^QhQo@^g>)^$W=QtZ37sc;L62YgZwm zndMLO@82m!e`#u2eUo7Gek?m!%<$ux=8mTZ((fMjj1CbOPkgPcv&>!4zYBCg3w>j`h{^>4k3`EBd<7sidt^qb2Hia1Ux~ro!FRuK<;#_ zMo+(XA#=78X*`})H9vx9STY&O<86bmHM+bI?%~t=|+ECQ%R5+4Vs}+CO*f0EGf11kBV^qMlzs*6;+ zCORa(ayk@}@KZuS+-czyoJp62b#R{eGOF@>DbNyN&tc5E`XGnceb!x$@|nIOmq~t^ zId)9%awQ@vbD7aIN=NniSi%?aX+4-8d_UzIT>{rinj6GcSW9jtg*d_1>Do9;e}wzl zkv%arN`>qbyo}A!fvGfu?9yd@2@ZVzS&SO8Mm}NZXwcaT@&<>}6dkZ`p(a*bN=R?G z>v%WbsC!{g7l!3rTS9mT1j~kKYz@8?feZl-a~r}ue7sG+B>B+U-?@#O-(1RZ$Cc$;H-jhV_{rlvdJsDUc+e{*n$n}8aW z{!L!Zn$KdaJ)NI9b_N+di`j+_RU5cDpe#hLN!#$E-J-5B;g!Zb2tH-q6X@GkPNZSi+42N@2CSf*p-C{lL;*FN?c|MLKRYq!h6NxA4 z1c(tHF7*`Phz!TqTgX7Ve{$^s{rWn!y^Yn;^*olgK88J-pH3|E1NT*;9}}6IhytT`lCSS zx6-Cz27EYo(#nT7jrd75cfnp|0Ce+EsJ0JaH9qIsg6 za=}F5%=G0F@V`rSu3t1ZHaHimnRD+cuUuq+*Vw=^Yd{LjfRK0(bpab_;T+zMr*^PS z$r8K!`|cYVqjnb61mat}Uv6!Do4R|52MutZ!rr@`xoaEBhq+}u#1!X#xu1*z4d>uN zrap9redoZ1Y1P5Hf620vm_0^?q&IQdGoW0aohw=1jedu@*HLC@Hf~WB);xKdb@Rq4 z_1=%ceug=CK@H(`lNi{a8U7NS*av$Aiatm13c(Mr>3O%Wt^vg<*zj9t7R55YmO?Vv zJfrxbYiZT;XZ`YuA63({uu_;T4FeT^B=i^hWceGNEuOh+Y;2;u(Hd%Re z>Tcx$38#=vh#0A&${z#j@DTMD2e4Oj!W;I)!J;F*s@F;rq?AX*FsXFY9~sfY6cCD zAz0w!SG2OueGf03b$}N@?4j$UgIT<{GsLUS2}e@2Mk+16NQ6<%!x^`wGB}Cj5|YQ_ z_8i)S6k9{6Fh^=-dw@?R$fK4GBr>BIS?P`D`teJ^eR%u?*d!Lg=IC3fl|G>81ogrdtXZL$*P#O&j1t*M`_u!0~N0 zG}{s==r;KEw^<8g3&F16vKFFD2ZC^;+0Qc;f5R_SuTjpL_2C5lF;`#iVk<7#NKW;$ zBFipsCg_R*iXYXgRwJm#LzV$_(G|u`Ww)XS3U*COubKrmS?px0;@Q)>3)MR;G z2w8FO#xs3^C+4-1N3H`vTV09J!>JFI`;f!Z6#K%1OSj}+LX@i32gmP^tjr%k|}ZSxAp%3Z!b9?-p_jrQ=W+P;Yyn z^T8qMMZa(vay<-K3Rr1?E{+cmgJj-h;dFo5Gwn@j1s%e-Dn8d(u*5N1E;??}PCAG6 z?26)UXJ=3h;k5}EG;yfFcie*U-OT-of0Y~#l#AtgTP~@7OiEqgxSNZ0wnv|g9-Sw2 zP^&hri%@<9eb@+cur(ZHmc@R6txTQIO^5 zEC~SZW|Fpuo^RmjQg6bk(XjTEv`QMz^O7SjD;nGNBPV0JAv7M`NemVzU@4L0sK!$W zplIe-8yZS_8|b&oD+#PLwBaGmT_JJxId?^s~IZV=68K zN(zzvWiaF7(8%m(au}0ZpMdM} zwuV@fbHCws3#Cqd?5C;c4J~iu5JLK^Pe`v1J0qTWM zevK)XUZAJJ|8fwNWCun6UYB*LHU3Gk~;tY|7^Y@-hX!{KjI<@ zVkim|D2YNi^r?zzg6-Y0f5cw?L^h?DbcYiJ-7U1pjmxh{i6mRHf+Rne{>HZ?0g~?% zE_*T~+I=r0a7#f%y9?F|OyKU=vF^OS+X|oCY|U>qXOgW=IF0tHoIUN3gL_>T+}6s# z4S`d5PhVtTOtL6+gW^pyC*5#8A-CS&6%p5S+G?oi29W690Zje9e`ANR)jr2>;%lPq z@&mRqf?ppb?6l&dEZ%$d{wTic~k-O1qO_eY2Ewrv~5`LeBI z8KD1Vg4!0`A5y=G#_|djioz6Lbnr)Q9*%w+;lZ?&mC7Bry#tdC&l7eBKG_! z%Dg9CO9+EKr~v~!8fwzC_EsXuJRoAAI^=!Cq561bBM4d^$9s^oqFr5)(0f=YaT4iQ zIbXW_oy^~@B?7XVPWiHAw*K;6BEiyw8KFbsmr```f9C@sTE1`)TY(DO+dY@T9&h2k zIFm6NP@eRL0Y-T~4la|@oFl1y1Kl!Trtw}s&}ZAc#k9EfMV+o{2fCBF(DsjFYn-Tl8@)L_k3>27_i!Rz zlPxBOf0vmk3$d1Du7Xtp@hD>A2|7J;oH1F$RgX_7XUWcn<+=!DmGY&xB;sh`RF5L> zubuOZf~VnziBn=N%mN3NY!X#2l|h(Y>!7Kc!PlA|Rm9^=ozkYyUICa7!cd2hVC(l7 z^(sx~CMZPnleMrwyq>J@!KS~wI?mzFBLW?le^E>e0#U3ME&8!3-MA}N)3pyp-;PhuWF}g3htsqhGVb{R+TzbXc7N< zfAnV8^w{$GEDb>`Br8!L-TwF-X+P|-J{`pQua^0FEa#^sek!wnhQcc%VmnA>@P<|~ zy5-m@WRprGu#E~P$p*^nKet&_{PU@sc!M}XR+C ztKAAy;G>`Q0R4as-%O|yjp;s`h&MCnufs53#6I?ny9w@6;5&OYcH7Eg(m5B_f4THa z+b<0QKW@~7;%E9=_vR0JswaL{PHTKn#y^-&0zYEF z(Xcjxy`JX3Xx}|vvU_jMCgY5%qYMjhg*w-YoLkMr76RqAY_YX)MDm9o6CU5EP-zo~~Bd)l<7 zR0|hJPKDoGn2YD(JfG(4Tndii0b2T?#iRNP`c@2vTY8-R%mHTEh9sdUdbsO?#Z%mS@Fx0^ay;)G`uBc;|f$=%hMd zpLE>YH0#6g08>c3xUzd5SfC``!`1xKz6;8e$^9Zsb}V&=I5p+d#KBRh+BPxejFk_bzaeaL|MGN!TnKEc%FV{q%ST20AIj0aRO2fdp8%$T&Bq*g*o- zVn}r1J^1{CsN~WFE|{B)2lydByk{O!U+!u2B04A{ zsA;pq0aNDVTlOD-87po~P0f-)DB7V~Wi|@p>xAF7K7AFt(NjYF0zxxc+Vkze9G}et zJSG-lU-E;IV?clI=LTKFujpcGWoe~N?Z))+K?n!Bl02>;4WT_#+U*MJn3Qofh(k@0 zsVByWE2h-}(@quBe;_jKs`ExVm+~{h>7)G5AxgU@k8a44KeGR2FDpEB-&DC_5TsU^ z`L@GW%KinI{`J9M;pndq{0W&*5JCwECI}p&FoHzU&nI4196_nAZoCq@IN9>0aJtEK z$9uySzUyGY)F%14636&AdI{7F4+Z^eKNpiHiJ;vnLce|d(ieu4^oGbZ@@-2^=ksFC5i0uqXe48GPh^;uE zVcQ!+A7eAfKH?hhNc#7bk=YlF)}`MOZ)JPitf@9>PPro<@GkM5e|3HTKJ3SL-mna!rg`t8^MVy`V0T%k&!TaFXd~XeTqJcM1omJQg<-mGGp+wL^ZG1h-S^6WzaW z(Czv5e^%Ol$);33VmAWN(XM_AH_ctiQFXuf;)CVIF2*jz>+Ono4Vn)Px(J7LwH5t6 zC%!8AJdZ6Tz0=1tW`TFTG>j>QgtsD+tz*aYLsn$NBMI;Bnv$7PanIi+Ozh4?QNFN2 z$-%S;787iXRhj%8_wy)@SXUydax3O7V7YPmckN zxL<9jzV8csvUB{wD|uevXuGhOK5oO&T<^T(%NI*+OXyG2&fE9=BhSn!powMb^P&yN zbeNA5b)3Mi2{nFJkI`~zQ4`~)UL{8IMV3ITE-oa1BK5*pf@3y~^nM=2@j7-#7SZqL ze^>W1B{Y9DR+(kPi{WCm1u!n@LR(S?U*o;yAd zw2(GABMGHjZC}AgN#!vrnfBe^1bo^g`SjaCJ{9i5b6^DPb$4?V1B!Uqj0vHQm zZQ=~z))}`VJ-AC2ZNsIzYy`2#e+0xXdX!Mx#;t$*?+coj&3>x>Wxe z(@&RBeZ2UE(Ejq;&yWZFwXwz2q&{7rG!Ke!gC_qv^qX;y3mi%38(6)db`uG^KYoWtHY#_G&o zEi8mjftMf;$#fCPDU263t23S)D3%zHE=3zFXdJHW3CEni>ih&G5C*#^ELNH}c`qo~`rjX1M@de;(J%8bl*c*p9LX zl~2}rY+;q){H5^3+P|CUD1NnEjR^3&ZH1yt*dL3az^B;u8yx(p+eto7Hgf0ywRY=A z4Vj15h^`cIMXVS3Srqz3DnT{%k#HYv|>i{dSgc7iB6We9otlG zahio+J^gT~TzYfpfBl%i>8T)7K0~VF0b@fvX+2O?8fGPifvL?UK0Qdjj|Z0wo)~Kl zuh6Ov)Ost6sekSabXnYTBAf0w5Yf~a_eEh(0G>0c)y*Dq>4Ou~jZ#YJG?y~f0pjB{ zbxulpAmN0U%FE^2M=P1ZGzGUb5z&`)G%rA#$az)}m1w}fl zFLq3n>J=gbdE`uwcVrAPs6}}+wAi&-G633}#Eto4mo;Y?^DJgsQ>t$pC!S9)rVcz& zxQY{l9W1E^2rFi25s$jhI4y0LXVOc6&r$h5h9~;<>>k%NO8-c+@43cg%QXtuM;rBz zF3*PbpPSf^e=Ph#<1mh(AWr^*QvZ{6zJk?%y~dAlwzWgU1PW6Gyy@^E59VZd2DVN=q5(A{=DfQp_`{7w);6|e{26F3fpt{IDb=6b`KLljIY@iKF#w? zuJen6vgK*-ZJO>YWis5Yf0>#i-zr0vsYCmx9_Q+#$2shi7Ak>6QpT|LmTlvQo=+pn zJP&JCf3WBr4IA7yCJ5~`i_=y>^FBIvIDQ6JK>D^(6MpeYtUX6_<;naQ5#czl*`^e? z&gwew%_0=tO>yXZsy2Z4RIM0Yl;=tp=NJx~WZSla*ow=Fb!8a6l3{HzC%r1BqL6>< z9n5|VC&}Az(h6+cscByZK2`)7$q*`08vNoofA^VEz_a9Jy1^H7e((-_pXc(Oo|GQt zt-klYY<$`bi^;T7Yrl|o*G*IpZJu?(lG2YUTm^Dsz%TB5j zxiQC_)z?!8`(z#kRWH!`P8_*X%Bj1+fkT#yfJ(_vKY(zy#{I~X*?ScQ#CgF5S=03Q ze^IHc^a!E+6H9Ci=yUyt(^b z;#obs%(Ni7`7>IUR#T}^^Tl_29$s(^f3#$4QYNn<@0#Kk6qU((tfs}HM>O`*&;VtS ze1M0VJmTZ&sR_5ufG}BUQfw!)!p=Z=Gy|d6@FSlG;N|LT)&W0F@B9+B&j4*Ag=Jt^ zKT>xPZ{_gRBe`t9r z4Et19I6BU7WZeX5tkwKANiiiI9pEIBZ{Hi8**vvRK|RHNPMD-CEA8P#sUvlpuXir> z1oExnQd-fOOflgyWsPXRvS}0mT(6lcS4RyR)@JGw<@A0XilaEXg*z^d4k;M(><+%< z8-7i--Wp!LBLzj6>P25&uLKPHe=LchT?v_+929waeba)FMopFmjgfzh3}lTCw#Z=j zqWC<4{F8Wu)hyZTp<5_@z7bxk(aBTNC9dpibzzzQ%L2vvCYdIS@%mrD6xK?e=`D$M z)>u+x*+JZ@G0gh360Z6;t%%KtO>M&-*q$oCJXAh3o?v}S7AE;gcDZ6qf2l@kmu5;@ z(&*4+Mu28%I;5Fq`#auVSpPN)W~4=w4ov1nizJ;EAKP`BM!vkhE+Esv#54dcPINqN zJMy$l)6*K>(i%;_X)gJ_-v*OX-MIyk1$J(Qf$#e+6xLV)%QZ))Wx67}-+B^QfKu?hw|e%VMEUkrmhRsKEYs zcn98_#ondiL&xL2wg{-!9wV#-_EiB@2#{5d<=?cmeto=GeKJo^g-64n#TP;5NAM00 zwYVT=c6UdwoGUDIZ2Nr0c>Ell9h8KC^XxB1`mRnr^N@uj@0Nu$;pSPrkR|ljmH0$SL z=px&hXK6W~9PY##+VPq!fC;jNuq+R}dQHhas$OodUdm9W)Dt<&v;7X?{2|Hk$l0_m zzWOVs(k~`|5>n_;w#fjMs$FsZNqR|?9`2g^f_))wu`_=|PiF=8{&C1DFWIfnHrLNT zjQ>{-dHu})e_{V``v0Tu&6?cAx-8Ilenr1?yTv?w5&ZyS9)*}B-k1j=kQl`9>o3So zSJ{;=yZYN(FNhJ07#NR=p5QBDrO(GsxBz2ls(1a=o2w(#uJFj3%kgyNglqITp9vdy{8}kmcU3=mTpBWw%CjH{Hz07qyCKAbx)Am2 zY`T#ZABy6csgU^0Ui@MJY-NOPd#P`npI__AcV1l8zFJP~tUiv6tF{5ck?unde|)9# znG%!f%Jq8lx@Rjhx|9YKWd%ZA^Tg<9JweHXAGv4)iJ$~wGB)BPJR*{K%zO5D))Vk7 zmqjOTAhzR!>SgSwa5W!z>>q0 z6KCiKNM~pKqJV&;7w7>VLyk;Gf7Xp^D$IS7PjA8>%nsR@-MaCs>Eq-f54XxD^jQw6 zMFJsyxGH#jVE5-8G-Bm1Vy=M%;AsCLn>xe{WTrw-sY> z9f&owU2IPQuA_w&_6uIO$}aHvTz9N(1xW;;zCv@8VzN zGG$!14R1ZyU8lZ0`XSI=f3u-Eshg?nM?f7~jqD~zyP0M4s2jao#HxZAJJKq zhc|xdZuv&z*ynIP0UCGlyY&hUIz)n;+LEAwmDy;V?KNz)0<_qCp>gAt!auU8##i0DHT$BHbpAp>AI$`0>=xT z$YKT$rpg^}$96{2f3uL@#2cU$W@Iqab_D3e14P*FIKmQBOQ<1@1uC-t;J*E zgZT)B9y`Mz`EuoaxMtJ=uo_*c`IA>wv&lGZ@Ho?=(`42qfAv|p6s5!VKw*?lmjtZ^ zl?wt6t74|-47P7W%YZ-=>XajC+tzC5us&f5MSARmC~c#8G!$`+xzM>+udFVm%8z0l zdGIK8f&;%ZgGH=+z*?@X;TySky>Vu9xsJCk@J@#jZMmzK@EGi2!x1m&(|wH&$8h_h z_y=ZgV*4Llf0!i8k46XSpN!bP=B0`4`1+djnY}4_%Hle0{H3SY)gj{$+%tpx&FamRf?c<5r}U$%U5K7(~a)) z;$IrD8@9G*gv!5u4xgGz1on64Y&$ed`q$$)f8h6q66yJxS2I}OAbNf&qIyDezP=K+ z$^kqP2{NynY8WJ?YkpoaYfj(BpMpWwy6mkcG&RK0Qtve4FHL#}K`s!&*iH z4kz7Dt_<#8UNz|WNWv43>MA?9c0D{TlLMbBSQg$hqcLqFuYtf^RH8RqRkK$7WP!nQZEa8@j@0K}Wk zR>$RG;nxZ!CL#}7Q;psDnbwKag=teUsu`1WDRZO^qq;sW!u6)t2BY}OB%XnR8z!}) z$389Nk`d^Jc5nnXhO2@cG&8wA$s#+ye^zs5d+x+Eo$Uy5=!PrCe>si={_#-a4~zs5 zxMx^cu@x*OLLNezb%jyZMHk5r>CcbjjsXJ0IGo)tfbYlLH4{K{y3UD>6taw;f@=!V zL>Rw}>Y>qG_>biX)PHB*-Z6ctYwvNk@PlvXrOxp+G`C58?&v;!&N&f9|F+ zO@3KT+6;hb8LPSpa4=&YKAxrYt28wx$JNPa;U)iRGTQ6+*) z`Av0MPik7hWCGeoYaA6t`!q8hqT=t+!)1H#kR`6nfpUCk zu*>$IQhKob{-!G&k0K9bgtl6%UYe&2V57pn>J=r575@E!f+6g(a{E#H4Xpd)xlS4v zOT_$q_pCZZ>=KS$ixTa__2`%B1AK?s-T4&R)g4*7-z|BkR6*GWxj*Z>#QT9>9PNmj z(ff$OE)j+I*2|Z;(&!zSio^SwV{~^A+ym?5{botJuZE!B%1(Ia1r)lY?k+5i-p7Ey z^eN)d9Zq}ymvCDBZ^5bJe=yZIIF$qgx?Yrf=zDwgyBqjM8{O$XLXt;t(YKnb96$XtcAEtn$NqAvh_oiTrvj=rJj3 zkVO2}>7(L~m-ZSL!ploeLwBKk<#A^1(hWRXD_}q}g9E;&dL9ZduH&Pa<(JrNI;qU1 zWP@s3!~5Z6-};kre>2d#J(;t3X%0o?8T$2kFaT*9s&RcL;9}ey5~2xqDW;4 zi<@zeJC|!Nx^Wn_G8Teu0f!4|WP!tB4>B=;q;Aus#-Pb8eeZEs`vZG;=m?E+@|lJsvB?<&+ZV z8n>P4oParPe?$SSN)B?@GVO$u?rZ4A^~FPIeRg`pqQzJeRR&F2fa~T&gfciU6qe2DN;DFA$~tLg z7i42S2Nif|2dkbu^<}nKl~JvicgBvkFhjIJOUcdef7QA;C5*}(HEKp*+R;A?$8})x zETJ<_gMqvLxK<7HBp+-LBMxpf=Tr$LILO^GTW{Xe?nqZ2&BAY>{{h^74A%W$;qL$5 z_5TXMzkBUpA~8(vrY~Co815k-`%K*iV_PA)!zR5?<8S3*`W}7H_E^f#EyidF}bTd zhxC_7eE%fy@&7v{HdhA!K;o?$`3{NyG;a9Me^D9uyQ=paDhK&bQ5pEVs`qzL8Td0S ze~!xi?x6Msl~?6^R7Si7NVfO6eOUjvBK|#rs^RKpZ#_YmEa?afY8W(2!JMV_pshHS z^9b|+%sxM5&WeWU6}!?m;EFgsT{R0fqeCRy zf5{yIsQKY{<%lG#)2)a8j?GU(3a(>V4cA((CGSPmtzt|rb_xs0awjBBSurP23}^fT zRspA{xtsH9yy42k`e2jIKzCKwyf_IzXVLMhQ;u)RU9L~inFew6!Pb$bois(fKgKKt zigTf4VqmuGV|YfF(Kr$WXPKBz(-J`ne_dr?f;&a9kn4&1BbW*rJ94+0E25x}$>9bN zcY*En#`O$P(x|xX%SdnF+6|Qh^(x!fEVyyvvblh{N6)!y+2sBpQ2ifP#DX$si~&9Y zCW$9?E#A)g>kV$Sz0SacbPCcIcOghz$L)o3LHVFy+Vf9M>I z<1pMHDQcslJf2QlEz7N-4E2+pNK50r4n?{c7Z!M>gdMF4L_Nf#Mj}V6c@An9=b4L8 zY3ie=1XV9APE>1nUHt6em#A*e6NviifWUb` z%ITst4@50qOgl833*9|b3gy$v+V#-@db=ckU!a<0Wq1Ebq`cqLF5Uoae}l5%KQg;yYy0@m^}~@m}P6))3mAb5nZn*>3o{`^qDG%Q*U(M?HkT zXD6bs=JPTBHDqgtb8LU{e+KFhywB{XZ+G8!z}J4WeG$Zt&*2;U>35HNpS6VE!x7oO zn(&v29-OmpmDRTtOF2PfapV4v{xW?!7;)x)(3I{tx(`5obBl+B`?k9;(bwQ){rpvq zzN#N2OGgJ6QWK}P%tjHMT`3QT4hV`4eBZGjMzIo ztd4LAy-Gn_kpn%dpVYMjqJIz)s8i=1DKNw{)_TZ2c_!S-M;`>p>4(t-gBsNHDY>>~ z47wm$3uJ0A!YsMTiP=8HRPL1fGjfDK^O^XN9FkJ0B_Pum4TJy0-~z%fL|C{p$v}ee={QA1SiqOhIDyS2cVg;6CT{X z*U>?0nfgcF+5N{H_|(NkD0`Z*%r$0=!_?8R*7}#_PNzs2_G`z6KzmY;$qV zYzW5DFoYU4OYolK7`%3mEb?QF%u)Zksm!o-V-N2X$1u=Zx%gdC6PgwH0!o$DnL= z(6+B5?^Y%i?PKVBcl8}SvK47x5=#>JZCRS^h1HicNN5+o{S0Ely?whwRJbGHR(+B0 zDZK4v+v~SVEJJtfz>{50NAFRNJIL)57WiH%ZVQgyjepXuz}prCrF-b(ZZrz*CztTA z=kI=mn2e`*^Sruu8~Su?;eQ=scK0xJDs^+eayA)GmW9E~AxI~v`+OXWn4 zb*TpNrbLM+taqq3Ag711?W3hGJ>^O=&d<(PiMz#*k$=%%<@xT}XAQ7;dlu=enA!`2 z7R=$4BG^WsXBj@lFT}q@bc0)xXk-!M!8!r90)N)XG)X@O=Fa8J10dE}q&PT#t+WLV z)7|pKRN%IcR5d1#$fE*;2C#XJ71LEuKUBncV8I0Djk|Qhnnc_%3Por|WsMga87E=M zUb-%H2qgRs#IW*b)dBv9W+_j3q^0q}y}0n&x*)WKhws zj3-|EZgI+QFFDABiYpOZD@4Zv-vGH)M&flY8#O`*Fm6L>7HV7VF1>xL@z* ze>iG!tnn9QvEsWogcoo43#vHG`lWEO{y>#4k9}JO@cXFp`6_^~sPe}uet#0`@mZ$F z%xW3%^bVkvpa~s-Ds~8a%$c!!w_YiUCR$E^qB4~G1U5uq>L5-qh4<=I)nZk6L&K_! z1t=n&sItb^aCWtiH)j|{@aCdfVa<-Hw5g&hr|NJl3+tuP$NB(0&sVYxj3s=wDc%JD zSXJp+h&?7v8)RuWTVPs_X`GEA#;0;rz&R0+jy_=^MmHgnRzxQU-bQ1*aO+_S z`QV6KaiE71lo2R>(L53fMNFl{P4ujgwoZ03Mn$DTR8JeS4Qetdfj01z0wV*_V@-h(a40&%z8^A{hBgTo9s#*4K zx9uA+p^QSvT+gnUPv41)BIz7v;a1Nr!Q;q?t58dLG0R<+VR8r@;fD7e1?|Z>54|gX zh%7N(RzKjP;N@0B!P4NvR!?eI9BElaVZpRg9vj3L!bXsD0e{R%fa;r;Gp0O-U?-4` z+K=P`B%aR}G*+ZD&GD^T$$JK)%>w3coTwR|dyS()BB==Aqy1|S9stn`LIuQl>0=useJ)60F)~IV? z$Xc$W0{?;-&wuiY0+Qmvw$qdDT$j@@H6@MJt-jS?15R@-5nMaAtC|B#+A8WXN!<+3dbxq^5On@B znihT1wAZ$~KZz+lJXe4F$qy+&R73bF5KxZHU4Q6uPD8Krgw)-b3d1pT=4Z_!$L2w& zMOt`4aJ)Obg8Iz4vfL>fLlZa;Vj>uwB!HGsw=1t`ZnVyp)ZaL)#c{UiCLR(;e>pxG zONNzrcO2JKT-IKCe)ZZu;f7&N_?uF*S5G>qPvq{%Me#gfmZNgKU+ zN36Xo=)DWOb0}gTzuGGJeVQ!Zop3^ICpfzsT(qB$?uw$HDSe}4pCsFJPKmcs9r^ZZ z&34J~R<{#xPlMz=g0@xV+xj=kMZV*kGk@wmg_iDR^=^6)?#*R9-J8;T#s{*KCl-S-hC@ckL3HSzg}3;6K;-G9D1 z^nCR(zgT{7-^~C3Pg39*wQ^Td>d3F*$bKgw|0?L%&;=|K0*C`3RltoXCQgb%EQK4d zzP2{UAZAyz_D;_V?kAggS?&caO)>0W+O4{GY{8}KY8jMC1APzm_$@2NF{nlk8a1@y z9r^`v#JP0@ZwYZXaf;$tUn<>Lmwz+%7;1I-Bk1@~Ze@1ZEj2N*JZ#v(S!XydeBlfn zlKzSN;++0rY|T0hx8vCEX$^d0YW-u-al>%zjj5Q+F*Bu7V8f2uKA?`4E(fm%!Zyn1 zV*=q^;lPu35Lc&~OK@HC8)e|=1t$xU%8&wU_zjAcpny)Un}7r~-4?$mWPc#5W4aOO zV|Z{SExJtkyUpjXT8-l_26>tvdmqR04)bYlk@RE!BC7+sEq_n)H${K#MfaKr zF6Y-)XVzDw7$anU1xUTiG#u^5kGdUCiuGZ}g>%5JTS$E9SF!T*R-)w}Vi3`NYd!W| z>T5kGdN+B`Adr$*eD8NVuRmfIICf8^Up>O+cckRk#{j=#!5^l2Er;VvePirj zZNLK0#~G~5q8+)04zf!%{s z@7HUJL^&uz6|)td)g|=OLgeZsyr1zo7lMwPX1gjVD0ggosef8oph%X`bilcsB8tFI zGaPyTGxf`?Tc1ef%2*I66s0KS(npQTNgTVN;ISkUtwr=S00VFM0b{3Cm1t$PRvg0ein8`2mVL9k{s)>Krf1jVoTr zfzv?@OKbQB!hb$%;sUt zd@1ftm|&8=RI007@CWQ@o*Y=`u)*!`8=!Ac0sew2-?@WWa?+z3d!TM~e=*2tv|gsl z8&Ck#UmKvnXC2T_8=z{~cD80R4sve~bP4fgQo{HG^nX&pWAqevQ$x#8MZD~eA3c{J z&c~{?zQi!)Bt zD%xR9Sbs1yti)w*qE^AfDj3kBdnv3>J+FY*8f$FYqBzL26}7Kd2|0cfyqvKxa|=88 zlU}y03I=t4w)>u&HS4LCh%bN)?rF0OKFZh@qS3F)&JV-D#ciX`KQ1)valYBG9)a`asKb*Xdf(v+%!G80n z{Cjl#0K2z=gwDl_!RagT#Yuwsigqq+I)5&{f!(Le{cN?sKUwZ)s|9|x+-(#4nfnC$ z#eIU`-6wWnJ5E`nVh_f2@#nUIIpx_d1g0Po%J(fdCEYV`px}$XFe4n5g?)jHi+low zjj^W!zisL&Bx8cl~<@z_&w4Z#Ci0q84|+bfC1SJeU`>}1I~6a*%WX}A)u;<=pNOTy_UE-&k4T=S z7vP*tfw%Tu1fC^Ysf9y<&Y+T3B@3aFu$(aITHk99YX#?UR#-%)8j_nQ(ZCGN5&*14LAK-2Q-BY>d2AOx%AqTI`_U#8y zf3}0{uH_L{V(0nFkk7M--6UqK1sO*CQbK*6>hn9mc7B>df3Ffk^Iys-t!+*`SJjd8 z@8egV0{kVmce}yK@X%AzWo7h~IHqvJlC^FfFx7IYjZh_ea9ws4_wm7B5C6p zJTOm{J%W&Brelfb=-0kA7_ECQK~H%e&b&z25tfhlIwrdUU1PkL2!sRbqM*6Xb6ML+vaS)I0nvq6#fCb~&#?5jqpfX>V%beW;;JTGefvsJjbrta| zvAEQ%tlcynn%>lLjwBP=y`3qk`|akH`QJ8wH1#j_)PLB^R#e^l|9?1||MmZ94)?Ci z-WfbQ2JI@svH1X&FL^x3_wlp;_O-qX{`u(>e<}GV;&)3Z+51l$C~PIwR*Xf+UZf?& zjv)Kd8nWv)lC94A-1G>4+fGvPj)5D<>{S=~ZaPtWqbYui7vc9LdHjwC+7ImLUAahN zKdbWK_auG%?oz$4xPR4adx8SKH@2v^nbIB!l!QwADeY@4t+hKaE z`@(lqYM;6eZ=H}ex?TN`TtAFXW7l3o*A0M19KQ!X( zn)zMQEKi?a>qUXc&O zTTxp9AJyAiaK8iKZ;rfu(bF>?V0!B8b|x`<_v0+Uc2_;P;L2+ALG@ookJNN{59Fo2 zytwLEtSE}dw0}*I$R(YM!4*4TjcPD?fFS5#h@mp%lwD_j1K!&TUvm9|mqDZA;qZjD zOK1g*H6@X6waxK$urU7N>43*vP-8p`Ioi8H62%;kp3w%=pX-YkB8>2!K^URI!+qAo z7*}2RcqHz?499y93;E3g3WI%aRiDUkiG)k|#aTg(Kz~xKR6F5S8{W3X@mX}Ait|lO zk7RT`cSMnS>MfKSVen0$t(vUXib-1XLwT5)%iZKovi=kwb+^)Z5LPcLnxl(!fK}cc z%)Gb~-7(hPgE+vpJptilSd$G=!T|HeF%FZg|LO6Tz&wTLC8^neZUwh3)sKq!)62&YH8wt?5!9Nl>qY}*plAbOx z(BAS)bU^b4zGkq<#?>V&mQ_4>yxh>N2ieP7N`D?HKFH%E|W z;eb?SYv-M)g6edaj1&80qA^mv>&6-wbX|;|a*5~AoJIb=oXN`ZNacCPAsf7L!UDkV z?MUZZO|yqCGw!|@HV0Df@VlEG46i*tb4M%dQHt&R`4!qwnj`f6qoH0PLzc zvw!YQdyrQ&551&P+x61&ZKfu)0`^STLg?=wz{EpXm;JlkNt@x%c=4tA`0)h$zaIa^ z{MP~6ezhnZfoOvK@mS{Hy3)79n!mluch1fT3GeYhB!VH^R|towPZ5oN2MD|a%b|BE zwbecw@MK?VpZ7dk^geRQcDv`#Rrqh5+J8`NpEM(OStCNdPf5Zz#-Z<4V)|}lMmzXy zShm~q#apTLGepC8W#k4@)cfd#Ciade@dm zzH7p4e|Ou}c8JY(PnUhl?U#rqy!)2Kx9UvxruJMz8jn$*tMJ412O*2?ZJe=U^nZ^m zRn~ zt3N+BNPL$)fsaE!q8;!qqP{3#=ItWOI}WyzC;daZ|NUd%E&qM&^zSTxUp?^eEPr1; z@K2;O4=Umx_Wh=rhg#JA$yJRP;D0(}cC0&Py5-ohm*bW#4!6jcMwdCDXSkK7l7qMH zqf|Mpg2Pi3+>W;gdKM`n|&k4K6@`9{(dW*|5cM(>78mj?%l2JkjIhO7vRQ^LU4M;8Iz?8rVL>E-#geODu@Rr)Ls6G@t!u3hgo`v3!oJUGOSwi>np z>o!hL;st5veEZa{7J$PR_F!4qGx`A~*2`%HgLn)hmnWbVh0A*&7rgU@{OFkL{^LZ@O=YxG4&tx-_nYAtf+icOaT3gvJ86fRVKAEY@jL^5s#{5CG)D{Cwu zgWXq<1V?6aVo-z-*Amawxt`QnMU`WyF8RyFL!>AVAzrf32?<{{<^i@2orS1jRBwR@ zxk67>I1Y$LOMiDQjiua@_##5Owk!wd5Z_tgdfX7rHk7tKs)aICP zyhiI;2006)Z9WL5=Nw|mS*0$ZDP~vsjyQD&;aSu_u|s&omgNFmAZ)9(9pX?f6(U{3 zkw+Gj2P3e6<*RhNW3LnaOpYNT9Z&Y9^YI8$xuG8@41YNg8zlp>_$AdBsYRX!HOCs3 zC^9c%Tk(HX97_xP!)->^!|3Wg12^dP5RJYSJ&$+gsbZQ&o&goR&<~`N$DHqae}<%} zSnD(!2P&>9hSeEO0f&6lq|=FU6|5dpMnCejIqA5S0!;V{5p-6<2 z@U+>>Vaijaze1;~o~?7I)2~UqI;0YKd<+`Wb}uh<0IfMagR;QZGvvOA<4IcxOl!$S zkUO1-JPJgXgi|j?o&SR~Y<658Vc-A9vEIKTe}5unAOFJG|4CCQOrR+8BeDC(FaF?i zKY8JI=gpr^wGi(kS!5?W*gH{U<31bd+ISHDwq2&9y_tYv`(KdH8|oOn>y*j2eL?c> ztZ)B|k#E{Zz2k(5okbDR-fNGEoo2zve&|d8%z2p(-w9RFE~MF*9vQ!bjOktNLt}3T zfq(ZAbe!xF#3a3+31IK3$?fgz9hCSTI0f&*n-JUE_)xkld*JsQ#D1CWDEPYr5G4N5 zg!l`2csC);ADR%Rv+@a`v;9Yl+O--Fk40hKDT=#5xXJ1Bwn?vg70)uqq#wS=0;Is{ zg)L%K-=i?*_h0lsahPu!WQSRd-DP>rCx0FO&>(;J*aSG$_Y};zQM2TH$+X*rKLY>9 z-7HTZOebG;=ep{vjP4>J;7=-`V{)md>%~~NRrK#aIr-Z#zqNl(R+3I3{ooYaKuob0N4TDOs6Xsei9 zoygryQo`QHxW|xLb3qvAgPwq`51KBTxiuwtIxd6ak%j?SMMOIuy$-g-$jC(=gQEk; z-$k!s6z$2zm%DWq*j7=_*{JDf%73oeYiO{`q9brD&46ArmeU-d;&JK=!!%#~c(^cv z$*yQD$WQn9be{2{*W5IB*tsIO7vDji!V(4-Xr);%dNO_sOyr5}d+A1{Sr$%R#6gJTJj;B&^dnW@SRm|TW88kovbM*>wYnecG=DgySV5>K zm}8@)1ShC^OizhnJOP8-oK~i0&gJziv~XN^fZL<|xjn=~cDj0~o)Uqz@$!R%R#iF( zr#?I{W!Bp#oE@evQ%f*=p~C%q4+C0pL#+gabJ4K3#{u>i*opKN6Q%AFk&in=E$|F$ zrz0LRo_aoJT1K?!mA$dmvwx6ohh9gU;%oz_gHx_2rMS@&9U!lZ``kc49Tm1F6?R5{{zt zsEbv)7}t9*d1*>olB|@)R_bGpKc9f_Pal3Gl1slc3CNbWR)f!vb$Dq*UjZ!nedDYQw2ar&&jN1TvOC3VmO7Qu$-KtrGAi)hjc!qMMMn;9|31KIuYZ2 zl9YtkgqiH-6Gk9Cz#z~V+r(=&&7mbBoexv!06mv<-bfpfT&zfAx|h}aNg(lZwaOm< z(Dg@NJZbScqXS^p<9}2eIFCWR-1bs0B@ykAk$> z9%Jzhya{yA2pfntZOSz=2(X`81Vh5!XB}Gq*AWrIb!PvrKTw7x4?;O-F zngz(<==#m$fqz=y!4lFwglh{4%>eUBu(AYPS#%G5s7bng)c%-gHphmdc~zq{JYj}P z0{B2vQ7IlLKgXTOzWQQNuKd%w^d~}@>^VJq&^=zj&gN3(&cp;9oFC8A6Ib=a<3JYx zdJ;m%pB5Q9jh$MJS0SwjCEvh*7-{+ukKzfG1l*0G0t zy?uMXBu(RQ^WX&EMZ9|hDSgjsk?$b0`13)naF43a$o(rpeC%e)GB(XTae-2(?T~!lUSmZ}^!g&)Y$m&g9k$&&s*BunZg zJU(3CHBFDIi6p7Es=9eb)R{#_<`@p1jI8!q>VFmL3Iy5`(yz`-lhV50rc$FZ?36_L z)4au+F<|^wOoamP#eKHwTiw_SkajWI3%j%v9iu#8pmFP*%QM~`Jog39+JymeD&ouW zG^xxBN*-lVVu{yRt#i;~P+3z`9?jNSy4O|fX<%3zj>`q04;O3x@lS^FywSU+uNWE)`1Kd3qB5W4q80C)Z=AxrHhvPk>5uGg7SEK3S=@uMCU9R@VW}Ik*G*9A-`=?}yIWiSsIWB+G z73O;9URdSn@Cx==Wm}^vypmVz3(vD`EbHT@Ys=}Bs|{VUcr-*v>Gm7=dO&Pj3*F}$ z)y+>(G5bExju-q8t$L|GJNy}eg2L<53}Z)fq^fJ1<2Mg{mUOH>^z+3AWPh>i4@a3* zbx<5-CVj@!`QfaK&>2#bt#*Et_=RSrm=}ws)q~@49;g~d8@Y9P+Cl(H(I(uwqNp0( zZ_2iMcS&-pJLFHO%=1Kqwm8!l4_KBc+A6 z_()7K94f6WGd%oS=4t^+yW$PIy~YG6BdQ(2$WZZA;}t7Pj6iZX)bz&IH!Q=X_NW)5 zFTyQl9t6F=nz?^HKg-k2AXlf(J+XtS_I79dlCxELCG;B)+#>mGuzx&A3@j&}Dei_d z`T^!??{H?LQPNtC>=yrIMDcn9x$qe(+fL#kmzcMVA;(|aO*_WVD9vCya&xe-kOKC#!w*LibSowIAA2{IyF==&1l7(pB#7M($rjK z>IUoLKpfSqV*Q~T$ba$LT*hJpB`9{oqJ2V6133$@LyaQno z@~sE`+>T}UrzZB$@r?$>U#8RJw}%V5%RTpmT4--S(aG0SLKyy6itfBDfq%lqvSdHK z+&Er>zI~{%{U|hpcY1}soynm04ffG7VxJ^~-cb<={hsVk_Zc)Y-R)Sm8%#Xh{^r58AJ7FC`A^~(U6%xF@I9FlGS-n!g41*@m6xKDdD?`17NLP+_}Fk*4S?dcoIp$2tBL4dTZv;WDm|P|@#$<2 zN$IerAr_6m+U09f%h_Y-K%PJbH%)Z8aMJ-eYm0O8#m?y=41apbA5p3x9-(V=qT#-$>384}eK z@?`p>^Z%0fUdxVZ+qU34Uvb_Qb%i(U4TO~d;oTeF2m!(f^YsNvvsdQM+-t3K&#j86 zipY#9A+XX;O4#pu8dEQ8|+`P>_kVxZ08r$O7%$c^e7wH$$LIt z*N}>#0tvyUxsq7ip;9O!xe>5uJ^&!Wl zYl=IO8v2!*(s8o$^P35g*+oDA&!2BXyMII2?516T-)u;9AE>A#R}G$$*Ym17VCr-y zoy9Na>Klqc6dEXs#!N#{=2-v*>8ISh7KFm4Nl*0xy&fGL3L`zEHFRfWCM#Fwl#m=%`+u@w zbS_@W!9nDgkeGbLe%Qx>B{^0^!uWs}k~(w;6!^(He6$8fm(1Tl zBKfhMj1KWKf*&g;2=eK%^f~%ycz+okfCN(q!et+;X)HSge;N3@=1A1h?;%7FiN!vi z3_JiChd;|iAE_XQe(FWBPfZSfq(D;i@V%zeww8DWubuBk|Kr!r@o4<*a7f${vmHq|`|EkE`XMg&~KGXA8 z$Ar+|8nY+bq?2MtwG7O{9Iw09I3L;};ITdHSYPP~ixhUdv!ugh2sn{^itar++`+;<+=&rxIG% z`;E;+Ag zZy&i1fDG$n@?BbPCd;-g@TrGdu zudzyQ$nn&hS-(AmM+MJTfI*9Y7CgHq2<3c1Z@_l3U#f1Q{*`kQ3u4Zzk_mA!;ONz2 zZqdWKT-C~7@vR;=LNIJwK#Yd>h%i>*8C^+0liX)Gw|`GIy;x7-GG&ARsL`(QFyS6_ z(zVzkwLE&0yaNN`S$oG~DnHB0O&qP_iTJ>^EoSKSGByjx*5RT@buV~30f(UN)SjgO z383bj|1GTk?csk7*Iy6)H^ly>(0|9Y7(Z$l;Ex#yoP45B^pI)9;DLnbr;GuFj~CIe z3ugB~GJmE%9jNzM^3!k-0*`jpJ9cJ!9Qx5_!0=HevB$+Ycx;TQj}Z#;y9I^xa2?oj z8;_0?ksr@%5U_si^rVUJg#FQO3i2!r=n_gLNtj{tc8 zDES~c`PYc8ABesFfY{(K5u2y~Ibz=`y8VWYl7Ia-5ZiG4-=MZVt8DNSYTGk#Z2Z;G z{_emWIJ1d`qS{SSvCe8MY2f$0W6h2+@kd4NRI3ZMY zvIy5-a&!}7%M`65d-dpKRL0`!AzG>sijV~ofF`KQaBTn`fjzsn#cw?#3cXnH+U0aF zU~Ge?C4A%HVEcLd9@0C)z8_dYRpQ+x2Y>Hfc$e{JMkFBS`boU8K1+^f4qr*49j!XJ zbPg`ReBJX;Ho{%c-PETD20KL&j@l{$~kL%@k-qu|uvN?0>-C_Td*3aNz#$`%KUv;fWj1A0m#HIkm5fsX~S%g9gQp-Y(;-!YT?O;`bZF0`MuKZ)!wN}6(H)pcp%Vi z;o@XV2M`0A;WkzxSCDnr_Y_H5wfi1gqvoY2mXO0si3qKQ5iJ5sTX_U;41W=n_7-x2 z6^mr9^1#KMgv8r253W609Vhq}tkPrD_i)^I#uFlF6stp*DSa3ODb@xADpW_^8SuAQGx^&YZ=js%2!9pY5KDe3&iht9uaonhsTHMH@zpHRBJ<|oZ@jp}CR+|= z{sl~pqYu-U_u>B^veu0j32U)J@!2S zl=%1y5FgKP>gF9{8MLAM}SlP6prs_lFLXIy@1QojdG- zd-jR0KkX)P?Om`kh1@99j_!|{|JGA@VOZT{zU}ZO zqsmKPwVB*LImOHU&}drr_N94}zQ-UxZk+9(62&$+{MaDsab1teD&FUq)`VH8Xbiji2J5Pbjmw!C3bmVytOUkk(b^4No zyk|lquSJ&`xu<{{Ul+&2nG-$=_MK%iu12xfh`H<*o{>3jsM4dG{1k#5huZ@6&Xr-G zB;SE*_FkxpfaaPJ?v~*)%#lXCPD49@bcy?p(U6sJdU;f*Y!8r?Ld^#&({j2XgKVdJf-h|jIE5n@c*tP}(T zB1H$uln+d#xeaUi^|%xT#_<@ZOA0B5lU~%&4PVt9>8Gm1*}EGx)1(F?9Bfp01@z44 z9&Ov*Tz{y)7h98f;3d|HZN8_}x-?1SUe@^;j9U>EL0=+u?=0sBZU}*lu~$308w1eD%3U+k za;S6@YVh^NJqgfjTV2LWzBp$X8)uxS5f8enb$?t^Gc6Zr$KJAtRwvDZfd1uN9At($ ze<8d3;3% zvCl{se-9X1hE zZhu(6rdJeGgt+Y9UQa`te~)};-C`KGGZ-TO z((i|u3oEWl=`{pH6<4!7wL?H`C-t$jPvvY3;M2TQO2>AO2&mslF|lv%Mg(Xi>s54S zDUi6PiE#?*upFqdFBXd@P82T;)Qt=XqknYd_DaF``GMa;;FQ*;+>SZ-dXtpPxWvN5 zC8_V!WMy4gzpsQ#LXR_(vCC8$>P{Hmy`r+Q6`px03TwdP$7N0PBUqH{Nq3A7Vrk@AFnIPf_GXguL?!U57hs0UGl?GFc!P_%_ZOYu``uK!0>W z^kCGxSo=6murU=)2epC2ISPSb zn@Oep5wFm~fAeP_;gmI?I2g~HwsB8U%bg&S?EwMHwRn%jhPGE`$@cLbH-~c)wt9Mg z**BAf>9RiQ_WnMynux9%gz7GyXn&lLvxwXWU{mfj?vl5v8|%5g@MCz-?L}4`KPgC5 zm^dyd-nL#$ibN#}b-J=1F4FP+xq;<6kqaQB>%jHMTfbD~%}ukRP_>}6ID2V2v3xkh zDHsQl9D_5mMa&2pFReCR+Bl06ouF-BwwrzA~oMEu~2X`qvqoyUep_bK{p$R-CHP-^(|-V;kW7yzuTEOWS{&@kGEYoX)=e z^7{4U1ziVv6dTlUMB8KiC$W&3v1u3Mre)6&%|^#ccyH-cgMUwCu2j#~2gI?|U?U_s zE{8phsRoP*y^D@OxPRuZbG=L%$Hc8UXUVAM3POVL`Fc`cFx$$e;kzv$z-6nY6=(=6 z)yA?+6S$%k3SFqw%~aS*%KH|#(njFc<)VX?(~z8%JiLM_>s9S&pcb`$%P~)*@65de zZ>^KCVYqma_tew7do+0R-`uL+ZbH-IDNaAo8Z=)M5u&Wr7k@n<(d2yNO(#3C)0TJ7 zCgEw>Mav!o!&$cj@Oh@m?u@2{a?#(T{xZPvF_YDcj2IS^&j5In9LiCyv9X;E{q`A&vU8e@|mum z-bPG|9LjJ~D#|i|?1C$2_%2T|rt)X#?)Xn+!y!$%15d;?Fu613qCSC{r@BQ$PI&~M zpj&HV4-UyHY?Ma51+lWsF5*>tvHBp0r_mm7W)}jn*MB|2aR+HZQTGY$O8H>+kRB_4 zE;gO0Ot-rWei9Xl-oH{efJ=^A@L8{+ybIG#tAWWLJe@u*W8Xl?;~b;%eYh`s^dT8H z9mWGmp}Sb`>EIjV*>C6dNL>!`oaw#<+-CnUBo+5(or^8zt#Gq&x$F;&Zu87W|03bR zS3crTfq$pGgJ(Sefy+N4x1MB>Uwydfk|(vve_j-Ejd#3KtMAsh@2XW&ag&c+L4_ed z7XrRsi75*8`;{VC-Qo*Y_^=AgPiOnFa=|hS!m5xhZXS>a1J3kfFe_3j20g#6->^C6 zOO9*jd%nViG_T&o@vdd+np%L91uou-wK}YdSbv?U!}T-%vg(vG`|I#Dh1!h;U>Z%GR}Ez!(_7VP6E zd;A3AoB=;ORZjTMY%+$1i(*As$ko)r$?c=9^oLC^~h-Tij5Yqsm?^oEblzz^r>{r-_ybnFp znddQ*{ea>aS*WwyapL_%{4s*y80o&>{uRD_5PpWv(K7wzM5fLNpRb_PAkF%;LemS) za#tX6kAE{KG&9p|OUpC;rp1^}W(J`z=-1zoLMQot zg3m8;qh}`1dnP|%E8hPC{v#9(@UuX;-@3{AuNz8+mpXv!EfV-Dbg9XM_rQJMc~tn1 zcS9o1#(jSlX7j~JEf)%g@Z-|m=Tt@c4#Jk}b@gcf!tGJyCJ}aNWbEk)(8`&+dCDFH;DTV` z2~j+60_Dzxk5bL0r`aT@f=MCS2ytqDE74aB3A0X96%|%##{zHXbQQyf8Fm_uK0tr^ zGWORi^lmtei80OI+S(bBJAJjx({incCei8ZB3zN1USv)E9DuRG#|F}8Dc2aW;UDMs z1HE*iXr{db7y%yh{ z$KwuFN)5G!u0Q9TE5H{N;Uw8ym`;CW@^|h+PYmS@87lw@-@48;70$od?(0@gc4N-T zW^^ZT;mkD^!e~MrubA(>#`@NSC(<&zd8uRC0x@hfP(TX}538d=UarO|TF5x)#Sos) z{7SUh(_7$a^gZD^o}Y8jcVd1OoAq^6xJKJ);eiA>`B$u6J+rThJHbB%|6PBV^!^l8 z?3GIAQ$_??jOYzY$~<2f&3cmOEgzAo)Swm?flhN=eF+0uGapW`gOk7^Ykc){X3A?^ zBwZirxGXYQaCB78f0d|D{4=}QF9o@OQdIq2gV?`&;18CtKOXewSOkIbUn;RO>d1c* z>8J1f;aPrYz6s>3_=);7sycr>)3c*)mio=YX?&zbQSt~W4nLwV?SYXa+Sp&Ggc<^wrmO|3GBv@OytQ7BakjTW-M1+kf)IcmG$A`yn_1{vtY=ndB|u=*C5DTM#Iw zHX?Tuq3cYz@TIwCJOF{q-LM;3=WY;J8G{gC!H(s#Lce*$QHoY;W+Sclkti^DeLLa% zb`J(?y3L&U7|jg;X*sjC!0BQCzMdG-zmUCBJs`Vk+x%P*{NR84lOVgs>Kfad4!8$A z`e)D55GT83mjY0j`PE*_Cm$ix*?7R@{buOs8DB?Vzk;JftQioHz`Lm4sChcjB6+qxpeWicNu2*pLjet%?_ zTeMI6WfTJ_ertapZkx>=&zJmGKjmWS3_Do81>)jmPB?OWF0f%}kbAqarwI*StJcLA zsEU`z2m|YFC}B_0y37da_Hni_w9F^GOnBv`IZ6{6&`?#<5YY6~hdJ1KslvEX)Ud)s z6kJN64(0nsy)M`sgF+B>(?xjQJp6f=@%zngi=cUA19^XkE^d}Wqb?e6TK)HZkTMS5IB#F3qD-l3C77;wnq;{CSoy4?dc&eKVcN_xd7TlF=)WpJP8=ttjSz zmv2_e>ok86&%rB++j4$x#Y0-9*ENy0p-|VeB5ct99Ur$vEHFey@f_=BjZRi&maN}&u>3{0OW?fyUTNiRCX-AjS4_NmOdb~>)!jM7^OzSJ3S2}r z&Sd~vbE@>j;8m#%Ug%MD*}0dnTm%o#LTAYJ@l=0;W6x#RM6M#X-S6|Mb06GOf0^BD zXaKqB)I2(IkVvP!ot@71D^X7DI>iQmxo|i5S$8oasqe}<)zUQ13kpH_jU`Sty5KGk zi1=Gm@ALVlp$h4wf;H3*wQM$gb10_i-cUm72+H3j*ImYm^U}cKnE}f-brDKeZ2?1q zElPhd=9Yz%8||@o?}GZxke^d4!u7J4t|)bh6YaEa=mQBDq?U8k$;?K-lLg5RmOX)y9EGYdRVgZ zA~ky1zuYIxTsup+RP==Qglbfed`#aZ1&4q59lrLfMpOBX+(UDt2QhzgT>#&Virep{ zIul0XbdGbrkZ^lK@uxfB*-DR*CmGpun1gdLrCnJ{1V`Ev%e|0iiCQku404|@Wft~B zbQS0=R<>cM+ncA>SeBmlP?@+&r1BsN*BmU^u+~s`yTNv4v{!e-Dqs#Fs-P8;6H9+V zK$>dNw3WHqd0*Zyi>% zN&E0Sm3bej)IWXjGyC~_hkWNfzubTQhh=Jt0#S&P3E+nmwF?KmD(>^hgqCe5%ypV;%kIf`j})Qh&*g?ng>ty?kRw27Pr; z{EJ28N3^8d^Af*b@)rEEo5c*M8)qww^ex#bACjKX<*f+bA#LS5J} zwMUZI;-DMASH6)a)wh-}@v?ujAM|MNa-?U!NSUM`w^cOqtxXp2wNI8ExJ&0d>N|Qm zt8a1H*Zj@li0J+_s((>1lYs%{H~RBm%FmVC3172W3bidX11IYc9&n7%@HFHtMU<6` z?Fe>);&0+iT&#JI3#@9?Ef&&4>rBi=BQV=PVsc)#z z8XJC8A)b?2zSQr-ks)$!rbFi z6=jJSu@Lg%8Yp7|yo3HL-(;FH+@ z+Jxs;BBT@$U!AUQ`$l*$vn@?DOYd>AEZBbuVhY>~!aVUPizZRgz62 z(iLr{yh1+zc&F1&Q;k`;GS43Nh?@?Cy>jXDoAf4BF)RB3%DOgX9rc@hOWSDbccpj7 z!U=H5w|*_%vgQhUptP((74~vj)$32q^x{vs#r;XS1^j=|C17Vn@5zXF2zyZb>~cP{ z7AsVb2lyy8P;Vk)9FbOiZm&vVvkiLYQ4J)EY2X;dq}YDOyLUccM8?b5hX|!e5E(+Ak<4=eKw)fT`O>2M*HSkRF8C!zaq5z4c(dw|j^{9! zyaR(kRcn7~`ZHSxSGlEdDBqq}$f^KK@ACL5s}DVMyXY)E-S@aK&GQ8w`8nsUq}R!e z^K;VDPkQw`l#O7jWGr+^W|c`3z=!iRJZ-GyhbXtvZ_oDC{rBn!co(pJ9anlF^`0qu zWJW4`M9H0GQPS}gWl$B383NEzS6}?jU!L|Y<+FcvDHV-Q9=S=O+6lYyiP^<53XSO= z?5q>U_jw@GJLV5gt;5wz0`6Zus`X%fyl$MyKt%sx?~&T={SHQK zg`g?Y;WQ7*#aRIJ1|#@b1f^=~?$bNDZ%=SNB@I&w}adeq+?O+-HuI08N@`r`PYFgvd~ zO7OCsDg9b!M;$)daPrCfkjJw3;dYoFc^@J@m=F#h`6q}t8tCmLYk!fDAM?ZCdM1BD zhqKR4@d)yx%KP+gNTY)^Md9(5_;iLyp`&_{3_m^E!y`2XLP!3I`mC-W){GxlAQ1hK z$B#x2#{R(I|NlzQrJtqeM}JfB|1;8a=^shYUmn#)-l^CgsTX>hSz?c@CgH;IX*&Vv zm$^NmW)s`jTfHG98_R*oG*jrGuabW@7q2`Hh=_@M!4tg`c*(?(l#RDL^-p>($_v1^ z79RApwA6Z)rY#GPviK*i1S z`go}y5`RL%Mto_|{NB2BaE6!1YxpptZ{hM@C<27z>6BIXI_gZ8WG!3@-!FflYHqoP zTdBgo-^BxZ)y~Kow_N9qt)`ufe`?~BDNEy3vit}sPusq)mql>gyGXN06ae#%&v~Y< z@fCZYi`N}?NNDM=Z&h4RCU-8~s`20}gf`tt&~h~u{E=%%PyC;fo}U5Nq+wco?o|HT zSE{%A$qkj2>0A9lcOJ9EAV{`TA$JlujZ#X(L&4L?Zb=!W*q)lm?? zR|yS%_n zJguhhlsO!|I;;#gh8bN2sHPPiGA{Gk9<}RGUn|fb@S4q(N_xSj#=h?7hM5vYeTN|P zm|oSkoVGiiOqSXkwFZAMW_ssvewzP@c`!Y;!?(7vA54Nl=u^VAZ~wW%>p$=My~OKR zyZun^g`)^b5GX~E5Q0EB3jT7%B}_k^gU|z&_NY6Ij~)nEa-_(J+ zaslXZeE2DOkC0<*7;-=y^{MqD@vogDcDN%yQaj|c40EI*J{~IvR+EPxOokpXezYz6 z>&|;Wbt{rQR+Ig5$%gIU;_T1Li^g)P!pz^xy&T;;N;tkwNzhd}y0?dFfc5pngx$>gmHb-d5VI9;7 z-&>Ur0<;9spHUEW;3 zUHhzfoZWv%P2YpbyYOQgNO%kBXSGQ;ffU&hl!3T|_vzgiYm02zJ?c+v%7Pj*954D* z~lGjThZRhXsky#A!6CyO79xn3DzxsE=s899W z_cI~5TO?V(ZJhU0NzW~uh}5A_nEZ>lT%vVj$F1YOmp`RX zv@pxM!tM9|FK|l`{zJDS`k8E2RCA?pdkBflqQXO9x#~8{j+|$c_qLd=d7LVY7%J#a z1Y`xggKP_-?M=KPx*Jc$1LtnVYkNy7gV7O$QcL4sciy&->Nyo|IImd@bELL0MRmp= z8o+;ce4iLmA!VC?9TIWGBh3}BOV;;=6*%IZe7>Vl0OxeQQoXL-Wv>j>x!&+7!m%y} zo}tKJRD#0B-ht|lXB88fd)p=m-8j#vGiDwHli?nLzZ#PF%a^s(j^aBn85Wx1Xx;ZL z@YolwsQxbSf{Q}BQo?{3num}Ytn^H$n|Oa|I0`=*VW-N`5+efgWX@BjYQ|N51Ghf* zwO1U#`bZ5{!sz`4_Zeh8=MQ7hE@FzO$=`+|eQKRBDTnXrY3RR%!~E;}c6kTx9aMgT zrGIePH;DS>AwO0m6CiqIzi}AHaSFyj0y$a|fe3+vIEJA(jDiG7z#xe1Qw8=*{Q7^i z9>Sudy@Q8JeCPh2CMZd(aJtEqnBMlF|7KI;W!biMEeH=-` zqgx&r9*g+`1Hc zd+zX=egeBg?gbzJ_Q-J`GYWnB`VoI0o%Q}AJH~W?@?YW??;kl|u>6K!cFGr-`~nBT zepl)oLn@=RV-VRv@NWfCA2Wp6WPd~i{Q>?-2Gv>|&qEOu6v5Hhhg-VHt--+6KQQ#I z+SuZqKkf9dwfS5z8By83R}UPm(3d@AK~&Z_@C^ih-l%Z-PqOQ)`X|ZQjaz>hBXKF$ zca5WKkOG7*)E%&^80bEQe$$mXf8Oc4tE|Lwxv?q#sA3?0*R)WQjNA zf;_nJ!D-Cs0CSq`Q!Mxx742OlxFX+0MoUf?>~R_mG#Lnfyv}y-Oz3$i@a3F$FM(h| z_UT9rSh*?CtNm<~^;1*LfzE%$aR0`{i@pjyuE*%P*jzD0s2tbX$eTBE!%uObVDWvQ zeqSoTKP~`Hdf7DN@hrh2isoqHX1F$_J<8l;#wh&_)1V=^f#-{6ZIs7d!6t92HM-pP zDbQ>S0M%yfRcm49?O2}I)|&@;MmZH`dyAYN9m%CnG&jN6p zB997Qo6DeYMS4gAWR_!)R|H)k;?+s~opY4IlC_VQ@tnxw^?10KTS@t5zO0@(0!0=D zOC-o(YU|1a%F30-HSUoqs1vZsTfTS>y9eAvi0~Ato;gcIgm!-=q}prb7{A>C>j6Ga z5bzV#lOit4nnyCFk!HLQbQYfUeFU~k_3rF! zv**9B;QDh>CGfL?tHm;xgz%EP3%wDLBoFH(k@It-{Ic;G3w&0dmwWKo4oe*a1pCIdsijNSU+@wlf%r6Np`oc+IAZ8WoJn>prs)(SqVRbL5AZ|46 zY+ZS3>lb39nF~4^CDjFk5>;nn&_?Z6%M^SmZ54QV!$p6*HToSQaiVy%ZL|{8C^qVY z)z|@va4KVlMi=x`hwD_gtQ(kx^KyOws>xVnZS6c*V7pu{uhxEkOB%iAuG=+qSrn8q zPa-DxdIE)4edENPB3bM^iLUNTt$-lE(Qnc$&k!xLf zy*`i^kRqI}MsIbbD_801^CQp{q;RWdbCd?{iAxXi7OGIw=Oz(6>gU}lli38JmQ}$&u_}ZDAq)oz3dKkY+gTNXqWC8TKWBf1Oi=*&(aS*FtX9Ym&DBi?B#gAlk{7d2^ zQ;lIqOio~j_zHx-n#HBik&e!=KVtF^1pj{>tI9qWa?!!Z4nO|zPYTc(2WxvF4~c>czWWPuWdG@g~edo(c&GzlQZ_ zKg{7IW7CORpFoTWx*z&1e_>Y)O{;(M29K?@ox6Of?b2)bTy$0-h0w7CA_@VQ=Z?uQ>&Eo{#Se?Aco()Xi=Vbf)}0z zLGbq{Zs-uuQfD>4?$D_XF{KG-v#)T-UlwzSvp&O^XMbnC?8Z6Msdhl^ehYtLq*(B=imd|36Q3|X2w~xL4_g2)3J#yfdS{OYm(hepb|b}FT%1~Gn(txnhE~4h zYyg?+`e3>f6x;}og|rQ5%ttQ>ff;D93S5?ea9*gVpLrzDs{rv-+TA0f;Xs z(_6Cx{ZFwfB2C^&{W|;ib#t}U!G ziHvbRqlCs8Qgw41MTTAY>82~K=%5e+?l}kqze*iHM{IpWJ-SU>P^K0PmROQqQ(AgB z*ZaHlQ)#tdw3zmKRAGf&g@mf34N$+Kr^=4SPURN9UPPuguC#yH`CL!m2-Ks7DBlwI zWr>Wu<3IKmz4KLEHMtOkOl+?laB@zgU)zsoee(%NY+4WZ?vwu(7csO^dME>cNB$5;1PL(%p za+vDG62v=ejb490sq<4E6CjBs)zwp;Hx&$ei`mQcHRw@^1MZiUr5ue+#Ri#hfpOkv z%C`eay@GkyNXek7u9^e4i(CzX%Wl5=L`+h{;KYpj;azweWHwr}SOonxxt+Y7$#GV% zbp4jDX;eCF1*Lwf0HSkWkD!UEDpA%dbP#XqHFXgCt+Rh3S3Yh2BuOkYk?oazZLn9| zcf!4jj5U+xvkg(eHGA0Dz@WS!ZIKEoA=y&c^Mk595`xS7J5r6oVBS;r$s)~3`R}tT z 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�qBhn#x7w!D8Oo#QUxz^EazuzYb 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≠-_?L7^j)9NEj`89gE-;3w(Lo7un`SyBeyDxv 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

  • H{9BJwl<(e#{K`wHG0A6; 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 G)Bgbo^e3GF diff --git a/Misc/NEWS.d/next/Library/2023-11-29-10-51-41.gh-issue-112516.rFKUKN.rst b/Misc/NEWS.d/next/Library/2023-11-29-10-51-41.gh-issue-112516.rFKUKN.rst new file mode 100644 index 000000000000000..530cf992dcd77af --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-29-10-51-41.gh-issue-112516.rFKUKN.rst @@ -0,0 +1 @@ +Update the bundled copy of pip to version 23.3.1. From 2ed20d3bd84fdcf511235cc473a241c5e8278a91 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 4 Dec 2023 19:35:46 +0000 Subject: [PATCH 36/87] gh-74690: Avoid a costly type check where possible in `_ProtocolMeta.__subclasscheck__` (#112717) --- Lib/test/test_typing.py | 19 +++++++++++++--- Lib/typing.py | 22 ++++++++++++++++--- ...3-12-04-16-45-11.gh-issue-74690.pQYP5U.rst | 2 ++ 3 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-04-16-45-11.gh-issue-74690.pQYP5U.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 3572df7737f6526..2d10c39840ddf32 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3533,13 +3533,26 @@ def __subclasshook__(cls, other): def test_issubclass_fails_correctly(self): @runtime_checkable - class P(Protocol): + class NonCallableMembers(Protocol): x = 1 + class NotRuntimeCheckable(Protocol): + def callable_member(self) -> int: ... + + @runtime_checkable + class RuntimeCheckable(Protocol): + def callable_member(self) -> int: ... + class C: pass - with self.assertRaisesRegex(TypeError, r"issubclass\(\) arg 1 must be a class"): - issubclass(C(), P) + # These three all exercise different code paths, + # but should result in the same error message: + for protocol in NonCallableMembers, NotRuntimeCheckable, RuntimeCheckable: + with self.subTest(proto_name=protocol.__name__): + with self.assertRaisesRegex( + TypeError, r"issubclass\(\) arg 1 must be a class" + ): + issubclass(C(), protocol) def test_defining_generic_protocols(self): T = TypeVar('T') diff --git a/Lib/typing.py b/Lib/typing.py index aa64ed93f76fbfd..61b88a560e9dc56 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -1790,6 +1790,23 @@ def _pickle_pskwargs(pskwargs): _abc_subclasscheck = ABCMeta.__subclasscheck__ +def _type_check_issubclass_arg_1(arg): + """Raise TypeError if `arg` is not an instance of `type` + in `issubclass(arg, )`. + + In most cases, this is verified by type.__subclasscheck__. + Checking it again unnecessarily would slow down issubclass() checks, + so, we don't perform this check unless we absolutely have to. + + For various error paths, however, + we want to ensure that *this* error message is shown to the user + where relevant, rather than a typing.py-specific error message. + """ + if not isinstance(arg, type): + # Same error message as for issubclass(1, int). + raise TypeError('issubclass() arg 1 must be a class') + + class _ProtocolMeta(ABCMeta): # This metaclass is somewhat unfortunate, # but is necessary for several reasons... @@ -1829,13 +1846,11 @@ def __subclasscheck__(cls, other): getattr(cls, '_is_protocol', False) and not _allow_reckless_class_checks() ): - if not isinstance(other, type): - # Same error message as for issubclass(1, int). - raise TypeError('issubclass() arg 1 must be a class') if ( not cls.__callable_proto_members_only__ and cls.__dict__.get("__subclasshook__") is _proto_hook ): + _type_check_issubclass_arg_1(other) non_method_attrs = sorted( attr for attr in cls.__protocol_attrs__ if not callable(getattr(cls, attr, None)) @@ -1845,6 +1860,7 @@ def __subclasscheck__(cls, other): f" Non-method members: {str(non_method_attrs)[1:-1]}." ) if not getattr(cls, '_is_runtime_protocol', False): + _type_check_issubclass_arg_1(other) raise TypeError( "Instance and class checks can only be used with " "@runtime_checkable protocols" diff --git a/Misc/NEWS.d/next/Library/2023-12-04-16-45-11.gh-issue-74690.pQYP5U.rst b/Misc/NEWS.d/next/Library/2023-12-04-16-45-11.gh-issue-74690.pQYP5U.rst new file mode 100644 index 000000000000000..8102f02e941c297 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-04-16-45-11.gh-issue-74690.pQYP5U.rst @@ -0,0 +1,2 @@ +Speedup :func:`issubclass` checks against simple :func:`runtime-checkable +protocols ` by around 6%. Patch by Alex Waygood. From a1551b48eebb4a68fda031b5ee9e5cbde8d924dd Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Mon, 4 Dec 2023 20:42:01 +0100 Subject: [PATCH 37/87] gh-103363: Add follow_symlinks argument to `pathlib.Path.owner()` and `group()` (#107962) --- Doc/library/pathlib.rst | 20 ++++- Doc/whatsnew/3.13.rst | 8 +- Lib/pathlib.py | 14 ++-- Lib/test/test_pathlib.py | 73 ++++++++++++++++--- ...-08-14-21-10-52.gh-issue-103363.u64_QI.rst | 2 + 5 files changed, 93 insertions(+), 24 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-14-21-10-52.gh-issue-103363.u64_QI.rst diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index 7ecfd120db8d154..62d4ed5e3f46b97 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -1017,15 +1017,21 @@ call fails (for example because the path doesn't exist). future Python release, patterns with this ending will match both files and directories. Add a trailing slash to match only directories. -.. method:: Path.group() +.. method:: Path.group(*, follow_symlinks=True) - Return the name of the group owning the file. :exc:`KeyError` is raised + Return the name of the group owning the file. :exc:`KeyError` is raised if the file's gid isn't found in the system database. + This method normally follows symlinks; to get the group of the symlink, add + the argument ``follow_symlinks=False``. + .. versionchanged:: 3.13 Raises :exc:`UnsupportedOperation` if the :mod:`grp` module is not available. In previous versions, :exc:`NotImplementedError` was raised. + .. versionchanged:: 3.13 + The *follow_symlinks* parameter was added. + .. method:: Path.is_dir(*, follow_symlinks=True) @@ -1291,15 +1297,21 @@ call fails (for example because the path doesn't exist). '#!/usr/bin/env python3\n' -.. method:: Path.owner() +.. method:: Path.owner(*, follow_symlinks=True) - Return the name of the user owning the file. :exc:`KeyError` is raised + Return the name of the user owning the file. :exc:`KeyError` is raised if the file's uid isn't found in the system database. + This method normally follows symlinks; to get the owner of the symlink, add + the argument ``follow_symlinks=False``. + .. versionchanged:: 3.13 Raises :exc:`UnsupportedOperation` if the :mod:`pwd` module is not available. In previous versions, :exc:`NotImplementedError` was raised. + .. versionchanged:: 3.13 + The *follow_symlinks* parameter was added. + .. method:: Path.read_bytes() diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index be890ff314dfa44..534813f3659c9d9 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -270,9 +270,11 @@ pathlib (Contributed by Barney Gale in :gh:`73435`.) * Add *follow_symlinks* keyword-only argument to :meth:`pathlib.Path.glob`, - :meth:`~pathlib.Path.rglob`, :meth:`~pathlib.Path.is_file`, and - :meth:`~pathlib.Path.is_dir`. - (Contributed by Barney Gale in :gh:`77609` and :gh:`105793`.) + :meth:`~pathlib.Path.rglob`, :meth:`~pathlib.Path.is_file`, + :meth:`~pathlib.Path.is_dir`, :meth:`~pathlib.Path.owner`, + :meth:`~pathlib.Path.group`. + (Contributed by Barney Gale in :gh:`77609` and :gh:`105793`, and + Kamil Turek in :gh:`107962`). pdb --- diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 81f75cd47ed0870..b728a0b3dfdb6c4 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -1319,13 +1319,13 @@ def rmdir(self): """ self._unsupported("rmdir") - def owner(self): + def owner(self, *, follow_symlinks=True): """ Return the login name of the file owner. """ self._unsupported("owner") - def group(self): + def group(self, *, follow_symlinks=True): """ Return the group name of the file gid. """ @@ -1440,18 +1440,20 @@ def resolve(self, strict=False): return self.with_segments(os.path.realpath(self, strict=strict)) if pwd: - def owner(self): + def owner(self, *, follow_symlinks=True): """ Return the login name of the file owner. """ - return pwd.getpwuid(self.stat().st_uid).pw_name + uid = self.stat(follow_symlinks=follow_symlinks).st_uid + return pwd.getpwuid(uid).pw_name if grp: - def group(self): + def group(self, *, follow_symlinks=True): """ Return the group name of the file gid. """ - return grp.getgrgid(self.stat().st_gid).gr_name + gid = self.stat(follow_symlinks=follow_symlinks).st_gid + return grp.getgrgid(gid).gr_name if hasattr(os, "readlink"): def readlink(self): diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index ccaef070974ffdc..1b10d6c2f0cb190 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -41,6 +41,9 @@ def test_is_notimplemented(self): only_posix = unittest.skipIf(os.name == 'nt', 'test requires a POSIX-compatible system') +root_in_posix = False +if hasattr(os, 'geteuid'): + root_in_posix = (os.geteuid() == 0) # # Tests for the pure classes. @@ -2975,27 +2978,75 @@ def test_chmod_follow_symlinks_true(self): # XXX also need a test for lchmod. - @unittest.skipUnless(pwd, "the pwd module is needed for this test") - def test_owner(self): - p = self.cls(BASE) / 'fileA' - uid = p.stat().st_uid + def _get_pw_name_or_skip_test(self, uid): try: - name = pwd.getpwuid(uid).pw_name + return pwd.getpwuid(uid).pw_name except KeyError: self.skipTest( "user %d doesn't have an entry in the system database" % uid) - self.assertEqual(name, p.owner()) - @unittest.skipUnless(grp, "the grp module is needed for this test") - def test_group(self): + @unittest.skipUnless(pwd, "the pwd module is needed for this test") + def test_owner(self): p = self.cls(BASE) / 'fileA' - gid = p.stat().st_gid + expected_uid = p.stat().st_uid + expected_name = self._get_pw_name_or_skip_test(expected_uid) + + self.assertEqual(expected_name, p.owner()) + + @unittest.skipUnless(pwd, "the pwd module is needed for this test") + @unittest.skipUnless(root_in_posix, "test needs root privilege") + def test_owner_no_follow_symlinks(self): + all_users = [u.pw_uid for u in pwd.getpwall()] + if len(all_users) < 2: + self.skipTest("test needs more than one user") + + target = self.cls(BASE) / 'fileA' + link = self.cls(BASE) / 'linkA' + + uid_1, uid_2 = all_users[:2] + os.chown(target, uid_1, -1) + os.chown(link, uid_2, -1, follow_symlinks=False) + + expected_uid = link.stat(follow_symlinks=False).st_uid + expected_name = self._get_pw_name_or_skip_test(expected_uid) + + self.assertEqual(expected_uid, uid_2) + self.assertEqual(expected_name, link.owner(follow_symlinks=False)) + + def _get_gr_name_or_skip_test(self, gid): try: - name = grp.getgrgid(gid).gr_name + return grp.getgrgid(gid).gr_name except KeyError: self.skipTest( "group %d doesn't have an entry in the system database" % gid) - self.assertEqual(name, p.group()) + + @unittest.skipUnless(grp, "the grp module is needed for this test") + def test_group(self): + p = self.cls(BASE) / 'fileA' + expected_gid = p.stat().st_gid + expected_name = self._get_gr_name_or_skip_test(expected_gid) + + self.assertEqual(expected_name, p.group()) + + @unittest.skipUnless(grp, "the grp module is needed for this test") + @unittest.skipUnless(root_in_posix, "test needs root privilege") + def test_group_no_follow_symlinks(self): + all_groups = [g.gr_gid for g in grp.getgrall()] + if len(all_groups) < 2: + self.skipTest("test needs more than one group") + + target = self.cls(BASE) / 'fileA' + link = self.cls(BASE) / 'linkA' + + gid_1, gid_2 = all_groups[:2] + os.chown(target, -1, gid_1) + os.chown(link, -1, gid_2, follow_symlinks=False) + + expected_gid = link.stat(follow_symlinks=False).st_gid + expected_name = self._get_pw_name_or_skip_test(expected_gid) + + self.assertEqual(expected_gid, gid_2) + self.assertEqual(expected_name, link.group(follow_symlinks=False)) def test_unlink(self): p = self.cls(BASE) / 'fileA' diff --git a/Misc/NEWS.d/next/Library/2023-08-14-21-10-52.gh-issue-103363.u64_QI.rst b/Misc/NEWS.d/next/Library/2023-08-14-21-10-52.gh-issue-103363.u64_QI.rst new file mode 100644 index 000000000000000..d4a27d624eb5e6a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-14-21-10-52.gh-issue-103363.u64_QI.rst @@ -0,0 +1,2 @@ +Add *follow_symlinks* keyword-only argument to :meth:`pathlib.Path.owner` +and :meth:`~pathlib.Path.group`, defaulting to ``True``. From 4eddb4c9d9452482c9af7fa9eec223d12b5a9f33 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Mon, 4 Dec 2023 12:04:05 -0800 Subject: [PATCH 38/87] gh-105967: Work around a macOS bug, limit zlib C library crc32 API calls to 1gig (#112615) Work around a macOS bug, limit zlib crc32 calls to 1GiB. Without this, `zlib.crc32` and `binascii.crc32` could produce incorrect results on multi-gigabyte inputs depending on the macOS version's Apple supplied zlib implementation. --- ...3-12-01-19-02-21.gh-issue-105967.Puq5Cn.rst | 4 ++++ Modules/binascii.c | 18 +++++++++++++----- Modules/zlibmodule.c | 18 +++++++++++++----- 3 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-12-01-19-02-21.gh-issue-105967.Puq5Cn.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-01-19-02-21.gh-issue-105967.Puq5Cn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-01-19-02-21.gh-issue-105967.Puq5Cn.rst new file mode 100644 index 000000000000000..c69511218e3e16c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-12-01-19-02-21.gh-issue-105967.Puq5Cn.rst @@ -0,0 +1,4 @@ +Workaround a bug in Apple's macOS platform zlib library where +:func:`zlib.crc32` and :func:`binascii.crc32` could produce incorrect results +on multi-gigabyte inputs. Including when using :mod:`zipfile` on zips +containing large data. diff --git a/Modules/binascii.c b/Modules/binascii.c index 17970aa5e9456c1..86493241a1fb7e2 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -770,12 +770,20 @@ binascii_crc32_impl(PyObject *module, Py_buffer *data, unsigned int crc) Py_BEGIN_ALLOW_THREADS /* Avoid truncation of length for very large buffers. crc32() takes - length as an unsigned int, which may be narrower than Py_ssize_t. */ - while ((size_t)len > UINT_MAX) { - crc = crc32(crc, buf, UINT_MAX); - buf += (size_t) UINT_MAX; - len -= (size_t) UINT_MAX; + length as an unsigned int, which may be narrower than Py_ssize_t. + We further limit size due to bugs in Apple's macOS zlib. + See https://github.com/python/cpython/issues/105967 + */ +#define ZLIB_CRC_CHUNK_SIZE 0x40000000 +#if ZLIB_CRC_CHUNK_SIZE > INT_MAX +# error "unsupported less than 32-bit platform?" +#endif + while ((size_t)len > ZLIB_CRC_CHUNK_SIZE) { + crc = crc32(crc, buf, ZLIB_CRC_CHUNK_SIZE); + buf += (size_t) ZLIB_CRC_CHUNK_SIZE; + len -= (size_t) ZLIB_CRC_CHUNK_SIZE; } +#undef ZLIB_CRC_CHUNK_SIZE crc = crc32(crc, buf, (unsigned int)len); Py_END_ALLOW_THREADS } else { diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 9b76afa0e56f76e..fe9a6d8d4150ab9 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -1896,12 +1896,20 @@ zlib_crc32_impl(PyObject *module, Py_buffer *data, unsigned int value) Py_BEGIN_ALLOW_THREADS /* Avoid truncation of length for very large buffers. crc32() takes - length as an unsigned int, which may be narrower than Py_ssize_t. */ - while ((size_t)len > UINT_MAX) { - value = crc32(value, buf, UINT_MAX); - buf += (size_t) UINT_MAX; - len -= (size_t) UINT_MAX; + length as an unsigned int, which may be narrower than Py_ssize_t. + We further limit size due to bugs in Apple's macOS zlib. + See https://github.com/python/cpython/issues/105967. + */ +#define ZLIB_CRC_CHUNK_SIZE 0x40000000 +#if ZLIB_CRC_CHUNK_SIZE > INT_MAX +# error "unsupported less than 32-bit platform?" +#endif + while ((size_t)len > ZLIB_CRC_CHUNK_SIZE) { + value = crc32(value, buf, ZLIB_CRC_CHUNK_SIZE); + buf += (size_t) ZLIB_CRC_CHUNK_SIZE; + len -= (size_t) ZLIB_CRC_CHUNK_SIZE; } +#undef ZLIB_CRC_CHUNK_SIZE value = crc32(value, buf, (unsigned int)len); Py_END_ALLOW_THREADS } else { From a8ce149628c9eaafb8c38fbf25fbd1ed483d2902 Mon Sep 17 00:00:00 2001 From: Amioplk Date: Mon, 4 Dec 2023 21:52:06 +0100 Subject: [PATCH 39/87] gh-112671: Fixing typo in the Macro Docs (GH-112715) Replace Py_T_STRING_INLINE with Py_T_STRING_INPLACE --- Doc/c-api/structures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 25cb4ed40f63e72..528813c255c0a57 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -592,7 +592,7 @@ Macro name C type Python type (*): Zero-terminated, UTF8-encoded C string. With :c:macro:`!Py_T_STRING` the C representation is a pointer; - with :c:macro:`!Py_T_STRING_INLINE` the string is stored directly + with :c:macro:`!Py_T_STRING_INPLACE` the string is stored directly in the structure. (**): String of length 1. Only ASCII is accepted. From c5fa8a54dbdf564d482e2e3857aa3efa61edd329 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 Dec 2023 23:40:06 +0100 Subject: [PATCH 40/87] gh-112535: Add test on _Py_ThreadId() (#112709) Add also test.support.Py_GIL_DISABLED constant. --- Lib/test/support/__init__.py | 3 +- Lib/test/test_capi/test_misc.py | 55 +++++++++++++++++++++++++ Lib/test/test_cppext/__init__.py | 3 +- Lib/test/test_importlib/test_windows.py | 4 +- Lib/test/test_sys.py | 4 +- Modules/_testinternalcapi.c | 14 +++++++ 6 files changed, 75 insertions(+), 8 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 318a0599a75acd7..c22d73c231b46e4 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -796,7 +796,8 @@ def check_cflags_pgo(): return any(option in cflags_nodist for option in pgo_options) -if sysconfig.get_config_var('Py_GIL_DISABLED'): +Py_GIL_DISABLED = bool(sysconfig.get_config_var('Py_GIL_DISABLED')) +if Py_GIL_DISABLED: _header = 'PHBBInP' else: _header = 'nP' diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 6cbf5d222038048..3d86ae37190475e 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2854,5 +2854,60 @@ def testfunc(n, m): self.assertIn("_FOR_ITER_TIER_TWO", uops) +@unittest.skipUnless(support.Py_GIL_DISABLED, 'need Py_GIL_DISABLED') +class TestPyThreadId(unittest.TestCase): + def test_py_thread_id(self): + # gh-112535: Test _Py_ThreadId(): make sure that thread identifiers + # in a few threads are unique + py_thread_id = _testinternalcapi.py_thread_id + short_sleep = 0.010 + + class GetThreadId(threading.Thread): + def __init__(self): + super().__init__() + self.get_lock = threading.Lock() + self.get_lock.acquire() + self.started_lock = threading.Event() + self.py_tid = None + + def run(self): + self.started_lock.set() + self.get_lock.acquire() + self.py_tid = py_thread_id() + time.sleep(short_sleep) + self.py_tid2 = py_thread_id() + + nthread = 5 + threads = [GetThreadId() for _ in range(nthread)] + + # first make run sure that all threads are running + for thread in threads: + thread.start() + for thread in threads: + thread.started_lock.wait() + + # call _Py_ThreadId() in the main thread + py_thread_ids = [py_thread_id()] + + # now call _Py_ThreadId() in each thread + for thread in threads: + thread.get_lock.release() + + # call _Py_ThreadId() in each thread and wait until threads complete + for thread in threads: + thread.join() + py_thread_ids.append(thread.py_tid) + # _PyThread_Id() should not change for a given thread. + # For example, it should remain the same after a short sleep. + self.assertEqual(thread.py_tid2, thread.py_tid) + + # make sure that all _Py_ThreadId() are unique + for tid in py_thread_ids: + self.assertIsInstance(tid, int) + self.assertGreater(tid, 0) + self.assertEqual(len(set(py_thread_ids)), len(py_thread_ids), + py_thread_ids) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_cppext/__init__.py b/Lib/test/test_cppext/__init__.py index 299a16ada2e32ef..c6039bd17b06624 100644 --- a/Lib/test/test_cppext/__init__.py +++ b/Lib/test/test_cppext/__init__.py @@ -2,7 +2,6 @@ # compatible with C++ and does not emit C++ compiler warnings. import os.path import shutil -import sys import unittest import subprocess import sysconfig @@ -15,7 +14,7 @@ # gh-110119: pip does not currently support 't' in the ABI flag use by # --disable-gil builds. Once it does, we can remove this skip. -@unittest.skipIf(sysconfig.get_config_var('Py_GIL_DISABLED') == 1, +@unittest.skipIf(support.Py_GIL_DISABLED, 'test does not work with --disable-gil') @support.requires_subprocess() class TestCPPExt(unittest.TestCase): diff --git a/Lib/test/test_importlib/test_windows.py b/Lib/test/test_importlib/test_windows.py index d25133240b1afdb..8a9a8fffcd10d49 100644 --- a/Lib/test/test_importlib/test_windows.py +++ b/Lib/test/test_importlib/test_windows.py @@ -4,8 +4,8 @@ import os import re import sys -import sysconfig import unittest +from test import support from test.support import import_helper from contextlib import contextmanager from test.test_importlib.util import temp_module @@ -112,7 +112,7 @@ def test_module_not_found(self): class WindowsExtensionSuffixTests: def test_tagged_suffix(self): suffixes = self.machinery.EXTENSION_SUFFIXES - abi_flags = "t" if sysconfig.get_config_var("Py_GIL_DISABLED") else "" + abi_flags = "t" if support.Py_GIL_DISABLED else "" ver = sys.version_info platform = re.sub('[^a-zA-Z0-9]', '_', get_platform()) expected_tag = f".cp{ver.major}{ver.minor}{abi_flags}-{platform}.pyd" diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 8c2c1a40f74bf24..db5ba16c4d97399 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1224,9 +1224,7 @@ def test_pystats(self): @test.support.cpython_only @unittest.skipUnless(hasattr(sys, 'abiflags'), 'need sys.abiflags') def test_disable_gil_abi(self): - abi_threaded = 't' in sys.abiflags - py_gil_disabled = (sysconfig.get_config_var('Py_GIL_DISABLED') == 1) - self.assertEqual(py_gil_disabled, abi_threaded) + self.assertEqual('t' in sys.abiflags, support.Py_GIL_DISABLED) @test.support.cpython_only diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 4607a3faf17f74c..ba7653f2d9c7aa7 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1625,6 +1625,17 @@ get_type_module_name(PyObject *self, PyObject *type) } +#ifdef Py_GIL_DISABLED +static PyObject * +get_py_thread_id(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + uintptr_t tid = _Py_ThreadId(); + Py_BUILD_ASSERT(sizeof(unsigned long long) >= sizeof(tid)); + return PyLong_FromUnsignedLongLong(tid); +} +#endif + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -1688,6 +1699,9 @@ static PyMethodDef module_functions[] = { {"restore_crossinterp_data", restore_crossinterp_data, METH_VARARGS}, _TESTINTERNALCAPI_TEST_LONG_NUMBITS_METHODDEF {"get_type_module_name", get_type_module_name, METH_O}, +#ifdef Py_GIL_DISABLED + {"py_thread_id", get_py_thread_id, METH_NOARGS}, +#endif {NULL, NULL} /* sentinel */ }; From 9fe7655c6ce0b8e9adc229daf681b6d30e6b1610 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Mon, 4 Dec 2023 15:08:19 -0800 Subject: [PATCH 41/87] gh-112334: Restore subprocess's use of `vfork()` & fix `extra_groups=[]` behavior (#112617) Restore `subprocess`'s intended use of `vfork()` by default for performance on Linux; also fixes the behavior of `extra_groups=[]` which was unintentionally broken in 3.12.0: Fixed a performance regression in 3.12's :mod:`subprocess` on Linux where it would no longer use the fast-path ``vfork()`` system call when it could have due to a logic bug, instead falling back to the safe but slower ``fork()``. Also fixed a security bug introduced in 3.12.0. If a value of ``extra_groups=[]`` was passed to :mod:`subprocess.Popen` or related APIs, the underlying ``setgroups(0, NULL)`` system call to clear the groups list would not be made in the child process prior to ``exec()``. The security issue was identified via code inspection in the process of fixing the first bug. Thanks to @vain for the detailed report and analysis in the initial bug on Github. Co-authored-by: Serhiy Storchaka --- Lib/test/test_subprocess.py | 38 +++++++++---------- ...-12-01-21-05-46.gh-issue-112334.DmNXKh.rst | 11 ++++++ Modules/_posixsubprocess.c | 12 +++++- 3 files changed, 38 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-01-21-05-46.gh-issue-112334.DmNXKh.rst diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index fe1a3675fced653..319bc0d26385638 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -2066,8 +2066,14 @@ def test_group_error(self): def test_extra_groups(self): gid = os.getegid() group_list = [65534 if gid != 65534 else 65533] + self._test_extra_groups_impl(gid=gid, group_list=group_list) + + @unittest.skipUnless(hasattr(os, 'setgroups'), 'no setgroups() on platform') + def test_extra_groups_empty_list(self): + self._test_extra_groups_impl(gid=os.getegid(), group_list=[]) + + def _test_extra_groups_impl(self, *, gid, group_list): name_group = _get_test_grp_name() - perm_error = False if grp is not None: group_list.append(name_group) @@ -2077,11 +2083,8 @@ def test_extra_groups(self): [sys.executable, "-c", "import os, sys, json; json.dump(os.getgroups(), sys.stdout)"], extra_groups=group_list) - except OSError as ex: - if ex.errno != errno.EPERM: - raise - perm_error = True - + except PermissionError: + self.skipTest("setgroup() EPERM; this test may require root.") else: parent_groups = os.getgroups() child_groups = json.loads(output) @@ -2092,12 +2095,15 @@ def test_extra_groups(self): else: desired_gids = group_list - if perm_error: - self.assertEqual(set(child_groups), set(parent_groups)) - else: - self.assertEqual(set(desired_gids), set(child_groups)) + self.assertEqual(set(desired_gids), set(child_groups)) - # make sure we bomb on negative values + if grp is None: + with self.assertRaises(ValueError): + subprocess.check_call(ZERO_RETURN_CMD, + extra_groups=[name_group]) + + # No skip necessary, this test won't make it to a setgroup() call. + def test_extra_groups_invalid_gid_t_values(self): with self.assertRaises(ValueError): subprocess.check_call(ZERO_RETURN_CMD, extra_groups=[-1]) @@ -2106,16 +2112,6 @@ def test_extra_groups(self): cwd=os.curdir, env=os.environ, extra_groups=[2**64]) - if grp is None: - with self.assertRaises(ValueError): - subprocess.check_call(ZERO_RETURN_CMD, - extra_groups=[name_group]) - - @unittest.skipIf(hasattr(os, 'setgroups'), 'setgroups() available on platform') - def test_extra_groups_error(self): - with self.assertRaises(ValueError): - subprocess.check_call(ZERO_RETURN_CMD, extra_groups=[]) - @unittest.skipIf(mswindows or not hasattr(os, 'umask'), 'POSIX umask() is not available.') def test_umask(self): diff --git a/Misc/NEWS.d/next/Library/2023-12-01-21-05-46.gh-issue-112334.DmNXKh.rst b/Misc/NEWS.d/next/Library/2023-12-01-21-05-46.gh-issue-112334.DmNXKh.rst new file mode 100644 index 000000000000000..3a53a8bf84230fa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-01-21-05-46.gh-issue-112334.DmNXKh.rst @@ -0,0 +1,11 @@ +Fixed a performance regression in 3.12's :mod:`subprocess` on Linux where it +would no longer use the fast-path ``vfork()`` system call when it could have +due to a logic bug, instead falling back to the safe but slower ``fork()``. + +Also fixed a second 3.12.0 potential security bug. If a value of +``extra_groups=[]`` was passed to :mod:`subprocess.Popen` or related APIs, +the underlying ``setgroups(0, NULL)`` system call to clear the groups list +would not be made in the child process prior to ``exec()``. + +This was identified via code inspection in the process of fixing the first +bug. diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 2898eedc3e3a8f5..d0dd8f064e03955 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -767,8 +767,10 @@ child_exec(char *const exec_array[], #endif #ifdef HAVE_SETGROUPS - if (extra_group_size > 0) + if (extra_group_size >= 0) { + assert((extra_group_size == 0) == (extra_groups == NULL)); POSIX_CALL(setgroups(extra_group_size, extra_groups)); + } #endif /* HAVE_SETGROUPS */ #ifdef HAVE_SETREGID @@ -1022,7 +1024,6 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, pid_t pid = -1; int need_to_reenable_gc = 0; char *const *argv = NULL, *const *envp = NULL; - Py_ssize_t extra_group_size = 0; int need_after_fork = 0; int saved_errno = 0; int *c_fds_to_keep = NULL; @@ -1103,6 +1104,13 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args, cwd = PyBytes_AsString(cwd_obj2); } + // Special initial value meaning that subprocess API was called with + // extra_groups=None leading to _posixsubprocess.fork_exec(gids=None). + // We use this to differentiate between code desiring a setgroups(0, NULL) + // call vs no call at all. The fast vfork() code path could be used when + // there is no setgroups call. + Py_ssize_t extra_group_size = -2; + if (extra_groups_packed != Py_None) { #ifdef HAVE_SETGROUPS if (!PyList_Check(extra_groups_packed)) { From 304a1b3f3a8ed9a734ef1d098cafccb6725162db Mon Sep 17 00:00:00 2001 From: Barney Gale Date: Mon, 4 Dec 2023 23:21:39 +0000 Subject: [PATCH 42/87] GH-112727: Speed up `pathlib.Path.absolute()` (#112728) Use `_from_parsed_parts()` to create a pre-joined/pre-parsed path, rather than passing multiple arguments to `with_segments()` Co-authored-by: Alex Waygood --- Lib/pathlib.py | 20 +++++++++++++------ ...-12-04-21-30-34.gh-issue-112727.jpgNRB.rst | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-04-21-30-34.gh-issue-112727.jpgNRB.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index b728a0b3dfdb6c4..c48cff307083a81 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -1415,21 +1415,29 @@ def absolute(self): """ if self.is_absolute(): return self - elif self.drive: + if self.root: + drive = os.path.splitroot(os.getcwd())[0] + return self._from_parsed_parts(drive, self.root, self._tail) + if self.drive: # There is a CWD on each drive-letter drive. cwd = os.path.abspath(self.drive) else: cwd = os.getcwd() + if not self._tail: # Fast path for "empty" paths, e.g. Path("."), Path("") or Path(). # We pass only one argument to with_segments() to avoid the cost # of joining, and we exploit the fact that getcwd() returns a # fully-normalized string by storing it in _str. This is used to # implement Path.cwd(). - if not self.root and not self._tail: - result = self.with_segments(cwd) - result._str = cwd - return result - return self.with_segments(cwd, self) + result = self.with_segments(cwd) + result._str = cwd + return result + drive, root, rel = os.path.splitroot(cwd) + if not rel: + return self._from_parsed_parts(drive, root, self._tail) + tail = rel.split(self.pathmod.sep) + tail.extend(self._tail) + return self._from_parsed_parts(drive, root, tail) def resolve(self, strict=False): """ diff --git a/Misc/NEWS.d/next/Library/2023-12-04-21-30-34.gh-issue-112727.jpgNRB.rst b/Misc/NEWS.d/next/Library/2023-12-04-21-30-34.gh-issue-112727.jpgNRB.rst new file mode 100644 index 000000000000000..bbe7aae5732d9aa --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-04-21-30-34.gh-issue-112727.jpgNRB.rst @@ -0,0 +1 @@ +Speed up :meth:`pathlib.Path.absolute`. Patch by Barney Gale. From dc824c5dc120ffed84bafd23f95e95a99678ed6a Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 5 Dec 2023 12:23:17 +0800 Subject: [PATCH 43/87] gh-112736: Refactor del-safe symbol handling in subprocess (#112738) Refactor delete-safe symbol handling in subprocess. Only module globals are force-cleared during interpreter finalization, using a class reference instead of individually listing the constants everywhere is simpler. --- Lib/subprocess.py | 48 +++++++++---------- ...-12-05-01-19-28.gh-issue-112736.rdHDrU.rst | 1 + 2 files changed, 25 insertions(+), 24 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-05-01-19-28.gh-issue-112736.rdHDrU.rst diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 6df5dd551ea67e9..d6edd1a9807d1be 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -74,8 +74,8 @@ else: _mswindows = True -# wasm32-emscripten and wasm32-wasi do not support processes -_can_fork_exec = sys.platform not in {"emscripten", "wasi"} +# some platforms do not support subprocesses +_can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "watchos"} if _mswindows: import _winapi @@ -103,18 +103,22 @@ if _can_fork_exec: from _posixsubprocess import fork_exec as _fork_exec # used in methods that are called by __del__ - _waitpid = os.waitpid - _waitstatus_to_exitcode = os.waitstatus_to_exitcode - _WIFSTOPPED = os.WIFSTOPPED - _WSTOPSIG = os.WSTOPSIG - _WNOHANG = os.WNOHANG + class _del_safe: + waitpid = os.waitpid + waitstatus_to_exitcode = os.waitstatus_to_exitcode + WIFSTOPPED = os.WIFSTOPPED + WSTOPSIG = os.WSTOPSIG + WNOHANG = os.WNOHANG + ECHILD = errno.ECHILD else: - _fork_exec = None - _waitpid = None - _waitstatus_to_exitcode = None - _WIFSTOPPED = None - _WSTOPSIG = None - _WNOHANG = None + class _del_safe: + waitpid = None + waitstatus_to_exitcode = None + WIFSTOPPED = None + WSTOPSIG = None + WNOHANG = None + ECHILD = errno.ECHILD + import select import selectors @@ -1951,20 +1955,16 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, raise child_exception_type(err_msg) - def _handle_exitstatus(self, sts, - _waitstatus_to_exitcode=_waitstatus_to_exitcode, - _WIFSTOPPED=_WIFSTOPPED, - _WSTOPSIG=_WSTOPSIG): + def _handle_exitstatus(self, sts, _del_safe=_del_safe): """All callers to this function MUST hold self._waitpid_lock.""" # This method is called (indirectly) by __del__, so it cannot # refer to anything outside of its local scope. - if _WIFSTOPPED(sts): - self.returncode = -_WSTOPSIG(sts) + if _del_safe.WIFSTOPPED(sts): + self.returncode = -_del_safe.WSTOPSIG(sts) else: - self.returncode = _waitstatus_to_exitcode(sts) + self.returncode = _del_safe.waitstatus_to_exitcode(sts) - def _internal_poll(self, _deadstate=None, _waitpid=_waitpid, - _WNOHANG=_WNOHANG, _ECHILD=errno.ECHILD): + def _internal_poll(self, _deadstate=None, _del_safe=_del_safe): """Check if child process has terminated. Returns returncode attribute. @@ -1980,13 +1980,13 @@ def _internal_poll(self, _deadstate=None, _waitpid=_waitpid, try: if self.returncode is not None: return self.returncode # Another thread waited. - pid, sts = _waitpid(self.pid, _WNOHANG) + pid, sts = _del_safe.waitpid(self.pid, _del_safe.WNOHANG) if pid == self.pid: self._handle_exitstatus(sts) except OSError as e: if _deadstate is not None: self.returncode = _deadstate - elif e.errno == _ECHILD: + elif e.errno == _del_safe.ECHILD: # This happens if SIGCLD is set to be ignored or # waiting for child processes has otherwise been # disabled for our process. This child is dead, we diff --git a/Misc/NEWS.d/next/Library/2023-12-05-01-19-28.gh-issue-112736.rdHDrU.rst b/Misc/NEWS.d/next/Library/2023-12-05-01-19-28.gh-issue-112736.rdHDrU.rst new file mode 100644 index 000000000000000..6c09e622923af8d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-05-01-19-28.gh-issue-112736.rdHDrU.rst @@ -0,0 +1 @@ +The use of del-safe symbols in ``subprocess`` was refactored to allow for use in cross-platform build environments. From aa5bee30abb28d73a838399f4c3a8bcdc5108fe3 Mon Sep 17 00:00:00 2001 From: Constantin Hong Date: Tue, 5 Dec 2023 16:24:56 +0900 Subject: [PATCH 44/87] gh-102130: Support tab completion in cmd for Libedit. (GH-107748) --- Co-authored-by: Tian Gao --- Doc/library/cmd.rst | 10 +++++++ Lib/cmd.py | 10 ++++++- Lib/test/test_cmd.py | 30 +++++++++++++++++++ Misc/ACKS | 1 + ...-08-07-21-11-24.gh-issue-102130._UyI5i.rst | 1 + 5 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-08-07-21-11-24.gh-issue-102130._UyI5i.rst diff --git a/Doc/library/cmd.rst b/Doc/library/cmd.rst index fd5df96dfd0b3d6..1318ffe5a48d53d 100644 --- a/Doc/library/cmd.rst +++ b/Doc/library/cmd.rst @@ -26,6 +26,13 @@ interface. key; it defaults to :kbd:`Tab`. If *completekey* is not :const:`None` and :mod:`readline` is available, command completion is done automatically. + The default, ``'tab'``, is treated specially, so that it refers to the + :kbd:`Tab` key on every :data:`readline.backend`. + Specifically, if :data:`readline.backend` is ``editline``, + ``Cmd`` will use ``'^I'`` instead of ``'tab'``. + Note that other values are not treated this way, and might only work + with a specific backend. + The optional arguments *stdin* and *stdout* specify the input and output file objects that the Cmd instance or subclass instance will use for input and output. If not specified, they will default to :data:`sys.stdin` and @@ -35,6 +42,9 @@ interface. :attr:`use_rawinput` attribute to ``False``, otherwise *stdin* will be ignored. + .. versionchanged:: 3.13 + ``completekey='tab'`` is replaced by ``'^I'`` for ``editline``. + .. _cmd-objects: diff --git a/Lib/cmd.py b/Lib/cmd.py index e933b8dbc1470a8..2e358d6cd5a02de 100644 --- a/Lib/cmd.py +++ b/Lib/cmd.py @@ -108,7 +108,15 @@ def cmdloop(self, intro=None): import readline self.old_completer = readline.get_completer() readline.set_completer(self.complete) - readline.parse_and_bind(self.completekey+": complete") + if readline.backend == "editline": + if self.completekey == 'tab': + # libedit uses "^I" instead of "tab" + command_string = "bind ^I rl_complete" + else: + command_string = f"bind {self.completekey} rl_complete" + else: + command_string = f"{self.completekey}: complete" + readline.parse_and_bind(command_string) except ImportError: pass try: diff --git a/Lib/test/test_cmd.py b/Lib/test/test_cmd.py index 951336fa08542d2..46ec82b704963da 100644 --- a/Lib/test/test_cmd.py +++ b/Lib/test/test_cmd.py @@ -9,7 +9,10 @@ import doctest import unittest import io +import textwrap from test import support +from test.support.import_helper import import_module +from test.support.pty_helper import run_pty class samplecmdclass(cmd.Cmd): """ @@ -259,6 +262,33 @@ class CmdPrintExceptionClass(cmd.Cmd): def default(self, line): print(sys.exc_info()[:2]) + +@support.requires_subprocess() +class CmdTestReadline(unittest.TestCase): + def setUpClass(): + # Ensure that the readline module is loaded + # If this fails, the test is skipped because SkipTest will be raised + readline = import_module('readline') + + def test_basic_completion(self): + script = textwrap.dedent(""" + import cmd + class simplecmd(cmd.Cmd): + def do_tab_completion_test(self, args): + print('tab completion success') + return True + + simplecmd().cmdloop() + """) + + # 't' and complete 'ab_completion_test' to 'tab_completion_test' + input = b"t\t\n" + + output = run_pty(script, input) + + self.assertIn(b'ab_completion_test', output) + self.assertIn(b'tab completion success', output) + def load_tests(loader, tests, pattern): tests.addTest(doctest.DocTestSuite()) return tests diff --git a/Misc/ACKS b/Misc/ACKS index 1c67d96ed3a528d..12335c911ae42a5 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -788,6 +788,7 @@ Thomas Holmes Craig Holmquist Philip Homburg Naofumi Honda +Constantin Hong Weipeng Hong Jeffrey Honig Rob Hooft diff --git a/Misc/NEWS.d/next/Library/2023-08-07-21-11-24.gh-issue-102130._UyI5i.rst b/Misc/NEWS.d/next/Library/2023-08-07-21-11-24.gh-issue-102130._UyI5i.rst new file mode 100644 index 000000000000000..f582ad5df39e843 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-08-07-21-11-24.gh-issue-102130._UyI5i.rst @@ -0,0 +1 @@ +Support tab completion in :mod:`cmd` for ``editline``. From 9f92b31339945da55559747c420e170c968e9e2b Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 5 Dec 2023 10:34:13 +0300 Subject: [PATCH 45/87] Minor refactoring of Object/abstract.c (UNARY_FUNC macro and more cases for BINARY_FUNC) (GH-112145) * Use BINARY_FUNC macro for some remaining ops * Add UNARY_FUNC macro to define unary PyNumber_* functions --- Objects/abstract.c | 115 ++++++++++----------------------------------- 1 file changed, 25 insertions(+), 90 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index 43842fbdd6aeddf..1ec5c5b8c3dc2f5 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1180,29 +1180,10 @@ PyNumber_Multiply(PyObject *v, PyObject *w) return result; } -PyObject * -PyNumber_MatrixMultiply(PyObject *v, PyObject *w) -{ - return binary_op(v, w, NB_SLOT(nb_matrix_multiply), "@"); -} - -PyObject * -PyNumber_FloorDivide(PyObject *v, PyObject *w) -{ - return binary_op(v, w, NB_SLOT(nb_floor_divide), "//"); -} - -PyObject * -PyNumber_TrueDivide(PyObject *v, PyObject *w) -{ - return binary_op(v, w, NB_SLOT(nb_true_divide), "/"); -} - -PyObject * -PyNumber_Remainder(PyObject *v, PyObject *w) -{ - return binary_op(v, w, NB_SLOT(nb_remainder), "%"); -} +BINARY_FUNC(PyNumber_MatrixMultiply, nb_matrix_multiply, "@") +BINARY_FUNC(PyNumber_FloorDivide, nb_floor_divide, "//") +BINARY_FUNC(PyNumber_TrueDivide, nb_true_divide, "/") +BINARY_FUNC(PyNumber_Remainder, nb_remainder, "%") PyObject * PyNumber_Power(PyObject *v, PyObject *w, PyObject *z) @@ -1379,73 +1360,27 @@ _PyNumber_InPlacePowerNoMod(PyObject *lhs, PyObject *rhs) /* Unary operators and functions */ -PyObject * -PyNumber_Negative(PyObject *o) -{ - if (o == NULL) { - return null_error(); - } - - PyNumberMethods *m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_negative) { - PyObject *res = (*m->nb_negative)(o); - assert(_Py_CheckSlotResult(o, "__neg__", res != NULL)); - return res; - } - - return type_error("bad operand type for unary -: '%.200s'", o); -} - -PyObject * -PyNumber_Positive(PyObject *o) -{ - if (o == NULL) { - return null_error(); - } - - PyNumberMethods *m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_positive) { - PyObject *res = (*m->nb_positive)(o); - assert(_Py_CheckSlotResult(o, "__pos__", res != NULL)); - return res; - } - - return type_error("bad operand type for unary +: '%.200s'", o); -} - -PyObject * -PyNumber_Invert(PyObject *o) -{ - if (o == NULL) { - return null_error(); - } - - PyNumberMethods *m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_invert) { - PyObject *res = (*m->nb_invert)(o); - assert(_Py_CheckSlotResult(o, "__invert__", res != NULL)); - return res; - } - - return type_error("bad operand type for unary ~: '%.200s'", o); -} - -PyObject * -PyNumber_Absolute(PyObject *o) -{ - if (o == NULL) { - return null_error(); - } - - PyNumberMethods *m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_absolute) { - PyObject *res = m->nb_absolute(o); - assert(_Py_CheckSlotResult(o, "__abs__", res != NULL)); - return res; - } - - return type_error("bad operand type for abs(): '%.200s'", o); -} +#define UNARY_FUNC(func, op, meth_name, descr) \ + PyObject * \ + func(PyObject *o) { \ + if (o == NULL) { \ + return null_error(); \ + } \ + \ + PyNumberMethods *m = Py_TYPE(o)->tp_as_number; \ + if (m && m->op) { \ + PyObject *res = (*m->op)(o); \ + assert(_Py_CheckSlotResult(o, #meth_name, res != NULL)); \ + return res; \ + } \ + \ + return type_error("bad operand type for "descr": '%.200s'", o); \ + } + +UNARY_FUNC(PyNumber_Negative, nb_negative, __neg__, "unary -") +UNARY_FUNC(PyNumber_Positive, nb_positive, __pow__, "unary +") +UNARY_FUNC(PyNumber_Invert, nb_invert, __invert__, "unary ~") +UNARY_FUNC(PyNumber_Absolute, nb_absolute, __abs__, "abs()") int From 81ee0260912dc4b55410f3c6ad755b5c4da82f4a Mon Sep 17 00:00:00 2001 From: pan324 <103143968+pan324@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:11:44 +0100 Subject: [PATCH 46/87] gh-82300: Add track parameter to multiprocessing.shared_memory (#110778) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a track parameter to shared memory to allow resource tracking via the side-launched resource tracker process to be disabled on platforms that use it (POSIX). This allows people who do not want automated cleanup at process exit because they are using the shared memory with processes not participating in Python's resource tracking to use the shared_memory API. Co-authored-by: Łukasz Langa Co-authored-by: Guido van Rossum Co-authored-by: Antoine Pitrou Co-authored-by: Gregory P. Smith --- Doc/library/multiprocessing.shared_memory.rst | 51 ++++++++++++------ Lib/multiprocessing/shared_memory.py | 24 ++++++--- Lib/test/_test_multiprocessing.py | 53 +++++++++++++++++++ ...3-10-12-18-19-47.gh-issue-82300.P8-O38.rst | 1 + 4 files changed, 106 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-12-18-19-47.gh-issue-82300.P8-O38.rst diff --git a/Doc/library/multiprocessing.shared_memory.rst b/Doc/library/multiprocessing.shared_memory.rst index f453e6403d932d4..671130d9b29fc08 100644 --- a/Doc/library/multiprocessing.shared_memory.rst +++ b/Doc/library/multiprocessing.shared_memory.rst @@ -36,7 +36,7 @@ or other communications requiring the serialization/deserialization and copying of data. -.. class:: SharedMemory(name=None, create=False, size=0) +.. class:: SharedMemory(name=None, create=False, size=0, *, track=True) Creates a new shared memory block or attaches to an existing shared memory block. Each shared memory block is assigned a unique name. @@ -64,26 +64,45 @@ copying of data. memory block may be larger or equal to the size requested. When attaching to an existing shared memory block, the ``size`` parameter is ignored. + *track*, when enabled, registers the shared memory block with a resource + tracker process on platforms where the OS does not do this automatically. + The resource tracker ensures proper cleanup of the shared memory even + if all other processes with access to the memory exit without doing so. + Python processes created from a common ancestor using :mod:`multiprocessing` + facilities share a single resource tracker process, and the lifetime of + shared memory segments is handled automatically among these processes. + Python processes created in any other way will receive their own + resource tracker when accessing shared memory with *track* enabled. + This will cause the shared memory to be deleted by the resource tracker + of the first process that terminates. + To avoid this issue, users of :mod:`subprocess` or standalone Python + processes should set *track* to ``False`` when there is already another + process in place that does the bookkeeping. + *track* is ignored on Windows, which has its own tracking and + automatically deletes shared memory when all handles to it have been closed. + + .. versionchanged:: 3.13 Added *track* parameter. + .. method:: close() - Closes access to the shared memory from this instance. In order to - ensure proper cleanup of resources, all instances should call - ``close()`` once the instance is no longer needed. Note that calling - ``close()`` does not cause the shared memory block itself to be - destroyed. + Closes the file descriptor/handle to the shared memory from this + instance. :meth:`close()` should be called once access to the shared + memory block from this instance is no longer needed. Depending + on operating system, the underlying memory may or may not be freed + even if all handles to it have been closed. To ensure proper cleanup, + use the :meth:`unlink()` method. .. method:: unlink() - Requests that the underlying shared memory block be destroyed. In - order to ensure proper cleanup of resources, ``unlink()`` should be - called once (and only once) across all processes which have need - for the shared memory block. After requesting its destruction, a - shared memory block may or may not be immediately destroyed and - this behavior may differ across platforms. Attempts to access data - inside the shared memory block after ``unlink()`` has been called may - result in memory access errors. Note: the last process relinquishing - its hold on a shared memory block may call ``unlink()`` and - :meth:`close()` in either order. + Deletes the underlying shared memory block. This should be called only + once per shared memory block regardless of the number of handles to it, + even in other processes. + :meth:`unlink()` and :meth:`close()` can be called in any order, but + trying to access data inside a shared memory block after :meth:`unlink()` + may result in memory access errors, depending on platform. + + This method has no effect on Windows, where the only way to delete a + shared memory block is to close all handles. .. attribute:: buf diff --git a/Lib/multiprocessing/shared_memory.py b/Lib/multiprocessing/shared_memory.py index 9a1e5aa17b87a23..67e70fdc27cf31d 100644 --- a/Lib/multiprocessing/shared_memory.py +++ b/Lib/multiprocessing/shared_memory.py @@ -71,8 +71,9 @@ class SharedMemory: _flags = os.O_RDWR _mode = 0o600 _prepend_leading_slash = True if _USE_POSIX else False + _track = True - def __init__(self, name=None, create=False, size=0): + def __init__(self, name=None, create=False, size=0, *, track=True): if not size >= 0: raise ValueError("'size' must be a positive integer") if create: @@ -82,6 +83,7 @@ def __init__(self, name=None, create=False, size=0): if name is None and not self._flags & os.O_EXCL: raise ValueError("'name' can only be None if create=True") + self._track = track if _USE_POSIX: # POSIX Shared Memory @@ -116,8 +118,8 @@ def __init__(self, name=None, create=False, size=0): except OSError: self.unlink() raise - - resource_tracker.register(self._name, "shared_memory") + if self._track: + resource_tracker.register(self._name, "shared_memory") else: @@ -236,12 +238,20 @@ def close(self): def unlink(self): """Requests that the underlying shared memory block be destroyed. - In order to ensure proper cleanup of resources, unlink should be - called once (and only once) across all processes which have access - to the shared memory block.""" + Unlink should be called once (and only once) across all handles + which have access to the shared memory block, even if these + handles belong to different processes. Closing and unlinking may + happen in any order, but trying to access data inside a shared + memory block after unlinking may result in memory errors, + depending on platform. + + This method has no effect on Windows, where the only way to + delete a shared memory block is to close all handles.""" + if _USE_POSIX and self._name: _posixshmem.shm_unlink(self._name) - resource_tracker.unregister(self._name, "shared_memory") + if self._track: + resource_tracker.unregister(self._name, "shared_memory") _encoding = "utf8" diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index ec003d8dc4314de..a94eb6c0ae4b8e7 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -4455,6 +4455,59 @@ def test_shared_memory_cleaned_after_process_termination(self): "resource_tracker: There appear to be 1 leaked " "shared_memory objects to clean up at shutdown", err) + @unittest.skipIf(os.name != "posix", "resource_tracker is posix only") + def test_shared_memory_untracking(self): + # gh-82300: When a separate Python process accesses shared memory + # with track=False, it must not cause the memory to be deleted + # when terminating. + cmd = '''if 1: + import sys + from multiprocessing.shared_memory import SharedMemory + mem = SharedMemory(create=False, name=sys.argv[1], track=False) + mem.close() + ''' + mem = shared_memory.SharedMemory(create=True, size=10) + # The resource tracker shares pipes with the subprocess, and so + # err existing means that the tracker process has terminated now. + try: + rc, out, err = script_helper.assert_python_ok("-c", cmd, mem.name) + self.assertNotIn(b"resource_tracker", err) + self.assertEqual(rc, 0) + mem2 = shared_memory.SharedMemory(create=False, name=mem.name) + mem2.close() + finally: + try: + mem.unlink() + except OSError: + pass + mem.close() + + @unittest.skipIf(os.name != "posix", "resource_tracker is posix only") + def test_shared_memory_tracking(self): + # gh-82300: When a separate Python process accesses shared memory + # with track=True, it must cause the memory to be deleted when + # terminating. + cmd = '''if 1: + import sys + from multiprocessing.shared_memory import SharedMemory + mem = SharedMemory(create=False, name=sys.argv[1], track=True) + mem.close() + ''' + mem = shared_memory.SharedMemory(create=True, size=10) + try: + rc, out, err = script_helper.assert_python_ok("-c", cmd, mem.name) + self.assertEqual(rc, 0) + self.assertIn( + b"resource_tracker: There appear to be 1 leaked " + b"shared_memory objects to clean up at shutdown", err) + finally: + try: + mem.unlink() + except OSError: + pass + resource_tracker.unregister(mem._name, "shared_memory") + mem.close() + # # Test to verify that `Finalize` works. # diff --git a/Misc/NEWS.d/next/Library/2023-10-12-18-19-47.gh-issue-82300.P8-O38.rst b/Misc/NEWS.d/next/Library/2023-10-12-18-19-47.gh-issue-82300.P8-O38.rst new file mode 100644 index 000000000000000..d7e6b225489b99d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-12-18-19-47.gh-issue-82300.P8-O38.rst @@ -0,0 +1 @@ +Add ``track`` parameter to :class:`multiprocessing.shared_memory.SharedMemory` that allows using shared memory blocks without having to register with the POSIX resource tracker that automatically releases them upon process exit. From d824512059eabbe9d45daeb24d1e2070ad13dd87 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 5 Dec 2023 09:03:32 +0000 Subject: [PATCH 47/87] gh-112535: Update _Py_ThreadId() to support PowerPC (gh-112624) --- Include/object.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Include/object.h b/Include/object.h index 81f777ad21f2f9f..dfeb43bda7d8411 100644 --- a/Include/object.h +++ b/Include/object.h @@ -261,6 +261,22 @@ _Py_ThreadId(void) __asm__ ("mrs %0, tpidrro_el0" : "=r" (tid)); #elif defined(__aarch64__) __asm__ ("mrs %0, tpidr_el0" : "=r" (tid)); +#elif defined(__powerpc64__) + #if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer) + tid = (uintptr_t)__builtin_thread_pointer(); + #else + register uintptr_t tp __asm__ ("r13"); + __asm__("" : "=r" (tp)); + tid = tp; + #endif +#elif defined(__powerpc__) + #if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer) + tid = (uintptr_t)__builtin_thread_pointer(); + #else + register uintptr_t tp __asm__ ("r2"); + __asm__ ("" : "=r" (tp)); + tid = tp; + #endif #else # error "define _Py_ThreadId for this platform" #endif From b31232ddf7f219ca8ff9e8d0401c02eb0b6ffec3 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Tue, 5 Dec 2023 04:21:09 -0500 Subject: [PATCH 48/87] gh-62897: Update PyUnicode C API parameter names (GH-12680) Standardize PyUnicode C API parameter names across the documentation. Co-authored-by: Serhiy Storchaka --- Doc/c-api/unicode.rst | 182 +++++++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index e654412965a727d..5541eaa521803bc 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -75,19 +75,19 @@ Python: The following APIs are C macros and static inlined functions for fast checks and access to internal read-only data of Unicode objects: -.. c:function:: int PyUnicode_Check(PyObject *o) +.. c:function:: int PyUnicode_Check(PyObject *obj) - Return true if the object *o* is a Unicode object or an instance of a Unicode + Return true if the object *obj* is a Unicode object or an instance of a Unicode subtype. This function always succeeds. -.. c:function:: int PyUnicode_CheckExact(PyObject *o) +.. c:function:: int PyUnicode_CheckExact(PyObject *obj) - Return true if the object *o* is a Unicode object, but not an instance of a + Return true if the object *obj* is a Unicode object, but not an instance of a subtype. This function always succeeds. -.. c:function:: int PyUnicode_READY(PyObject *o) +.. c:function:: int PyUnicode_READY(PyObject *unicode) Returns ``0``. This API is kept only for backward compatibility. @@ -97,17 +97,17 @@ access to internal read-only data of Unicode objects: This API does nothing since Python 3.12. -.. c:function:: Py_ssize_t PyUnicode_GET_LENGTH(PyObject *o) +.. c:function:: Py_ssize_t PyUnicode_GET_LENGTH(PyObject *unicode) - Return the length of the Unicode string, in code points. *o* has to be a + Return the length of the Unicode string, in code points. *unicode* has to be a Unicode object in the "canonical" representation (not checked). .. versionadded:: 3.3 -.. c:function:: Py_UCS1* PyUnicode_1BYTE_DATA(PyObject *o) - Py_UCS2* PyUnicode_2BYTE_DATA(PyObject *o) - Py_UCS4* PyUnicode_4BYTE_DATA(PyObject *o) +.. c:function:: Py_UCS1* PyUnicode_1BYTE_DATA(PyObject *unicode) + Py_UCS2* PyUnicode_2BYTE_DATA(PyObject *unicode) + Py_UCS4* PyUnicode_4BYTE_DATA(PyObject *unicode) Return a pointer to the canonical representation cast to UCS1, UCS2 or UCS4 integer types for direct character access. No checks are performed if the @@ -129,18 +129,18 @@ access to internal read-only data of Unicode objects: ``PyUnicode_WCHAR_KIND`` has been removed. -.. c:function:: int PyUnicode_KIND(PyObject *o) +.. c:function:: int PyUnicode_KIND(PyObject *unicode) Return one of the PyUnicode kind constants (see above) that indicate how many - bytes per character this Unicode object uses to store its data. *o* has to + bytes per character this Unicode object uses to store its data. *unicode* has to be a Unicode object in the "canonical" representation (not checked). .. versionadded:: 3.3 -.. c:function:: void* PyUnicode_DATA(PyObject *o) +.. c:function:: void* PyUnicode_DATA(PyObject *unicode) - Return a void pointer to the raw Unicode buffer. *o* has to be a Unicode + Return a void pointer to the raw Unicode buffer. *unicode* has to be a Unicode object in the "canonical" representation (not checked). .. versionadded:: 3.3 @@ -168,25 +168,25 @@ access to internal read-only data of Unicode objects: .. versionadded:: 3.3 -.. c:function:: Py_UCS4 PyUnicode_READ_CHAR(PyObject *o, Py_ssize_t index) +.. c:function:: Py_UCS4 PyUnicode_READ_CHAR(PyObject *unicode, Py_ssize_t index) - Read a character from a Unicode object *o*, which must be in the "canonical" + Read a character from a Unicode object *unicode*, which must be in the "canonical" representation. This is less efficient than :c:func:`PyUnicode_READ` if you do multiple consecutive reads. .. versionadded:: 3.3 -.. c:function:: Py_UCS4 PyUnicode_MAX_CHAR_VALUE(PyObject *o) +.. c:function:: Py_UCS4 PyUnicode_MAX_CHAR_VALUE(PyObject *unicode) Return the maximum code point that is suitable for creating another string - based on *o*, which must be in the "canonical" representation. This is + based on *unicode*, which must be in the "canonical" representation. This is always an approximation but more efficient than iterating over the string. .. versionadded:: 3.3 -.. c:function:: int PyUnicode_IsIdentifier(PyObject *o) +.. c:function:: int PyUnicode_IsIdentifier(PyObject *unicode) Return ``1`` if the string is a valid identifier according to the language definition, section :ref:`identifiers`. Return ``0`` otherwise. @@ -358,9 +358,9 @@ APIs: .. versionadded:: 3.3 -.. c:function:: PyObject* PyUnicode_FromStringAndSize(const char *u, Py_ssize_t size) +.. c:function:: PyObject* PyUnicode_FromStringAndSize(const char *str, Py_ssize_t size) - Create a Unicode object from the char buffer *u*. The bytes will be + Create a Unicode object from the char buffer *str*. The bytes will be interpreted as being UTF-8 encoded. The buffer is copied into the new object. The return value might be a shared object, i.e. modification of the data is @@ -369,16 +369,16 @@ APIs: This function raises :exc:`SystemError` when: * *size* < 0, - * *u* is ``NULL`` and *size* > 0 + * *str* is ``NULL`` and *size* > 0 .. versionchanged:: 3.12 - *u* == ``NULL`` with *size* > 0 is not allowed anymore. + *str* == ``NULL`` with *size* > 0 is not allowed anymore. -.. c:function:: PyObject *PyUnicode_FromString(const char *u) +.. c:function:: PyObject *PyUnicode_FromString(const char *str) Create a Unicode object from a UTF-8 encoded null-terminated char buffer - *u*. + *str*. .. c:function:: PyObject* PyUnicode_FromFormat(const char *format, ...) @@ -646,29 +646,29 @@ APIs: .. versionadded:: 3.3 -.. c:function:: PyObject* PyUnicode_Substring(PyObject *str, Py_ssize_t start, \ +.. c:function:: PyObject* PyUnicode_Substring(PyObject *unicode, Py_ssize_t start, \ Py_ssize_t end) - Return a substring of *str*, from character index *start* (included) to + Return a substring of *unicode*, from character index *start* (included) to character index *end* (excluded). Negative indices are not supported. .. versionadded:: 3.3 -.. c:function:: Py_UCS4* PyUnicode_AsUCS4(PyObject *u, Py_UCS4 *buffer, \ +.. c:function:: Py_UCS4* PyUnicode_AsUCS4(PyObject *unicode, Py_UCS4 *buffer, \ Py_ssize_t buflen, int copy_null) - Copy the string *u* into a UCS4 buffer, including a null character, if + Copy the string *unicode* into a UCS4 buffer, including a null character, if *copy_null* is set. Returns ``NULL`` and sets an exception on error (in particular, a :exc:`SystemError` if *buflen* is smaller than the length of - *u*). *buffer* is returned on success. + *unicode*). *buffer* is returned on success. .. versionadded:: 3.3 -.. c:function:: Py_UCS4* PyUnicode_AsUCS4Copy(PyObject *u) +.. c:function:: Py_UCS4* PyUnicode_AsUCS4Copy(PyObject *unicode) - Copy the string *u* into a new UCS4 buffer that is allocated using + Copy the string *unicode* into a new UCS4 buffer that is allocated using :c:func:`PyMem_Malloc`. If this fails, ``NULL`` is returned with a :exc:`MemoryError` set. The returned buffer always has an extra null code point appended. @@ -683,7 +683,7 @@ The current locale encoding can be used to decode text from the operating system. .. c:function:: PyObject* PyUnicode_DecodeLocaleAndSize(const char *str, \ - Py_ssize_t len, \ + Py_ssize_t length, \ const char *errors) Decode a string from UTF-8 on Android and VxWorks, or from the current @@ -788,7 +788,7 @@ conversion function: Accepts a :term:`path-like object`. -.. c:function:: PyObject* PyUnicode_DecodeFSDefaultAndSize(const char *s, Py_ssize_t size) +.. c:function:: PyObject* PyUnicode_DecodeFSDefaultAndSize(const char *str, Py_ssize_t size) Decode a string from the :term:`filesystem encoding and error handler`. @@ -804,7 +804,7 @@ conversion function: handler>` is now used. -.. c:function:: PyObject* PyUnicode_DecodeFSDefault(const char *s) +.. c:function:: PyObject* PyUnicode_DecodeFSDefault(const char *str) Decode a null-terminated string from the :term:`filesystem encoding and error handler`. @@ -841,17 +841,17 @@ wchar_t Support :c:type:`wchar_t` support for platforms which support it: -.. c:function:: PyObject* PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) +.. c:function:: PyObject* PyUnicode_FromWideChar(const wchar_t *wstr, Py_ssize_t size) - Create a Unicode object from the :c:type:`wchar_t` buffer *w* of the given *size*. + Create a Unicode object from the :c:type:`wchar_t` buffer *wstr* of the given *size*. Passing ``-1`` as the *size* indicates that the function must itself compute the length, - using wcslen. + using :c:func:`!wcslen`. Return ``NULL`` on failure. -.. c:function:: Py_ssize_t PyUnicode_AsWideChar(PyObject *unicode, wchar_t *w, Py_ssize_t size) +.. c:function:: Py_ssize_t PyUnicode_AsWideChar(PyObject *unicode, wchar_t *wstr, Py_ssize_t size) - Copy the Unicode object contents into the :c:type:`wchar_t` buffer *w*. At most + Copy the Unicode object contents into the :c:type:`wchar_t` buffer *wstr*. At most *size* :c:type:`wchar_t` characters are copied (excluding a possibly trailing null termination character). Return the number of :c:type:`wchar_t` characters copied or ``-1`` in case of an error. Note that the resulting :c:expr:`wchar_t*` @@ -915,10 +915,10 @@ Generic Codecs These are the generic codec APIs: -.. c:function:: PyObject* PyUnicode_Decode(const char *s, Py_ssize_t size, \ +.. c:function:: PyObject* PyUnicode_Decode(const char *str, Py_ssize_t size, \ const char *encoding, const char *errors) - Create a Unicode object by decoding *size* bytes of the encoded string *s*. + Create a Unicode object by decoding *size* bytes of the encoded string *str*. *encoding* and *errors* have the same meaning as the parameters of the same name in the :func:`str` built-in function. The codec to be used is looked up using the Python codec registry. Return ``NULL`` if an exception was raised by @@ -941,13 +941,13 @@ UTF-8 Codecs These are the UTF-8 codec APIs: -.. c:function:: PyObject* PyUnicode_DecodeUTF8(const char *s, Py_ssize_t size, const char *errors) +.. c:function:: PyObject* PyUnicode_DecodeUTF8(const char *str, Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the UTF-8 encoded string - *s*. Return ``NULL`` if an exception was raised by the codec. + *str*. Return ``NULL`` if an exception was raised by the codec. -.. c:function:: PyObject* PyUnicode_DecodeUTF8Stateful(const char *s, Py_ssize_t size, \ +.. c:function:: PyObject* PyUnicode_DecodeUTF8Stateful(const char *str, Py_ssize_t size, \ const char *errors, Py_ssize_t *consumed) If *consumed* is ``NULL``, behave like :c:func:`PyUnicode_DecodeUTF8`. If @@ -1004,7 +1004,7 @@ UTF-32 Codecs These are the UTF-32 codec APIs: -.. c:function:: PyObject* PyUnicode_DecodeUTF32(const char *s, Py_ssize_t size, \ +.. c:function:: PyObject* PyUnicode_DecodeUTF32(const char *str, Py_ssize_t size, \ const char *errors, int *byteorder) Decode *size* bytes from a UTF-32 encoded buffer string and return the @@ -1031,7 +1031,7 @@ These are the UTF-32 codec APIs: Return ``NULL`` if an exception was raised by the codec. -.. c:function:: PyObject* PyUnicode_DecodeUTF32Stateful(const char *s, Py_ssize_t size, \ +.. c:function:: PyObject* PyUnicode_DecodeUTF32Stateful(const char *str, Py_ssize_t size, \ const char *errors, int *byteorder, Py_ssize_t *consumed) If *consumed* is ``NULL``, behave like :c:func:`PyUnicode_DecodeUTF32`. If @@ -1054,7 +1054,7 @@ UTF-16 Codecs These are the UTF-16 codec APIs: -.. c:function:: PyObject* PyUnicode_DecodeUTF16(const char *s, Py_ssize_t size, \ +.. c:function:: PyObject* PyUnicode_DecodeUTF16(const char *str, Py_ssize_t size, \ const char *errors, int *byteorder) Decode *size* bytes from a UTF-16 encoded buffer string and return the @@ -1082,7 +1082,7 @@ These are the UTF-16 codec APIs: Return ``NULL`` if an exception was raised by the codec. -.. c:function:: PyObject* PyUnicode_DecodeUTF16Stateful(const char *s, Py_ssize_t size, \ +.. c:function:: PyObject* PyUnicode_DecodeUTF16Stateful(const char *str, Py_ssize_t size, \ const char *errors, int *byteorder, Py_ssize_t *consumed) If *consumed* is ``NULL``, behave like :c:func:`PyUnicode_DecodeUTF16`. If @@ -1105,13 +1105,13 @@ UTF-7 Codecs These are the UTF-7 codec APIs: -.. c:function:: PyObject* PyUnicode_DecodeUTF7(const char *s, Py_ssize_t size, const char *errors) +.. c:function:: PyObject* PyUnicode_DecodeUTF7(const char *str, Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the UTF-7 encoded string - *s*. Return ``NULL`` if an exception was raised by the codec. + *str*. Return ``NULL`` if an exception was raised by the codec. -.. c:function:: PyObject* PyUnicode_DecodeUTF7Stateful(const char *s, Py_ssize_t size, \ +.. c:function:: PyObject* PyUnicode_DecodeUTF7Stateful(const char *str, Py_ssize_t size, \ const char *errors, Py_ssize_t *consumed) If *consumed* is ``NULL``, behave like :c:func:`PyUnicode_DecodeUTF7`. If @@ -1126,11 +1126,11 @@ Unicode-Escape Codecs These are the "Unicode Escape" codec APIs: -.. c:function:: PyObject* PyUnicode_DecodeUnicodeEscape(const char *s, \ +.. c:function:: PyObject* PyUnicode_DecodeUnicodeEscape(const char *str, \ Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the Unicode-Escape encoded - string *s*. Return ``NULL`` if an exception was raised by the codec. + string *str*. Return ``NULL`` if an exception was raised by the codec. .. c:function:: PyObject* PyUnicode_AsUnicodeEscapeString(PyObject *unicode) @@ -1146,11 +1146,11 @@ Raw-Unicode-Escape Codecs These are the "Raw Unicode Escape" codec APIs: -.. c:function:: PyObject* PyUnicode_DecodeRawUnicodeEscape(const char *s, \ +.. c:function:: PyObject* PyUnicode_DecodeRawUnicodeEscape(const char *str, \ Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the Raw-Unicode-Escape - encoded string *s*. Return ``NULL`` if an exception was raised by the codec. + encoded string *str*. Return ``NULL`` if an exception was raised by the codec. .. c:function:: PyObject* PyUnicode_AsRawUnicodeEscapeString(PyObject *unicode) @@ -1167,10 +1167,10 @@ These are the Latin-1 codec APIs: Latin-1 corresponds to the first 256 Unicode ordinals and only these are accepted by the codecs during encoding. -.. c:function:: PyObject* PyUnicode_DecodeLatin1(const char *s, Py_ssize_t size, const char *errors) +.. c:function:: PyObject* PyUnicode_DecodeLatin1(const char *str, Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the Latin-1 encoded string - *s*. Return ``NULL`` if an exception was raised by the codec. + *str*. Return ``NULL`` if an exception was raised by the codec. .. c:function:: PyObject* PyUnicode_AsLatin1String(PyObject *unicode) @@ -1187,10 +1187,10 @@ These are the ASCII codec APIs. Only 7-bit ASCII data is accepted. All other codes generate errors. -.. c:function:: PyObject* PyUnicode_DecodeASCII(const char *s, Py_ssize_t size, const char *errors) +.. c:function:: PyObject* PyUnicode_DecodeASCII(const char *str, Py_ssize_t size, const char *errors) Create a Unicode object by decoding *size* bytes of the ASCII encoded string - *s*. Return ``NULL`` if an exception was raised by the codec. + *str*. Return ``NULL`` if an exception was raised by the codec. .. c:function:: PyObject* PyUnicode_AsASCIIString(PyObject *unicode) @@ -1211,10 +1211,10 @@ decode characters. The mapping objects provided must support the These are the mapping codec APIs: -.. c:function:: PyObject* PyUnicode_DecodeCharmap(const char *data, Py_ssize_t size, \ +.. c:function:: PyObject* PyUnicode_DecodeCharmap(const char *str, Py_ssize_t length, \ PyObject *mapping, const char *errors) - Create a Unicode object by decoding *size* bytes of the encoded string *s* + Create a Unicode object by decoding *size* bytes of the encoded string *str* using the given *mapping* object. Return ``NULL`` if an exception was raised by the codec. @@ -1241,7 +1241,7 @@ These are the mapping codec APIs: The following codec API is special in that maps Unicode to Unicode. -.. c:function:: PyObject* PyUnicode_Translate(PyObject *str, PyObject *table, const char *errors) +.. c:function:: PyObject* PyUnicode_Translate(PyObject *unicode, PyObject *table, const char *errors) Translate a string by applying a character mapping table to it and return the resulting Unicode object. Return ``NULL`` if an exception was raised by the @@ -1266,13 +1266,13 @@ use the Win32 MBCS converters to implement the conversions. Note that MBCS (or DBCS) is a class of encodings, not just one. The target encoding is defined by the user settings on the machine running the codec. -.. c:function:: PyObject* PyUnicode_DecodeMBCS(const char *s, Py_ssize_t size, const char *errors) +.. c:function:: PyObject* PyUnicode_DecodeMBCS(const char *str, Py_ssize_t size, const char *errors) - Create a Unicode object by decoding *size* bytes of the MBCS encoded string *s*. + Create a Unicode object by decoding *size* bytes of the MBCS encoded string *str*. Return ``NULL`` if an exception was raised by the codec. -.. c:function:: PyObject* PyUnicode_DecodeMBCSStateful(const char *s, Py_ssize_t size, \ +.. c:function:: PyObject* PyUnicode_DecodeMBCSStateful(const char *str, Py_ssize_t size, \ const char *errors, Py_ssize_t *consumed) If *consumed* is ``NULL``, behave like :c:func:`PyUnicode_DecodeMBCS`. If @@ -1318,7 +1318,7 @@ They all return ``NULL`` or ``-1`` if an exception occurs. Concat two strings giving a new Unicode string. -.. c:function:: PyObject* PyUnicode_Split(PyObject *s, PyObject *sep, Py_ssize_t maxsplit) +.. c:function:: PyObject* PyUnicode_Split(PyObject *unicode, PyObject *sep, Py_ssize_t maxsplit) Split a string giving a list of Unicode strings. If *sep* is ``NULL``, splitting will be done at all whitespace substrings. Otherwise, splits occur at the given @@ -1326,10 +1326,10 @@ They all return ``NULL`` or ``-1`` if an exception occurs. set. Separators are not included in the resulting list. -.. c:function:: PyObject* PyUnicode_Splitlines(PyObject *s, int keepend) +.. c:function:: PyObject* PyUnicode_Splitlines(PyObject *unicode, int keepends) Split a Unicode string at line breaks, returning a list of Unicode strings. - CRLF is considered to be one line break. If *keepend* is ``0``, the line break + CRLF is considered to be one line break. If *keepends* is ``0``, the Line break characters are not included in the resulting strings. @@ -1339,28 +1339,28 @@ They all return ``NULL`` or ``-1`` if an exception occurs. Unicode string. -.. c:function:: Py_ssize_t PyUnicode_Tailmatch(PyObject *str, PyObject *substr, \ +.. c:function:: Py_ssize_t PyUnicode_Tailmatch(PyObject *unicode, PyObject *substr, \ Py_ssize_t start, Py_ssize_t end, int direction) - Return ``1`` if *substr* matches ``str[start:end]`` at the given tail end + Return ``1`` if *substr* matches ``unicode[start:end]`` at the given tail end (*direction* == ``-1`` means to do a prefix match, *direction* == ``1`` a suffix match), ``0`` otherwise. Return ``-1`` if an error occurred. -.. c:function:: Py_ssize_t PyUnicode_Find(PyObject *str, PyObject *substr, \ +.. c:function:: Py_ssize_t PyUnicode_Find(PyObject *unicode, PyObject *substr, \ Py_ssize_t start, Py_ssize_t end, int direction) - Return the first position of *substr* in ``str[start:end]`` using the given + Return the first position of *substr* in ``unicode[start:end]`` using the given *direction* (*direction* == ``1`` means to do a forward search, *direction* == ``-1`` a backward search). The return value is the index of the first match; a value of ``-1`` indicates that no match was found, and ``-2`` indicates that an error occurred and an exception has been set. -.. c:function:: Py_ssize_t PyUnicode_FindChar(PyObject *str, Py_UCS4 ch, \ +.. c:function:: Py_ssize_t PyUnicode_FindChar(PyObject *unicode, Py_UCS4 ch, \ Py_ssize_t start, Py_ssize_t end, int direction) - Return the first position of the character *ch* in ``str[start:end]`` using + Return the first position of the character *ch* in ``unicode[start:end]`` using the given *direction* (*direction* == ``1`` means to do a forward search, *direction* == ``-1`` a backward search). The return value is the index of the first match; a value of ``-1`` indicates that no match was found, and ``-2`` @@ -1369,20 +1369,20 @@ They all return ``NULL`` or ``-1`` if an exception occurs. .. versionadded:: 3.3 .. versionchanged:: 3.7 - *start* and *end* are now adjusted to behave like ``str[start:end]``. + *start* and *end* are now adjusted to behave like ``unicode[start:end]``. -.. c:function:: Py_ssize_t PyUnicode_Count(PyObject *str, PyObject *substr, \ +.. c:function:: Py_ssize_t PyUnicode_Count(PyObject *unicode, PyObject *substr, \ Py_ssize_t start, Py_ssize_t end) Return the number of non-overlapping occurrences of *substr* in - ``str[start:end]``. Return ``-1`` if an error occurred. + ``unicode[start:end]``. Return ``-1`` if an error occurred. -.. c:function:: PyObject* PyUnicode_Replace(PyObject *str, PyObject *substr, \ +.. c:function:: PyObject* PyUnicode_Replace(PyObject *unicode, PyObject *substr, \ PyObject *replstr, Py_ssize_t maxcount) - Replace at most *maxcount* occurrences of *substr* in *str* with *replstr* and + Replace at most *maxcount* occurrences of *substr* in *unicode* with *replstr* and return the resulting Unicode object. *maxcount* == ``-1`` means replace all occurrences. @@ -1418,9 +1418,9 @@ They all return ``NULL`` or ``-1`` if an exception occurs. .. versionadded:: 3.13 -.. c:function:: int PyUnicode_CompareWithASCIIString(PyObject *uni, const char *string) +.. c:function:: int PyUnicode_CompareWithASCIIString(PyObject *unicode, const char *string) - Compare a Unicode object, *uni*, with *string* and return ``-1``, ``0``, ``1`` for less + Compare a Unicode object, *unicode*, with *string* and return ``-1``, ``0``, ``1`` for less than, equal, and greater than, respectively. It is best to pass only ASCII-encoded strings, but the function interprets the input string as ISO-8859-1 if it contains non-ASCII characters. @@ -1428,7 +1428,7 @@ They all return ``NULL`` or ``-1`` if an exception occurs. This function does not raise exceptions. -.. c:function:: PyObject* PyUnicode_RichCompare(PyObject *left, PyObject *right, int op) +.. c:function:: PyObject* PyUnicode_RichCompare(PyObject *left, PyObject *right, int op) Rich compare two Unicode strings and return one of the following: @@ -1446,29 +1446,29 @@ They all return ``NULL`` or ``-1`` if an exception occurs. ``format % args``. -.. c:function:: int PyUnicode_Contains(PyObject *container, PyObject *element) +.. c:function:: int PyUnicode_Contains(PyObject *unicode, PyObject *substr) - Check whether *element* is contained in *container* and return true or false + Check whether *substr* is contained in *unicode* and return true or false accordingly. - *element* has to coerce to a one element Unicode string. ``-1`` is returned + *substr* has to coerce to a one element Unicode string. ``-1`` is returned if there was an error. -.. c:function:: void PyUnicode_InternInPlace(PyObject **string) +.. c:function:: void PyUnicode_InternInPlace(PyObject **p_unicode) - Intern the argument *\*string* in place. The argument must be the address of a + Intern the argument :c:expr:`*p_unicode` in place. The argument must be the address of a pointer variable pointing to a Python Unicode string object. If there is an - existing interned string that is the same as *\*string*, it sets *\*string* to + existing interned string that is the same as :c:expr:`*p_unicode`, it sets :c:expr:`*p_unicode` to it (releasing the reference to the old string object and creating a new :term:`strong reference` to the interned string object), otherwise it leaves - *\*string* alone and interns it (creating a new :term:`strong reference`). + :c:expr:`*p_unicode` alone and interns it (creating a new :term:`strong reference`). (Clarification: even though there is a lot of talk about references, think of this function as reference-neutral; you own the object after the call if and only if you owned it before the call.) -.. c:function:: PyObject* PyUnicode_InternFromString(const char *v) +.. c:function:: PyObject* PyUnicode_InternFromString(const char *str) A combination of :c:func:`PyUnicode_FromString` and :c:func:`PyUnicode_InternInPlace`, returning either a new Unicode string From 268415bbb32b1fafccae3d542c43d487b6f0f48d Mon Sep 17 00:00:00 2001 From: Jeffrey Kintscher <49998481+websurfer5@users.noreply.github.com> Date: Tue, 5 Dec 2023 01:33:51 -0800 Subject: [PATCH 49/87] gh-81441: shutil.rmtree() FileNotFoundError race condition (GH-14064) Ignore missing files and directories while enumerating directory entries in shutil.rmtree(). Co-authored-by: Serhiy Storchaka --- Doc/library/shutil.rst | 4 ++ Lib/shutil.py | 45 +++++++++++---- Lib/test/test_shutil.py | 57 +++++++++++++++++++ .../2019-06-14-22-37-32.bpo-37260.oecdIf.rst | 2 + 4 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-06-14-22-37-32.bpo-37260.oecdIf.rst diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index d1949d698f56144..d30d289710b129a 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -343,6 +343,10 @@ Directory and files operations .. versionchanged:: 3.12 Added the *onexc* parameter, deprecated *onerror*. + .. versionchanged:: 3.13 + :func:`!rmtree` now ignores :exc:`FileNotFoundError` exceptions for all + but the top-level path. + .. attribute:: rmtree.avoids_symlink_attacks Indicates whether the current platform and implementation provides a diff --git a/Lib/shutil.py b/Lib/shutil.py index dd93872e83c9e2c..93b00d73a0fd467 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -590,23 +590,21 @@ def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, dirs_exist_ok=dirs_exist_ok) if hasattr(os.stat_result, 'st_file_attributes'): - def _rmtree_islink(path): - try: - st = os.lstat(path) - return (stat.S_ISLNK(st.st_mode) or - (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT - and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT)) - except OSError: - return False + def _rmtree_islink(st): + return (stat.S_ISLNK(st.st_mode) or + (st.st_file_attributes & stat.FILE_ATTRIBUTE_REPARSE_POINT + and st.st_reparse_tag == stat.IO_REPARSE_TAG_MOUNT_POINT)) else: - def _rmtree_islink(path): - return os.path.islink(path) + def _rmtree_islink(st): + return stat.S_ISLNK(st.st_mode) # version vulnerable to race conditions def _rmtree_unsafe(path, onexc): try: with os.scandir(path) as scandir_it: entries = list(scandir_it) + except FileNotFoundError: + return except OSError as err: onexc(os.scandir, path, err) entries = [] @@ -614,6 +612,8 @@ def _rmtree_unsafe(path, onexc): fullname = entry.path try: is_dir = entry.is_dir(follow_symlinks=False) + except FileNotFoundError: + continue except OSError: is_dir = False @@ -624,6 +624,8 @@ def _rmtree_unsafe(path, onexc): # 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 FileNotFoundError: + continue except OSError as err: onexc(os.path.islink, fullname, err) continue @@ -631,10 +633,14 @@ def _rmtree_unsafe(path, onexc): else: try: os.unlink(fullname) + except FileNotFoundError: + continue except OSError as err: onexc(os.unlink, fullname, err) try: os.rmdir(path) + except FileNotFoundError: + pass except OSError as err: onexc(os.rmdir, path, err) @@ -643,6 +649,8 @@ def _rmtree_safe_fd(topfd, path, onexc): try: with os.scandir(topfd) as scandir_it: entries = list(scandir_it) + except FileNotFoundError: + return except OSError as err: err.filename = path onexc(os.scandir, path, err) @@ -651,6 +659,8 @@ def _rmtree_safe_fd(topfd, path, onexc): fullname = os.path.join(path, entry.name) try: is_dir = entry.is_dir(follow_symlinks=False) + except FileNotFoundError: + continue except OSError: is_dir = False else: @@ -658,6 +668,8 @@ def _rmtree_safe_fd(topfd, path, onexc): try: orig_st = entry.stat(follow_symlinks=False) is_dir = stat.S_ISDIR(orig_st.st_mode) + except FileNotFoundError: + continue except OSError as err: onexc(os.lstat, fullname, err) continue @@ -665,6 +677,8 @@ def _rmtree_safe_fd(topfd, path, onexc): try: dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd) dirfd_closed = False + except FileNotFoundError: + continue except OSError as err: onexc(os.open, fullname, err) else: @@ -675,6 +689,8 @@ def _rmtree_safe_fd(topfd, path, onexc): os.close(dirfd) dirfd_closed = True os.rmdir(entry.name, dir_fd=topfd) + except FileNotFoundError: + continue except OSError as err: onexc(os.rmdir, fullname, err) else: @@ -692,6 +708,8 @@ def _rmtree_safe_fd(topfd, path, onexc): else: try: os.unlink(entry.name, dir_fd=topfd) + except FileNotFoundError: + continue except OSError as err: onexc(os.unlink, fullname, err) @@ -781,7 +799,12 @@ def onexc(*args): if dir_fd is not None: raise NotImplementedError("dir_fd unavailable on this platform") try: - if _rmtree_islink(path): + st = os.lstat(path) + except OSError as err: + onexc(os.lstat, path, err) + return + try: + if _rmtree_islink(st): # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") except OSError as err: diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index ae6c6814fcc3eca..7ea2496230da476 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -633,6 +633,63 @@ def test_rmtree_on_junction(self): finally: shutil.rmtree(TESTFN, ignore_errors=True) + @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_rmtree_deleted_race_condition(self): + # bpo-37260 + # + # Test that a file or a directory deleted after it is enumerated + # by scandir() but before unlink() or rmdr() is called doesn't + # generate any errors. + def _onexc(fn, path, exc): + assert fn in (os.rmdir, os.unlink) + if not isinstance(exc, PermissionError): + raise + # Make the parent and the children writeable. + for p, mode in zip(paths, old_modes): + os.chmod(p, mode) + # Remove other dirs except one. + keep = next(p for p in dirs if p != path) + for p in dirs: + if p != keep: + os.rmdir(p) + # Remove other files except one. + keep = next(p for p in files if p != path) + for p in files: + if p != keep: + os.unlink(p) + + os.mkdir(TESTFN) + paths = [TESTFN] + [os.path.join(TESTFN, f'child{i}') + for i in range(6)] + dirs = paths[1::2] + files = paths[2::2] + for path in dirs: + os.mkdir(path) + for path in files: + write_file(path, '') + + old_modes = [os.stat(path).st_mode for path in paths] + + # Make the parent and the children non-writeable. + new_mode = stat.S_IREAD|stat.S_IEXEC + for path in reversed(paths): + os.chmod(path, new_mode) + + try: + shutil.rmtree(TESTFN, onexc=_onexc) + except: + # Test failed, so cleanup artifacts. + for path, mode in zip(paths, old_modes): + try: + os.chmod(path, mode) + except OSError: + pass + shutil.rmtree(TESTFN) + raise + class TestCopyTree(BaseTest, unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2019-06-14-22-37-32.bpo-37260.oecdIf.rst b/Misc/NEWS.d/next/Library/2019-06-14-22-37-32.bpo-37260.oecdIf.rst new file mode 100644 index 000000000000000..a5f2c5e8e18919c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-06-14-22-37-32.bpo-37260.oecdIf.rst @@ -0,0 +1,2 @@ +Fixed a race condition in :func:`shutil.rmtree` in which directory entries removed by another process or thread while ``shutil.rmtree()`` is running can cause it to raise FileNotFoundError. Patch by Jeffrey Kintscher. + From 2f20cafdbfc39925f9374f36f9d53bac365ed32a Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 5 Dec 2023 09:59:52 +0000 Subject: [PATCH 50/87] gh-101100: Fix many easily solvable Sphinx nitpicks in the datamodel docs (#112737) --- Doc/library/exceptions.rst | 8 +++-- Doc/reference/datamodel.rst | 58 ++++++++++++++++++++----------------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index cd85df8723a76be..b67215b8b3a3627 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -429,9 +429,11 @@ The following exceptions are the exceptions that are usually raised. :meth:`~iterator.__next__` method to signal that there are no further items produced by the iterator. - The exception object has a single attribute :attr:`value`, which is - given as an argument when constructing the exception, and defaults - to :const:`None`. + .. attribute:: StopIteration.value + + The exception object has a single attribute :attr:`!value`, which is + given as an argument when constructing the exception, and defaults + to :const:`None`. When a :term:`generator` or :term:`coroutine` function returns, a new :exc:`StopIteration` instance is diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 29298b79ef06dd9..06e61393fccc24a 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -88,7 +88,7 @@ Some objects contain references to "external" resources such as open files or windows. It is understood that these resources are freed when the object is garbage-collected, but since garbage collection is not guaranteed to happen, such objects also provide an explicit way to release the external resource, -usually a :meth:`close` method. Programs are strongly recommended to explicitly +usually a :meth:`!close` method. Programs are strongly recommended to explicitly close such objects. The ':keyword:`try`...\ :keyword:`finally`' statement and the ':keyword:`with`' statement provide convenient ways to do this. @@ -681,8 +681,8 @@ underlying the class method. When an instance method object is called, the underlying function (:attr:`__func__`) is called, inserting the class instance (:attr:`__self__`) in front of the argument list. For instance, when -:class:`C` is a class which contains a definition for a function -:meth:`f`, and ``x`` is an instance of :class:`C`, calling ``x.f(1)`` is +:class:`!C` is a class which contains a definition for a function +:meth:`!f`, and ``x`` is an instance of :class:`!C`, calling ``x.f(1)`` is equivalent to calling ``C.f(x, 1)``. When an instance method object is derived from a class method object, the @@ -795,7 +795,7 @@ Classes Classes are callable. These objects normally act as factories for new instances of themselves, but variations are possible for class types that override :meth:`~object.__new__`. The arguments of the call are passed to -:meth:`__new__` and, in the typical case, to :meth:`~object.__init__` to +:meth:`!__new__` and, in the typical case, to :meth:`~object.__init__` to initialize the new instance. @@ -899,9 +899,9 @@ https://www.python.org/download/releases/2.3/mro/. pair: object; dictionary pair: class; attribute -When a class attribute reference (for class :class:`C`, say) would yield a +When a class attribute reference (for class :class:`!C`, say) would yield a class method object, it is transformed into an instance method object whose -:attr:`__self__` attribute is :class:`C`. When it would yield a static +:attr:`__self__` attribute is :class:`!C`. When it would yield a static method object, it is transformed into the object wrapped by the static method object. See section :ref:`descriptors` for another way in which attributes retrieved from a class may differ from those actually contained in its @@ -1903,13 +1903,17 @@ class' :attr:`~object.__dict__`. Called to delete the attribute on an instance *instance* of the owner class. +Instances of descriptors may also have the :attr:`!__objclass__` attribute +present: -The attribute :attr:`__objclass__` is interpreted by the :mod:`inspect` module -as specifying the class where this object was defined (setting this -appropriately can assist in runtime introspection of dynamic class attributes). -For callables, it may indicate that an instance of the given type (or a -subclass) is expected or required as the first positional argument (for example, -CPython sets this attribute for unbound methods that are implemented in C). +.. attribute:: object.__objclass__ + + The attribute :attr:`!__objclass__` is interpreted by the :mod:`inspect` module + as specifying the class where this object was defined (setting this + appropriately can assist in runtime introspection of dynamic class attributes). + For callables, it may indicate that an instance of the given type (or a + subclass) is expected or required as the first positional argument (for example, + CPython sets this attribute for unbound methods that are implemented in C). .. _descriptor-invocation: @@ -1990,13 +1994,14 @@ For instance bindings, the precedence of descriptor invocation depends on which descriptor methods are defined. A descriptor can define any combination of :meth:`~object.__get__`, :meth:`~object.__set__` and :meth:`~object.__delete__`. If it does not -define :meth:`__get__`, then accessing the attribute will return the descriptor +define :meth:`!__get__`, then accessing the attribute will return the descriptor object itself unless there is a value in the object's instance dictionary. If -the descriptor defines :meth:`__set__` and/or :meth:`__delete__`, it is a data +the descriptor defines :meth:`!__set__` and/or :meth:`!__delete__`, it is a data descriptor; if it defines neither, it is a non-data descriptor. Normally, data -descriptors define both :meth:`__get__` and :meth:`__set__`, while non-data -descriptors have just the :meth:`__get__` method. Data descriptors with -:meth:`__get__` and :meth:`__set__` (and/or :meth:`__delete__`) defined always override a redefinition in an +descriptors define both :meth:`!__get__` and :meth:`!__set__`, while non-data +descriptors have just the :meth:`!__get__` method. Data descriptors with +:meth:`!__get__` and :meth:`!__set__` (and/or :meth:`!__delete__`) defined +always override a redefinition in an instance dictionary. In contrast, non-data descriptors can be overridden by instances. @@ -2573,16 +2578,17 @@ either to emulate a sequence or to emulate a mapping; the difference is that for a sequence, the allowable keys should be the integers *k* for which ``0 <= k < N`` where *N* is the length of the sequence, or :class:`slice` objects, which define a range of items. It is also recommended that mappings provide the methods -:meth:`keys`, :meth:`values`, :meth:`items`, :meth:`get`, :meth:`clear`, -:meth:`setdefault`, :meth:`pop`, :meth:`popitem`, :meth:`!copy`, and -:meth:`update` behaving similar to those for Python's standard :class:`dictionary ` +:meth:`!keys`, :meth:`!values`, :meth:`!items`, :meth:`!get`, :meth:`!clear`, +:meth:`!setdefault`, :meth:`!pop`, :meth:`!popitem`, :meth:`!copy`, and +:meth:`!update` behaving similar to those for Python's standard :class:`dictionary ` objects. The :mod:`collections.abc` module provides a :class:`~collections.abc.MutableMapping` :term:`abstract base class` to help create those methods from a base set of -:meth:`~object.__getitem__`, :meth:`~object.__setitem__`, :meth:`~object.__delitem__`, and :meth:`keys`. -Mutable sequences should provide methods :meth:`append`, :meth:`count`, -:meth:`index`, :meth:`extend`, :meth:`insert`, :meth:`pop`, :meth:`remove`, -:meth:`reverse` and :meth:`sort`, like Python standard :class:`list` +:meth:`~object.__getitem__`, :meth:`~object.__setitem__`, +:meth:`~object.__delitem__`, and :meth:`!keys`. +Mutable sequences should provide methods :meth:`!append`, :meth:`!count`, +:meth:`!index`, :meth:`!extend`, :meth:`!insert`, :meth:`!pop`, :meth:`!remove`, +:meth:`!reverse` and :meth:`!sort`, like Python standard :class:`list` objects. Finally, sequence types should implement addition (meaning concatenation) and multiplication (meaning repetition) by defining the methods @@ -2595,7 +2601,7 @@ operator; for mappings, ``in`` should search the mapping's keys; for sequences, it should search through the values. It is further recommended that both mappings and sequences implement the :meth:`~object.__iter__` method to allow efficient iteration -through the container; for mappings, :meth:`__iter__` should iterate +through the container; for mappings, :meth:`!__iter__` should iterate through the object's keys; for sequences, it should iterate through the values. .. method:: object.__len__(self) @@ -3174,7 +3180,7 @@ generators, coroutines do not directly support iteration. to the :meth:`~generator.send` method of the iterator that caused the coroutine to suspend. The result (return value, :exc:`StopIteration`, or other exception) is the same as when - iterating over the :meth:`__await__` return value, described above. + iterating over the :meth:`!__await__` return value, described above. .. method:: coroutine.throw(value) coroutine.throw(type[, value[, traceback]]) From 5aa317e4ca619c3735e1d67b507f01a8e49a4c49 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Tue, 5 Dec 2023 10:44:19 +0000 Subject: [PATCH 51/87] gh-112535: Add comment for ppc32/64 registers (gh-112746) --- Include/object.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Include/object.h b/Include/object.h index dfeb43bda7d8411..85abd30b5ad7d6a 100644 --- a/Include/object.h +++ b/Include/object.h @@ -265,6 +265,7 @@ _Py_ThreadId(void) #if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer) tid = (uintptr_t)__builtin_thread_pointer(); #else + // r13 is reserved for use as system thread ID by the Power 64-bit ABI. register uintptr_t tp __asm__ ("r13"); __asm__("" : "=r" (tp)); tid = tp; @@ -273,6 +274,7 @@ _Py_ThreadId(void) #if defined(__clang__) && _Py__has_builtin(__builtin_thread_pointer) tid = (uintptr_t)__builtin_thread_pointer(); #else + // r2 is reserved for use as system thread ID by the Power 32-bit ABI. register uintptr_t tp __asm__ ("r2"); __asm__ ("" : "=r" (tp)); tid = tp; From 8cdfee1bb902fd1e38d79170b751ef13a0907262 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Tue, 5 Dec 2023 21:30:59 +0800 Subject: [PATCH 52/87] bpo-43153: Don't mask `PermissionError` with `NotADirectoryError` during tempdirectory cleanup (GH-29940) Co-authored-by: andrei kulakov Co-authored-by: Serhiy Storchaka --- Lib/tempfile.py | 28 +++++++++++++++++-- Lib/test/test_tempfile.py | 11 ++++++++ .../2021-12-06-22-10-53.bpo-43153.J7mjSy.rst | 4 +++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-12-06-22-10-53.bpo-43153.J7mjSy.rst diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 2b4f43132471285..55403ad1faf46d8 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -41,6 +41,7 @@ import io as _io import os as _os import shutil as _shutil +import stat as _stat import errno as _errno from random import Random as _Random import sys as _sys @@ -889,8 +890,31 @@ def resetperms(path): try: _os.unlink(path) - # PermissionError is raised on FreeBSD for directories - except (IsADirectoryError, PermissionError): + except IsADirectoryError: + cls._rmtree(path, ignore_errors=ignore_errors) + except PermissionError: + # The PermissionError handler was originally added for + # FreeBSD in directories, but it seems that it is raised + # on Windows too. + # bpo-43153: Calling _rmtree again may + # raise NotADirectoryError and mask the PermissionError. + # So we must re-raise the current PermissionError if + # path is not a directory. + try: + st = _os.lstat(path) + except OSError: + if ignore_errors: + return + raise + if (_stat.S_ISLNK(st.st_mode) or + not _stat.S_ISDIR(st.st_mode) or + (hasattr(st, 'st_file_attributes') and + st.st_file_attributes & _stat.FILE_ATTRIBUTE_REPARSE_POINT and + st.st_reparse_tag == _stat.IO_REPARSE_TAG_MOUNT_POINT) + ): + if ignore_errors: + return + raise cls._rmtree(path, ignore_errors=ignore_errors) except FileNotFoundError: pass diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 1673507e2f7c91f..f4aef887799ed4a 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1641,6 +1641,17 @@ def test_explicit_cleanup_ignore_errors(self): temp_path.exists(), f"TemporaryDirectory {temp_path!s} exists after cleanup") + @unittest.skipUnless(os.name == "nt", "Only on Windows.") + def test_explicit_cleanup_correct_error(self): + with tempfile.TemporaryDirectory() as working_dir: + temp_dir = self.do_create(dir=working_dir) + with open(os.path.join(temp_dir.name, "example.txt"), 'wb'): + # Previously raised NotADirectoryError on some OSes + # (e.g. Windows). See bpo-43153. + with self.assertRaises(PermissionError): + temp_dir.cleanup() + + @os_helper.skip_unless_symlink def test_cleanup_with_symlink_to_a_directory(self): # cleanup() should not follow symlinks to directories (issue #12464) diff --git a/Misc/NEWS.d/next/Library/2021-12-06-22-10-53.bpo-43153.J7mjSy.rst b/Misc/NEWS.d/next/Library/2021-12-06-22-10-53.bpo-43153.J7mjSy.rst new file mode 100644 index 000000000000000..7800e0a4869adff --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-12-06-22-10-53.bpo-43153.J7mjSy.rst @@ -0,0 +1,4 @@ +On Windows, ``tempfile.TemporaryDirectory`` previously masked a +``PermissionError`` with ``NotADirectoryError`` during directory cleanup. It +now correctly raises ``PermissionError`` if errors are not ignored. Patch by +Andrei Kulakov and Ken Jin. From e7e1116a781434763c309b55a31204a98237f7b4 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 5 Dec 2023 05:52:28 -0900 Subject: [PATCH 53/87] gh-105323: Remove `WITH_APPLE_EDITLINE` to use the same declaration for all editline (gh-112513) --- Modules/readline.c | 8 ++------ configure | 17 ----------------- configure.ac | 10 ---------- pyconfig.h.in | 3 --- 4 files changed, 2 insertions(+), 36 deletions(-) diff --git a/Modules/readline.c b/Modules/readline.c index afbb7f8f0ec18f6..e29051c37f88271 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1043,10 +1043,8 @@ on_hook(PyObject *func) static int #if defined(_RL_FUNCTION_TYPEDEF) on_startup_hook(void) -#elif defined(WITH_APPLE_EDITLINE) -on_startup_hook(const char *Py_UNUSED(text), int Py_UNUSED(state)) #else -on_startup_hook(void) +on_startup_hook(const char *Py_UNUSED(text), int Py_UNUSED(state)) #endif { int r; @@ -1065,10 +1063,8 @@ on_startup_hook(void) static int #if defined(_RL_FUNCTION_TYPEDEF) on_pre_input_hook(void) -#elif defined(WITH_APPLE_EDITLINE) -on_pre_input_hook(const char *Py_UNUSED(text), int Py_UNUSED(state)) #else -on_pre_input_hook(void) +on_pre_input_hook(const char *Py_UNUSED(text), int Py_UNUSED(state)) #endif { int r; diff --git a/configure b/configure index 319009537f461c4..8894122a11e86e4 100755 --- a/configure +++ b/configure @@ -23971,7 +23971,6 @@ fi - # Check whether --with-readline was given. if test ${with_readline+y} then : @@ -23994,22 +23993,6 @@ else $as_nop fi -# gh-105323: Need to handle the macOS editline as an alias of readline. -case $ac_sys_system/$ac_sys_release in #( - Darwin/*) : - ac_fn_c_check_type "$LINENO" "Function" "ac_cv_type_Function" "#include -" -if test "x$ac_cv_type_Function" = xyes -then : - printf "%s\n" "#define WITH_APPLE_EDITLINE 1" >>confdefs.h - -fi - ;; #( - *) : - - ;; -esac - if test "x$with_readline" = xreadline then : diff --git a/configure.ac b/configure.ac index b78472e04846b78..1512e6d9e8c42ad 100644 --- a/configure.ac +++ b/configure.ac @@ -5914,7 +5914,6 @@ dnl library (tinfo ncursesw ncurses termcap). We now assume that libreadline dnl or readline.pc provide correct linker information. AH_TEMPLATE([WITH_EDITLINE], [Define to build the readline module against libedit.]) -AH_TEMPLATE([WITH_APPLE_EDITLINE], [Define to build the readline module against Apple BSD editline.]) AC_ARG_WITH( [readline], @@ -5931,15 +5930,6 @@ AC_ARG_WITH( [with_readline=readline] ) -# gh-105323: Need to handle the macOS editline as an alias of readline. -AS_CASE([$ac_sys_system/$ac_sys_release], - [Darwin/*], [AC_CHECK_TYPE([Function], - [AC_DEFINE([WITH_APPLE_EDITLINE])], - [], - [@%:@include ])], - [] -) - AS_VAR_IF([with_readline], [readline], [ PKG_CHECK_MODULES([LIBREADLINE], [readline], [ LIBREADLINE=readline diff --git a/pyconfig.h.in b/pyconfig.h.in index bf708926e22c435..2978fa2c17301f0 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1800,9 +1800,6 @@ /* Define if WINDOW in curses.h offers a field _flags. */ #undef WINDOW_HAS_FLAGS -/* Define to build the readline module against Apple BSD editline. */ -#undef WITH_APPLE_EDITLINE - /* Define if you want build the _decimal module using a coroutine-local rather than a thread-local context */ #undef WITH_DECIMAL_CONTEXTVAR From bc68f4a4abcfbea60bb1db1ccadb07613561931c Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Tue, 5 Dec 2023 15:07:50 +0000 Subject: [PATCH 54/87] gh-110190: Fix ctypes structs with array on Arm (#112604) Set MAX_STRUCT_SIZE to 32 in stgdict.c when on Arm platforms. This because on Arm platforms structs with at most 4 elements of any floating point type values can be passed through registers. If the type is double the maximum size of the struct is 32 bytes. On x86-64 Linux, it's maximum 16 bytes hence we need to differentiate. --- Lib/test/test_ctypes/test_structures.py | 123 +++++++++++++++++- ...-12-01-18-05-09.gh-issue-110190.5bf-c9.rst | 1 + Modules/_ctypes/_ctypes_test.c | 36 +++++ Modules/_ctypes/stgdict.c | 53 +++++--- 4 files changed, 193 insertions(+), 20 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-01-18-05-09.gh-issue-110190.5bf-c9.rst diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index f05ee5e491a41e3..771205ffb32ecca 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -2,7 +2,7 @@ import struct import sys import unittest -from ctypes import (CDLL, Structure, Union, POINTER, sizeof, byref, alignment, +from ctypes import (CDLL, Array, Structure, Union, POINTER, sizeof, byref, alignment, c_void_p, c_char, c_wchar, c_byte, c_ubyte, c_uint8, c_uint16, c_uint32, c_short, c_ushort, c_int, c_uint, @@ -494,12 +494,59 @@ class Test3B(Test3A): ('more_data', c_float * 2), ] + class Test3C1(Structure): + _fields_ = [ + ("data", c_double * 4) + ] + + class DataType4(Array): + _type_ = c_double + _length_ = 4 + + class Test3C2(Structure): + _fields_ = [ + ("data", DataType4) + ] + + class Test3C3(Structure): + _fields_ = [ + ("x", c_double), + ("y", c_double), + ("z", c_double), + ("t", c_double) + ] + + class Test3D1(Structure): + _fields_ = [ + ("data", c_double * 5) + ] + + class DataType5(Array): + _type_ = c_double + _length_ = 5 + + class Test3D2(Structure): + _fields_ = [ + ("data", DataType5) + ] + + class Test3D3(Structure): + _fields_ = [ + ("x", c_double), + ("y", c_double), + ("z", c_double), + ("t", c_double), + ("u", c_double) + ] + + # Load the shared library + dll = CDLL(_ctypes_test.__file__) + s = Test2() expected = 0 for i in range(16): s.data[i] = i expected += i - dll = CDLL(_ctypes_test.__file__) func = dll._testfunc_array_in_struct1 func.restype = c_int func.argtypes = (Test2,) @@ -540,6 +587,78 @@ class Test3B(Test3A): self.assertAlmostEqual(s.more_data[0], -3.0, places=6) self.assertAlmostEqual(s.more_data[1], -2.0, places=6) + # Tests for struct Test3C + expected = (1.0, 2.0, 3.0, 4.0) + func = dll._testfunc_array_in_struct_set_defaults_3C + func.restype = Test3C1 + result = func() + # check the default values have been set properly + self.assertEqual( + (result.data[0], + result.data[1], + result.data[2], + result.data[3]), + expected + ) + + func = dll._testfunc_array_in_struct_set_defaults_3C + func.restype = Test3C2 + result = func() + # check the default values have been set properly + self.assertEqual( + (result.data[0], + result.data[1], + result.data[2], + result.data[3]), + expected + ) + + func = dll._testfunc_array_in_struct_set_defaults_3C + func.restype = Test3C3 + result = func() + # check the default values have been set properly + self.assertEqual((result.x, result.y, result.z, result.t), expected) + + # Tests for struct Test3D + expected = (1.0, 2.0, 3.0, 4.0, 5.0) + func = dll._testfunc_array_in_struct_set_defaults_3D + func.restype = Test3D1 + result = func() + # check the default values have been set properly + self.assertEqual( + (result.data[0], + result.data[1], + result.data[2], + result.data[3], + result.data[4]), + expected + ) + + func = dll._testfunc_array_in_struct_set_defaults_3D + func.restype = Test3D2 + result = func() + # check the default values have been set properly + self.assertEqual( + (result.data[0], + result.data[1], + result.data[2], + result.data[3], + result.data[4]), + expected + ) + + func = dll._testfunc_array_in_struct_set_defaults_3D + func.restype = Test3D3 + result = func() + # check the default values have been set properly + self.assertEqual( + (result.x, + result.y, + result.z, + result.t, + result.u), + expected) + def test_38368(self): class U(Union): _fields_ = [ diff --git a/Misc/NEWS.d/next/Library/2023-12-01-18-05-09.gh-issue-110190.5bf-c9.rst b/Misc/NEWS.d/next/Library/2023-12-01-18-05-09.gh-issue-110190.5bf-c9.rst new file mode 100644 index 000000000000000..730b9d491198052 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-01-18-05-09.gh-issue-110190.5bf-c9.rst @@ -0,0 +1 @@ +Fix ctypes structs with array on Arm platform by setting ``MAX_STRUCT_SIZE`` to 32 in stgdict. Patch by Diego Russo. diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index d33e6fc7586d286..fc9fc131f6249a6 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -150,6 +150,42 @@ _testfunc_array_in_struct2a(Test3B in) return result; } +/* + * See gh-110190. structs containing arrays of up to four floating point types + * (max 32 bytes) are passed in registers on Arm. + */ + +typedef struct { + double data[4]; +} Test3C; + +EXPORT(Test3C) +_testfunc_array_in_struct_set_defaults_3C(void) +{ + Test3C s; + s.data[0] = 1.0; + s.data[1] = 2.0; + s.data[2] = 3.0; + s.data[3] = 4.0; + return s; +} + +typedef struct { + double data[5]; +} Test3D; + +EXPORT(Test3D) +_testfunc_array_in_struct_set_defaults_3D(void) +{ + Test3D s; + s.data[0] = 1.0; + s.data[1] = 2.0; + s.data[2] = 3.0; + s.data[3] = 4.0; + s.data[4] = 5.0; + return s; +} + typedef union { long a_long; struct { diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c index 6fbcf77a115371d..04dd9bae32cd5ee 100644 --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -697,29 +697,43 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct stgdict->align = total_align; stgdict->length = len; /* ADD ffi_ofs? */ -#define MAX_STRUCT_SIZE 16 +/* + * On Arm platforms, structs with at most 4 elements of any floating point + * type values can be passed through registers. If the type is double the + * maximum size of the struct is 32 bytes. + * By Arm platforms it is meant both 32 and 64-bit. +*/ +#if defined(__aarch64__) || defined(__arm__) +# define MAX_STRUCT_SIZE 32 +#else +# define MAX_STRUCT_SIZE 16 +#endif if (arrays_seen && (size <= MAX_STRUCT_SIZE)) { /* - * See bpo-22273. Arrays are normally treated as pointers, which is - * fine when an array name is being passed as parameter, but not when - * passing structures by value that contain arrays. On 64-bit Linux, - * small structures passed by value are passed in registers, and in - * order to do this, libffi needs to know the true type of the array - * members of structs. Treating them as pointers breaks things. + * See bpo-22273 and gh-110190. Arrays are normally treated as + * pointers, which is fine when an array name is being passed as + * parameter, but not when passing structures by value that contain + * arrays. + * On x86_64 Linux and Arm platforms, small structures passed by + * value are passed in registers, and in order to do this, libffi needs + * to know the true type of the array members of structs. Treating them + * as pointers breaks things. * - * By small structures, we mean ones that are 16 bytes or less. In that - * case, there can't be more than 16 elements after unrolling arrays, - * as we (will) disallow bitfields. So we can collect the true ffi_type - * values in a fixed-size local array on the stack and, if any arrays - * were seen, replace the ffi_type_pointer.elements with a more - * accurate set, to allow libffi to marshal them into registers - * correctly. It means one more loop over the fields, but if we got - * here, the structure is small, so there aren't too many of those. + * By small structures, we mean ones that are 16 bytes or less on + * x86-64 and 32 bytes or less on Arm. In that case, there can't be + * more than 16 or 32 elements after unrolling arrays, as we (will) + * disallow bitfields. So we can collect the true ffi_type values in + * a fixed-size local array on the stack and, if any arrays were seen, + * replace the ffi_type_pointer.elements with a more accurate set, + * to allow libffi to marshal them into registers correctly. + * It means one more loop over the fields, but if we got here, + * the structure is small, so there aren't too many of those. * - * Although the passing in registers is specific to 64-bit Linux, the - * array-in-struct vs. pointer problem is general. But we restrict the - * type transformation to small structs nonetheless. + * Although the passing in registers is specific to x86_64 Linux + * and Arm platforms, the array-in-struct vs. pointer problem is + * general. But we restrict the type transformation to small structs + * nonetheless. * * Note that although a union may be small in terms of memory usage, it * could contain many overlapping declarations of arrays, e.g. @@ -745,6 +759,9 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct * struct { uint_32 e1; uint_32 e2; ... uint_32 e_4; } f6; * } * + * The same principle applies for a struct 32 bytes in size like in + * the case of Arm platforms. + * * So the struct/union needs setting up as follows: all non-array * elements copied across as is, and all array elements replaced with * an equivalent struct which has as many fields as the array has From 563ccded6e83bfdd8c5622663c4edb679e96e08b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 5 Dec 2023 17:40:49 +0200 Subject: [PATCH 55/87] gh-94692: Only catch OSError in shutil.rmtree() (#112756) Previously a symlink attack resistant version of shutil.rmtree() could ignore or pass to the error handler arbitrary exception when invalid arguments were provided. --- Lib/shutil.py | 4 +-- Lib/test/test_shutil.py | 33 +++++++++---------- ...3-12-05-16-20-40.gh-issue-94692.-e5C3c.rst | 4 +++ 3 files changed, 22 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-05-16-20-40.gh-issue-94692.-e5C3c.rst diff --git a/Lib/shutil.py b/Lib/shutil.py index 93b00d73a0fd467..bdbbcbc282e266b 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -768,13 +768,13 @@ def onexc(*args): # lstat()/open()/fstat() trick. try: orig_st = os.lstat(path, dir_fd=dir_fd) - except Exception as err: + except OSError 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 as err: + except OSError as err: onexc(os.open, path, err) return try: diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 7ea2496230da476..9b8ec42a99dd692 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -317,7 +317,7 @@ def test_rmtree_works_on_junctions(self): self.assertTrue(os.path.exists(dir3)) self.assertTrue(os.path.exists(file1)) - def test_rmtree_errors_onerror(self): + def test_rmtree_errors(self): # filename is guaranteed not to exist filename = tempfile.mktemp(dir=self.mkdtemp()) self.assertRaises(FileNotFoundError, shutil.rmtree, filename) @@ -326,8 +326,8 @@ def test_rmtree_errors_onerror(self): # existing file tmpdir = self.mkdtemp() - write_file((tmpdir, "tstfile"), "") filename = os.path.join(tmpdir, "tstfile") + write_file(filename, "") with self.assertRaises(NotADirectoryError) as cm: shutil.rmtree(filename) self.assertEqual(cm.exception.filename, filename) @@ -335,6 +335,19 @@ def test_rmtree_errors_onerror(self): # test that ignore_errors option is honored shutil.rmtree(filename, ignore_errors=True) self.assertTrue(os.path.exists(filename)) + + self.assertRaises(TypeError, shutil.rmtree, None) + self.assertRaises(TypeError, shutil.rmtree, None, ignore_errors=True) + exc = TypeError if shutil.rmtree.avoids_symlink_attacks else NotImplementedError + with self.assertRaises(exc): + shutil.rmtree(filename, dir_fd='invalid') + with self.assertRaises(exc): + shutil.rmtree(filename, dir_fd='invalid', ignore_errors=True) + + def test_rmtree_errors_onerror(self): + tmpdir = self.mkdtemp() + filename = os.path.join(tmpdir, "tstfile") + write_file(filename, "") errors = [] def onerror(*args): errors.append(args) @@ -350,23 +363,9 @@ def onerror(*args): 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)) + write_file(filename, "") errors = [] def onexc(*args): errors.append(args) diff --git a/Misc/NEWS.d/next/Library/2023-12-05-16-20-40.gh-issue-94692.-e5C3c.rst b/Misc/NEWS.d/next/Library/2023-12-05-16-20-40.gh-issue-94692.-e5C3c.rst new file mode 100644 index 000000000000000..c67ba6c9ececdb1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-05-16-20-40.gh-issue-94692.-e5C3c.rst @@ -0,0 +1,4 @@ +:func:`shutil.rmtree` now only catches OSError exceptions. Previously a +symlink attack resistant version of ``shutil.rmtree()`` could ignore or pass +to the error handler arbitrary exception when invalid arguments were +provided. From de6bca956432cc852a4a41e2a2cee9cdacd19f35 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Tue, 5 Dec 2023 08:27:36 -0800 Subject: [PATCH 56/87] gh-112328: [Enum] Make some private attributes public. (GH-112514) * [Enum] Make some private attributes public. - ``_EnumDict`` --> ``EnumDict`` - ``EnumDict._member_names`` --> ``EnumDict.member_names`` - ``Enum._add_alias_`` - ``Enum._add_value_alias_`` --------- Co-authored-by: Alex Waygood Co-authored-by: Nikita Sobolev --- Doc/howto/enum.rst | 67 ++++-- Doc/library/enum.rst | 60 ++++-- Lib/enum.py | 203 +++++++++++------- Lib/test/test_enum.py | 86 +++++++- ...-11-28-20-47-39.gh-issue-112328.Z2AxEY.rst | 2 + 5 files changed, 301 insertions(+), 117 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-11-28-20-47-39.gh-issue-112328.Z2AxEY.rst diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst index ffdafb749c73a92..1e9ac9b6761b647 100644 --- a/Doc/howto/enum.rst +++ b/Doc/howto/enum.rst @@ -868,7 +868,7 @@ Others While :class:`IntEnum` is part of the :mod:`enum` module, it would be very simple to implement independently:: - class IntEnum(int, Enum): + class IntEnum(int, ReprEnum): # or Enum instead of ReprEnum pass This demonstrates how similar derived enumerations can be defined; for example @@ -876,8 +876,8 @@ a :class:`FloatEnum` that mixes in :class:`float` instead of :class:`int`. Some rules: -1. When subclassing :class:`Enum`, mix-in types must appear before - :class:`Enum` itself in the sequence of bases, as in the :class:`IntEnum` +1. When subclassing :class:`Enum`, mix-in types must appear before the + :class:`Enum` class itself in the sequence of bases, as in the :class:`IntEnum` example above. 2. Mix-in types must be subclassable. For example, :class:`bool` and :class:`range` are not subclassable and will throw an error during Enum @@ -961,30 +961,34 @@ all the members are created it is no longer used. Supported ``_sunder_`` names """""""""""""""""""""""""""" -- ``_name_`` -- name of the member -- ``_value_`` -- value of the member; can be set / modified in ``__new__`` +- :attr:`~Enum._name_` -- name of the member +- :attr:`~Enum._value_` -- value of the member; can be set in ``__new__`` +- :meth:`~Enum._missing_` -- a lookup function used when a value is not found; + may be overridden +- :attr:`~Enum._ignore_` -- a list of names, either as a :class:`list` or a + :class:`str`, that will not be transformed into members, and will be removed + from the final class +- :meth:`~Enum._generate_next_value_` -- used to get an appropriate value for + an enum member; may be overridden +- :meth:`~Enum._add_alias_` -- adds a new name as an alias to an existing + member. +- :meth:`~Enum._add_value_alias_` -- adds a new value as an alias to an + existing member. See `MultiValueEnum`_ for an example. -- ``_missing_`` -- a lookup function used when a value is not found; may be - overridden -- ``_ignore_`` -- a list of names, either as a :class:`list` or a :class:`str`, - that will not be transformed into members, and will be removed from the final - class -- ``_order_`` -- used in Python 2/3 code to ensure member order is consistent - (class attribute, removed during class creation) -- ``_generate_next_value_`` -- used by the `Functional API`_ and by - :class:`auto` to get an appropriate value for an enum member; may be - overridden + .. note:: -.. note:: + For standard :class:`Enum` classes the next value chosen is the highest + value seen incremented by one. - For standard :class:`Enum` classes the next value chosen is the last value seen - incremented by one. + For :class:`Flag` classes the next value chosen will be the next highest + power-of-two. - For :class:`Flag` classes the next value chosen will be the next highest - power-of-two, regardless of the last value seen. + .. versionchanged:: 3.13 + Prior versions would use the last seen value instead of the highest value. .. versionadded:: 3.6 ``_missing_``, ``_order_``, ``_generate_next_value_`` .. versionadded:: 3.7 ``_ignore_`` +.. versionadded:: 3.13 ``_add_alias_``, ``_add_value_alias_`` To help keep Python 2 / Python 3 code in sync an :attr:`_order_` attribute can be provided. It will be checked against the actual order of the enumeration @@ -1447,6 +1451,29 @@ alias:: disallowing aliases, the :func:`unique` decorator can be used instead. +MultiValueEnum +^^^^^^^^^^^^^^^^^ + +Supports having more than one value per member:: + + >>> class MultiValueEnum(Enum): + ... def __new__(cls, value, *values): + ... self = object.__new__(cls) + ... self._value_ = value + ... for v in values: + ... self._add_value_alias_(v) + ... return self + ... + >>> class DType(MultiValueEnum): + ... float32 = 'f', 8 + ... double64 = 'd', 9 + ... + >>> DType('f') + + >>> DType(9) + + + Planet ^^^^^^ diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index 2d5ae361c3f1e3a..20222bfb3611ab9 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -235,6 +235,10 @@ Data Types >>> len(Color) 3 + .. attribute:: EnumType.__members__ + + Returns a mapping of every enum name to its member, including aliases + .. method:: EnumType.__reversed__(cls) Returns each member in *cls* in reverse definition order:: @@ -242,9 +246,19 @@ Data Types >>> list(reversed(Color)) [, , ] + .. method:: EnumType._add_alias_ + + Adds a new name as an alias to an existing member. Raises a + :exc:`NameError` if the name is already assigned to a different member. + + .. method:: EnumType._add_value_alias_ + + Adds a new value as an alias to an existing member. Raises a + :exc:`ValueError` if the value is already linked with a different member. + .. versionadded:: 3.11 - Before 3.11 ``enum`` used ``EnumMeta`` type, which is kept as an alias. + Before 3.11 ``EnumType`` was called ``EnumMeta``, which is still available as an alias. .. class:: Enum @@ -323,7 +337,7 @@ Data Types >>> PowersOfThree.SECOND.value 9 - .. method:: Enum.__init_subclass__(cls, **kwds) + .. method:: Enum.__init_subclass__(cls, \**kwds) A *classmethod* that is used to further configure subsequent subclasses. By default, does nothing. @@ -549,7 +563,7 @@ Data Types .. method:: __invert__(self): - Returns all the flags in *type(self)* that are not in self:: + Returns all the flags in *type(self)* that are not in *self*:: >>> ~white @@ -769,37 +783,41 @@ Supported ``__dunder__`` names :attr:`~EnumType.__members__` is a read-only ordered mapping of ``member_name``:``member`` items. It is only available on the class. -:meth:`~object.__new__`, if specified, must create and return the enum members; it is -also a very good idea to set the member's :attr:`!_value_` appropriately. Once -all the members are created it is no longer used. +:meth:`~object.__new__`, if specified, must create and return the enum members; +it is also a very good idea to set the member's :attr:`!_value_` appropriately. +Once all the members are created it is no longer used. Supported ``_sunder_`` names """""""""""""""""""""""""""" -- ``_name_`` -- name of the member -- ``_value_`` -- value of the member; can be set / modified in ``__new__`` - -- ``_missing_`` -- a lookup function used when a value is not found; may be - overridden -- ``_ignore_`` -- a list of names, either as a :class:`list` or a :class:`str`, - that will not be transformed into members, and will be removed from the final - class -- ``_order_`` -- used in Python 2/3 code to ensure member order is consistent - (class attribute, removed during class creation) -- ``_generate_next_value_`` -- used to get an appropriate value for an enum - member; may be overridden +- :meth:`~EnumType._add_alias_` -- adds a new name as an alias to an existing + member. +- :meth:`~EnumType._add_value_alias_` -- adds a new value as an alias to an + existing member. +- :attr:`~Enum._name_` -- name of the member +- :attr:`~Enum._value_` -- value of the member; can be set in ``__new__`` +- :meth:`~Enum._missing_` -- a lookup function used when a value is not found; + may be overridden +- :attr:`~Enum._ignore_` -- a list of names, either as a :class:`list` or a + :class:`str`, that will not be transformed into members, and will be removed + from the final class +- :attr:`~Enum._order_` -- used in Python 2/3 code to ensure member order is + consistent (class attribute, removed during class creation) +- :meth:`~Enum._generate_next_value_` -- used to get an appropriate value for + an enum member; may be overridden .. note:: - For standard :class:`Enum` classes the next value chosen is the last value seen - incremented by one. + For standard :class:`Enum` classes the next value chosen is the highest + value seen incremented by one. For :class:`Flag` classes the next value chosen will be the next highest - power-of-two, regardless of the last value seen. + power-of-two. .. versionadded:: 3.6 ``_missing_``, ``_order_``, ``_generate_next_value_`` .. versionadded:: 3.7 ``_ignore_`` +.. versionadded:: 3.13 ``_add_alias_``, ``_add_value_alias_`` --------------- diff --git a/Lib/enum.py b/Lib/enum.py index 648401e80be685b..a8a50a583803758 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -4,7 +4,7 @@ __all__ = [ - 'EnumType', 'EnumMeta', + 'EnumType', 'EnumMeta', 'EnumDict', 'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag', 'ReprEnum', 'auto', 'unique', 'property', 'verify', 'member', 'nonmember', 'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP', @@ -313,45 +313,8 @@ def __set_name__(self, enum_class, member_name): ): # no other instances found, record this member in _member_names_ enum_class._member_names_.append(member_name) - # if necessary, get redirect in place and then add it to _member_map_ - found_descriptor = None - descriptor_type = None - class_type = None - for base in enum_class.__mro__[1:]: - attr = base.__dict__.get(member_name) - if attr is not None: - if isinstance(attr, (property, DynamicClassAttribute)): - found_descriptor = attr - class_type = base - descriptor_type = 'enum' - break - elif _is_descriptor(attr): - found_descriptor = attr - descriptor_type = descriptor_type or 'desc' - class_type = class_type or base - continue - else: - descriptor_type = 'attr' - class_type = base - if found_descriptor: - redirect = property() - redirect.member = enum_member - redirect.__set_name__(enum_class, member_name) - if descriptor_type in ('enum','desc'): - # earlier descriptor found; copy fget, fset, fdel to this one. - redirect.fget = getattr(found_descriptor, 'fget', None) - redirect._get = getattr(found_descriptor, '__get__', None) - redirect.fset = getattr(found_descriptor, 'fset', None) - redirect._set = getattr(found_descriptor, '__set__', None) - redirect.fdel = getattr(found_descriptor, 'fdel', None) - redirect._del = getattr(found_descriptor, '__delete__', None) - redirect._attr_type = descriptor_type - redirect._cls_type = class_type - setattr(enum_class, member_name, redirect) - else: - setattr(enum_class, member_name, enum_member) - # now add to _member_map_ (even aliases) - enum_class._member_map_[member_name] = enum_member + + enum_class._add_member_(member_name, enum_member) try: # This may fail if value is not hashable. We can't add the value # to the map, and by-value lookups for this value will be @@ -360,9 +323,10 @@ def __set_name__(self, enum_class, member_name): except TypeError: # keep track of the value in a list so containment checks are quick enum_class._unhashable_values_.append(value) + enum_class._unhashable_values_map_.setdefault(member_name, []).append(value) -class _EnumDict(dict): +class EnumDict(dict): """ Track enum member order and ensure member names are not reused. @@ -371,7 +335,7 @@ class _EnumDict(dict): """ def __init__(self): super().__init__() - self._member_names = {} # use a dict to keep insertion order + self._member_names = {} # use a dict -- faster look-up than a list, and keeps insertion order since 3.7 self._last_values = [] self._ignore = [] self._auto_called = False @@ -393,6 +357,7 @@ def __setitem__(self, key, value): '_order_', '_generate_next_value_', '_numeric_repr_', '_missing_', '_ignore_', '_iter_member_', '_iter_member_by_value_', '_iter_member_by_def_', + '_add_alias_', '_add_value_alias_', ): raise ValueError( '_sunder_ names, such as %r, are reserved for future Enum use' @@ -468,6 +433,10 @@ def __setitem__(self, key, value): self._last_values.append(value) super().__setitem__(key, value) + @property + def member_names(self): + return list(self._member_names) + def update(self, members, **more_members): try: for name in members.keys(): @@ -478,6 +447,8 @@ def update(self, members, **more_members): for name, value in more_members.items(): self[name] = value +_EnumDict = EnumDict # keep private name for backwards compatibility + class EnumType(type): """ @@ -489,7 +460,7 @@ def __prepare__(metacls, cls, bases, **kwds): # check that previous enum members do not exist metacls._check_for_existing_members_(cls, bases) # create the namespace dict - enum_dict = _EnumDict() + enum_dict = EnumDict() enum_dict._cls_name = cls # inherit previous flags and _generate_next_value_ function member_type, first_enum = metacls._get_mixins_(cls, bases) @@ -552,6 +523,7 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k classdict['_member_map_'] = {} classdict['_value2member_map_'] = {} classdict['_unhashable_values_'] = [] + classdict['_unhashable_values_map_'] = {} classdict['_member_type_'] = member_type # now set the __repr__ for the value classdict['_value_repr_'] = metacls._find_data_repr_(cls, bases) @@ -754,7 +726,10 @@ def __contains__(cls, value): """ if isinstance(value, cls): return True - return value in cls._value2member_map_ or value in cls._unhashable_values_ + try: + return value in cls._value2member_map_ + except TypeError: + return value in cls._unhashable_values_ def __delattr__(cls, attr): # nicer error message when someone tries to delete an attribute @@ -1050,7 +1025,57 @@ def _find_new_(mcls, classdict, member_type, first_enum): else: use_args = True return __new__, save_new, use_args -EnumMeta = EnumType + + def _add_member_(cls, name, member): + # _value_ structures are not updated + if name in cls._member_map_: + if cls._member_map_[name] is not member: + raise NameError('%r is already bound: %r' % (name, cls._member_map_[name])) + return + # + # if necessary, get redirect in place and then add it to _member_map_ + found_descriptor = None + descriptor_type = None + class_type = None + for base in cls.__mro__[1:]: + attr = base.__dict__.get(name) + if attr is not None: + if isinstance(attr, (property, DynamicClassAttribute)): + found_descriptor = attr + class_type = base + descriptor_type = 'enum' + break + elif _is_descriptor(attr): + found_descriptor = attr + descriptor_type = descriptor_type or 'desc' + class_type = class_type or base + continue + else: + descriptor_type = 'attr' + class_type = base + if found_descriptor: + redirect = property() + redirect.member = member + redirect.__set_name__(cls, name) + if descriptor_type in ('enum', 'desc'): + # earlier descriptor found; copy fget, fset, fdel to this one. + redirect.fget = getattr(found_descriptor, 'fget', None) + redirect._get = getattr(found_descriptor, '__get__', None) + redirect.fset = getattr(found_descriptor, 'fset', None) + redirect._set = getattr(found_descriptor, '__set__', None) + redirect.fdel = getattr(found_descriptor, 'fdel', None) + redirect._del = getattr(found_descriptor, '__delete__', None) + redirect._attr_type = descriptor_type + redirect._cls_type = class_type + setattr(cls, name, redirect) + else: + setattr(cls, name, member) + # now add to _member_map_ (even aliases) + cls._member_map_[name] = member + # + cls._member_map_[name] = member + +EnumMeta = EnumType # keep EnumMeta name for backwards compatibility class Enum(metaclass=EnumType): @@ -1116,9 +1141,9 @@ def __new__(cls, value): pass except TypeError: # not there, now do long search -- O(n) behavior - for member in cls._member_map_.values(): - if member._value_ == value: - return member + for name, values in cls._unhashable_values_map_.items(): + if value in values: + return cls[name] # still not found -- verify that members exist, in-case somebody got here mistakenly # (such as via super when trying to override __new__) if not cls._member_map_: @@ -1159,6 +1184,33 @@ def __new__(cls, value): def __init__(self, *args, **kwds): pass + def _add_alias_(self, name): + self.__class__._add_member_(name, self) + + def _add_value_alias_(self, value): + cls = self.__class__ + try: + if value in cls._value2member_map_: + if cls._value2member_map_[value] is not self: + raise ValueError('%r is already bound: %r' % (value, cls._value2member_map_[value])) + return + except TypeError: + # unhashable value, do long search + for m in cls._member_map_.values(): + if m._value_ == value: + if m is not self: + raise ValueError('%r is already bound: %r' % (value, cls._value2member_map_[value])) + return + try: + # This may fail if value is not hashable. We can't add the value + # to the map, and by-value lookups for this value will be + # linear. + cls._value2member_map_.setdefault(value, self) + except TypeError: + # keep track of the value in a list so containment checks are quick + cls._unhashable_values_.append(value) + cls._unhashable_values_map_.setdefault(self.name, []).append(value) + @staticmethod def _generate_next_value_(name, start, count, last_values): """ @@ -1671,7 +1723,8 @@ def convert_class(cls): body['_member_names_'] = member_names = [] body['_member_map_'] = member_map = {} body['_value2member_map_'] = value2member_map = {} - body['_unhashable_values_'] = [] + body['_unhashable_values_'] = unhashable_values = [] + body['_unhashable_values_map_'] = {} body['_member_type_'] = member_type = etype._member_type_ body['_value_repr_'] = etype._value_repr_ if issubclass(etype, Flag): @@ -1718,14 +1771,9 @@ def convert_class(cls): for name, value in attrs.items(): if isinstance(value, auto) and auto.value is _auto_null: value = gnv(name, 1, len(member_names), gnv_last_values) - if value in value2member_map: + if value in value2member_map or value in unhashable_values: # an alias to an existing member - member = value2member_map[value] - redirect = property() - redirect.member = member - redirect.__set_name__(enum_class, name) - setattr(enum_class, name, redirect) - member_map[name] = member + enum_class(value)._add_alias_(name) else: # create the member if use_args: @@ -1740,12 +1788,12 @@ def convert_class(cls): member._name_ = name member.__objclass__ = enum_class member.__init__(value) - redirect = property() - redirect.member = member - redirect.__set_name__(enum_class, name) - setattr(enum_class, name, redirect) - member_map[name] = member member._sort_order_ = len(member_names) + if name not in ('name', 'value'): + setattr(enum_class, name, member) + member_map[name] = member + else: + enum_class._add_member_(name, member) value2member_map[value] = member if _is_single_bit(value): # not a multi-bit alias, record in _member_names_ and _flag_mask_ @@ -1768,14 +1816,13 @@ def convert_class(cls): if value.value is _auto_null: value.value = gnv(name, 1, len(member_names), gnv_last_values) value = value.value - if value in value2member_map: + try: + contained = value in value2member_map + except TypeError: + contained = value in unhashable_values + if contained: # an alias to an existing member - member = value2member_map[value] - redirect = property() - redirect.member = member - redirect.__set_name__(enum_class, name) - setattr(enum_class, name, redirect) - member_map[name] = member + enum_class(value)._add_alias_(name) else: # create the member if use_args: @@ -1791,14 +1838,22 @@ def convert_class(cls): member.__objclass__ = enum_class member.__init__(value) member._sort_order_ = len(member_names) - redirect = property() - redirect.member = member - redirect.__set_name__(enum_class, name) - setattr(enum_class, name, redirect) - member_map[name] = member - value2member_map[value] = member + if name not in ('name', 'value'): + setattr(enum_class, name, member) + member_map[name] = member + else: + enum_class._add_member_(name, member) member_names.append(name) gnv_last_values.append(value) + try: + # This may fail if value is not hashable. We can't add the value + # to the map, and by-value lookups for this value will be + # linear. + enum_class._value2member_map_.setdefault(value, member) + except TypeError: + # keep track of the value in a list so containment checks are quick + enum_class._unhashable_values_.append(value) + enum_class._unhashable_values_map_.setdefault(name, []).append(value) if '__new__' in body: enum_class.__new_member__ = enum_class.__new__ enum_class.__new__ = Enum.__new__ diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index c602913ca692777..f99d4ca204b5a7e 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -514,6 +514,7 @@ def test_contains_tf(self): self.assertFalse('first' in MainEnum) val = MainEnum.dupe self.assertIn(val, MainEnum) + self.assertNotIn(float('nan'), MainEnum) # class OtherEnum(Enum): one = auto() @@ -3268,6 +3269,65 @@ def __new__(cls, value): member._value_ = Base(value) return member + def test_extra_member_creation(self): + class IDEnumMeta(EnumMeta): + def __new__(metacls, cls, bases, classdict, **kwds): + # add new entries to classdict + for name in classdict.member_names: + classdict[f'{name}_DESC'] = f'-{classdict[name]}' + return super().__new__(metacls, cls, bases, classdict, **kwds) + class IDEnum(StrEnum, metaclass=IDEnumMeta): + pass + class MyEnum(IDEnum): + ID = 'id' + NAME = 'name' + self.assertEqual(list(MyEnum), [MyEnum.ID, MyEnum.NAME, MyEnum.ID_DESC, MyEnum.NAME_DESC]) + + def test_add_alias(self): + class mixin: + @property + def ORG(self): + return 'huh' + class Color(mixin, Enum): + RED = 1 + GREEN = 2 + BLUE = 3 + Color.RED._add_alias_('ROJO') + self.assertIs(Color.RED, Color['ROJO']) + self.assertIs(Color.RED, Color.ROJO) + Color.BLUE._add_alias_('ORG') + self.assertIs(Color.BLUE, Color['ORG']) + self.assertIs(Color.BLUE, Color.ORG) + self.assertEqual(Color.RED.ORG, 'huh') + self.assertEqual(Color.GREEN.ORG, 'huh') + self.assertEqual(Color.BLUE.ORG, 'huh') + self.assertEqual(Color.ORG.ORG, 'huh') + + def test_add_value_alias_after_creation(self): + class Color(Enum): + RED = 1 + GREEN = 2 + BLUE = 3 + Color.RED._add_value_alias_(5) + self.assertIs(Color.RED, Color(5)) + + def test_add_value_alias_during_creation(self): + class Types(Enum): + Unknown = 0, + Source = 1, 'src' + NetList = 2, 'nl' + def __new__(cls, int_value, *value_aliases): + member = object.__new__(cls) + member._value_ = int_value + for alias in value_aliases: + member._add_value_alias_(alias) + return member + self.assertIs(Types(0), Types.Unknown) + self.assertIs(Types(1), Types.Source) + self.assertIs(Types('src'), Types.Source) + self.assertIs(Types(2), Types.NetList) + self.assertIs(Types('nl'), Types.NetList) + class TestOrder(unittest.TestCase): "test usage of the `_order_` attribute" @@ -4941,12 +5001,14 @@ class CheckedColor(Enum): @bltns.property def zeroth(self): return 'zeroed %s' % self.name - self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None) + _test_simple_enum(CheckedColor, SimpleColor) SimpleColor.MAGENTA._value_ = 9 self.assertRaisesRegex( TypeError, "enum mismatch", _test_simple_enum, CheckedColor, SimpleColor, ) + # + # class CheckedMissing(IntFlag, boundary=KEEP): SIXTY_FOUR = 64 ONE_TWENTY_EIGHT = 128 @@ -4963,8 +5025,28 @@ class Missing: ALL = 2048 + 128 + 64 + 12 M = Missing self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT]) - # _test_simple_enum(CheckedMissing, Missing) + # + # + class CheckedUnhashable(Enum): + ONE = dict() + TWO = set() + name = 'python' + self.assertIn(dict(), CheckedUnhashable) + self.assertIn('python', CheckedUnhashable) + self.assertEqual(CheckedUnhashable.name.value, 'python') + self.assertEqual(CheckedUnhashable.name.name, 'name') + # + @_simple_enum() + class Unhashable: + ONE = dict() + TWO = set() + name = 'python' + self.assertIn(dict(), Unhashable) + self.assertIn('python', Unhashable) + self.assertEqual(Unhashable.name.value, 'python') + self.assertEqual(Unhashable.name.name, 'name') + _test_simple_enum(Unhashable, Unhashable) class MiscTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-11-28-20-47-39.gh-issue-112328.Z2AxEY.rst b/Misc/NEWS.d/next/Library/2023-11-28-20-47-39.gh-issue-112328.Z2AxEY.rst new file mode 100644 index 000000000000000..6e6902486b7bc98 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-11-28-20-47-39.gh-issue-112328.Z2AxEY.rst @@ -0,0 +1,2 @@ +[Enum] Make ``EnumDict``, ``EnumDict.member_names``, +``EnumType._add_alias_`` and ``EnumType._add_value_alias_`` public. From 11d88a178b077e42025da538b890db3151a47070 Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Tue, 5 Dec 2023 09:09:39 -0800 Subject: [PATCH 57/87] bpo-35332: Handle os.close() errors in shutil.rmtree() (GH-23766) * Ignore os.close() errors when ignore_errors is True. * Pass os.close() errors to the error handler if specified. * os.close no longer retried after error. Co-authored-by: Serhiy Storchaka --- Lib/shutil.py | 20 +++++++++-- Lib/test/test_shutil.py | 35 +++++++++++++++++++ .../2020-12-14-09-31-13.bpo-35332.s22wAx.rst | 3 ++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-14-09-31-13.bpo-35332.s22wAx.rst diff --git a/Lib/shutil.py b/Lib/shutil.py index bdbbcbc282e266b..dc3aac3e07f9104 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -687,7 +687,12 @@ def _rmtree_safe_fd(topfd, path, onexc): _rmtree_safe_fd(dirfd, fullname, onexc) try: os.close(dirfd) + except OSError as err: + # close() should not be retried after an error. dirfd_closed = True + onexc(os.close, fullname, err) + dirfd_closed = True + try: os.rmdir(entry.name, dir_fd=topfd) except FileNotFoundError: continue @@ -704,7 +709,10 @@ def _rmtree_safe_fd(topfd, path, onexc): onexc(os.path.islink, fullname, err) finally: if not dirfd_closed: - os.close(dirfd) + try: + os.close(dirfd) + except OSError as err: + onexc(os.close, fullname, err) else: try: os.unlink(entry.name, dir_fd=topfd) @@ -782,7 +790,12 @@ def onexc(*args): _rmtree_safe_fd(fd, path, onexc) try: os.close(fd) + except OSError as err: + # close() should not be retried after an error. fd_closed = True + onexc(os.close, path, err) + fd_closed = True + try: os.rmdir(path, dir_fd=dir_fd) except OSError as err: onexc(os.rmdir, path, err) @@ -794,7 +807,10 @@ def onexc(*args): onexc(os.path.islink, path, err) finally: if not fd_closed: - os.close(fd) + try: + os.close(fd) + except OSError as err: + onexc(os.close, path, err) else: if dir_fd is not None: raise NotImplementedError("dir_fd unavailable on this platform") diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 9b8ec42a99dd692..d7061b2f9d87249 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -576,6 +576,41 @@ def _raiser(*args, **kwargs): self.assertFalse(shutil._use_fd_functions) self.assertFalse(shutil.rmtree.avoids_symlink_attacks) + @unittest.skipUnless(shutil._use_fd_functions, "requires safe rmtree") + def test_rmtree_fails_on_close(self): + # Test that the error handler is called for failed os.close() and that + # os.close() is only called once for a file descriptor. + tmp = self.mkdtemp() + dir1 = os.path.join(tmp, 'dir1') + os.mkdir(dir1) + dir2 = os.path.join(dir1, 'dir2') + os.mkdir(dir2) + def close(fd): + orig_close(fd) + nonlocal close_count + close_count += 1 + raise OSError + + close_count = 0 + with support.swap_attr(os, 'close', close) as orig_close: + with self.assertRaises(OSError): + shutil.rmtree(dir1) + self.assertTrue(os.path.isdir(dir2)) + self.assertEqual(close_count, 2) + + close_count = 0 + errors = [] + def onexc(*args): + errors.append(args) + with support.swap_attr(os, 'close', close) as orig_close: + shutil.rmtree(dir1, onexc=onexc) + self.assertEqual(len(errors), 2) + self.assertIs(errors[0][0], close) + self.assertEqual(errors[0][1], dir2) + self.assertIs(errors[1][0], close) + self.assertEqual(errors[1][1], dir1) + self.assertEqual(close_count, 2) + @unittest.skipUnless(shutil._use_fd_functions, "dir_fd is not supported") def test_rmtree_with_dir_fd(self): tmp_dir = self.mkdtemp() diff --git a/Misc/NEWS.d/next/Library/2020-12-14-09-31-13.bpo-35332.s22wAx.rst b/Misc/NEWS.d/next/Library/2020-12-14-09-31-13.bpo-35332.s22wAx.rst new file mode 100644 index 000000000000000..80564b99a079c6f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-14-09-31-13.bpo-35332.s22wAx.rst @@ -0,0 +1,3 @@ +The :func:`shutil.rmtree` function now ignores errors when calling +:func:`os.close` when *ignore_errors* is ``True``, and +:func:`os.close` no longer retried after error. From c2e2df83560a3d4cb602f6d57cb70ac8aad7f9e6 Mon Sep 17 00:00:00 2001 From: "Jurjen N. E. Bos" Date: Tue, 5 Dec 2023 19:44:06 +0100 Subject: [PATCH 58/87] Minor stylistic edit to the grouper recipe (gh112759) --- Doc/library/itertools.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index ebb4ebcfa7618a1..8a4254cf15ebe29 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -916,9 +916,9 @@ which incur interpreter overhead. args = [iter(iterable)] * n if incomplete == 'fill': return zip_longest(*args, fillvalue=fillvalue) - if incomplete == 'strict': + elif incomplete == 'strict': return zip(*args, strict=True) - if incomplete == 'ignore': + elif incomplete == 'ignore': return zip(*args) else: raise ValueError('Expected fill, strict, or ignore') From d109f637c048c2b5fc95dc7fdfd50f8ac41a7747 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Tue, 5 Dec 2023 19:27:59 +0000 Subject: [PATCH 59/87] gh-101100: Properly document frame object attributes (#112735) --- Doc/c-api/frame.rst | 8 ++-- Doc/c-api/init.rst | 5 ++- Doc/library/dis.rst | 4 +- Doc/library/inspect.rst | 4 +- Doc/library/sys.rst | 9 ++-- Doc/library/types.rst | 3 +- Doc/reference/datamodel.rst | 84 ++++++++++++++++++++++++++----------- Doc/whatsnew/2.3.rst | 4 +- Doc/whatsnew/3.10.rst | 7 ++-- Doc/whatsnew/3.11.rst | 5 ++- Doc/whatsnew/3.6.rst | 2 +- Doc/whatsnew/3.7.rst | 2 +- 12 files changed, 88 insertions(+), 49 deletions(-) diff --git a/Doc/c-api/frame.rst b/Doc/c-api/frame.rst index 1accee2767a4852..6bb1e9b5803b580 100644 --- a/Doc/c-api/frame.rst +++ b/Doc/c-api/frame.rst @@ -50,7 +50,7 @@ See also :ref:`Reflection `. .. c:function:: PyObject* PyFrame_GetBuiltins(PyFrameObject *frame) - Get the *frame*'s ``f_builtins`` attribute. + Get the *frame*'s :attr:`~frame.f_builtins` attribute. Return a :term:`strong reference`. The result cannot be ``NULL``. @@ -81,7 +81,7 @@ See also :ref:`Reflection `. .. c:function:: PyObject* PyFrame_GetGlobals(PyFrameObject *frame) - Get the *frame*'s ``f_globals`` attribute. + Get the *frame*'s :attr:`~frame.f_globals` attribute. Return a :term:`strong reference`. The result cannot be ``NULL``. @@ -90,7 +90,7 @@ See also :ref:`Reflection `. .. c:function:: int PyFrame_GetLasti(PyFrameObject *frame) - Get the *frame*'s ``f_lasti`` attribute. + Get the *frame*'s :attr:`~frame.f_lasti` attribute. Returns -1 if ``frame.f_lasti`` is ``None``. @@ -120,7 +120,7 @@ See also :ref:`Reflection `. .. c:function:: PyObject* PyFrame_GetLocals(PyFrameObject *frame) - Get the *frame*'s ``f_locals`` attribute (:class:`dict`). + Get the *frame*'s :attr:`~frame.f_locals` attribute (:class:`dict`). Return a :term:`strong reference`. diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index e89641f74c7491e..f8fd48e781d6da1 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1662,7 +1662,8 @@ Python-level trace functions in previous versions. The value passed as the *what* parameter to a :c:type:`Py_tracefunc` function (but not a profiling function) when a line-number event is being reported. - It may be disabled for a frame by setting :attr:`f_trace_lines` to *0* on that frame. + It may be disabled for a frame by setting :attr:`~frame.f_trace_lines` to + *0* on that frame. .. c:var:: int PyTrace_RETURN @@ -1694,7 +1695,7 @@ Python-level trace functions in previous versions. The value for the *what* parameter to :c:type:`Py_tracefunc` functions (but not profiling functions) when a new opcode is about to be executed. This event is not emitted by default: it must be explicitly requested by setting - :attr:`f_trace_opcodes` to *1* on the frame. + :attr:`~frame.f_trace_opcodes` to *1* on the frame. .. c:function:: void PyEval_SetProfile(Py_tracefunc func, PyObject *obj) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 7e97f1a4524554c..cf238f81b9cc645 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -865,8 +865,8 @@ iterations of the loop. .. opcode:: RERAISE Re-raises the exception currently on top of the stack. If oparg is non-zero, - pops an additional value from the stack which is used to set ``f_lasti`` - of the current frame. + pops an additional value from the stack which is used to set + :attr:`~frame.f_lasti` of the current frame. .. versionadded:: 3.9 diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 6fd0d32afe7415c..08f15ae09b1b874 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1605,8 +1605,8 @@ the following flags: .. data:: CO_NEWLOCALS - If set, a new dict will be created for the frame's ``f_locals`` when - the code object is executed. + If set, a new dict will be created for the frame's :attr:`~frame.f_locals` + when the code object is executed. .. data:: CO_VARARGS diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 7f359819e6847ee..aaf79205d44282b 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1600,7 +1600,8 @@ always available. :file:`Objects/lnotab_notes.txt` for a detailed explanation of how this works. Per-line events may be disabled for a frame by setting - :attr:`!f_trace_lines` to :const:`False` on that :ref:`frame `. + :attr:`~frame.f_trace_lines` to :const:`False` on that + :ref:`frame `. ``'return'`` A function (or other code block) is about to return. The local trace @@ -1618,7 +1619,7 @@ always available. opcode details). The local trace function is called; *arg* is ``None``; the return value specifies the new local trace function. Per-opcode events are not emitted by default: they must be explicitly - requested by setting :attr:`!f_trace_opcodes` to :const:`True` on the + requested by setting :attr:`~frame.f_trace_opcodes` to :const:`True` on the :ref:`frame `. Note that as an exception is propagated down the chain of callers, an @@ -1648,8 +1649,8 @@ always available. .. versionchanged:: 3.7 - ``'opcode'`` event type added; :attr:`!f_trace_lines` and - :attr:`!f_trace_opcodes` attributes added to frames + ``'opcode'`` event type added; :attr:`~frame.f_trace_lines` and + :attr:`~frame.f_trace_opcodes` attributes added to frames .. function:: set_asyncgen_hooks(firstiter, finalizer) diff --git a/Doc/library/types.rst b/Doc/library/types.rst index 54c3907dec98ccb..22766462822af97 100644 --- a/Doc/library/types.rst +++ b/Doc/library/types.rst @@ -388,7 +388,8 @@ Standard names are defined for the following types: .. data:: GetSetDescriptorType The type of objects defined in extension modules with ``PyGetSetDef``, such - as ``FrameType.f_locals`` or ``array.array.typecode``. This type is used as + as :attr:`FrameType.f_locals ` or ``array.array.typecode``. + This type is used as descriptor for object attributes; it has the same purpose as the :class:`property` type, but for classes defined in extension modules. diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 06e61393fccc24a..8a94b7bb22c3621 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1174,16 +1174,36 @@ Frame objects represent execution frames. They may occur in traceback objects single: f_lasti (frame attribute) single: f_builtins (frame attribute) -Special read-only attributes: :attr:`f_back` is to the previous stack frame -(towards the caller), or ``None`` if this is the bottom stack frame; -:attr:`f_code` is the code object being executed in this frame; :attr:`f_locals` -is the dictionary used to look up local variables; :attr:`f_globals` is used for -global variables; :attr:`f_builtins` is used for built-in (intrinsic) names; -:attr:`f_lasti` gives the precise instruction (this is an index into the -bytecode string of the code object). +Special read-only attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Accessing ``f_code`` raises an :ref:`auditing event ` -``object.__getattr__`` with arguments ``obj`` and ``"f_code"``. +.. list-table:: + + * - .. attribute:: frame.f_back + - Points to the previous stack frame (towards the caller), + or ``None`` if this is the bottom stack frame + + * - .. attribute:: frame.f_code + - The :ref:`code object ` being executed in this frame. + Accessing this attribute raises an :ref:`auditing event ` + ``object.__getattr__`` with arguments ``obj`` and ``"f_code"``. + + * - .. attribute:: frame.f_locals + - The dictionary used by the frame to look up + :ref:`local variables ` + + * - .. attribute:: frame.f_globals + - The dictionary used by the frame to look up + :ref:`global variables ` + + * - .. attribute:: frame.f_builtins + - The dictionary used by the frame to look up + :ref:`built-in (intrinsic) names ` + + * - .. attribute:: frame.f_lasti + - The "precise instruction" of the frame object + (this is an index into the :term:`bytecode` string of the + :ref:`code object `) .. index:: single: f_trace (frame attribute) @@ -1191,30 +1211,44 @@ Accessing ``f_code`` raises an :ref:`auditing event ` single: f_trace_opcodes (frame attribute) single: f_lineno (frame attribute) -Special writable attributes: :attr:`f_trace`, if not ``None``, is a function -called for various events during code execution (this is used by the debugger). -Normally an event is triggered for each new source line - this can be -disabled by setting :attr:`f_trace_lines` to :const:`False`. +Special writable attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + + * - .. attribute:: frame.f_trace + - If not ``None``, this is a function called for various events during + code execution (this is used by debuggers). Normally an event is + triggered for each new source line (see :attr:`~frame.f_trace_lines`). + + * - .. attribute:: frame.f_trace_lines + - Set this attribute to :const:`False` to disable triggering a tracing + event for each source line. + + * - .. attribute:: frame.f_trace_opcodes + - Set this attribute to :const:`True` to allow per-opcode events to be + requested. Note that this may lead to + undefined interpreter behaviour if exceptions raised by the trace + function escape to the function being traced. -Implementations *may* allow per-opcode events to be requested by setting -:attr:`f_trace_opcodes` to :const:`True`. Note that this may lead to -undefined interpreter behaviour if exceptions raised by the trace -function escape to the function being traced. + * - .. attribute:: frame.f_lineno + - The current line number of the frame -- writing to this + from within a trace function jumps to the given line (only for the bottom-most + frame). A debugger can implement a Jump command (aka Set Next Statement) + by writing to this attribute. -:attr:`f_lineno` is the current line number of the frame --- writing to this -from within a trace function jumps to the given line (only for the bottom-most -frame). A debugger can implement a Jump command (aka Set Next Statement) -by writing to f_lineno. +Frame object methods +~~~~~~~~~~~~~~~~~~~~ Frame objects support one method: .. method:: frame.clear() - This method clears all references to local variables held by the - frame. Also, if the frame belonged to a generator, the generator + This method clears all references to :ref:`local variables ` held by the + frame. Also, if the frame belonged to a :term:`generator`, the generator is finalized. This helps break reference cycles involving frame - objects (for example when catching an exception and storing its - traceback for later use). + objects (for example when catching an :ref:`exception ` + and storing its :ref:`traceback ` for later use). :exc:`RuntimeError` is raised if the frame is currently executing or suspended. diff --git a/Doc/whatsnew/2.3.rst b/Doc/whatsnew/2.3.rst index af332b28a28231e..c989e6d3fa57879 100644 --- a/Doc/whatsnew/2.3.rst +++ b/Doc/whatsnew/2.3.rst @@ -1998,13 +1998,13 @@ Some of the more notable changes are: It would be difficult to detect any resulting difference from Python code, apart from a slight speed up when Python is run without :option:`-O`. - C extensions that access the :attr:`f_lineno` field of frame objects should + C extensions that access the :attr:`~frame.f_lineno` field of frame objects should instead call ``PyCode_Addr2Line(f->f_code, f->f_lasti)``. This will have the added effect of making the code work as desired under "python -O" in earlier versions of Python. A nifty new feature is that trace functions can now assign to the - :attr:`f_lineno` attribute of frame objects, changing the line that will be + :attr:`~frame.f_lineno` attribute of frame objects, changing the line that will be executed next. A ``jump`` command has been added to the :mod:`pdb` debugger taking advantage of this new feature. (Implemented by Richie Hindle.) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index df821d68eb8d9fc..15479cc979624f8 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -399,7 +399,8 @@ PEP 626: Precise line numbers for debugging and other tools PEP 626 brings more precise and reliable line numbers for debugging, profiling and coverage tools. Tracing events, with the correct line number, are generated for all lines of code executed and only for lines of code that are executed. -The ``f_lineno`` attribute of frame objects will always contain the expected line number. +The :attr:`~frame.f_lineno` attribute of frame objects will always contain the +expected line number. The ``co_lnotab`` attribute of code objects is deprecated and will be removed in 3.12. Code that needs to convert from offset to line number should use the new ``co_lines()`` method instead. @@ -1959,11 +1960,11 @@ Changes in the C API source_buf = PyBytes_AsString(source_bytes_object); code = Py_CompileString(source_buf, filename, Py_file_input); - * For ``FrameObject`` objects, the ``f_lasti`` member now represents a wordcode + * For ``FrameObject`` objects, the :attr:`~frame.f_lasti` member now represents a wordcode offset instead of a simple offset into the bytecode string. This means that this number needs to be multiplied by 2 to be used with APIs that expect a byte offset instead (like :c:func:`PyCode_Addr2Line` for example). Notice as well that the - ``f_lasti`` member of ``FrameObject`` objects is not considered stable: please + :attr:`!f_lasti` member of ``FrameObject`` objects is not considered stable: please use :c:func:`PyFrame_GetLineNumber` instead. CPython bytecode changes diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 48a0e621baad023..8db133b90a7a4be 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -2458,11 +2458,12 @@ Porting to Python 3.11 * ``f_valuestack``: removed. The Python frame object is now created lazily. A side effect is that the - ``f_back`` member must not be accessed directly, since its value is now also + :attr:`~frame.f_back` member must not be accessed directly, + since its value is now also computed lazily. The :c:func:`PyFrame_GetBack` function must be called instead. - Debuggers that accessed the ``f_locals`` directly *must* call + Debuggers that accessed the :attr:`~frame.f_locals` directly *must* call :c:func:`PyFrame_GetLocals` instead. They no longer need to call :c:func:`PyFrame_FastToLocalsWithError` or :c:func:`PyFrame_LocalsToFast`, in fact they should not call those functions. The necessary updating of the diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index c15d8be651fd176..2f618929793fc6f 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2162,7 +2162,7 @@ Changes in the Python API * The format of the ``co_lnotab`` attribute of code objects changed to support a negative line number delta. By default, Python does not emit bytecode with - a negative line number delta. Functions using ``frame.f_lineno``, + a negative line number delta. Functions using :attr:`frame.f_lineno`, ``PyFrame_GetLineNumber()`` or ``PyCode_Addr2Line()`` are not affected. Functions directly decoding ``co_lnotab`` should be updated to use a signed 8-bit integer type for the line number delta, but this is only required to diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index a7d5c3db6ddcb2b..99f280af84ab015 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -1891,7 +1891,7 @@ Other CPython Implementation Changes * Trace hooks may now opt out of receiving the ``line`` and opt into receiving the ``opcode`` events from the interpreter by setting the corresponding new - ``f_trace_lines`` and ``f_trace_opcodes`` attributes on the + :attr:`~frame.f_trace_lines` and :attr:`~frame.f_trace_opcodes` attributes on the frame being traced. (Contributed by Nick Coghlan in :issue:`31344`.) * Fixed some consistency problems with namespace package module attributes. From d384813ff18b33280a90b6d2011654528a2b6ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Tue, 5 Dec 2023 20:39:28 +0100 Subject: [PATCH 60/87] gh-112769: test_zlib: Fix comparison of ZLIB_RUNTIME_VERSION with non-int suffix (GH-112771) zlib-ng defines the version as "1.3.0.zlib-ng". --- Lib/test/test_zlib.py | 29 +++++++++++-------- ...-12-05-19-50-03.gh-issue-112769.kdLJmS.rst | 3 ++ 2 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-12-05-19-50-03.gh-issue-112769.kdLJmS.rst diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 1dc8b91a453f927..ef02c64f886f8ac 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -18,6 +18,21 @@ hasattr(zlib.decompressobj(), "copy"), 'requires Decompress.copy()') + +def _zlib_runtime_version_tuple(zlib_version=zlib.ZLIB_RUNTIME_VERSION): + # Register "1.2.3" as "1.2.3.0" + # or "1.2.0-linux","1.2.0.f","1.2.0.f-linux" + v = zlib_version.split('-', 1)[0].split('.') + if len(v) < 4: + v.append('0') + elif not v[-1].isnumeric(): + v[-1] = '0' + return tuple(map(int, v)) + + +ZLIB_RUNTIME_VERSION_TUPLE = _zlib_runtime_version_tuple() + + # bpo-46623: On s390x, when a hardware accelerator is used, using different # ways to compress data with zlib can produce different compressed data. # Simplified test_pair() code: @@ -473,9 +488,8 @@ def test_flushes(self): sync_opt = ['Z_NO_FLUSH', 'Z_SYNC_FLUSH', 'Z_FULL_FLUSH', 'Z_PARTIAL_FLUSH'] - ver = tuple(int(v) for v in zlib.ZLIB_RUNTIME_VERSION.split('.')) # Z_BLOCK has a known failure prior to 1.2.5.3 - if ver >= (1, 2, 5, 3): + if ZLIB_RUNTIME_VERSION_TUPLE >= (1, 2, 5, 3): sync_opt.append('Z_BLOCK') sync_opt = [getattr(zlib, opt) for opt in sync_opt @@ -793,16 +807,7 @@ def test_large_unconsumed_tail(self, size): def test_wbits(self): # wbits=0 only supported since zlib v1.2.3.5 - # Register "1.2.3" as "1.2.3.0" - # or "1.2.0-linux","1.2.0.f","1.2.0.f-linux" - v = zlib.ZLIB_RUNTIME_VERSION.split('-', 1)[0].split('.') - if len(v) < 4: - v.append('0') - elif not v[-1].isnumeric(): - v[-1] = '0' - - v = tuple(map(int, v)) - supports_wbits_0 = v >= (1, 2, 3, 5) + supports_wbits_0 = ZLIB_RUNTIME_VERSION_TUPLE >= (1, 2, 3, 5) co = zlib.compressobj(level=1, wbits=15) zlib15 = co.compress(HAMLET_SCENE) + co.flush() diff --git a/Misc/NEWS.d/next/Tests/2023-12-05-19-50-03.gh-issue-112769.kdLJmS.rst b/Misc/NEWS.d/next/Tests/2023-12-05-19-50-03.gh-issue-112769.kdLJmS.rst new file mode 100644 index 000000000000000..1bbbb26fc322fa9 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-12-05-19-50-03.gh-issue-112769.kdLJmS.rst @@ -0,0 +1,3 @@ +The tests now correctly compare zlib version when +:const:`zlib.ZLIB_RUNTIME_VERSION` contains non-integer suffixes. For +example zlib-ng defines the version as ``1.3.0.zlib-ng``. From a2a46f9f1e08be26fa1f732a2b92e355ad812abf Mon Sep 17 00:00:00 2001 From: Matt Prodani Date: Wed, 6 Dec 2023 01:54:57 -0500 Subject: [PATCH 61/87] gh-112606: Use sem_clockwait with monotonic time when supported in parking_lot.c (gh-112733) --- Python/parking_lot.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Python/parking_lot.c b/Python/parking_lot.c index 664e622cc174741..d44c1b4b93b4d2b 100644 --- a/Python/parking_lot.c +++ b/Python/parking_lot.c @@ -118,10 +118,19 @@ _PySemaphore_PlatformWait(_PySemaphore *sema, _PyTime_t timeout) if (timeout >= 0) { struct timespec ts; +#if defined(CLOCK_MONOTONIC) && defined(HAVE_SEM_CLOCKWAIT) + _PyTime_t deadline = _PyTime_Add(_PyTime_GetMonotonicClock(), timeout); + + _PyTime_AsTimespec_clamp(deadline, &ts); + + err = sem_clockwait(&sema->platform_sem, CLOCK_MONOTONIC, &ts); +#else _PyTime_t deadline = _PyTime_Add(_PyTime_GetSystemClock(), timeout); - _PyTime_AsTimespec(deadline, &ts); + + _PyTime_AsTimespec_clamp(deadline, &ts); err = sem_timedwait(&sema->platform_sem, &ts); +#endif } else { err = sem_wait(&sema->platform_sem); @@ -151,7 +160,7 @@ _PySemaphore_PlatformWait(_PySemaphore *sema, _PyTime_t timeout) struct timespec ts; _PyTime_t deadline = _PyTime_Add(_PyTime_GetSystemClock(), timeout); - _PyTime_AsTimespec(deadline, &ts); + _PyTime_AsTimespec_clamp(deadline, &ts); err = pthread_cond_timedwait(&sema->cond, &sema->mutex, &ts); } From f8c0198e3bfa2f6f65e426765a5efddd8ece78b0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 6 Dec 2023 09:48:27 +0200 Subject: [PATCH 62/87] gh-108927: Include new dir test/regrtestdata in the installation (GH-112765) Co-authored-by: Victor Stinner --- Makefile.pre.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile.pre.in b/Makefile.pre.in index e7f8abce43d648c..b5edb4e6748fb09 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2194,6 +2194,9 @@ TESTSUBDIRS= idlelib/idle_test \ test/leakers \ test/libregrtest \ test/mathdata \ + test/regrtestdata \ + test/regrtestdata/import_from_tests \ + test/regrtestdata/import_from_tests/test_regrtest_b \ test/subprocessdata \ test/support \ test/support/_hypothesis_stubs \ From e3f670e13792305cfb977d5cffd8e6aa03e8fe7f Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 6 Dec 2023 08:44:06 +0000 Subject: [PATCH 63/87] gh-101100: Fix most Sphinx nitpicks in the glossary and `stdtypes.rst` (#112757) --- Doc/glossary.rst | 47 ++++++++++++++++++++++------------------ Doc/library/stdtypes.rst | 26 ++++++++++++---------- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 29f2f80cebd5f0f..601443d5aade942 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -151,9 +151,9 @@ Glossary A :term:`file object` able to read and write :term:`bytes-like objects `. Examples of binary files are files opened in binary mode (``'rb'``, - ``'wb'`` or ``'rb+'``), :data:`sys.stdin.buffer`, - :data:`sys.stdout.buffer`, and instances of :class:`io.BytesIO` and - :class:`gzip.GzipFile`. + ``'wb'`` or ``'rb+'``), :data:`sys.stdin.buffer `, + :data:`sys.stdout.buffer `, and instances of + :class:`io.BytesIO` and :class:`gzip.GzipFile`. See also :term:`text file` for a file object able to read and write :class:`str` objects. @@ -304,8 +304,9 @@ Glossary :ref:`class definitions ` for more about decorators. descriptor - Any object which defines the methods :meth:`__get__`, :meth:`__set__`, or - :meth:`__delete__`. When a class attribute is a descriptor, its special + Any object which defines the methods :meth:`~object.__get__`, + :meth:`~object.__set__`, or :meth:`~object.__delete__`. + When a class attribute is a descriptor, its special binding behavior is triggered upon attribute lookup. Normally, using *a.b* to get, set or delete an attribute looks up the object named *b* in the class dictionary for *a*, but if *b* is a descriptor, the respective @@ -319,7 +320,8 @@ Glossary dictionary An associative array, where arbitrary keys are mapped to values. The - keys can be any object with :meth:`__hash__` and :meth:`__eq__` methods. + keys can be any object with :meth:`~object.__hash__` and + :meth:`~object.__eq__` methods. Called a hash in Perl. dictionary comprehension @@ -383,7 +385,7 @@ Glossary file object An object exposing a file-oriented API (with methods such as - :meth:`read()` or :meth:`write()`) to an underlying resource. Depending + :meth:`!read` or :meth:`!write`) to an underlying resource. Depending on the way it was created, a file object can mediate access to a real on-disk file or to another type of storage or communication device (for example standard input/output, in-memory buffers, sockets, pipes, @@ -559,8 +561,9 @@ Glossary hashable An object is *hashable* if it has a hash value which never changes during - its lifetime (it needs a :meth:`__hash__` method), and can be compared to - other objects (it needs an :meth:`__eq__` method). Hashable objects which + its lifetime (it needs a :meth:`~object.__hash__` method), and can be + compared to other objects (it needs an :meth:`~object.__eq__` method). + Hashable objects which compare equal must have the same hash value. Hashability makes an object usable as a dictionary key and a set member, @@ -646,7 +649,8 @@ Glossary iterables include all sequence types (such as :class:`list`, :class:`str`, and :class:`tuple`) and some non-sequence types like :class:`dict`, :term:`file objects `, and objects of any classes you define - with an :meth:`__iter__` method or with a :meth:`~object.__getitem__` method + with an :meth:`~iterator.__iter__` method or with a + :meth:`~object.__getitem__` method that implements :term:`sequence` semantics. Iterables can be @@ -655,7 +659,7 @@ Glossary as an argument to the built-in function :func:`iter`, it returns an iterator for the object. This iterator is good for one pass over the set of values. When using iterables, it is usually not necessary to call - :func:`iter` or deal with iterator objects yourself. The ``for`` + :func:`iter` or deal with iterator objects yourself. The :keyword:`for` statement does that automatically for you, creating a temporary unnamed variable to hold the iterator for the duration of the loop. See also :term:`iterator`, :term:`sequence`, and :term:`generator`. @@ -666,8 +670,8 @@ Glossary :func:`next`) return successive items in the stream. When no more data are available a :exc:`StopIteration` exception is raised instead. At this point, the iterator object is exhausted and any further calls to its - :meth:`__next__` method just raise :exc:`StopIteration` again. Iterators - are required to have an :meth:`__iter__` method that returns the iterator + :meth:`!__next__` method just raise :exc:`StopIteration` again. Iterators + are required to have an :meth:`~iterator.__iter__` method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a @@ -681,7 +685,7 @@ Glossary .. impl-detail:: CPython does not consistently apply the requirement that an iterator - define :meth:`__iter__`. + define :meth:`~iterator.__iter__`. key function A key function or collation function is a callable that returns a value @@ -875,7 +879,8 @@ Glossary Old name for the flavor of classes now used for all class objects. In earlier Python versions, only new-style classes could use Python's newer, versatile features like :attr:`~object.__slots__`, descriptors, - properties, :meth:`__getattribute__`, class methods, and static methods. + properties, :meth:`~object.__getattribute__`, class methods, and static + methods. object Any data with state (attributes or value) and defined behavior @@ -955,7 +960,7 @@ Glossary finders implement. path entry hook - A callable on the :data:`sys.path_hook` list which returns a :term:`path + A callable on the :data:`sys.path_hooks` list which returns a :term:`path entry finder` if it knows how to find modules on a specific :term:`path entry`. @@ -1089,18 +1094,18 @@ Glossary sequence An :term:`iterable` which supports efficient element access using integer indices via the :meth:`~object.__getitem__` special method and defines a - :meth:`__len__` method that returns the length of the sequence. + :meth:`~object.__len__` method that returns the length of the sequence. Some built-in sequence types are :class:`list`, :class:`str`, :class:`tuple`, and :class:`bytes`. Note that :class:`dict` also - supports :meth:`~object.__getitem__` and :meth:`__len__`, but is considered a + supports :meth:`~object.__getitem__` and :meth:`!__len__`, but is considered a mapping rather than a sequence because the lookups use arbitrary :term:`immutable` keys rather than integers. The :class:`collections.abc.Sequence` abstract base class defines a much richer interface that goes beyond just - :meth:`~object.__getitem__` and :meth:`__len__`, adding :meth:`count`, - :meth:`index`, :meth:`__contains__`, and - :meth:`__reversed__`. Types that implement this expanded + :meth:`~object.__getitem__` and :meth:`~object.__len__`, adding + :meth:`count`, :meth:`index`, :meth:`~object.__contains__`, and + :meth:`~object.__reversed__`. Types that implement this expanded interface can be registered explicitly using :func:`~abc.ABCMeta.register`. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index f204b287b565eb3..44c13bd9474ea1c 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -44,7 +44,8 @@ Any object can be tested for truth value, for use in an :keyword:`if` or .. index:: single: true By default, an object is considered true unless its class defines either a -:meth:`~object.__bool__` method that returns ``False`` or a :meth:`__len__` method that +:meth:`~object.__bool__` method that returns ``False`` or a +:meth:`~object.__len__` method that returns zero, when called with the object. [1]_ Here are most of the built-in objects considered false: @@ -197,7 +198,7 @@ exception. Two more operations with the same syntactic priority, :keyword:`in` and :keyword:`not in`, are supported by types that are :term:`iterable` or -implement the :meth:`__contains__` method. +implement the :meth:`~object.__contains__` method. .. _typesnumeric: @@ -717,7 +718,7 @@ that's defined for any rational number, and hence applies to all instances of :class:`int` and :class:`fractions.Fraction`, and all finite instances of :class:`float` and :class:`decimal.Decimal`. Essentially, this function is given by reduction modulo ``P`` for a fixed prime ``P``. The value of ``P`` is -made available to Python as the :attr:`modulus` attribute of +made available to Python as the :attr:`~sys.hash_info.modulus` attribute of :data:`sys.hash_info`. .. impl-detail:: @@ -906,9 +907,9 @@ Generator Types --------------- Python's :term:`generator`\s provide a convenient way to implement the iterator -protocol. If a container object's :meth:`__iter__` method is implemented as a +protocol. If a container object's :meth:`~iterator.__iter__` method is implemented as a generator, it will automatically return an iterator object (technically, a -generator object) supplying the :meth:`__iter__` and :meth:`~generator.__next__` +generator object) supplying the :meth:`!__iter__` and :meth:`~generator.__next__` methods. More information about generators can be found in :ref:`the documentation for the yield expression `. @@ -3672,7 +3673,7 @@ The conversion types are: +------------+-----------------------------------------------------+-------+ | ``'b'`` | Bytes (any object that follows the | \(5) | | | :ref:`buffer protocol ` or has | | -| | :meth:`__bytes__`). | | +| | :meth:`~object.__bytes__`). | | +------------+-----------------------------------------------------+-------+ | ``'s'`` | ``'s'`` is an alias for ``'b'`` and should only | \(6) | | | be used for Python2/3 code bases. | | @@ -4410,7 +4411,8 @@ The constructors for both classes work the same: :meth:`symmetric_difference_update` methods will accept any iterable as an argument. - Note, the *elem* argument to the :meth:`__contains__`, :meth:`remove`, and + Note, the *elem* argument to the :meth:`~object.__contains__`, + :meth:`remove`, and :meth:`discard` methods may be a set. To support searching for an equivalent frozenset, a temporary one is created from *elem*. @@ -5236,9 +5238,11 @@ instantiated from the type:: TypeError: cannot create 'types.UnionType' instances .. note:: - The :meth:`__or__` method for type objects was added to support the syntax - ``X | Y``. If a metaclass implements :meth:`__or__`, the Union may - override it:: + The :meth:`!__or__` method for type objects was added to support the syntax + ``X | Y``. If a metaclass implements :meth:`!__or__`, the Union may + override it: + + .. doctest:: >>> class M(type): ... def __or__(self, other): @@ -5250,7 +5254,7 @@ instantiated from the type:: >>> C | int 'Hello' >>> int | C - int | __main__.C + int | C .. seealso:: From 00cce0fe495ee820cd3ca5878bdbe3dd65b1be7b Mon Sep 17 00:00:00 2001 From: Christopher Chavez Date: Wed, 6 Dec 2023 03:44:41 -0600 Subject: [PATCH 64/87] gh-111178: Docs: fix `traverseproc`, `inquiry`, and `destructor` parameters in slot typedefs table (GH-112742) In the slot typedefs table, the parameter of `destructor` and the first parameter of `traverseproc` should both be `PyObject *` rather than `void *`. Same for `inquiry`. --- Doc/c-api/typeobj.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index 10c05beda7c66f0..8a26f237652d125 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -343,13 +343,13 @@ slot typedefs | | :c:type:`PyTypeObject` * | | | | :c:type:`Py_ssize_t` | | +-----------------------------+-----------------------------+----------------------+ -| :c:type:`destructor` | void * | void | +| :c:type:`destructor` | :c:type:`PyObject` * | void | +-----------------------------+-----------------------------+----------------------+ | :c:type:`freefunc` | void * | void | +-----------------------------+-----------------------------+----------------------+ | :c:type:`traverseproc` | .. line-block:: | int | | | | | -| | void * | | +| | :c:type:`PyObject` * | | | | :c:type:`visitproc` | | | | void * | | +-----------------------------+-----------------------------+----------------------+ @@ -426,7 +426,7 @@ slot typedefs | | :c:type:`PyObject` * | | | | :c:type:`Py_buffer` * | | +-----------------------------+-----------------------------+----------------------+ -| :c:type:`inquiry` | void * | int | +| :c:type:`inquiry` | :c:type:`PyObject` * | int | +-----------------------------+-----------------------------+----------------------+ | :c:type:`unaryfunc` | .. line-block:: | :c:type:`PyObject` * | | | | | From f8852634edf1232ac1aa4561e34796b52f9f7aa2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 6 Dec 2023 12:55:58 +0100 Subject: [PATCH 65/87] gh-108223: Refer to PEP 703 as Free Threading (#112780) --- Doc/using/configure.rst | 5 ++++- Lib/test/libregrtest/utils.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 56d2d6dc4ab5f12..cb7eda42fe3fad0 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -292,7 +292,10 @@ General Options .. option:: --disable-gil Enables **experimental** support for running Python without the - :term:`global interpreter lock` (GIL). + :term:`global interpreter lock` (GIL): free threading build. + + Defines the ``Py_GIL_DISABLED`` macro and adds ``"t"`` to + :data:`sys.abiflags`. See :pep:`703` "Making the Global Interpreter Lock Optional in CPython". diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index d4972ce4a50d2a1..26481e71221ade0 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -291,7 +291,7 @@ def get_build_info(): # --disable-gil if sysconfig.get_config_var('Py_GIL_DISABLED'): - build.append("nogil") + build.append("free_threading") if hasattr(sys, 'gettotalrefcount'): # --with-pydebug From 828451dfde324f9499ffebc023a22b84dc5a125b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 6 Dec 2023 15:09:22 +0100 Subject: [PATCH 66/87] gh-111545: Add Py_HashPointer() function (#112096) * Implement _Py_HashPointerRaw() as a static inline function. * Add Py_HashPointer() tests to test_capi.test_hash. * Keep _Py_HashPointer() function as an alias to Py_HashPointer(). --- Doc/c-api/hash.rst | 10 ++++ Doc/whatsnew/3.13.rst | 3 ++ Include/cpython/pyhash.h | 6 ++- Include/internal/pycore_pyhash.h | 16 ++++++- Lib/test/test_capi/test_hash.py | 48 ++++++++++++++++++- ...-11-15-01-26-59.gh-issue-111545.iAoFtA.rst | 2 + Modules/_testcapi/hash.c | 16 +++++++ Python/hashtable.c | 2 +- Python/pyhash.c | 22 ++------- 9 files changed, 103 insertions(+), 22 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2023-11-15-01-26-59.gh-issue-111545.iAoFtA.rst diff --git a/Doc/c-api/hash.rst b/Doc/c-api/hash.rst index 3bfaf8b9f54c14f..91d88ae27bc9f49 100644 --- a/Doc/c-api/hash.rst +++ b/Doc/c-api/hash.rst @@ -49,3 +49,13 @@ See also the :c:member:`PyTypeObject.tp_hash` member. :pep:`456` "Secure and interchangeable hash algorithm". .. versionadded:: 3.4 + + +.. c:function:: Py_hash_t Py_HashPointer(const void *ptr) + + Hash a pointer value: process the pointer value as an integer (cast it to + ``uintptr_t`` internally). The pointer is not dereferenced. + + The function cannot fail: it cannot return ``-1``. + + .. versionadded:: 3.13 diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 534813f3659c9d9..c9facad6375ef3f 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -1249,6 +1249,9 @@ New Features :exc:`KeyError` if the key missing. (Contributed by Stefan Behnel and Victor Stinner in :gh:`111262`.) +* Add :c:func:`Py_HashPointer` function to hash a pointer. + (Contributed by Victor Stinner in :gh:`111545`.) + Porting to Python 3.13 ---------------------- diff --git a/Include/cpython/pyhash.h b/Include/cpython/pyhash.h index 6f7113daa5fe4de..396c208e1b106a9 100644 --- a/Include/cpython/pyhash.h +++ b/Include/cpython/pyhash.h @@ -21,7 +21,9 @@ /* Helpers for hash functions */ PyAPI_FUNC(Py_hash_t) _Py_HashDouble(PyObject *, double); -PyAPI_FUNC(Py_hash_t) _Py_HashPointer(const void*); + +// Kept for backward compatibility +#define _Py_HashPointer Py_HashPointer /* hash function definition */ @@ -33,3 +35,5 @@ typedef struct { } PyHash_FuncDef; PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void); + +PyAPI_FUNC(Py_hash_t) Py_HashPointer(const void *ptr); diff --git a/Include/internal/pycore_pyhash.h b/Include/internal/pycore_pyhash.h index c3b72d90de3a694..0ce08900e96f0b2 100644 --- a/Include/internal/pycore_pyhash.h +++ b/Include/internal/pycore_pyhash.h @@ -5,8 +5,20 @@ # error "this header requires Py_BUILD_CORE define" #endif -// Similar to _Py_HashPointer(), but don't replace -1 with -2 -extern Py_hash_t _Py_HashPointerRaw(const void*); +// Similar to Py_HashPointer(), but don't replace -1 with -2. +static inline Py_hash_t +_Py_HashPointerRaw(const void *ptr) +{ + uintptr_t x = (uintptr_t)ptr; + Py_BUILD_ASSERT(sizeof(x) == sizeof(ptr)); + + // Bottom 3 or 4 bits are likely to be 0; rotate x by 4 to the right + // to avoid excessive hash collisions for dicts and sets. + x = (x >> 4) | (x << (8 * sizeof(uintptr_t) - 4)); + + Py_BUILD_ASSERT(sizeof(x) == sizeof(Py_hash_t)); + return (Py_hash_t)x; +} // Export for '_datetime' shared extension PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void*, Py_ssize_t); diff --git a/Lib/test/test_capi/test_hash.py b/Lib/test/test_capi/test_hash.py index 59dec15bc21445f..8436da7c32df10f 100644 --- a/Lib/test/test_capi/test_hash.py +++ b/Lib/test/test_capi/test_hash.py @@ -4,7 +4,8 @@ _testcapi = import_helper.import_module('_testcapi') -SIZEOF_PY_HASH_T = _testcapi.SIZEOF_VOID_P +SIZEOF_VOID_P = _testcapi.SIZEOF_VOID_P +SIZEOF_PY_HASH_T = SIZEOF_VOID_P class CAPITest(unittest.TestCase): @@ -31,3 +32,48 @@ def test_hash_getfuncdef(self): self.assertEqual(func_def.name, hash_info.algorithm) self.assertEqual(func_def.hash_bits, hash_info.hash_bits) self.assertEqual(func_def.seed_bits, hash_info.seed_bits) + + def test_hash_pointer(self): + # Test Py_HashPointer() + hash_pointer = _testcapi.hash_pointer + + UHASH_T_MASK = ((2 ** (8 * SIZEOF_PY_HASH_T)) - 1) + HASH_T_MAX = (2 ** (8 * SIZEOF_PY_HASH_T - 1) - 1) + + def python_hash_pointer(x): + # Py_HashPointer() rotates the pointer bits by 4 bits to the right + x = (x >> 4) | ((x & 15) << (8 * SIZEOF_VOID_P - 4)) + + # Convert unsigned uintptr_t (Py_uhash_t) to signed Py_hash_t + if HASH_T_MAX < x: + x = (~x) + 1 + x &= UHASH_T_MASK + x = (~x) + 1 + return x + + if SIZEOF_VOID_P == 8: + values = ( + 0xABCDEF1234567890, + 0x1234567890ABCDEF, + 0xFEE4ABEDD1CECA5E, + ) + else: + values = ( + 0x12345678, + 0x1234ABCD, + 0xDEADCAFE, + ) + + for value in values: + expected = python_hash_pointer(value) + with self.subTest(value=value): + self.assertEqual(hash_pointer(value), expected, + f"hash_pointer({value:x}) = " + f"{hash_pointer(value):x} != {expected:x}") + + # Py_HashPointer(NULL) returns 0 + self.assertEqual(hash_pointer(0), 0) + + # Py_HashPointer((void*)(uintptr_t)-1) doesn't return -1 but -2 + VOID_P_MAX = -1 & (2 ** (8 * SIZEOF_VOID_P) - 1) + self.assertEqual(hash_pointer(VOID_P_MAX), -2) diff --git a/Misc/NEWS.d/next/C API/2023-11-15-01-26-59.gh-issue-111545.iAoFtA.rst b/Misc/NEWS.d/next/C API/2023-11-15-01-26-59.gh-issue-111545.iAoFtA.rst new file mode 100644 index 000000000000000..7bde2498acf9993 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-11-15-01-26-59.gh-issue-111545.iAoFtA.rst @@ -0,0 +1,2 @@ +Add :c:func:`Py_HashPointer` function to hash a pointer. Patch by Victor +Stinner. diff --git a/Modules/_testcapi/hash.c b/Modules/_testcapi/hash.c index d0b8127020c5c14..aee76787dcddb3b 100644 --- a/Modules/_testcapi/hash.c +++ b/Modules/_testcapi/hash.c @@ -44,8 +44,24 @@ hash_getfuncdef(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) return result; } + +static PyObject * +hash_pointer(PyObject *Py_UNUSED(module), PyObject *arg) +{ + void *ptr = PyLong_AsVoidPtr(arg); + if (ptr == NULL && PyErr_Occurred()) { + return NULL; + } + + Py_hash_t hash = Py_HashPointer(ptr); + Py_BUILD_ASSERT(sizeof(long long) >= sizeof(hash)); + return PyLong_FromLongLong(hash); +} + + static PyMethodDef test_methods[] = { {"hash_getfuncdef", hash_getfuncdef, METH_NOARGS}, + {"hash_pointer", hash_pointer, METH_O}, {NULL}, }; diff --git a/Python/hashtable.c b/Python/hashtable.c index 8f5e8168ba1339e..faf68fe4ff0bca1 100644 --- a/Python/hashtable.c +++ b/Python/hashtable.c @@ -45,7 +45,7 @@ */ #include "Python.h" -#include "pycore_hashtable.h" +#include "pycore_hashtable.h" // export _Py_hashtable_new() #include "pycore_pyhash.h" // _Py_HashPointerRaw() #define HASHTABLE_MIN_SIZE 16 diff --git a/Python/pyhash.c b/Python/pyhash.c index f9060b8003a0a7d..141407c265677a1 100644 --- a/Python/pyhash.c +++ b/Python/pyhash.c @@ -83,8 +83,6 @@ static Py_ssize_t hashstats[Py_HASH_STATS_MAX + 1] = {0}; */ -Py_hash_t _Py_HashPointer(const void *); - Py_hash_t _Py_HashDouble(PyObject *inst, double v) { @@ -132,23 +130,13 @@ _Py_HashDouble(PyObject *inst, double v) } Py_hash_t -_Py_HashPointerRaw(const void *p) -{ - size_t y = (size_t)p; - /* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid - excessive hash collisions for dicts and sets */ - y = (y >> 4) | (y << (8 * SIZEOF_VOID_P - 4)); - return (Py_hash_t)y; -} - -Py_hash_t -_Py_HashPointer(const void *p) +Py_HashPointer(const void *ptr) { - Py_hash_t x = _Py_HashPointerRaw(p); - if (x == -1) { - x = -2; + Py_hash_t hash = _Py_HashPointerRaw(ptr); + if (hash == -1) { + hash = -2; } - return x; + return hash; } Py_hash_t From cc7e45cc572dd818412a649970fdee579417701f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 6 Dec 2023 16:42:15 +0200 Subject: [PATCH 67/87] gh-75666: Tkinter: "unbind(sequence, funcid)" now only unbinds "funcid" (GH-111322) Previously, "widget.unbind(sequence, funcid)" destroyed the current binding for "sequence", leaving "sequence" unbound, and deleted the "funcid" command. Now it removes only "funcid" from the binding for "sequence", keeping other commands, and deletes the "funcid" command. It leaves "sequence" unbound only if "funcid" was the last bound command. Co-authored-by: GiovanniL <13402461+GiovaLomba@users.noreply.github.com> --- Lib/test/test_tkinter/test_misc.py | 34 +++++++++++++++---- Lib/tkinter/__init__.py | 22 +++++++++--- ...3-10-25-16-37-13.gh-issue-75666.BpsWut.rst | 6 ++++ 3 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-25-16-37-13.gh-issue-75666.BpsWut.rst diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py index ca99caaf88b80dd..6639eaaa59936a9 100644 --- a/Lib/test/test_tkinter/test_misc.py +++ b/Lib/test/test_tkinter/test_misc.py @@ -479,26 +479,46 @@ def test2(e): pass def test_unbind2(self): f = self.frame + f.wait_visibility() + f.focus_force() + f.update_idletasks() event = '' self.assertEqual(f.bind(), ()) self.assertEqual(f.bind(event), '') - def test1(e): pass - def test2(e): pass + def test1(e): events.append('a') + def test2(e): events.append('b') + def test3(e): events.append('c') funcid = f.bind(event, test1) funcid2 = f.bind(event, test2, add=True) + funcid3 = f.bind(event, test3, add=True) + events = [] + f.event_generate(event) + self.assertEqual(events, ['a', 'b', 'c']) - f.unbind(event, funcid) + f.unbind(event, funcid2) script = f.bind(event) - self.assertNotIn(funcid, script) - self.assertCommandNotExist(funcid) - self.assertCommandExist(funcid2) + self.assertNotIn(funcid2, script) + self.assertIn(funcid, script) + self.assertIn(funcid3, script) + self.assertEqual(f.bind(), (event,)) + self.assertCommandNotExist(funcid2) + self.assertCommandExist(funcid) + self.assertCommandExist(funcid3) + events = [] + f.event_generate(event) + self.assertEqual(events, ['a', 'c']) - f.unbind(event, funcid2) + f.unbind(event, funcid) + f.unbind(event, funcid3) self.assertEqual(f.bind(event), '') self.assertEqual(f.bind(), ()) self.assertCommandNotExist(funcid) self.assertCommandNotExist(funcid2) + self.assertCommandNotExist(funcid3) + events = [] + f.event_generate(event) + self.assertEqual(events, []) # non-idempotent self.assertRaises(tkinter.TclError, f.unbind, event, funcid2) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 0df7f9d889413c8..124882420c255c3 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1527,10 +1527,24 @@ def bind(self, sequence=None, func=None, add=None): return self._bind(('bind', self._w), sequence, func, add) def unbind(self, sequence, funcid=None): - """Unbind for this widget for event SEQUENCE the - function identified with FUNCID.""" - self.tk.call('bind', self._w, sequence, '') - if funcid: + """Unbind for this widget the event SEQUENCE. + + If FUNCID is given, only unbind the function identified with FUNCID + and also delete the corresponding Tcl command. + + Otherwise destroy the current binding for SEQUENCE, leaving SEQUENCE + unbound. + """ + if funcid is None: + self.tk.call('bind', self._w, sequence, '') + else: + lines = self.tk.call('bind', self._w, sequence).split('\n') + prefix = f'if {{"[{funcid} ' + keep = '\n'.join(line for line in lines + if not line.startswith(prefix)) + if not keep.strip(): + keep = '' + self.tk.call('bind', self._w, sequence, keep) self.deletecommand(funcid) def bind_all(self, sequence=None, func=None, add=None): diff --git a/Misc/NEWS.d/next/Library/2023-10-25-16-37-13.gh-issue-75666.BpsWut.rst b/Misc/NEWS.d/next/Library/2023-10-25-16-37-13.gh-issue-75666.BpsWut.rst new file mode 100644 index 000000000000000..d774cc4f7c687f2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-25-16-37-13.gh-issue-75666.BpsWut.rst @@ -0,0 +1,6 @@ +Fix the behavior of :mod:`tkinter` widget's ``unbind()`` method with two +arguments. Previously, ``widget.unbind(sequence, funcid)`` destroyed the +current binding for *sequence*, leaving *sequence* unbound, and deleted the +*funcid* command. Now it removes only *funcid* from the binding for +*sequence*, keeping other commands, and deletes the *funcid* command. It +leaves *sequence* unbound only if *funcid* was the last bound command. From b920d6ceaa5532bf2bc8128e006229ec583374d0 Mon Sep 17 00:00:00 2001 From: Christopher Chavez Date: Wed, 6 Dec 2023 09:30:37 -0600 Subject: [PATCH 68/87] gh-111178: Define `visitproc` callback functions properly and remove unnecessary casts in gcmodule.c (#112687) --- Modules/gcmodule.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 568e02a4210a2b2..8233fc56159b600 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -491,15 +491,16 @@ subtract_refs(PyGC_Head *containers) PyObject *op = FROM_GC(gc); traverse = Py_TYPE(op)->tp_traverse; (void) traverse(op, - (visitproc)visit_decref, + visit_decref, op); } } /* A traversal callback for move_unreachable. */ static int -visit_reachable(PyObject *op, PyGC_Head *reachable) +visit_reachable(PyObject *op, void *arg) { + PyGC_Head *reachable = arg; OBJECT_STAT_INC(object_visits); if (!_PyObject_IS_GC(op)) { return 0; @@ -603,7 +604,7 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable) // NOTE: visit_reachable may change gc->_gc_next when // young->_gc_prev == gc. Don't do gc = GC_NEXT(gc) before! (void) traverse(op, - (visitproc)visit_reachable, + visit_reachable, (void *)young); // relink gc_prev to prev element. _PyGCHead_SET_PREV(gc, prev); @@ -726,8 +727,9 @@ clear_unreachable_mask(PyGC_Head *unreachable) /* A traversal callback for move_legacy_finalizer_reachable. */ static int -visit_move(PyObject *op, PyGC_Head *tolist) +visit_move(PyObject *op, void *arg) { + PyGC_Head *tolist = arg; OBJECT_STAT_INC(object_visits); if (_PyObject_IS_GC(op)) { PyGC_Head *gc = AS_GC(op); @@ -751,7 +753,7 @@ move_legacy_finalizer_reachable(PyGC_Head *finalizers) /* Note that the finalizers list may grow during this. */ traverse = Py_TYPE(FROM_GC(gc))->tp_traverse; (void) traverse(FROM_GC(gc), - (visitproc)visit_move, + visit_move, (void *)finalizers); } } @@ -1684,8 +1686,9 @@ gc_get_count_impl(PyObject *module) } static int -referrersvisit(PyObject* obj, PyObject *objs) +referrersvisit(PyObject* obj, void *arg) { + PyObject *objs = arg; Py_ssize_t i; for (i = 0; i < PyTuple_GET_SIZE(objs); i++) if (PyTuple_GET_ITEM(objs, i) == obj) @@ -1704,7 +1707,7 @@ gc_referrers_for(PyObject *objs, PyGC_Head *list, PyObject *resultlist) traverse = Py_TYPE(obj)->tp_traverse; if (obj == objs || obj == resultlist) continue; - if (traverse(obj, (visitproc)referrersvisit, objs)) { + if (traverse(obj, referrersvisit, objs)) { if (PyList_Append(resultlist, obj) < 0) return 0; /* error */ } @@ -1740,8 +1743,9 @@ gc_get_referrers(PyObject *self, PyObject *args) /* Append obj to list; return true if error (out of memory), false if OK. */ static int -referentsvisit(PyObject *obj, PyObject *list) +referentsvisit(PyObject *obj, void *arg) { + PyObject *list = arg; return PyList_Append(list, obj) < 0; } @@ -1770,7 +1774,7 @@ gc_get_referents(PyObject *self, PyObject *args) traverse = Py_TYPE(obj)->tp_traverse; if (! traverse) continue; - if (traverse(obj, (visitproc)referentsvisit, result)) { + if (traverse(obj, referentsvisit, result)) { Py_DECREF(result); return NULL; } From e9707d3c3deb45a8352e85dbd5cf41afdb4a2a26 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 6 Dec 2023 20:15:46 +0000 Subject: [PATCH 69/87] gh-101100: Improve documentation of code object attributes (#112781) --- Doc/c-api/function.rst | 4 +- Doc/c-api/import.rst | 2 +- Doc/library/dis.rst | 19 +++--- Doc/library/inspect.rst | 4 +- Doc/reference/datamodel.rst | 114 ++++++++++++++++++++++++++---------- Doc/whatsnew/2.7.rst | 2 +- Doc/whatsnew/3.10.rst | 3 +- Doc/whatsnew/3.12.rst | 5 +- Doc/whatsnew/3.13.rst | 5 +- Doc/whatsnew/3.6.rst | 7 ++- 10 files changed, 112 insertions(+), 53 deletions(-) diff --git a/Doc/c-api/function.rst b/Doc/c-api/function.rst index 5857dba82c11c64..0a18e63c7e7a2cf 100644 --- a/Doc/c-api/function.rst +++ b/Doc/c-api/function.rst @@ -37,7 +37,7 @@ There are a few functions specific to Python functions. The function's docstring and name are retrieved from the code object. *__module__* is retrieved from *globals*. The argument defaults, annotations and closure are set to ``NULL``. *__qualname__* is set to the same value as the code object's - ``co_qualname`` field. + :attr:`~codeobject.co_qualname` field. .. c:function:: PyObject* PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname) @@ -45,7 +45,7 @@ There are a few functions specific to Python functions. As :c:func:`PyFunction_New`, but also allows setting the function object's ``__qualname__`` attribute. *qualname* should be a unicode object or ``NULL``; if ``NULL``, the ``__qualname__`` attribute is set to the same value as the - code object's ``co_qualname`` field. + code object's :attr:`~codeobject.co_qualname` field. .. versionadded:: 3.3 diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 137780cc359cf9d..51c20b202f091c5 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -154,7 +154,7 @@ Importing Modules :class:`~importlib.machinery.SourceFileLoader` otherwise. The module's :attr:`__file__` attribute will be set to the code object's - :attr:`!co_filename`. If applicable, :attr:`__cached__` will also + :attr:`~codeobject.co_filename`. If applicable, :attr:`__cached__` will also be set. This function will reload the module if it was already imported. See diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index cf238f81b9cc645..0d93bc9f5da774c 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -346,8 +346,9 @@ operation is being performed, so the intermediate analysis object isn't useful: Line numbers can be decreasing. Before, they were always increasing. .. versionchanged:: 3.10 - The :pep:`626` ``co_lines`` method is used instead of the ``co_firstlineno`` - and ``co_lnotab`` attributes of the code object. + The :pep:`626` ``co_lines`` method is used instead of the + :attr:`~codeobject.co_firstlineno` and :attr:`~codeobject.co_lnotab` + attributes of the code object. .. versionchanged:: 3.13 Line numbers can be ``None`` for bytecode that does not map to source lines. @@ -983,13 +984,13 @@ iterations of the loop. .. opcode:: STORE_NAME (namei) Implements ``name = STACK.pop()``. *namei* is the index of *name* in the attribute - :attr:`!co_names` of the :ref:`code object `. + :attr:`~codeobject.co_names` of the :ref:`code object `. The compiler tries to use :opcode:`STORE_FAST` or :opcode:`STORE_GLOBAL` if possible. .. opcode:: DELETE_NAME (namei) - Implements ``del name``, where *namei* is the index into :attr:`!co_names` + Implements ``del name``, where *namei* is the index into :attr:`~codeobject.co_names` attribute of the :ref:`code object `. @@ -1029,7 +1030,7 @@ iterations of the loop. value = STACK.pop() obj.name = value - where *namei* is the index of name in :attr:`!co_names` of the + where *namei* is the index of name in :attr:`~codeobject.co_names` of the :ref:`code object `. .. opcode:: DELETE_ATTR (namei) @@ -1039,7 +1040,7 @@ iterations of the loop. obj = STACK.pop() del obj.name - where *namei* is the index of name into :attr:`!co_names` of the + where *namei* is the index of name into :attr:`~codeobject.co_names` of the :ref:`code object `. @@ -1402,7 +1403,7 @@ iterations of the loop. Pushes a reference to the object the cell contains on the stack. .. versionchanged:: 3.11 - ``i`` is no longer offset by the length of ``co_varnames``. + ``i`` is no longer offset by the length of :attr:`~codeobject.co_varnames`. .. opcode:: LOAD_FROM_DICT_OR_DEREF (i) @@ -1424,7 +1425,7 @@ iterations of the loop. storage. .. versionchanged:: 3.11 - ``i`` is no longer offset by the length of ``co_varnames``. + ``i`` is no longer offset by the length of :attr:`~codeobject.co_varnames`. .. opcode:: DELETE_DEREF (i) @@ -1435,7 +1436,7 @@ iterations of the loop. .. versionadded:: 3.2 .. versionchanged:: 3.11 - ``i`` is no longer offset by the length of ``co_varnames``. + ``i`` is no longer offset by the length of :attr:`~codeobject.co_varnames`. .. opcode:: COPY_FREE_VARS (n) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 08f15ae09b1b874..0138557f5fd84c8 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1596,8 +1596,8 @@ updated as expected: Code Objects Bit Flags ---------------------- -Python code objects have a ``co_flags`` attribute, which is a bitmap of -the following flags: +Python code objects have a :attr:`~codeobject.co_flags` attribute, +which is a bitmap of the following flags: .. data:: CO_OPTIMIZED diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 8a94b7bb22c3621..3bcc170faa087a7 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1077,57 +1077,111 @@ indirectly) to mutable objects. single: co_freevars (code object attribute) single: co_qualname (code object attribute) -Special read-only attributes: :attr:`co_name` gives the function name; -:attr:`co_qualname` gives the fully qualified function name; -:attr:`co_argcount` is the total number of positional arguments -(including positional-only arguments and arguments with default values); -:attr:`co_posonlyargcount` is the number of positional-only arguments -(including arguments with default values); :attr:`co_kwonlyargcount` is -the number of keyword-only arguments (including arguments with default -values); :attr:`co_nlocals` is the number of local variables used by the -function (including arguments); :attr:`co_varnames` is a tuple containing -the names of the local variables (starting with the argument names); -:attr:`co_cellvars` is a tuple containing the names of local variables -that are referenced by nested functions; :attr:`co_freevars` is a tuple -containing the names of free variables; :attr:`co_code` is a string -representing the sequence of bytecode instructions; :attr:`co_consts` is -a tuple containing the literals used by the bytecode; :attr:`co_names` is -a tuple containing the names used by the bytecode; :attr:`co_filename` is -the filename from which the code was compiled; :attr:`co_firstlineno` is -the first line number of the function; :attr:`co_lnotab` is a string -encoding the mapping from bytecode offsets to line numbers (for details -see the source code of the interpreter, is deprecated since 3.12 -and may be removed in 3.14); :attr:`co_stacksize` is the -required stack size; :attr:`co_flags` is an integer encoding a number -of flags for the interpreter. +Special read-only attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. list-table:: + + * - .. attribute:: codeobject.co_name + - The function name + + * - .. attribute:: codeobject.co_qualname + - The fully qualified function name + + * - .. attribute:: codeobject.co_argcount + - The total number of positional :term:`parameters ` + (including positional-only parameters and parameters with default values) + that the function has + + * - .. attribute:: codeobject.co_posonlyargcount + - The number of positional-only :term:`parameters ` + (including arguments with default values) that the function has + + * - .. attribute:: codeobject.co_kwonlyargcount + - The number of keyword-only :term:`parameters ` + (including arguments with default values) that the function has + + * - .. attribute:: codeobject.co_nlocals + - The number of :ref:`local variables ` used by the function + (including parameters) + + * - .. attribute:: codeobject.co_varnames + - A :class:`tuple` containing the names of the local variables in the + function (starting with the parameter names) + + * - .. attribute:: codeobject.co_cellvars + - A :class:`tuple` containing the names of :ref:`local variables ` + that are referenced by nested functions inside the function + + * - .. attribute:: codeobject.co_freevars + - A :class:`tuple` containing the names of free variables in the function + + * - .. attribute:: codeobject.co_code + - A string representing the sequence of :term:`bytecode` instructions in + the function + + * - .. attribute:: codeobject.co_consts + - A :class:`tuple` containing the literals used by the :term:`bytecode` in + the function + + * - .. attribute:: codeobject.co_names + - A :class:`tuple` containing the names used by the :term:`bytecode` in + the function + + * - .. attribute:: codeobject.co_filename + - The name of the file from which the code was compiled + + * - .. attribute:: codeobject.co_firstlineno + - The line number of the first line of the function + + * - .. attribute:: codeobject.co_lnotab + - A string encoding the mapping from :term:`bytecode` offsets to line + numbers. For details, see the source code of the interpreter. + + .. deprecated:: 3.12 + This attribute of code objects is deprecated, and may be removed in + Python 3.14. + + * - .. attribute:: codeobject.co_stacksize + - The required stack size of the code object + + * - .. attribute:: codeobject.co_flags + - An :class:`integer ` encoding a number of flags for the + interpreter. .. index:: pair: object; generator -The following flag bits are defined for :attr:`co_flags`: bit ``0x04`` is set if +The following flag bits are defined for :attr:`~codeobject.co_flags`: +bit ``0x04`` is set if the function uses the ``*arguments`` syntax to accept an arbitrary number of positional arguments; bit ``0x08`` is set if the function uses the ``**keywords`` syntax to accept arbitrary keyword arguments; bit ``0x20`` is set -if the function is a generator. +if the function is a generator. See :ref:`inspect-module-co-flags` for details +on the semantics of each flags that might be present. Future feature declarations (``from __future__ import division``) also use bits -in :attr:`co_flags` to indicate whether a code object was compiled with a +in :attr:`~codeobject.co_flags` to indicate whether a code object was compiled with a particular feature enabled: bit ``0x2000`` is set if the function was compiled with future division enabled; bits ``0x10`` and ``0x1000`` were used in earlier versions of Python. -Other bits in :attr:`co_flags` are reserved for internal use. +Other bits in :attr:`~codeobject.co_flags` are reserved for internal use. .. index:: single: documentation string -If a code object represents a function, the first item in :attr:`co_consts` is +If a code object represents a function, the first item in +:attr:`~codeobject.co_consts` is the documentation string of the function, or ``None`` if undefined. +The :meth:`!co_positions` method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .. method:: codeobject.co_positions() - Returns an iterable over the source code positions of each bytecode + Returns an iterable over the source code positions of each :term:`bytecode` instruction in the code object. - The iterator returns tuples containing the ``(start_line, end_line, + The iterator returns :class:`tuple`\s containing the ``(start_line, end_line, start_column, end_column)``. The *i-th* tuple corresponds to the position of the source code that compiled to the *i-th* instruction. Column information is 0-indexed utf-8 byte offsets on the given source diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 4072e040dc9130d..162dd74637479a5 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -2405,7 +2405,7 @@ Other Changes and Fixes :issue:`5464`.) * When importing a module from a :file:`.pyc` or :file:`.pyo` file - with an existing :file:`.py` counterpart, the :attr:`co_filename` + with an existing :file:`.py` counterpart, the :attr:`~codeobject.co_filename` attributes of the resulting code objects are overwritten when the original filename is obsolete. This can happen if the file has been renamed, moved, or is accessed through different paths. (Patch by diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 15479cc979624f8..2da90b7ed557445 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -402,7 +402,8 @@ Tracing events, with the correct line number, are generated for all lines of cod The :attr:`~frame.f_lineno` attribute of frame objects will always contain the expected line number. -The ``co_lnotab`` attribute of code objects is deprecated and will be removed in 3.12. +The :attr:`~codeobject.co_lnotab` attribute of code objects is deprecated and +will be removed in 3.12. Code that needs to convert from offset to line number should use the new ``co_lines()`` method instead. PEP 634: Structural Pattern Matching diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index fc17c86665335c5..07d22a4a5fb7736 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1323,7 +1323,8 @@ Deprecated ``int``, convert to int explicitly: ``~int(x)``. (Contributed by Tim Hoffmann in :gh:`103487`.) -* Accessing ``co_lnotab`` on code objects was deprecated in Python 3.10 via :pep:`626`, +* Accessing :attr:`~codeobject.co_lnotab` on code objects was deprecated in + Python 3.10 via :pep:`626`, but it only got a proper :exc:`DeprecationWarning` in 3.12, therefore it will be removed in 3.14. (Contributed by Nikita Sobolev in :gh:`101866`.) @@ -1430,7 +1431,7 @@ and will be removed in Python 3.14. * The ``__package__`` and ``__cached__`` attributes on module objects. -* The ``co_lnotab`` attribute of code objects. +* The :attr:`~codeobject.co_lnotab` attribute of code objects. Pending Removal in Python 3.15 ------------------------------ diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index c9facad6375ef3f..f5723e050a2762e 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -572,7 +572,8 @@ Pending Removal in Python 3.14 * date and datetime adapter, date and timestamp converter: see the :mod:`sqlite3` documentation for suggested replacement recipes. -* :class:`types.CodeType`: Accessing ``co_lnotab`` was deprecated in :pep:`626` +* :class:`types.CodeType`: Accessing :attr:`~codeobject.co_lnotab` was + deprecated in :pep:`626` since 3.10 and was planned to be removed in 3.12, but it only got a proper :exc:`DeprecationWarning` in 3.12. May be removed in 3.14. @@ -735,7 +736,7 @@ although there is currently no date scheduled for their removal. * :mod:`!sre_compile`, :mod:`!sre_constants` and :mod:`!sre_parse` modules. -* ``types.CodeType.co_lnotab``: use the ``co_lines`` attribute instead. +* :attr:`~codeobject.co_lnotab`: use the ``co_lines`` attribute instead. * :class:`typing.Text` (:gh:`92332`). diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 2f618929793fc6f..5a3cea0ec87cb23 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2160,14 +2160,15 @@ Changes in the Python API * :c:func:`PyErr_SetImportError` now sets :exc:`TypeError` when its **msg** argument is not set. Previously only ``NULL`` was returned. -* The format of the ``co_lnotab`` attribute of code objects changed to support +* The format of the :attr:`~codeobject.co_lnotab` attribute of code objects + changed to support a negative line number delta. By default, Python does not emit bytecode with a negative line number delta. Functions using :attr:`frame.f_lineno`, ``PyFrame_GetLineNumber()`` or ``PyCode_Addr2Line()`` are not affected. - Functions directly decoding ``co_lnotab`` should be updated to use a signed + Functions directly decoding :attr:`!co_lnotab` should be updated to use a signed 8-bit integer type for the line number delta, but this is only required to support applications using a negative line number delta. See - ``Objects/lnotab_notes.txt`` for the ``co_lnotab`` format and how to decode + ``Objects/lnotab_notes.txt`` for the :attr:`!co_lnotab` format and how to decode it, and see the :pep:`511` for the rationale. * The functions in the :mod:`compileall` module now return booleans instead From 3870d19d151c31d77b737d6a480aa946b4e87af6 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 6 Dec 2023 20:16:12 +0000 Subject: [PATCH 70/87] gh-101100: Fix Sphinx nitpicks in `library/reprlib.rst` (#112811) --- Doc/library/reprlib.rst | 52 ++++++++++++++++++++++++----------------- Doc/tools/.nitignore | 1 - 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/Doc/library/reprlib.rst b/Doc/library/reprlib.rst index 5ebb0a7780c37bc..678a11c6f454908 100644 --- a/Doc/library/reprlib.rst +++ b/Doc/library/reprlib.rst @@ -10,7 +10,7 @@ -------------- -The :mod:`reprlib` module provides a means for producing object representations +The :mod:`!reprlib` module provides a means for producing object representations with limits on the size of the resulting strings. This is used in the Python debugger and may be useful in other contexts as well. @@ -58,29 +58,31 @@ This module provides a class, an instance, and a function: limits on most sizes. In addition to size-limiting tools, the module also provides a decorator for -detecting recursive calls to :meth:`__repr__` and substituting a placeholder -string instead. +detecting recursive calls to :meth:`~object.__repr__` and substituting a +placeholder string instead. .. index:: single: ...; placeholder .. decorator:: recursive_repr(fillvalue="...") - Decorator for :meth:`__repr__` methods to detect recursive calls within the + Decorator for :meth:`~object.__repr__` methods to detect recursive calls within the same thread. If a recursive call is made, the *fillvalue* is returned, - otherwise, the usual :meth:`__repr__` call is made. For example: - - >>> from reprlib import recursive_repr - >>> class MyList(list): - ... @recursive_repr() - ... def __repr__(self): - ... return '<' + '|'.join(map(repr, self)) + '>' - ... - >>> m = MyList('abc') - >>> m.append(m) - >>> m.append('x') - >>> print(m) - <'a'|'b'|'c'|...|'x'> + otherwise, the usual :meth:`!__repr__` call is made. For example: + + .. doctest:: + + >>> from reprlib import recursive_repr + >>> class MyList(list): + ... @recursive_repr() + ... def __repr__(self): + ... return '<' + '|'.join(map(repr, self)) + '>' + ... + >>> m = MyList('abc') + >>> m.append(m) + >>> m.append('x') + >>> print(m) + <'a'|'b'|'c'|...|'x'> .. versionadded:: 3.2 @@ -148,10 +150,10 @@ which format specific object types. with no line breaks or indentation, like the standard :func:`repr`. For example: - .. code-block:: pycon + .. doctest:: indent >>> example = [ - 1, 'spam', {'a': 2, 'b': 'spam eggs', 'c': {3: 4.5, 6: []}}, 'ham'] + ... 1, 'spam', {'a': 2, 'b': 'spam eggs', 'c': {3: 4.5, 6: []}}, 'ham'] >>> import reprlib >>> aRepr = reprlib.Repr() >>> print(aRepr.repr(example)) @@ -160,7 +162,7 @@ which format specific object types. If :attr:`~Repr.indent` is set to a string, each recursion level is placed on its own line, indented by that string: - .. code-block:: pycon + .. doctest:: indent >>> aRepr.indent = '-->' >>> print(aRepr.repr(example)) @@ -181,7 +183,7 @@ which format specific object types. Setting :attr:`~Repr.indent` to a positive integer value behaves as if it was set to a string with that number of spaces: - .. code-block:: pycon + .. doctest:: indent >>> aRepr.indent = 4 >>> print(aRepr.repr(example)) @@ -234,7 +236,9 @@ Subclassing Repr Objects The use of dynamic dispatching by :meth:`Repr.repr1` allows subclasses of :class:`Repr` to add support for additional built-in object types or to modify the handling of types already supported. This example shows how special support -for file objects could be added:: +for file objects could be added: + +.. testcode:: import reprlib import sys @@ -248,3 +252,7 @@ for file objects could be added:: aRepr = MyRepr() print(aRepr.repr(sys.stdin)) # prints '' + +.. testoutput:: + + diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore index 50f04d72c0dee01..ada1fc5fafc9c93 100644 --- a/Doc/tools/.nitignore +++ b/Doc/tools/.nitignore @@ -84,7 +84,6 @@ Doc/library/pydoc.rst Doc/library/pyexpat.rst Doc/library/random.rst Doc/library/readline.rst -Doc/library/reprlib.rst Doc/library/resource.rst Doc/library/rlcompleter.rst Doc/library/select.rst From 16448cab44e23d350824e9ac75e699f5bcc48a14 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Wed, 6 Dec 2023 22:29:54 +0000 Subject: [PATCH 71/87] gh-112730: Use color to highlight error locations (gh-112732) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pablo Galindo Co-authored-by: Łukasz Langa --- Doc/using/cmdline.rst | 27 +++ Doc/whatsnew/3.13.rst | 6 + Lib/test/test_traceback.py | 126 ++++++++++- Lib/traceback.py | 197 ++++++++++++++---- ...-12-04-23-09-07.gh-issue-112730.BXHlFa.rst | 1 + Modules/clinic/posixmodule.c.h | 28 ++- Modules/posixmodule.c | 22 ++ Python/initconfig.c | 2 + 8 files changed, 369 insertions(+), 40 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-12-04-23-09-07.gh-issue-112730.BXHlFa.rst diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index 39c8d114f1e2c5e..56235bf4c28c7c2 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -612,6 +612,27 @@ Miscellaneous options .. versionadded:: 3.13 The ``-X presite`` option. +Controlling Color +~~~~~~~~~~~~~~~~~ + +The Python interpreter is configured by default to use colors to highlight +output in certain situations such as when displaying tracebacks. This +behavior can be controlled by setting different environment variables. + +Setting the environment variable ``TERM`` to ``dumb`` will disable color. + +If the environment variable ``FORCE_COLOR`` is set, then color will be +enabled regardless of the value of TERM. This is useful on CI systems which +aren’t terminals but can none-the-less display ANSI escape sequences. + +If the environment variable ``NO_COLOR`` is set, Python will disable all color +in the output. This takes precedence over ``FORCE_COLOR``. + +All these environment variables are used also by other tools to control color +output. To control the color output only in the Python interpreter, the +:envvar:`PYTHON_COLORS` environment variable can be used. This variable takes +precedence over ``NO_COLOR``, which in turn takes precedence over +``FORCE_COLOR``. Options you shouldn't use ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1110,6 +1131,12 @@ conflict. .. versionadded:: 3.13 +.. envvar:: PYTHON_COLORS + + If this variable is set to ``1``, the interpreter will colorize various kinds + of output. Setting it to ``0`` deactivates this behavior. + + .. versionadded:: 3.13 Debug-mode variables ~~~~~~~~~~~~~~~~~~~~ diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index f5723e050a2762e..9adf7a3893bd708 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -85,7 +85,13 @@ Important deprecations, removals or restrictions: New Features ============ +Improved Error Messages +----------------------- +* The interpreter now colorizes error messages when displaying tracebacks by default. + This feature can be controlled via the new :envvar:`PYTHON_COLORS` environment + variable as well as the canonical ``NO_COLOR`` and ``FORCE_COLOR`` environment + variables. (Contributed by Pablo Galindo Salgado in :gh:`112730`.) Other Language Changes ====================== diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index b60e06ff37f494a..a6708119b811911 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -8,6 +8,7 @@ import inspect import builtins import unittest +import unittest.mock import re import tempfile import random @@ -24,6 +25,7 @@ import json import textwrap import traceback +import contextlib from functools import partial from pathlib import Path @@ -41,6 +43,14 @@ class TracebackCases(unittest.TestCase): # For now, a very minimal set of tests. I want to be sure that # formatting of SyntaxErrors works based on changes for 2.1. + def setUp(self): + super().setUp() + self.colorize = traceback._COLORIZE + traceback._COLORIZE = False + + def tearDown(self): + super().tearDown() + traceback._COLORIZE = self.colorize def get_exception_format(self, func, exc): try: @@ -521,7 +531,7 @@ def test_signatures(self): self.assertEqual( str(inspect.signature(traceback.print_exception)), ('(exc, /, value=, tb=, ' - 'limit=None, file=None, chain=True)')) + 'limit=None, file=None, chain=True, **kwargs)')) self.assertEqual( str(inspect.signature(traceback.format_exception)), @@ -3031,7 +3041,7 @@ def some_inner(k, v): def test_custom_format_frame(self): class CustomStackSummary(traceback.StackSummary): - def format_frame_summary(self, frame_summary): + def format_frame_summary(self, frame_summary, colorize=False): return f'{frame_summary.filename}:{frame_summary.lineno}' def some_inner(): @@ -3056,7 +3066,7 @@ def g(): tb = g() class Skip_G(traceback.StackSummary): - def format_frame_summary(self, frame_summary): + def format_frame_summary(self, frame_summary, colorize=False): if frame_summary.name == 'g': return None return super().format_frame_summary(frame_summary) @@ -3076,7 +3086,6 @@ def __repr__(self) -> str: raise Exception("Unrepresentable") class TestTracebackException(unittest.TestCase): - def do_test_smoke(self, exc, expected_type_str): try: raise exc @@ -4245,6 +4254,115 @@ def test_levenshtein_distance_short_circuit(self): res3 = traceback._levenshtein_distance(a, b, threshold) self.assertGreater(res3, threshold, msg=(a, b, threshold)) +class TestColorizedTraceback(unittest.TestCase): + def test_colorized_traceback(self): + def foo(*args): + x = {'a':{'b': None}} + y = x['a']['b']['c'] + + def baz(*args): + return foo(1,2,3,4) + + def bar(): + return baz(1, + 2,3 + ,4) + try: + bar() + except Exception as e: + exc = traceback.TracebackException.from_exception( + e, capture_locals=True + ) + lines = "".join(exc.format(colorize=True)) + red = traceback._ANSIColors.RED + boldr = traceback._ANSIColors.BOLD_RED + reset = traceback._ANSIColors.RESET + self.assertIn("y = " + red + "x['a']['b']" + reset + boldr + "['c']" + reset, lines) + self.assertIn("return " + red + "foo" + reset + boldr + "(1,2,3,4)" + reset, lines) + self.assertIn("return " + red + "baz" + reset + boldr + "(1," + reset, lines) + self.assertIn(boldr + "2,3" + reset, lines) + self.assertIn(boldr + ",4)" + reset, lines) + self.assertIn(red + "bar" + reset + boldr + "()" + reset, lines) + + def test_colorized_syntax_error(self): + try: + compile("a $ b", "", "exec") + except SyntaxError as e: + exc = traceback.TracebackException.from_exception( + e, capture_locals=True + ) + actual = "".join(exc.format(colorize=True)) + red = traceback._ANSIColors.RED + magenta = traceback._ANSIColors.MAGENTA + boldm = traceback._ANSIColors.BOLD_MAGENTA + boldr = traceback._ANSIColors.BOLD_RED + reset = traceback._ANSIColors.RESET + expected = "".join([ + f' File {magenta}""{reset}, line {magenta}1{reset}\n', + f' a {boldr}${reset} b\n', + f' {boldr}^{reset}\n', + f'{boldm}SyntaxError{reset}: {magenta}invalid syntax{reset}\n'] + ) + self.assertIn(expected, actual) + + def test_colorized_traceback_is_the_default(self): + def foo(): + 1/0 + + from _testcapi import exception_print + try: + foo() + self.fail("No exception thrown.") + except Exception as e: + with captured_output("stderr") as tbstderr: + with unittest.mock.patch('traceback._can_colorize', return_value=True): + exception_print(e) + actual = tbstderr.getvalue().splitlines() + + red = traceback._ANSIColors.RED + boldr = traceback._ANSIColors.BOLD_RED + magenta = traceback._ANSIColors.MAGENTA + boldm = traceback._ANSIColors.BOLD_MAGENTA + reset = traceback._ANSIColors.RESET + lno_foo = foo.__code__.co_firstlineno + expected = ['Traceback (most recent call last):', + f' File {magenta}"{__file__}"{reset}, ' + f'line {magenta}{lno_foo+5}{reset}, in {magenta}test_colorized_traceback_is_the_default{reset}', + f' {red}foo{reset+boldr}(){reset}', + f' {red}~~~{reset+boldr}^^{reset}', + f' File {magenta}"{__file__}"{reset}, ' + f'line {magenta}{lno_foo+1}{reset}, in {magenta}foo{reset}', + f' {red}1{reset+boldr}/{reset+red}0{reset}', + f' {red}~{reset+boldr}^{reset+red}~{reset}', + f'{boldm}ZeroDivisionError{reset}: {magenta}division by zero{reset}'] + self.assertEqual(actual, expected) + + def test_colorized_detection_checks_for_environment_variables(self): + if sys.platform == "win32": + virtual_patching = unittest.mock.patch("nt._supports_virtual_terminal", return_value=True) + else: + virtual_patching = contextlib.nullcontext() + with virtual_patching: + with unittest.mock.patch("os.isatty") as isatty_mock: + isatty_mock.return_value = True + with unittest.mock.patch("os.environ", {'TERM': 'dumb'}): + self.assertEqual(traceback._can_colorize(), False) + with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '1'}): + self.assertEqual(traceback._can_colorize(), True) + with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '0'}): + self.assertEqual(traceback._can_colorize(), False) + with unittest.mock.patch("os.environ", {'NO_COLOR': '1'}): + self.assertEqual(traceback._can_colorize(), False) + with unittest.mock.patch("os.environ", {'NO_COLOR': '1', "PYTHON_COLORS": '1'}): + self.assertEqual(traceback._can_colorize(), True) + with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1'}): + self.assertEqual(traceback._can_colorize(), True) + with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1', 'NO_COLOR': '1'}): + self.assertEqual(traceback._can_colorize(), False) + with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1', "PYTHON_COLORS": '0'}): + self.assertEqual(traceback._can_colorize(), False) + isatty_mock.return_value = False + self.assertEqual(traceback._can_colorize(), False) if __name__ == "__main__": unittest.main() diff --git a/Lib/traceback.py b/Lib/traceback.py index a0485a7023d07d7..1cf008c7e9da979 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1,5 +1,7 @@ """Extract, format and print information about Python stack traces.""" +import os +import io import collections.abc import itertools import linecache @@ -19,6 +21,8 @@ # Formatting and printing lists of traceback lines. # +_COLORIZE = True + def print_list(extracted_list, file=None): """Print the list of tuples as returned by extract_tb() or extract_stack() as a formatted stack trace to the given file.""" @@ -110,7 +114,7 @@ def _parse_value_tb(exc, value, tb): def print_exception(exc, /, value=_sentinel, tb=_sentinel, limit=None, \ - file=None, chain=True): + file=None, chain=True, **kwargs): """Print exception up to 'limit' stack trace entries from 'tb' to 'file'. This differs from print_tb() in the following ways: (1) if @@ -121,17 +125,44 @@ def print_exception(exc, /, value=_sentinel, tb=_sentinel, limit=None, \ occurred with a caret on the next line indicating the approximate position of the error. """ + colorize = kwargs.get("colorize", False) value, tb = _parse_value_tb(exc, value, tb) te = TracebackException(type(value), value, tb, limit=limit, compact=True) - te.print(file=file, chain=chain) + te.print(file=file, chain=chain, colorize=colorize) BUILTIN_EXCEPTION_LIMIT = object() +def _can_colorize(): + if sys.platform == "win32": + try: + import nt + if not nt._supports_virtual_terminal(): + return False + except (ImportError, AttributeError): + return False + + if os.environ.get("PYTHON_COLORS") == "0": + return False + if os.environ.get("PYTHON_COLORS") == "1": + return True + if "NO_COLOR" in os.environ: + return False + if not _COLORIZE: + return False + if "FORCE_COLOR" in os.environ: + return True + if os.environ.get("TERM") == "dumb": + return False + try: + return os.isatty(sys.stderr.fileno()) + except io.UnsupportedOperation: + return sys.stderr.isatty() def _print_exception_bltin(exc, /): file = sys.stderr if sys.stderr is not None else sys.__stderr__ - return print_exception(exc, limit=BUILTIN_EXCEPTION_LIMIT, file=file) + colorize = _can_colorize() + return print_exception(exc, limit=BUILTIN_EXCEPTION_LIMIT, file=file, colorize=colorize) def format_exception(exc, /, value=_sentinel, tb=_sentinel, limit=None, \ @@ -172,13 +203,19 @@ def format_exception_only(exc, /, value=_sentinel, *, show_group=False): # -- not official API but folk probably use these two functions. -def _format_final_exc_line(etype, value, *, insert_final_newline=True): +def _format_final_exc_line(etype, value, *, insert_final_newline=True, colorize=False): valuestr = _safe_string(value, 'exception') end_char = "\n" if insert_final_newline else "" - if value is None or not valuestr: - line = f"{etype}{end_char}" + if colorize: + if value is None or not valuestr: + line = f"{_ANSIColors.BOLD_MAGENTA}{etype}{_ANSIColors.RESET}{end_char}" + else: + line = f"{_ANSIColors.BOLD_MAGENTA}{etype}{_ANSIColors.RESET}: {_ANSIColors.MAGENTA}{valuestr}{_ANSIColors.RESET}{end_char}" else: - line = f"{etype}: {valuestr}{end_char}" + if value is None or not valuestr: + line = f"{etype}{end_char}" + else: + line = f"{etype}: {valuestr}{end_char}" return line def _safe_string(value, what, func=str): @@ -406,6 +443,14 @@ def _get_code_position(code, instruction_index): _RECURSIVE_CUTOFF = 3 # Also hardcoded in traceback.c. +class _ANSIColors: + RED = '\x1b[31m' + BOLD_RED = '\x1b[1;31m' + MAGENTA = '\x1b[35m' + BOLD_MAGENTA = '\x1b[1;35m' + GREY = '\x1b[90m' + RESET = '\x1b[0m' + class StackSummary(list): """A list of FrameSummary objects, representing a stack of frames.""" @@ -496,18 +541,33 @@ def from_list(klass, a_list): result.append(FrameSummary(filename, lineno, name, line=line)) return result - def format_frame_summary(self, frame_summary): + def format_frame_summary(self, frame_summary, **kwargs): """Format the lines for a single FrameSummary. Returns a string representing one frame involved in the stack. This gets called for every frame to be printed in the stack summary. """ + colorize = kwargs.get("colorize", False) row = [] filename = frame_summary.filename if frame_summary.filename.startswith("-"): filename = "" - row.append(' File "{}", line {}, in {}\n'.format( - filename, frame_summary.lineno, frame_summary.name)) + if colorize: + row.append(' File {}"{}"{}, line {}{}{}, in {}{}{}\n'.format( + _ANSIColors.MAGENTA, + filename, + _ANSIColors.RESET, + _ANSIColors.MAGENTA, + frame_summary.lineno, + _ANSIColors.RESET, + _ANSIColors.MAGENTA, + frame_summary.name, + _ANSIColors.RESET, + ) + ) + else: + row.append(' File "{}", line {}, in {}\n'.format( + filename, frame_summary.lineno, frame_summary.name)) if frame_summary._dedented_lines and frame_summary._dedented_lines.strip(): if ( frame_summary.colno is None or @@ -619,7 +679,31 @@ def output_line(lineno): carets.append(secondary_char) else: carets.append(primary_char) - result.append("".join(carets) + "\n") + if colorize: + # Replace the previous line with a red version of it only in the parts covered + # by the carets. + line = result[-1] + colorized_line_parts = [] + colorized_carets_parts = [] + + for color, group in itertools.groupby(itertools.zip_longest(line, carets, fillvalue=""), key=lambda x: x[1]): + caret_group = list(group) + if color == "^": + colorized_line_parts.append(_ANSIColors.BOLD_RED + "".join(char for char, _ in caret_group) + _ANSIColors.RESET) + colorized_carets_parts.append(_ANSIColors.BOLD_RED + "".join(caret for _, caret in caret_group) + _ANSIColors.RESET) + elif color == "~": + colorized_line_parts.append(_ANSIColors.RED + "".join(char for char, _ in caret_group) + _ANSIColors.RESET) + colorized_carets_parts.append(_ANSIColors.RED + "".join(caret for _, caret in caret_group) + _ANSIColors.RESET) + else: + colorized_line_parts.append("".join(char for char, _ in caret_group)) + colorized_carets_parts.append("".join(caret for _, caret in caret_group)) + + colorized_line = "".join(colorized_line_parts) + colorized_carets = "".join(colorized_carets_parts) + result[-1] = colorized_line + result.append(colorized_carets + "\n") + else: + result.append("".join(carets) + "\n") # display significant lines sig_lines_list = sorted(significant_lines) @@ -643,7 +727,7 @@ def output_line(lineno): return ''.join(row) - def format(self): + def format(self, **kwargs): """Format the stack ready for printing. Returns a list of strings ready for printing. Each string in the @@ -655,13 +739,14 @@ def format(self): repetitions are shown, followed by a summary line stating the exact number of further repetitions. """ + colorize = kwargs.get("colorize", False) result = [] last_file = None last_line = None last_name = None count = 0 for frame_summary in self: - formatted_frame = self.format_frame_summary(frame_summary) + formatted_frame = self.format_frame_summary(frame_summary, colorize=colorize) if formatted_frame is None: continue if (last_file is None or last_file != frame_summary.filename or @@ -1118,7 +1203,7 @@ def __eq__(self, other): def __str__(self): return self._str - def format_exception_only(self, *, show_group=False, _depth=0): + def format_exception_only(self, *, show_group=False, _depth=0, **kwargs): """Format the exception part of the traceback. The return value is a generator of strings, each ending in a newline. @@ -1135,10 +1220,11 @@ def format_exception_only(self, *, show_group=False, _depth=0): :exc:`BaseExceptionGroup`, the nested exceptions are included as well, recursively, with indentation relative to their nesting depth. """ + colorize = kwargs.get("colorize", False) indent = 3 * _depth * ' ' if not self._have_exc_type: - yield indent + _format_final_exc_line(None, self._str) + yield indent + _format_final_exc_line(None, self._str, colorize=colorize) return stype = self.exc_type_str @@ -1146,16 +1232,16 @@ def format_exception_only(self, *, show_group=False, _depth=0): if _depth > 0: # Nested exceptions needs correct handling of multiline messages. formatted = _format_final_exc_line( - stype, self._str, insert_final_newline=False, + stype, self._str, insert_final_newline=False, colorize=colorize ).split('\n') yield from [ indent + l + '\n' for l in formatted ] else: - yield _format_final_exc_line(stype, self._str) + yield _format_final_exc_line(stype, self._str, colorize=colorize) else: - yield from [indent + l for l in self._format_syntax_error(stype)] + yield from [indent + l for l in self._format_syntax_error(stype, colorize=colorize)] if ( isinstance(self.__notes__, collections.abc.Sequence) @@ -1169,15 +1255,26 @@ def format_exception_only(self, *, show_group=False, _depth=0): if self.exceptions and show_group: for ex in self.exceptions: - yield from ex.format_exception_only(show_group=show_group, _depth=_depth+1) + yield from ex.format_exception_only(show_group=show_group, _depth=_depth+1, colorize=colorize) - def _format_syntax_error(self, stype): + def _format_syntax_error(self, stype, **kwargs): """Format SyntaxError exceptions (internal helper).""" # Show exactly where the problem was found. + colorize = kwargs.get("colorize", False) filename_suffix = '' if self.lineno is not None: - yield ' File "{}", line {}\n'.format( - self.filename or "", self.lineno) + if colorize: + yield ' File {}"{}"{}, line {}{}{}\n'.format( + _ANSIColors.MAGENTA, + self.filename or "", + _ANSIColors.RESET, + _ANSIColors.MAGENTA, + self.lineno, + _ANSIColors.RESET, + ) + else: + yield ' File "{}", line {}\n'.format( + self.filename or "", self.lineno) elif self.filename is not None: filename_suffix = ' ({})'.format(self.filename) @@ -1189,9 +1286,9 @@ def _format_syntax_error(self, stype): rtext = text.rstrip('\n') ltext = rtext.lstrip(' \n\f') spaces = len(rtext) - len(ltext) - yield ' {}\n'.format(ltext) - - if self.offset is not None: + if self.offset is None: + yield ' {}\n'.format(ltext) + else: offset = self.offset end_offset = self.end_offset if self.end_offset not in {None, 0} else offset if self.text and offset > len(self.text): @@ -1204,14 +1301,43 @@ def _format_syntax_error(self, stype): # Convert 1-based column offset to 0-based index into stripped text colno = offset - 1 - spaces end_colno = end_offset - 1 - spaces + caretspace = ' ' if colno >= 0: # non-space whitespace (likes tabs) must be kept for alignment caretspace = ((c if c.isspace() else ' ') for c in ltext[:colno]) - yield ' {}{}'.format("".join(caretspace), ('^' * (end_colno - colno) + "\n")) + start_color = end_color = "" + if colorize: + # colorize from colno to end_colno + ltext = ( + ltext[:colno] + + _ANSIColors.BOLD_RED + ltext[colno:end_colno] + _ANSIColors.RESET + + ltext[end_colno:] + ) + start_color = _ANSIColors.BOLD_RED + end_color = _ANSIColors.RESET + yield ' {}\n'.format(ltext) + yield ' {}{}{}{}\n'.format( + "".join(caretspace), + start_color, + ('^' * (end_colno - colno)), + end_color, + ) + else: + yield ' {}\n'.format(ltext) msg = self.msg or "" - yield "{}: {}{}\n".format(stype, msg, filename_suffix) + if colorize: + yield "{}{}{}: {}{}{}{}\n".format( + _ANSIColors.BOLD_MAGENTA, + stype, + _ANSIColors.RESET, + _ANSIColors.MAGENTA, + msg, + _ANSIColors.RESET, + filename_suffix) + else: + yield "{}: {}{}\n".format(stype, msg, filename_suffix) - def format(self, *, chain=True, _ctx=None): + def format(self, *, chain=True, _ctx=None, **kwargs): """Format the exception. If chain is not *True*, *__cause__* and *__context__* will not be formatted. @@ -1223,7 +1349,7 @@ def format(self, *, chain=True, _ctx=None): The message indicating which exception occurred is always the last string in the output. """ - + colorize = kwargs.get("colorize", False) if _ctx is None: _ctx = _ExceptionPrintContext() @@ -1253,8 +1379,8 @@ def format(self, *, chain=True, _ctx=None): if exc.exceptions is None: if exc.stack: yield from _ctx.emit('Traceback (most recent call last):\n') - yield from _ctx.emit(exc.stack.format()) - yield from _ctx.emit(exc.format_exception_only()) + yield from _ctx.emit(exc.stack.format(colorize=colorize)) + yield from _ctx.emit(exc.format_exception_only(colorize=colorize)) elif _ctx.exception_group_depth > self.max_group_depth: # exception group, but depth exceeds limit yield from _ctx.emit( @@ -1269,9 +1395,9 @@ def format(self, *, chain=True, _ctx=None): yield from _ctx.emit( 'Exception Group Traceback (most recent call last):\n', margin_char = '+' if is_toplevel else None) - yield from _ctx.emit(exc.stack.format()) + yield from _ctx.emit(exc.stack.format(colorize=colorize)) - yield from _ctx.emit(exc.format_exception_only()) + yield from _ctx.emit(exc.format_exception_only(colorize=colorize)) num_excs = len(exc.exceptions) if num_excs <= self.max_group_width: n = num_excs @@ -1312,11 +1438,12 @@ def format(self, *, chain=True, _ctx=None): _ctx.exception_group_depth = 0 - def print(self, *, file=None, chain=True): + def print(self, *, file=None, chain=True, **kwargs): """Print the result of self.format(chain=chain) to 'file'.""" + colorize = kwargs.get("colorize", False) if file is None: file = sys.stderr - for line in self.format(chain=chain): + for line in self.format(chain=chain, colorize=colorize): print(line, file=file, end="") diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-04-23-09-07.gh-issue-112730.BXHlFa.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-04-23-09-07.gh-issue-112730.BXHlFa.rst new file mode 100644 index 000000000000000..51758dd5f4c3180 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-12-04-23-09-07.gh-issue-112730.BXHlFa.rst @@ -0,0 +1 @@ +Use color to highlight error locations in tracebacks. Patch by Pablo Galindo diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index a6c76370f241be1..9d6cd337f4a2f4f 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -11756,6 +11756,28 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #endif /* (defined(WIFEXITED) || defined(MS_WINDOWS)) */ +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(os__supports_virtual_terminal__doc__, +"_supports_virtual_terminal($module, /)\n" +"--\n" +"\n" +"Checks if virtual terminal is supported in windows"); + +#define OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF \ + {"_supports_virtual_terminal", (PyCFunction)os__supports_virtual_terminal, METH_NOARGS, os__supports_virtual_terminal__doc__}, + +static PyObject * +os__supports_virtual_terminal_impl(PyObject *module); + +static PyObject * +os__supports_virtual_terminal(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return os__supports_virtual_terminal_impl(module); +} + +#endif /* defined(MS_WINDOWS) */ + #ifndef OS_TTYNAME_METHODDEF #define OS_TTYNAME_METHODDEF #endif /* !defined(OS_TTYNAME_METHODDEF) */ @@ -12395,4 +12417,8 @@ 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=2900675ac5219924 input=a9049054013a1b77]*/ + +#ifndef OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF + #define OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF +#endif /* !defined(OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF) */ +/*[clinic end generated code: output=ff0ec3371de19904 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 70d107a297f315d..ddbb4cd43babfcf 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -16073,6 +16073,26 @@ os_waitstatus_to_exitcode_impl(PyObject *module, PyObject *status_obj) } #endif +#if defined(MS_WINDOWS) +/*[clinic input] +os._supports_virtual_terminal + +Checks if virtual terminal is supported in windows +[clinic start generated code]*/ + +static PyObject * +os__supports_virtual_terminal_impl(PyObject *module) +/*[clinic end generated code: output=bd0556a6d9d99fe6 input=0752c98e5d321542]*/ +{ + DWORD mode = 0; + HANDLE handle = GetStdHandle(STD_ERROR_HANDLE); + if (!GetConsoleMode(handle, &mode)) { + Py_RETURN_FALSE; + } + return PyBool_FromLong(mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING); +} +#endif + static PyMethodDef posix_methods[] = { @@ -16277,6 +16297,8 @@ static PyMethodDef posix_methods[] = { OS__PATH_ISFILE_METHODDEF OS__PATH_ISLINK_METHODDEF OS__PATH_EXISTS_METHODDEF + + OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF {NULL, NULL} /* Sentinel */ }; diff --git a/Python/initconfig.c b/Python/initconfig.c index d7f3195ed5fcf0f..06e317907b8ec96 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -293,6 +293,8 @@ static const char usage_envvars[] = "PYTHON_FROZEN_MODULES : if this variable is set, it determines whether or not \n" " frozen modules should be used. The default is \"on\" (or \"off\" if you are \n" " running a local build).\n" +"PYTHON_COLORS : If this variable is set to 1, the interpreter will" +" colorize various kinds of output. Setting it to 0 deactivates this behavior.\n" "These variables have equivalent command-line parameters (see --help for details):\n" "PYTHONDEBUG : enable parser debug mode (-d)\n" "PYTHONDONTWRITEBYTECODE : don't write .pyc files (-B)\n" From 953ee622b3901d3467e65e3484dcfa75ba6fcddf Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 7 Dec 2023 10:30:15 +0100 Subject: [PATCH 72/87] gh-109981: Fix support.fd_count() on macOS 14 (#112797) Use scanning "/dev/fd/" on macOS in support.fd_count(). That's both more efficient than scanning all possible file descriptors, and avoids crashing the interpreter when there are open "guarded" file descriptors. "Guarded" file descriptors are a macOS feature where file descriptors used by system libraries are marked and cause hard crashes when used by "user" code. Co-authored-by: Victor Stinner --- Lib/test/support/os_helper.py | 11 +++++++++-- .../2023-12-06-12-11-13.gh-issue-109981.mOHg10.rst | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/macOS/2023-12-06-12-11-13.gh-issue-109981.mOHg10.rst diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py index 46ae53aa11a91f5..7a67d87fb9e846e 100644 --- a/Lib/test/support/os_helper.py +++ b/Lib/test/support/os_helper.py @@ -592,10 +592,17 @@ def fd_count(): """Count the number of open file descriptors. """ if sys.platform.startswith(('linux', 'freebsd', 'emscripten')): + fd_path = "/proc/self/fd" + elif sys.platform == "darwin": + fd_path = "/dev/fd" + else: + fd_path = None + + if fd_path is not None: try: - names = os.listdir("/proc/self/fd") + names = os.listdir(fd_path) # Subtract one because listdir() internally opens a file - # descriptor to list the content of the /proc/self/fd/ directory. + # descriptor to list the content of the directory. return len(names) - 1 except FileNotFoundError: pass diff --git a/Misc/NEWS.d/next/macOS/2023-12-06-12-11-13.gh-issue-109981.mOHg10.rst b/Misc/NEWS.d/next/macOS/2023-12-06-12-11-13.gh-issue-109981.mOHg10.rst new file mode 100644 index 000000000000000..f86ab2c37ee6ecf --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-12-06-12-11-13.gh-issue-109981.mOHg10.rst @@ -0,0 +1,3 @@ +Use ``/dev/fd`` on macOS to determine the number of open files in +``test.support.os_helper.fd_count`` to avoid a crash with "guarded" file +descriptors when probing for open files. From 8660fb7fd7cdcbfe58ef304f5720efe97ca7c842 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 7 Dec 2023 12:19:43 +0200 Subject: [PATCH 73/87] gh-112660: Do not clear arbitrary errors on import (GH-112661) Previously arbitrary errors could be cleared during formatting error messages for ImportError or AttributeError for modules. Now all unexpected errors are reported. --- ...-12-03-15-29-53.gh-issue-112660.gldBvh.rst | 2 + Objects/moduleobject.c | 57 ++++++++----------- Python/ceval.c | 46 ++++++++++----- Python/import.c | 25 ++++---- 4 files changed, 72 insertions(+), 58 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-12-03-15-29-53.gh-issue-112660.gldBvh.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-03-15-29-53.gh-issue-112660.gldBvh.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-03-15-29-53.gh-issue-112660.gldBvh.rst new file mode 100644 index 000000000000000..ea9052b3e35c485 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-12-03-15-29-53.gh-issue-112660.gldBvh.rst @@ -0,0 +1,2 @@ +Do not clear unexpected errors during formatting error messages for +ImportError and AttributeError for modules. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index bba77ce8ab7e7b1..e2741fef6debd3e 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -749,27 +749,20 @@ module_repr(PyModuleObject *m) } /* Check if the "_initializing" attribute of the module spec is set to true. - Clear the exception and return 0 if spec is NULL. */ int _PyModuleSpec_IsInitializing(PyObject *spec) { - if (spec != NULL) { - PyObject *value; - int ok = PyObject_GetOptionalAttr(spec, &_Py_ID(_initializing), &value); - if (ok == 0) { - return 0; - } - if (value != NULL) { - int initializing = PyObject_IsTrue(value); - Py_DECREF(value); - if (initializing >= 0) { - return initializing; - } - } + if (spec == NULL) { + return 0; } - PyErr_Clear(); - return 0; + PyObject *value; + int rc = PyObject_GetOptionalAttr(spec, &_Py_ID(_initializing), &value); + if (rc > 0) { + rc = PyObject_IsTrue(value); + Py_DECREF(value); + } + return rc; } /* Check if the submodule name is in the "_uninitialized_submodules" attribute @@ -782,17 +775,13 @@ _PyModuleSpec_IsUninitializedSubmodule(PyObject *spec, PyObject *name) return 0; } - PyObject *value = PyObject_GetAttr(spec, &_Py_ID(_uninitialized_submodules)); - if (value == NULL) { - return 0; + PyObject *value; + int rc = PyObject_GetOptionalAttr(spec, &_Py_ID(_uninitialized_submodules), &value); + if (rc > 0) { + rc = PySequence_Contains(value, name); + Py_DECREF(value); } - - int is_uninitialized = PySequence_Contains(value, name); - Py_DECREF(value); - if (is_uninitialized == -1) { - return 0; - } - return is_uninitialized; + return rc; } PyObject* @@ -840,23 +829,27 @@ _Py_module_getattro_impl(PyModuleObject *m, PyObject *name, int suppress) return NULL; } if (suppress != 1) { - if (_PyModuleSpec_IsInitializing(spec)) { + int rc = _PyModuleSpec_IsInitializing(spec); + if (rc > 0) { PyErr_Format(PyExc_AttributeError, "partially initialized " "module '%U' has no attribute '%U' " "(most likely due to a circular import)", mod_name, name); } - else if (_PyModuleSpec_IsUninitializedSubmodule(spec, name)) { - PyErr_Format(PyExc_AttributeError, + else if (rc == 0) { + rc = _PyModuleSpec_IsUninitializedSubmodule(spec, name); + if (rc > 0) { + PyErr_Format(PyExc_AttributeError, "cannot access submodule '%U' of module '%U' " "(most likely due to a circular import)", name, mod_name); - } - else { - PyErr_Format(PyExc_AttributeError, + } + else if (rc == 0) { + PyErr_Format(PyExc_AttributeError, "module '%U' has no attribute '%U'", mod_name, name); + } } } Py_XDECREF(spec); diff --git a/Python/ceval.c b/Python/ceval.c index 1806ceb7fa96819..f8fa50eb46c75ea 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2614,11 +2614,10 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name) /* Issue #17636: in case this failed because of a circular relative import, try to fallback on reading the module directly from sys.modules. */ - pkgname = PyObject_GetAttr(v, &_Py_ID(__name__)); - if (pkgname == NULL) { - goto error; + if (PyObject_GetOptionalAttr(v, &_Py_ID(__name__), &pkgname) < 0) { + return NULL; } - if (!PyUnicode_Check(pkgname)) { + if (pkgname == NULL || !PyUnicode_Check(pkgname)) { Py_CLEAR(pkgname); goto error; } @@ -2635,42 +2634,59 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name) Py_DECREF(pkgname); return x; error: - pkgpath = PyModule_GetFilenameObject(v); if (pkgname == NULL) { pkgname_or_unknown = PyUnicode_FromString(""); if (pkgname_or_unknown == NULL) { - Py_XDECREF(pkgpath); return NULL; } } else { pkgname_or_unknown = pkgname; } + pkgpath = NULL; + if (PyModule_Check(v)) { + pkgpath = PyModule_GetFilenameObject(v); + if (pkgpath == NULL) { + if (!PyErr_ExceptionMatches(PyExc_SystemError)) { + Py_DECREF(pkgname_or_unknown); + return NULL; + } + // module filename missing + _PyErr_Clear(tstate); + } + } if (pkgpath == NULL || !PyUnicode_Check(pkgpath)) { - _PyErr_Clear(tstate); + Py_CLEAR(pkgpath); errmsg = PyUnicode_FromFormat( "cannot import name %R from %R (unknown location)", name, pkgname_or_unknown ); - /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */ - _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, NULL, name); } else { - PyObject *spec = PyObject_GetAttr(v, &_Py_ID(__spec__)); + PyObject *spec; + int rc = PyObject_GetOptionalAttr(v, &_Py_ID(__spec__), &spec); + if (rc > 0) { + rc = _PyModuleSpec_IsInitializing(spec); + Py_DECREF(spec); + } + if (rc < 0) { + Py_DECREF(pkgname_or_unknown); + Py_DECREF(pkgpath); + return NULL; + } const char *fmt = - _PyModuleSpec_IsInitializing(spec) ? + rc ? "cannot import name %R from partially initialized module %R " "(most likely due to a circular import) (%S)" : "cannot import name %R from %R (%S)"; - Py_XDECREF(spec); errmsg = PyUnicode_FromFormat(fmt, name, pkgname_or_unknown, pkgpath); - /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */ - _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, pkgpath, name); } + /* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */ + _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, pkgpath, name); Py_XDECREF(errmsg); - Py_XDECREF(pkgname_or_unknown); + Py_DECREF(pkgname_or_unknown); Py_XDECREF(pkgpath); return NULL; } diff --git a/Python/import.c b/Python/import.c index f37393bbdc42695..ef81f46a4d65c1f 100644 --- a/Python/import.c +++ b/Python/import.c @@ -252,18 +252,21 @@ import_ensure_initialized(PyInterpreterState *interp, PyObject *mod, PyObject *n NOTE: because of this, initializing must be set *before* stuffing the new module in sys.modules. */ - spec = PyObject_GetAttr(mod, &_Py_ID(__spec__)); - int busy = _PyModuleSpec_IsInitializing(spec); - Py_XDECREF(spec); - if (busy) { - /* Wait until module is done importing. */ - PyObject *value = PyObject_CallMethodOneArg( - IMPORTLIB(interp), &_Py_ID(_lock_unlock_module), name); - if (value == NULL) { - return -1; - } - Py_DECREF(value); + int rc = PyObject_GetOptionalAttr(mod, &_Py_ID(__spec__), &spec); + if (rc > 0) { + rc = _PyModuleSpec_IsInitializing(spec); + Py_DECREF(spec); + } + if (rc <= 0) { + return rc; } + /* Wait until module is done importing. */ + PyObject *value = PyObject_CallMethodOneArg( + IMPORTLIB(interp), &_Py_ID(_lock_unlock_module), name); + if (value == NULL) { + return -1; + } + Py_DECREF(value); return 0; } From 4ba15de19153bb97308996ec85242bdeda358387 Mon Sep 17 00:00:00 2001 From: Kushal Das Date: Thu, 7 Dec 2023 11:22:52 +0100 Subject: [PATCH 74/87] gh-74616: Raise ValueError in case of null character in input prompt (GH-1738) If the input prompt to the builtin input function on terminal has any null character, then raise ValueError instead of silently truncating it. Co-authored-by: Serhiy Storchaka --- Lib/test/test_builtin.py | 44 +++++++++++++++---- ...3-12-07-12-00-04.gh-issue-74616.kgTGVb.rst | 2 + Python/bltinmodule.c | 5 +++ 3 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-12-07-12-00-04.gh-issue-74616.kgTGVb.rst diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 535856adaea4d35..558715383c82ee1 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -2269,7 +2269,10 @@ def _run_child(self, child, terminal_input): return lines - def check_input_tty(self, prompt, terminal_input, stdio_encoding=None): + def check_input_tty(self, prompt, terminal_input, stdio_encoding=None, *, + expected=None, + stdin_errors='surrogateescape', + stdout_errors='replace'): if not sys.stdin.isatty() or not sys.stdout.isatty(): self.skipTest("stdin and stdout must be ttys") def child(wpipe): @@ -2277,22 +2280,26 @@ def child(wpipe): if stdio_encoding: sys.stdin = io.TextIOWrapper(sys.stdin.detach(), encoding=stdio_encoding, - errors='surrogateescape') + errors=stdin_errors) sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding=stdio_encoding, - errors='replace') + errors=stdout_errors) print("tty =", sys.stdin.isatty() and sys.stdout.isatty(), file=wpipe) - print(ascii(input(prompt)), file=wpipe) + try: + print(ascii(input(prompt)), file=wpipe) + except BaseException as e: + print(ascii(f'{e.__class__.__name__}: {e!s}'), file=wpipe) lines = self.run_child(child, terminal_input + b"\r\n") # Check we did exercise the GNU readline path self.assertIn(lines[0], {'tty = True', 'tty = False'}) if lines[0] != 'tty = True': self.skipTest("standard IO in should have been a tty") input_result = eval(lines[1]) # ascii() -> eval() roundtrip - if stdio_encoding: - expected = terminal_input.decode(stdio_encoding, 'surrogateescape') - else: - expected = terminal_input.decode(sys.stdin.encoding) # what else? + if expected is None: + if stdio_encoding: + expected = terminal_input.decode(stdio_encoding, 'surrogateescape') + else: + expected = terminal_input.decode(sys.stdin.encoding) # what else? self.assertEqual(input_result, expected) def test_input_tty(self): @@ -2313,13 +2320,32 @@ def skip_if_readline(self): def test_input_tty_non_ascii(self): self.skip_if_readline() # Check stdin/stdout encoding is used when invoking PyOS_Readline() - self.check_input_tty("prompté", b"quux\xe9", "utf-8") + self.check_input_tty("prompté", b"quux\xc3\xa9", "utf-8") def test_input_tty_non_ascii_unicode_errors(self): self.skip_if_readline() # Check stdin/stdout error handler is used when invoking PyOS_Readline() self.check_input_tty("prompté", b"quux\xe9", "ascii") + def test_input_tty_null_in_prompt(self): + self.check_input_tty("prompt\0", b"", + expected='ValueError: input: prompt string cannot contain ' + 'null characters') + + def test_input_tty_nonencodable_prompt(self): + self.skip_if_readline() + self.check_input_tty("prompté", b"quux", "ascii", stdout_errors='strict', + expected="UnicodeEncodeError: 'ascii' codec can't encode " + "character '\\xe9' in position 6: ordinal not in " + "range(128)") + + def test_input_tty_nondecodable_input(self): + self.skip_if_readline() + self.check_input_tty("prompt", b"quux\xe9", "ascii", stdin_errors='strict', + expected="UnicodeDecodeError: 'ascii' codec can't decode " + "byte 0xe9 in position 4: ordinal not in " + "range(128)") + def test_input_no_stdout_fileno(self): # Issue #24402: If stdin is the original terminal but stdout.fileno() # fails, do not use the original stdout file descriptor diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-07-12-00-04.gh-issue-74616.kgTGVb.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-07-12-00-04.gh-issue-74616.kgTGVb.rst new file mode 100644 index 000000000000000..5c345be9de6d0bb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-12-07-12-00-04.gh-issue-74616.kgTGVb.rst @@ -0,0 +1,2 @@ +:func:`input` now raises a ValueError when output on the terminal if the +prompt contains embedded null characters instead of silently truncating it. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 7a9625134761f9d..960bca01990c837 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2262,6 +2262,11 @@ builtin_input_impl(PyObject *module, PyObject *prompt) goto _readline_errors; assert(PyBytes_Check(po)); promptstr = PyBytes_AS_STRING(po); + if ((Py_ssize_t)strlen(promptstr) != PyBytes_GET_SIZE(po)) { + PyErr_SetString(PyExc_ValueError, + "input: prompt string cannot contain null characters"); + goto _readline_errors; + } } else { po = NULL; From 4b125dd31a634871d3b2d06ebfd1b9aef539766b Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 7 Dec 2023 11:27:30 +0100 Subject: [PATCH 75/87] gh-51944: Add missing macOS constants to termios (#112823) * gh-51944: Add some macOS constants to termios This changeset adds all public constants in and on macOS that weren't present already. Based on the macOS 14.2 SDK Co-authored-by: Serhiy Storchaka --- ...3-12-06-14-06-14.gh-issue-51944.-5qq_L.rst | 6 ++ Modules/termios.c | 61 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-12-06-14-06-14.gh-issue-51944.-5qq_L.rst diff --git a/Misc/NEWS.d/next/Library/2023-12-06-14-06-14.gh-issue-51944.-5qq_L.rst b/Misc/NEWS.d/next/Library/2023-12-06-14-06-14.gh-issue-51944.-5qq_L.rst new file mode 100644 index 000000000000000..821eefa7cffcd5c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-06-14-06-14.gh-issue-51944.-5qq_L.rst @@ -0,0 +1,6 @@ +Add the following constants to the :mod:`termios` module. These values are +present in macOS system headers: ``ALTWERASE``, ``B14400``, ``B28800``, +``B7200``, ``B76800``, ``CCAR_OFLOW``, ``CCTS_OFLOW``, ``CDSR_OFLOW``, +``CDTR_IFLOW``, ``CIGNORE``, ``CRTS_IFLOW``, ``EXTPROC``, ``IUTF8``, +``MDMBUF``, ``NL2``, ``NL3``, ``NOKERNINFO``, ``ONOEOT``, ``OXTABS``, +``VDSUSP``, ``VSTATUS``. diff --git a/Modules/termios.c b/Modules/termios.c index 9fc2673ce0e7881..1d97a3a2757966f 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -702,6 +702,9 @@ static struct constant { #ifdef IMAXBEL {"IMAXBEL", IMAXBEL}, #endif +#ifdef IUTF8 + {"IUTF8", IUTF8}, +#endif /* struct termios.c_oflag constants */ {"OPOST", OPOST}, @@ -726,6 +729,12 @@ static struct constant { #ifdef OFDEL {"OFDEL", OFDEL}, #endif +#ifdef OXTABS + {"OXTABS", OXTABS}, +#endif +#ifdef ONOEOT + {"ONOEOT", ONOEOT}, +#endif #ifdef NLDLY {"NLDLY", NLDLY}, #endif @@ -752,6 +761,12 @@ static struct constant { #ifdef NL1 {"NL1", NL1}, #endif +#ifdef NL2 + {"NL2", NL2}, +#endif +#ifdef NL3 + {"NL3", NL3}, +#endif #ifdef CR0 {"CR0", CR0}, #endif @@ -799,6 +814,9 @@ static struct constant { #endif /* struct termios.c_cflag constants */ +#ifdef CIGNORE + {"CIGNORE", CIGNORE}, +#endif {"CSIZE", CSIZE}, {"CSTOPB", CSTOPB}, {"CREAD", CREAD}, @@ -813,6 +831,22 @@ static struct constant { {"CRTSCTS", (long)CRTSCTS}, #endif +#ifdef CRTS_IFLOW + {"CRTS_IFLOW", CRTS_IFLOW}, +#endif +#ifdef CDTR_IFLOW + {"CDTR_IFLOW", CDTR_IFLOW}, +#endif +#ifdef CDSR_OFLOW + {"CDSR_OFLOW", CDSR_OFLOW}, +#endif +#ifdef CCAR_OFLOW + {"CCAR_OFLOW", CCAR_OFLOW}, +#endif +#ifdef MDMBUF + {"MDMBUF", MDMBUF}, +#endif + /* struct termios.c_cflag-related values (character size) */ {"CS5", CS5}, {"CS6", CS6}, @@ -820,6 +854,9 @@ static struct constant { {"CS8", CS8}, /* struct termios.c_lflag constants */ +#ifdef ALTWERASE + {"ALTWERASE", ALTWERASE}, +#endif {"ISIG", ISIG}, {"ICANON", ICANON}, #ifdef XCASE @@ -840,6 +877,9 @@ static struct constant { #endif #ifdef FLUSHO {"FLUSHO", FLUSHO}, +#endif +#ifdef NOKERNINFO + {"NOKERNINFO", NOKERNINFO}, #endif {"NOFLSH", NOFLSH}, {"TOSTOP", TOSTOP}, @@ -847,6 +887,9 @@ static struct constant { {"PENDIN", PENDIN}, #endif {"IEXTEN", IEXTEN}, +#ifdef EXTPROC + {"EXTPROC", EXTPROC}, +#endif /* indexes into the control chars array returned by tcgetattr() */ {"VINTR", VINTR}, @@ -855,6 +898,9 @@ static struct constant { {"VKILL", VKILL}, {"VEOF", VEOF}, {"VTIME", VTIME}, +#ifdef VSTATUS + {"VSTATUS", VSTATUS}, +#endif {"VMIN", VMIN}, #ifdef VSWTC /* The #defines above ensure that if either is defined, both are, @@ -865,6 +911,9 @@ static struct constant { {"VSTART", VSTART}, {"VSTOP", VSTOP}, {"VSUSP", VSUSP}, +#ifdef VDSUSP + {"VDSUSP", VREPRINT}, +#endif {"VEOL", VEOL}, #ifdef VREPRINT {"VREPRINT", VREPRINT}, @@ -883,6 +932,18 @@ static struct constant { #endif +#ifdef B7200 + {"B7200", B7200}, +#endif +#ifdef B14400 + {"B14400", B14400}, +#endif +#ifdef B28800 + {"B28800", B28800}, +#endif +#ifdef B76800 + {"B76800", B76800}, +#endif #ifdef B460800 {"B460800", B460800}, #endif From 3d712a9f4c9f366edbe16b804ec4f6ae50b0a59f Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 7 Dec 2023 02:19:33 -0900 Subject: [PATCH 76/87] gh-102980: Redirect output of pdb's `interact` command, add tests and improve docs (#111194) --- Doc/library/pdb.rst | 19 ++++++- Lib/pdb.py | 17 ++++-- Lib/test/test_pdb.py | 53 +++++++++++++++++++ ...-10-23-03-49-34.gh-issue-102980.aXBd54.rst | 1 + 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-10-23-03-49-34.gh-issue-102980.aXBd54.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index bbc6aacc62aafa7..2495dcf50bb17f5 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -570,10 +570,27 @@ can be overridden by the local file. Start an interactive interpreter (using the :mod:`code` module) whose global namespace contains all the (global and local) names found in the current - scope. + scope. Use ``exit()`` or ``quit()`` to exit the interpreter and return to + the debugger. + + .. note:: + + Because interact creates a new global namespace with the current global + and local namespace for execution, assignment to variables will not + affect the original namespaces. + However, modification to the mutable objects will be reflected in the + original namespaces. .. versionadded:: 3.2 + .. versionadded:: 3.13 + ``exit()`` and ``quit()`` can be used to exit :pdbcmd:`interact` + command. + + .. versionchanged:: 3.13 + :pdbcmd:`interact` directs its output to the debugger's + output channel rather than :data:`sys.stderr`. + .. _debugger-aliases: .. pdbcommand:: alias [name [command]] diff --git a/Lib/pdb.py b/Lib/pdb.py index 9d124189df11cfc..83b7fefec63636d 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -207,6 +207,15 @@ def namespace(self): ) +class _PdbInteractiveConsole(code.InteractiveConsole): + def __init__(self, ns, message): + self._message = message + super().__init__(locals=ns, local_exit=True) + + def write(self, data): + self._message(data, end='') + + # Interaction prompt line will separate file and call info from code # text using value of line_prefix string. A newline and arrow may # be to your liking. You can set it once pdb is imported using the @@ -672,8 +681,8 @@ def handle_command_def(self, line): # interface abstraction functions - def message(self, msg): - print(msg, file=self.stdout) + def message(self, msg, end='\n'): + print(msg, end=end, file=self.stdout) def error(self, msg): print('***', msg, file=self.stdout) @@ -1786,7 +1795,9 @@ def do_interact(self, arg): contains all the (global and local) names found in the current scope. """ ns = {**self.curframe.f_globals, **self.curframe_locals} - code.interact("*interactive*", local=ns, local_exit=True) + console = _PdbInteractiveConsole(ns, message=self.message) + console.interact(banner="*pdb interact start*", + exitmsg="*exit from pdb interact command*") def do_alias(self, arg): """alias [name [command]] diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 50d8c8f52a909de..d53fe3c611bc35e 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -778,6 +778,59 @@ def test_pdb_where_command(): (Pdb) continue """ +def test_pdb_interact_command(): + """Test interact command + + >>> g = 0 + >>> dict_g = {} + + >>> def test_function(): + ... x = 1 + ... lst_local = [] + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + ... 'interact', + ... 'x', + ... 'g', + ... 'x = 2', + ... 'g = 3', + ... 'dict_g["a"] = True', + ... 'lst_local.append(x)', + ... 'exit()', + ... 'p x', + ... 'p g', + ... 'p dict_g', + ... 'p lst_local', + ... 'continue', + ... ]): + ... test_function() + --Return-- + > (4)test_function()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) interact + *pdb interact start* + ... x + 1 + ... g + 0 + ... x = 2 + ... g = 3 + ... dict_g["a"] = True + ... lst_local.append(x) + ... exit() + *exit from pdb interact command* + (Pdb) p x + 1 + (Pdb) p g + 0 + (Pdb) p dict_g + {'a': True} + (Pdb) p lst_local + [2] + (Pdb) continue + """ + def test_convenience_variables(): """Test convenience variables diff --git a/Misc/NEWS.d/next/Library/2023-10-23-03-49-34.gh-issue-102980.aXBd54.rst b/Misc/NEWS.d/next/Library/2023-10-23-03-49-34.gh-issue-102980.aXBd54.rst new file mode 100644 index 000000000000000..d4bae4790d6fa45 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-10-23-03-49-34.gh-issue-102980.aXBd54.rst @@ -0,0 +1 @@ +Redirect the output of ``interact`` command of :mod:`pdb` to the same channel as the debugger. Add tests and improve docs. From b449415b2f1b41e1c44cb453428657fdf6ff1d36 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 7 Dec 2023 12:49:40 +0000 Subject: [PATCH 77/87] GH-111485: Separate out parsing, analysis and code-gen phases of tier 1 code generator (GH-112299) --- Include/internal/pycore_opcode_metadata.h | 6 +- Makefile.pre.in | 3 +- Python/abstract_interp_cases.c.h | 3 +- Python/bytecodes.c | 5 +- Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 1047 +++++++++++---------- Tools/cases_generator/analyzer.py | 456 +++++++++ Tools/cases_generator/cwriter.py | 111 +++ Tools/cases_generator/generate_cases.py | 1 - Tools/cases_generator/lexer.py | 9 +- Tools/cases_generator/mypy.ini | 2 + Tools/cases_generator/parser.py | 55 ++ Tools/cases_generator/parsing.py | 3 +- Tools/cases_generator/stack.py | 81 ++ Tools/cases_generator/tier1_generator.py | 417 ++++++++ 15 files changed, 1675 insertions(+), 526 deletions(-) create mode 100644 Tools/cases_generator/analyzer.py create mode 100644 Tools/cases_generator/cwriter.py create mode 100644 Tools/cases_generator/parser.py create mode 100644 Tools/cases_generator/stack.py create mode 100644 Tools/cases_generator/tier1_generator.py diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 4ae15e71e8d3182..774c0f99379ed66 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1285,11 +1285,11 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { case _INIT_CALL_PY_EXACT_ARGS: return 1; case _PUSH_FRAME: - return 1; + return 0; case CALL_BOUND_METHOD_EXACT_ARGS: - return 1; + return 0; case CALL_PY_EXACT_ARGS: - return 1; + return 0; case CALL_PY_WITH_DEFAULTS: return 1; case CALL_TYPE_1: diff --git a/Makefile.pre.in b/Makefile.pre.in index b5edb4e6748fb09..6ac68d59c8c47f1 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1587,7 +1587,6 @@ regen-cases: $(PYTHON_FOR_REGEN) \ $(srcdir)/Tools/cases_generator/generate_cases.py \ $(CASESFLAG) \ - -o $(srcdir)/Python/generated_cases.c.h.new \ -n $(srcdir)/Include/opcode_ids.h.new \ -t $(srcdir)/Python/opcode_targets.h.new \ -m $(srcdir)/Include/internal/pycore_opcode_metadata.h.new \ @@ -1595,6 +1594,8 @@ regen-cases: -p $(srcdir)/Lib/_opcode_metadata.py.new \ -a $(srcdir)/Python/abstract_interp_cases.c.h.new \ $(srcdir)/Python/bytecodes.c + $(PYTHON_FOR_REGEN) \ + $(srcdir)/Tools/cases_generator/tier1_generator.py -o $(srcdir)/Python/generated_cases.c.h.new $(srcdir)/Python/bytecodes.c $(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new $(UPDATE_FILE) $(srcdir)/Include/opcode_ids.h $(srcdir)/Include/opcode_ids.h.new $(UPDATE_FILE) $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/opcode_targets.h.new diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 0d7fbe8a39a5d46..96ac0aabd1b59f4 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -774,7 +774,8 @@ } case _PUSH_FRAME: { - PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); + STACK_SHRINK(1); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(0)), true); break; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 2075c195df3d383..bcad8dcf0e7dabc 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -800,11 +800,11 @@ dummy_func( // We also push it onto the stack on exit, but that's a // different frame, and it's accounted for by _PUSH_FRAME. op(_POP_FRAME, (retval --)) { - assert(EMPTY()); #if TIER_ONE assert(frame != &entry_frame); #endif STORE_SP(); + assert(EMPTY()); _Py_LeaveRecursiveCallPy(tstate); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; @@ -1165,7 +1165,6 @@ dummy_func( } } - inst(STORE_NAME, (v -- )) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *ns = LOCALS(); @@ -3130,7 +3129,7 @@ dummy_func( // The 'unused' output effect represents the return value // (which will be pushed when the frame returns). // It is needed so CALL_PY_EXACT_ARGS matches its family. - op(_PUSH_FRAME, (new_frame: _PyInterpreterFrame* -- unused)) { + op(_PUSH_FRAME, (new_frame: _PyInterpreterFrame* -- unused if (0))) { // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 547be6f13237dd0..974e3f28a411b87 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -661,11 +661,11 @@ PyObject *retval; retval = stack_pointer[-1]; STACK_SHRINK(1); - assert(EMPTY()); #if TIER_ONE assert(frame != &entry_frame); #endif STORE_SP(); + assert(EMPTY()); _Py_LeaveRecursiveCallPy(tstate); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 0ac99e759deb125..24243ecfb5b8dfb 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1,6 +1,6 @@ -// This file is generated by Tools/cases_generator/generate_cases.py +// This file is generated by Tools/cases_generator/tier1_generator.py // from: -// Python/bytecodes.c +// ['./Python/bytecodes.c'] // Do not edit! #ifdef TIER_TWO @@ -8,6 +8,7 @@ #endif #define TIER_ONE 1 + TARGET(BEFORE_ASYNC_WITH) { frame->instr_ptr = next_instr; next_instr += 1; @@ -45,9 +46,9 @@ Py_DECREF(exit); if (true) goto pop_1_error; } - STACK_GROW(1); - stack_pointer[-2] = exit; - stack_pointer[-1] = res; + stack_pointer[-1] = exit; + stack_pointer[0] = res; + stack_pointer += 1; DISPATCH(); } @@ -91,9 +92,9 @@ Py_DECREF(exit); if (true) goto pop_1_error; } - STACK_GROW(1); - stack_pointer[-2] = exit; - stack_pointer[-1] = res; + stack_pointer[-1] = exit; + stack_pointer[0] = res; + stack_pointer += 1; DISPATCH(); } @@ -103,7 +104,6 @@ INSTRUCTION_STATS(BINARY_OP); PREDICTED(BINARY_OP); _Py_CODEUNIT *this_instr = next_instr - 2; - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *rhs; PyObject *lhs; PyObject *res; @@ -133,8 +133,8 @@ Py_DECREF(rhs); if (res == NULL) goto pop_2_error; } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -142,6 +142,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_OP_ADD_FLOAT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -156,12 +157,12 @@ { STAT_INC(BINARY_OP, hit); double dres = - ((PyFloatObject *)left)->ob_fval + - ((PyFloatObject *)right)->ob_fval; + ((PyFloatObject *)left)->ob_fval + + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -169,6 +170,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_OP_ADD_INT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -187,8 +189,8 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -196,6 +198,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_OP_ADD_UNICODE); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -214,8 +217,8 @@ _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -223,6 +226,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_OP_INPLACE_ADD_UNICODE); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; // _GUARD_BOTH_UNICODE @@ -258,7 +262,7 @@ assert(next_instr->op.code == STORE_FAST); SKIP_OVER(1); } - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -266,6 +270,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_OP_MULTIPLY_FLOAT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -280,12 +285,12 @@ { STAT_INC(BINARY_OP, hit); double dres = - ((PyFloatObject *)left)->ob_fval * - ((PyFloatObject *)right)->ob_fval; + ((PyFloatObject *)left)->ob_fval * + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -293,6 +298,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_OP_MULTIPLY_INT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -311,8 +317,8 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -320,6 +326,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_OP_SUBTRACT_FLOAT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -334,12 +341,12 @@ { STAT_INC(BINARY_OP, hit); double dres = - ((PyFloatObject *)left)->ob_fval - - ((PyFloatObject *)right)->ob_fval; + ((PyFloatObject *)left)->ob_fval - + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -347,6 +354,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_OP_SUBTRACT_INT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -365,8 +373,8 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -393,8 +401,8 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - STACK_SHRINK(2); - stack_pointer[-1] = res; + stack_pointer[-3] = res; + stack_pointer += -2; DISPATCH(); } @@ -404,7 +412,6 @@ INSTRUCTION_STATS(BINARY_SUBSCR); PREDICTED(BINARY_SUBSCR); _Py_CODEUNIT *this_instr = next_instr - 2; - static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); PyObject *sub; PyObject *container; PyObject *res; @@ -431,8 +438,8 @@ Py_DECREF(sub); if (res == NULL) goto pop_2_error; } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -440,6 +447,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_SUBSCR_DICT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); PyObject *sub; PyObject *dict; PyObject *res; @@ -454,8 +462,9 @@ Py_DECREF(dict); Py_DECREF(sub); if (rc <= 0) goto pop_2_error; - STACK_SHRINK(1); - stack_pointer[-1] = res; + // not found or error + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -463,6 +472,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_SUBSCR_GETITEM); + static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); PyObject *sub; PyObject *container; sub = stack_pointer[-1]; @@ -494,6 +504,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_SUBSCR_LIST_INT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); PyObject *sub; PyObject *list; PyObject *res; @@ -501,7 +512,6 @@ list = stack_pointer[-2]; DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); - // Deopt unless 0 <= sub < PyList_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; @@ -512,8 +522,8 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -521,6 +531,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_SUBSCR_STR_INT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); PyObject *sub; PyObject *str; PyObject *res; @@ -538,8 +549,8 @@ res = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(str); - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -547,6 +558,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(BINARY_SUBSCR_TUPLE_INT); + static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); PyObject *sub; PyObject *tuple; PyObject *res; @@ -554,7 +566,6 @@ tuple = stack_pointer[-2]; DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); - // Deopt unless 0 <= sub < PyTuple_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; @@ -565,8 +576,8 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -578,7 +589,7 @@ PyObject **values; PyObject *map; keys = stack_pointer[-1]; - values = stack_pointer - 1 - oparg; + values = &stack_pointer[-1 - oparg]; if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -586,15 +597,15 @@ GOTO_ERROR(error); // Pop the keys and values. } map = _PyDict_FromItems( - &PyTuple_GET_ITEM(keys, 0), 1, - values, 1, oparg); + &PyTuple_GET_ITEM(keys, 0), 1, + values, 1, oparg); 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; + if (map == NULL) { stack_pointer += -1 - oparg; goto error; } + stack_pointer[-1 - oparg] = map; + stack_pointer += -oparg; DISPATCH(); } @@ -604,12 +615,11 @@ INSTRUCTION_STATS(BUILD_LIST); PyObject **values; PyObject *list; - values = stack_pointer - oparg; + values = &stack_pointer[-oparg]; list = _PyList_FromArraySteal(values, oparg); - if (list == NULL) { STACK_SHRINK(oparg); goto error; } - STACK_SHRINK(oparg); - STACK_GROW(1); - stack_pointer[-1] = list; + if (list == NULL) { stack_pointer += -oparg; goto error; } + stack_pointer[-oparg] = list; + stack_pointer += 1 - oparg; DISPATCH(); } @@ -619,18 +629,17 @@ INSTRUCTION_STATS(BUILD_MAP); PyObject **values; PyObject *map; - values = stack_pointer - oparg*2; + values = &stack_pointer[-oparg*2]; map = _PyDict_FromItems( - values, 2, - values+1, 2, - oparg); + values, 2, + values+1, 2, + oparg); for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } - if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - STACK_SHRINK(oparg*2); - STACK_GROW(1); - stack_pointer[-1] = map; + if (map == NULL) { stack_pointer += -oparg*2; goto error; } + stack_pointer[-oparg*2] = map; + stack_pointer += 1 - oparg*2; DISPATCH(); } @@ -640,24 +649,23 @@ INSTRUCTION_STATS(BUILD_SET); PyObject **values; PyObject *set; - values = stack_pointer - oparg; + values = &stack_pointer[-oparg]; set = PySet_New(NULL); if (set == NULL) - GOTO_ERROR(error); + GOTO_ERROR(error); int err = 0; for (int i = 0; i < oparg; i++) { PyObject *item = values[i]; if (err == 0) - err = PySet_Add(set, item); + err = PySet_Add(set, item); Py_DECREF(item); } if (err != 0) { Py_DECREF(set); - if (true) { STACK_SHRINK(oparg); goto error; } + if (true) { stack_pointer += -oparg; goto error; } } - STACK_SHRINK(oparg); - STACK_GROW(1); - stack_pointer[-1] = set; + stack_pointer[-oparg] = set; + stack_pointer += 1 - oparg; DISPATCH(); } @@ -669,17 +677,16 @@ PyObject *stop; PyObject *start; PyObject *slice; - if (oparg == 3) { step = stack_pointer[-(oparg == 3 ? 1 : 0)]; } - stop = stack_pointer[-1 - (oparg == 3 ? 1 : 0)]; - start = stack_pointer[-2 - (oparg == 3 ? 1 : 0)]; + if (oparg == 3) { step = stack_pointer[-(((oparg == 3) ? 1 : 0))]; } + stop = stack_pointer[-1 - (((oparg == 3) ? 1 : 0))]; + start = stack_pointer[-2 - (((oparg == 3) ? 1 : 0))]; slice = PySlice_New(start, stop, step); Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - STACK_SHRINK(((oparg == 3) ? 1 : 0)); - STACK_SHRINK(1); - stack_pointer[-1] = slice; + if (slice == NULL) { stack_pointer += -2 - (((oparg == 3) ? 1 : 0)); goto error; } + stack_pointer[-2 - (((oparg == 3) ? 1 : 0))] = slice; + stack_pointer += -1 - (((oparg == 3) ? 1 : 0)); DISPATCH(); } @@ -689,15 +696,14 @@ INSTRUCTION_STATS(BUILD_STRING); PyObject **pieces; PyObject *str; - pieces = stack_pointer - oparg; + pieces = &stack_pointer[-oparg]; str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } - if (str == NULL) { STACK_SHRINK(oparg); goto error; } - STACK_SHRINK(oparg); - STACK_GROW(1); - stack_pointer[-1] = str; + if (str == NULL) { stack_pointer += -oparg; goto error; } + stack_pointer[-oparg] = str; + stack_pointer += 1 - oparg; DISPATCH(); } @@ -707,12 +713,11 @@ INSTRUCTION_STATS(BUILD_TUPLE); PyObject **values; PyObject *tup; - values = stack_pointer - oparg; + values = &stack_pointer[-oparg]; tup = _PyTuple_FromArraySteal(values, oparg); - if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - STACK_SHRINK(oparg); - STACK_GROW(1); - stack_pointer[-1] = tup; + if (tup == NULL) { stack_pointer += -oparg; goto error; } + stack_pointer[-oparg] = tup; + stack_pointer += 1 - oparg; DISPATCH(); } @@ -730,13 +735,12 @@ INSTRUCTION_STATS(CALL); PREDICTED(CALL); _Py_CODEUNIT *this_instr = next_instr - 4; - static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; // _SPECIALIZE_CALL - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; { @@ -793,12 +797,12 @@ } /* Callable is not a normal Python function */ res = PyObject_Vectorcall( - callable, args, - total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - NULL); + callable, args, + total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + NULL); if (opcode == INSTRUMENTED_CALL) { PyObject *arg = total_args == 0 ? - &_PyInstrumentation_MISSING : args[0]; + &_PyInstrumentation_MISSING : args[0]; if (res == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, @@ -818,11 +822,10 @@ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -831,10 +834,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_ALLOC_AND_ENTER_INIT); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *null; PyObject *callable; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* This instruction does the following: @@ -890,13 +894,15 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_BOUND_METHOD_EXACT_ARGS); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject *null; PyObject *callable; + PyObject *func; PyObject *self; PyObject *self_or_null; - PyObject *func; PyObject **args; _PyInterpreterFrame *new_frame; + /* Skip 1 cache entry */ // _CHECK_PEP_523 { DEOPT_IF(tstate->interp->eval_frame, CALL); @@ -936,7 +942,8 @@ DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL); } // _INIT_CALL_PY_EXACT_ARGS - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; { int argcount = oparg; if (self_or_null != NULL) { @@ -960,26 +967,26 @@ #endif } // _PUSH_FRAME - STACK_SHRINK(oparg); - STACK_SHRINK(2); { // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); - STORE_SP(); + stack_pointer += -2 - oparg; + _PyFrame_SetStackPointer(frame, stack_pointer); new_frame->previous = frame; CALL_STAT_INC(inlined_py_calls); frame = tstate->current_frame = new_frame; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); - #if LLTRACE && TIER_ONE + #if LLTRACE && TIER_ONE lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); if (lltrace < 0) { goto exit_unwind; } - #endif + #endif } + stack_pointer += (((0) ? 1 : 0)); DISPATCH(); } @@ -987,11 +994,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_BUILTIN_CLASS); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; int total_args = oparg; @@ -1009,10 +1017,9 @@ Py_DECREF(args[i]); } Py_DECREF(tp); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1021,11 +1028,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_BUILTIN_FAST); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL functions, without keywords */ @@ -1044,21 +1052,19 @@ args, total_args); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - /* Not deopting because this doesn't mean our optimization was - wrong. `res` can be NULL for valid reasons. Eg. getattr(x, - 'invalid'). In those cases an exception is set, so we must - handle it. - */ - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + /* Not deopting because this doesn't mean our optimization was + wrong. `res` can be NULL for valid reasons. Eg. getattr(x, + 'invalid'). In those cases an exception is set, so we must + handle it. + */ + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1067,11 +1073,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_BUILTIN_FAST_WITH_KEYWORDS); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ @@ -1085,20 +1092,18 @@ STAT_INC(CALL, hit); /* res = func(self, args, nargs, kwnames) */ _PyCFunctionFastWithKeywords cfunc = - (_PyCFunctionFastWithKeywords)(void(*)(void)) - PyCFunction_GET_FUNCTION(callable); + (_PyCFunctionFastWithKeywords)(void(*)(void)) + PyCFunction_GET_FUNCTION(callable); res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1107,11 +1112,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_BUILTIN_O); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* Builtin METH_O functions */ @@ -1134,13 +1140,11 @@ res = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable), arg); _Py_LeaveRecursiveCallTstate(tstate); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - Py_DECREF(arg); Py_DECREF(callable); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1155,9 +1159,9 @@ PyObject *callargs; PyObject *func; PyObject *result; - if (oparg & 1) { kwargs = stack_pointer[-(oparg & 1 ? 1 : 0)]; } - callargs = stack_pointer[-1 - (oparg & 1 ? 1 : 0)]; - func = stack_pointer[-3 - (oparg & 1 ? 1 : 0)]; + if (oparg & 1) { kwargs = stack_pointer[-((oparg & 1))]; } + callargs = stack_pointer[-1 - ((oparg & 1))]; + func = stack_pointer[-3 - ((oparg & 1))]; // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -1177,7 +1181,7 @@ !PyFunction_Check(func) && !PyMethod_Check(func) ) { PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? - PyTuple_GET_ITEM(callargs, 0) : Py_None; + PyTuple_GET_ITEM(callargs, 0) : Py_None; int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, func, arg); @@ -1205,10 +1209,9 @@ Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex(tstate, - (PyFunctionObject *)func, locals, - nargs, callargs, kwargs); + (PyFunctionObject *)func, locals, + nargs, callargs, kwargs); // Need to manually shrink the stack since we exit with DISPATCH_INLINED. STACK_SHRINK(oparg + 3); if (new_frame == NULL) { @@ -1224,10 +1227,9 @@ Py_DECREF(callargs); Py_XDECREF(kwargs); assert(PEEK(2 + (oparg & 1)) == NULL); - if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - STACK_SHRINK(((oparg & 1) ? 1 : 0)); - STACK_SHRINK(2); - stack_pointer[-1] = result; + if (result == NULL) { stack_pointer += -3 - ((oparg & 1)); goto error; } + stack_pointer[-3 - ((oparg & 1))] = result; + stack_pointer += -2 - ((oparg & 1)); CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1261,8 +1263,8 @@ Py_DECREF(value2); Py_DECREF(value1); if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -1270,11 +1272,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_ISINSTANCE); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* isinstance(o, o2) */ @@ -1295,14 +1298,12 @@ } res = PyBool_FromLong(retval); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - Py_DECREF(inst); Py_DECREF(cls); Py_DECREF(callable); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; DISPATCH(); } @@ -1318,7 +1319,7 @@ PyObject *callable; PyObject *res; kwnames = stack_pointer[-1]; - args = stack_pointer - 1 - oparg; + args = &stack_pointer[-1 - oparg]; self_or_null = stack_pointer[-2 - oparg]; callable = stack_pointer[-3 - oparg]; // oparg counts all of the args, but *not* self: @@ -1363,12 +1364,12 @@ } /* Callable is not a normal Python function */ res = PyObject_Vectorcall( - callable, args, - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames); + callable, args, + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames); if (opcode == INSTRUMENTED_CALL_KW) { PyObject *arg = total_args == 0 ? - &_PyInstrumentation_MISSING : args[0]; + &_PyInstrumentation_MISSING : args[0]; if (res == NULL) { _Py_call_instrumentation_exc2( tstate, PY_MONITORING_EVENT_C_RAISE, @@ -1389,10 +1390,9 @@ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } - if (res == NULL) { STACK_SHRINK(oparg); goto pop_3_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(2); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -3 - oparg; goto error; } + stack_pointer[-3 - oparg] = res; + stack_pointer += -2 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1401,11 +1401,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_LEN); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* len(o) */ @@ -1425,13 +1426,11 @@ } res = PyLong_FromSsize_t(len_i); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - Py_DECREF(callable); Py_DECREF(arg); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; DISPATCH(); } @@ -1439,10 +1438,11 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_LIST_APPEND); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self; PyObject *callable; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; assert(oparg == 1); @@ -1467,11 +1467,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_FAST); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; int total_args = oparg; @@ -1488,7 +1489,7 @@ DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type), CALL); STAT_INC(CALL, hit); _PyCFunctionFast cfunc = - (_PyCFunctionFast)(void(*)(void))meth->ml_meth; + (_PyCFunctionFast)(void(*)(void))meth->ml_meth; int nargs = total_args - 1; res = cfunc(self, args + 1, nargs); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); @@ -1497,10 +1498,9 @@ Py_DECREF(args[i]); } Py_DECREF(callable); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1509,11 +1509,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; int total_args = oparg; @@ -1531,19 +1532,17 @@ STAT_INC(CALL, hit); int nargs = total_args - 1; _PyCFunctionFastWithKeywords cfunc = - (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; + (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; res = cfunc(self, args + 1, nargs, NULL); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } Py_DECREF(callable); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1552,11 +1551,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_NOARGS); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; assert(oparg == 0 || oparg == 1); @@ -1584,10 +1584,9 @@ assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(self); Py_DECREF(callable); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1596,11 +1595,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_METHOD_DESCRIPTOR_O); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; int total_args = oparg; @@ -1629,10 +1629,9 @@ Py_DECREF(self); Py_DECREF(arg); Py_DECREF(callable); - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1641,10 +1640,12 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_PY_EXACT_ARGS); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject *self_or_null; PyObject *callable; PyObject **args; _PyInterpreterFrame *new_frame; + /* Skip 1 cache entry */ // _CHECK_PEP_523 { DEOPT_IF(tstate->interp->eval_frame, CALL); @@ -1668,7 +1669,8 @@ DEOPT_IF(tstate->py_recursion_remaining <= 1, CALL); } // _INIT_CALL_PY_EXACT_ARGS - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; { int argcount = oparg; if (self_or_null != NULL) { @@ -1692,26 +1694,26 @@ #endif } // _PUSH_FRAME - STACK_SHRINK(oparg); - STACK_SHRINK(2); { // Write it out explicitly because it's subtly different. // Eventually this should be the only occurrence of this code. assert(tstate->interp->eval_frame == NULL); - STORE_SP(); + stack_pointer += -2 - oparg; + _PyFrame_SetStackPointer(frame, stack_pointer); new_frame->previous = frame; CALL_STAT_INC(inlined_py_calls); frame = tstate->current_frame = new_frame; tstate->py_recursion_remaining--; LOAD_SP(); LOAD_IP(0); - #if LLTRACE && TIER_ONE + #if LLTRACE && TIER_ONE lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); if (lltrace < 0) { goto exit_unwind; } - #endif + #endif } + stack_pointer += (((0) ? 1 : 0)); DISPATCH(); } @@ -1719,10 +1721,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_PY_WITH_DEFAULTS); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *self_or_null; PyObject *callable; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; uint32_t func_version = read_u32(&this_instr[2].cache); @@ -1763,11 +1766,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_STR_1); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; assert(oparg == 1); @@ -1778,10 +1782,9 @@ res = PyObject_Str(arg); Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1790,11 +1793,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_TUPLE_1); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; assert(oparg == 1); @@ -1805,10 +1809,9 @@ res = PySequence_Tuple(arg); Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple - if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; CHECK_EVAL_BREAKER(); DISPATCH(); } @@ -1817,11 +1820,12 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_TYPE_1); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject **args; PyObject *null; PyObject *callable; PyObject *res; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; assert(oparg == 1); @@ -1832,9 +1836,8 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - STACK_SHRINK(oparg); - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; DISPATCH(); } @@ -1853,18 +1856,15 @@ Py_DECREF(match_type); if (true) goto pop_2_error; } - match = NULL; rest = NULL; int res = _PyEval_ExceptionGroupMatch(exc_value, match_type, - &match, &rest); + &match, &rest); Py_DECREF(exc_value); Py_DECREF(match_type); if (res < 0) goto pop_2_error; - assert((match == NULL) == (rest == NULL)); if (match == NULL) goto pop_2_error; - if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } @@ -1884,10 +1884,9 @@ left = stack_pointer[-2]; assert(PyExceptionInstance_Check(left)); if (_PyEval_CheckExceptTypeValid(tstate, right) < 0) { - Py_DECREF(right); - if (true) goto pop_1_error; + Py_DECREF(right); + if (true) goto pop_1_error; } - int res = PyErr_GivenExceptionMatches(left, right); Py_DECREF(right); b = res ? Py_True : Py_False; @@ -1922,9 +1921,9 @@ monitor_reraise(tstate, frame, this_instr); goto exception_unwind; } - STACK_SHRINK(1); - stack_pointer[-2] = none; - stack_pointer[-1] = value; + stack_pointer[-3] = none; + stack_pointer[-2] = value; + stack_pointer += -1; DISPATCH(); } @@ -1934,7 +1933,6 @@ INSTRUCTION_STATS(COMPARE_OP); PREDICTED(COMPARE_OP); _Py_CODEUNIT *this_instr = next_instr - 2; - static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -1968,8 +1966,8 @@ res = res_bool ? Py_True : Py_False; } } - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -1977,6 +1975,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(COMPARE_OP_FLOAT); + static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -1993,8 +1992,8 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -2002,6 +2001,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(COMPARE_OP_INT); + static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -2022,8 +2022,8 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -2031,6 +2031,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(COMPARE_OP_STR); + static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; @@ -2048,8 +2049,8 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -2067,8 +2068,8 @@ Py_DECREF(right); if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - STACK_SHRINK(1); - stack_pointer[-1] = b; + stack_pointer[-2] = b; + stack_pointer += -1; DISPATCH(); } @@ -2098,8 +2099,8 @@ bottom = stack_pointer[-1 - (oparg-1)]; assert(oparg > 0); top = Py_NewRef(bottom); - STACK_GROW(1); - stack_pointer[-1] = top; + stack_pointer[0] = top; + stack_pointer += 1; DISPATCH(); } @@ -2130,7 +2131,7 @@ int err = PyObject_DelAttr(owner, name); Py_DECREF(owner); if (err) goto pop_1_error; - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -2172,7 +2173,7 @@ if (err != 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); + NAME_ERROR_MSG, name); } GOTO_ERROR(error); } @@ -2195,8 +2196,8 @@ // Can't use ERROR_IF here. if (err != 0) { _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, - name); + NAME_ERROR_MSG, + name); GOTO_ERROR(error); } DISPATCH(); @@ -2215,7 +2216,7 @@ Py_DECREF(container); Py_DECREF(sub); if (err) goto pop_2_error; - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -2235,7 +2236,7 @@ if (true) goto pop_1_error; } Py_DECREF(update); - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -2250,14 +2251,14 @@ if (PyDict_Update(dict, update) < 0) { if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object is not a mapping", - Py_TYPE(update)->tp_name); + "'%.200s' object is not a mapping", + Py_TYPE(update)->tp_name); } Py_DECREF(update); if (true) goto pop_1_error; } Py_DECREF(update); - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -2281,7 +2282,7 @@ monitor_reraise(tstate, frame, this_instr); goto exception_unwind; } - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -2290,17 +2291,17 @@ next_instr += 1; INSTRUCTION_STATS(END_FOR); PyObject *value; - // POP_TOP + // _POP_TOP value = stack_pointer[-1]; { Py_DECREF(value); } - // POP_TOP + // _POP_TOP value = stack_pointer[-2]; { Py_DECREF(value); } - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -2313,8 +2314,8 @@ value = stack_pointer[-1]; receiver = stack_pointer[-2]; Py_DECREF(receiver); - STACK_SHRINK(1); - stack_pointer[-1] = value; + stack_pointer[-2] = value; + stack_pointer += -1; DISPATCH(); } @@ -2324,7 +2325,6 @@ INSTRUCTION_STATS(ENTER_EXECUTOR); TIER_ONE_ONLY CHECK_EVAL_BREAKER(); - PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; int original_oparg = executor->vm_data.oparg | (oparg & 0xfffff00); @@ -2352,11 +2352,11 @@ assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, - "__init__() should return None, not '%.200s'", - Py_TYPE(should_be_none)->tp_name); + "__init__() should return None, not '%.200s'", + Py_TYPE(should_be_none)->tp_name); GOTO_ERROR(error); } - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -2405,8 +2405,8 @@ Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -2416,7 +2416,6 @@ INSTRUCTION_STATS(FOR_ITER); PREDICTED(FOR_ITER); _Py_CODEUNIT *this_instr = next_instr - 2; - static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter; PyObject *next; // _SPECIALIZE_FOR_ITER @@ -2448,7 +2447,7 @@ } /* iterator ended normally */ assert(next_instr[oparg].op.code == END_FOR || - next_instr[oparg].op.code == INSTRUMENTED_END_FOR); + next_instr[oparg].op.code == INSTRUMENTED_END_FOR); Py_DECREF(iter); STACK_SHRINK(1); /* Jump forward oparg, then skip following END_FOR instruction */ @@ -2457,8 +2456,8 @@ } // Common case: no jump, leave it to the code generator } - STACK_GROW(1); - stack_pointer[-1] = next; + stack_pointer[0] = next; + stack_pointer += 1; DISPATCH(); } @@ -2466,6 +2465,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(FOR_ITER_GEN); + static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter; iter = stack_pointer[-1]; DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); @@ -2489,8 +2489,10 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(FOR_ITER_LIST); + static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter; PyObject *next; + /* Skip 1 cache entry */ // _ITER_CHECK_LIST iter = stack_pointer[-1]; { @@ -2523,8 +2525,8 @@ assert(it->it_index < PyList_GET_SIZE(seq)); next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); } - STACK_GROW(1); - stack_pointer[-1] = next; + stack_pointer[0] = next; + stack_pointer += 1; DISPATCH(); } @@ -2532,8 +2534,10 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(FOR_ITER_RANGE); + static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter; PyObject *next; + /* Skip 1 cache entry */ // _ITER_CHECK_RANGE iter = stack_pointer[-1]; { @@ -2564,8 +2568,8 @@ next = PyLong_FromLong(value); if (next == NULL) goto error; } - STACK_GROW(1); - stack_pointer[-1] = next; + stack_pointer[0] = next; + stack_pointer += 1; DISPATCH(); } @@ -2573,8 +2577,10 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(FOR_ITER_TUPLE); + static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter; PyObject *next; + /* Skip 1 cache entry */ // _ITER_CHECK_TUPLE iter = stack_pointer[-1]; { @@ -2607,8 +2613,8 @@ assert(it->it_index < PyTuple_GET_SIZE(seq)); next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); } - STACK_GROW(1); - stack_pointer[-1] = next; + stack_pointer[0] = next; + stack_pointer += 1; DISPATCH(); } @@ -2621,11 +2627,9 @@ obj = stack_pointer[-1]; unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); - if (type->tp_as_async != NULL) { getter = type->tp_as_async->am_aiter; } - if (getter == NULL) { _PyErr_Format(tstate, PyExc_TypeError, "'async for' requires an object with " @@ -2634,14 +2638,11 @@ Py_DECREF(obj); if (true) goto pop_1_error; } - iter = (*getter)(obj); Py_DECREF(obj); if (iter == NULL) goto pop_1_error; - if (Py_TYPE(iter)->tp_as_async == NULL || - Py_TYPE(iter)->tp_as_async->am_anext == NULL) { - + Py_TYPE(iter)->tp_as_async->am_anext == NULL) { _PyErr_Format(tstate, PyExc_TypeError, "'async for' received an object from __aiter__ " "that does not implement __anext__: %.100s", @@ -2663,7 +2664,6 @@ unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); - if (PyAsyncGen_CheckExact(aiter)) { awaitable = type->tp_as_async->am_anext(aiter); if (awaitable == NULL) { @@ -2673,7 +2673,6 @@ if (type->tp_as_async != NULL){ getter = type->tp_as_async->am_anext; } - if (getter != NULL) { next_iter = (*getter)(aiter); if (next_iter == NULL) { @@ -2687,7 +2686,6 @@ type->tp_name); GOTO_ERROR(error); } - awaitable = _PyCoro_GetAwaitableIter(next_iter); if (awaitable == NULL) { _PyErr_FormatFromCause( @@ -2695,15 +2693,14 @@ "'async for' received an invalid object " "from __anext__: %.100s", Py_TYPE(next_iter)->tp_name); - Py_DECREF(next_iter); GOTO_ERROR(error); } else { Py_DECREF(next_iter); } } - STACK_GROW(1); - stack_pointer[-1] = awaitable; + stack_pointer[0] = awaitable; + stack_pointer += 1; DISPATCH(); } @@ -2715,13 +2712,10 @@ PyObject *iter; iterable = stack_pointer[-1]; iter = _PyCoro_GetAwaitableIter(iterable); - if (iter == NULL) { _PyEval_FormatAwaitableError(tstate, Py_TYPE(iterable), oparg); } - Py_DECREF(iterable); - if (iter != NULL && PyCoro_CheckExact(iter)) { PyObject *yf = _PyGen_yf((PyGenObject*)iter); if (yf != NULL) { @@ -2735,7 +2729,6 @@ /* The code below jumps to `error` if `iter` is NULL. */ } } - if (iter == NULL) goto pop_1_error; stack_pointer[-1] = iter; DISPATCH(); @@ -2768,8 +2761,8 @@ if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - STACK_GROW(1); - stack_pointer[-1] = len_o; + stack_pointer[0] = len_o; + stack_pointer += 1; DISPATCH(); } @@ -2819,8 +2812,8 @@ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - STACK_GROW(1); - stack_pointer[-1] = res; + stack_pointer[0] = res; + stack_pointer += 1; DISPATCH(); } @@ -2839,8 +2832,8 @@ Py_DECREF(level); Py_DECREF(fromlist); if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - stack_pointer[-1] = res; + stack_pointer[-2] = res; + stack_pointer += -1; DISPATCH(); } @@ -2852,10 +2845,10 @@ int total_args = oparg + is_meth; PyObject *function = PEEK(oparg + 2); PyObject *arg = total_args == 0 ? - &_PyInstrumentation_MISSING : PEEK(total_args); + &_PyInstrumentation_MISSING : PEEK(total_args); int err = _Py_call_instrumentation_2args( - tstate, PY_MONITORING_EVENT_CALL, - frame, this_instr, function, arg); + tstate, PY_MONITORING_EVENT_CALL, + frame, this_instr, function, arg); if (err) goto error; INCREMENT_ADAPTIVE_COUNTER(this_instr[1].cache); GO_TO_INSTRUCTION(CALL); @@ -2876,10 +2869,10 @@ int total_args = oparg + is_meth; PyObject *function = PEEK(oparg + 3); PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING - : PEEK(total_args + 1); + : PEEK(total_args + 1); int err = _Py_call_instrumentation_2args( - tstate, PY_MONITORING_EVENT_CALL, - frame, this_instr, function, arg); + tstate, PY_MONITORING_EVENT_CALL, + frame, this_instr, function, arg); if (err) goto error; GO_TO_INSTRUCTION(CALL_KW); } @@ -2904,7 +2897,7 @@ } Py_DECREF(receiver); Py_DECREF(value); - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -2925,8 +2918,8 @@ PyErr_SetRaisedException(NULL); } Py_DECREF(receiver); - STACK_SHRINK(1); - stack_pointer[-1] = value; + stack_pointer[-2] = value; + stack_pointer += -1; DISPATCH(); } @@ -3094,7 +3087,7 @@ } _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation( - tstate, oparg > 0, frame, this_instr); + tstate, oparg > 0, frame, this_instr); stack_pointer = _PyFrame_GetStackPointer(frame); if (err) goto error; if (frame->instr_ptr != this_instr) { @@ -3112,8 +3105,8 @@ INSTRUCTION_STATS(INSTRUMENTED_RETURN_CONST); PyObject *retval = GETITEM(FRAME_CO_CONSTS, oparg); int err = _Py_call_instrumentation_arg( - tstate, PY_MONITORING_EVENT_PY_RETURN, - frame, this_instr, retval); + tstate, PY_MONITORING_EVENT_PY_RETURN, + frame, this_instr, retval); if (err) GOTO_ERROR(error); Py_INCREF(retval); assert(EMPTY()); @@ -3136,8 +3129,8 @@ PyObject *retval; retval = stack_pointer[-1]; int err = _Py_call_instrumentation_arg( - tstate, PY_MONITORING_EVENT_PY_RETURN, - frame, this_instr, retval); + tstate, PY_MONITORING_EVENT_PY_RETURN, + frame, this_instr, retval); if (err) GOTO_ERROR(error); STACK_SHRINK(1); assert(EMPTY()); @@ -3167,8 +3160,8 @@ gen->gi_frame_state = FRAME_SUSPENDED + oparg; _PyFrame_SetStackPointer(frame, stack_pointer - 1); int err = _Py_call_instrumentation_arg( - tstate, PY_MONITORING_EVENT_PY_YIELD, - frame, this_instr, retval); + tstate, PY_MONITORING_EVENT_PY_YIELD, + frame, this_instr, retval); if (err) GOTO_ERROR(error); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; @@ -3211,8 +3204,8 @@ Py_DECREF(left); Py_DECREF(right); b = res ? Py_True : Py_False; - STACK_SHRINK(1); - stack_pointer[-1] = b; + stack_pointer[-2] = b; + stack_pointer += -1; DISPATCH(); } @@ -3286,7 +3279,7 @@ v = stack_pointer[-1]; list = stack_pointer[-2 - (oparg-1)]; if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -3301,19 +3294,19 @@ PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && - (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable))) + (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable))) { _PyErr_Clear(tstate); _PyErr_Format(tstate, PyExc_TypeError, - "Value after * must be an iterable, not %.200s", - Py_TYPE(iterable)->tp_name); + "Value after * must be an iterable, not %.200s", + Py_TYPE(iterable)->tp_name); } Py_DECREF(iterable); if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); Py_DECREF(iterable); - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -3323,8 +3316,8 @@ INSTRUCTION_STATS(LOAD_ASSERTION_ERROR); PyObject *value; value = Py_NewRef(PyExc_AssertionError); - STACK_GROW(1); - stack_pointer[-1] = value; + stack_pointer[0] = value; + stack_pointer += 1; DISPATCH(); } @@ -3334,7 +3327,6 @@ INSTRUCTION_STATS(LOAD_ATTR); PREDICTED(LOAD_ATTR); _Py_CODEUNIT *this_instr = next_instr - 10; - static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; PyObject *self_or_null = NULL; @@ -3374,7 +3366,7 @@ the second element of the stack to NULL, to signal CALL that it's not a method call. NULL | meth | arg1 | ... | argN - */ + */ Py_DECREF(owner); if (attr == NULL) goto pop_1_error; self_or_null = NULL; @@ -3387,9 +3379,9 @@ if (attr == NULL) goto pop_1_error; } } - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = self_or_null; } + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = self_or_null; + stack_pointer += ((oparg & 1)); DISPATCH(); } @@ -3397,9 +3389,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_CLASS); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; PyObject *null = NULL; + /* Skip 1 cache entry */ // _CHECK_ATTR_CLASS owner = stack_pointer[-1]; { @@ -3408,6 +3402,7 @@ assert(type_version != 0); DEOPT_IF(((PyTypeObject *)owner)->tp_version_tag != type_version, LOAD_ATTR); } + /* Skip 2 cache entries */ // _LOAD_ATTR_CLASS { PyObject *descr = read_obj(&this_instr[6].cache); @@ -3417,9 +3412,9 @@ null = NULL; Py_DECREF(owner); } - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += ((oparg & 1)); DISPATCH(); } @@ -3427,6 +3422,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); @@ -3445,7 +3441,6 @@ assert(code->co_argcount == 2); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 1); Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); @@ -3461,9 +3456,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_INSTANCE_VALUE); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; PyObject *null = NULL; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -3490,9 +3487,10 @@ null = NULL; Py_DECREF(owner); } - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + /* Skip 5 cache entries */ + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += ((oparg & 1)); DISPATCH(); } @@ -3500,9 +3498,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_METHOD_LAZY_DICT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; - PyObject *self; + PyObject *self = NULL; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -3519,6 +3519,7 @@ /* This object has a __dict__, just not yet created */ DEOPT_IF(dict != NULL, LOAD_ATTR); } + /* Skip 2 cache entries */ // _LOAD_ATTR_METHOD_LAZY_DICT { PyObject *descr = read_obj(&this_instr[6].cache); @@ -3529,9 +3530,9 @@ attr = Py_NewRef(descr); self = owner; } - STACK_GROW(1); - stack_pointer[-2] = attr; - stack_pointer[-1] = self; + stack_pointer[-1] = attr; + if (1) stack_pointer[0] = self; + stack_pointer += (((1) ? 1 : 0)); DISPATCH(); } @@ -3539,9 +3540,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_METHOD_NO_DICT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; - PyObject *self; + PyObject *self = NULL; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -3550,6 +3553,7 @@ assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); } + /* Skip 2 cache entries */ // _LOAD_ATTR_METHOD_NO_DICT { PyObject *descr = read_obj(&this_instr[6].cache); @@ -3561,9 +3565,9 @@ attr = Py_NewRef(descr); self = owner; } - STACK_GROW(1); - stack_pointer[-2] = attr; - stack_pointer[-1] = self; + stack_pointer[-1] = attr; + if (1) stack_pointer[0] = self; + stack_pointer += (((1) ? 1 : 0)); DISPATCH(); } @@ -3571,9 +3575,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_METHOD_WITH_VALUES); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; - PyObject *self; + PyObject *self = NULL; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -3606,9 +3612,9 @@ assert(_PyType_HasFeature(Py_TYPE(attr), Py_TPFLAGS_METHOD_DESCRIPTOR)); self = owner; } - STACK_GROW(1); - stack_pointer[-2] = attr; - stack_pointer[-1] = self; + stack_pointer[-1] = attr; + if (1) stack_pointer[0] = self; + stack_pointer += (((1) ? 1 : 0)); DISPATCH(); } @@ -3616,9 +3622,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_MODULE); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; PyObject *null = NULL; + /* Skip 1 cache entry */ // _CHECK_ATTR_MODULE owner = stack_pointer[-1]; { @@ -3642,9 +3650,10 @@ null = NULL; Py_DECREF(owner); } - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + /* Skip 5 cache entries */ + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += ((oparg & 1)); DISPATCH(); } @@ -3652,8 +3661,10 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_NO_DICT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -3662,6 +3673,7 @@ assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); } + /* Skip 2 cache entries */ // _LOAD_ATTR_NONDESCRIPTOR_NO_DICT { PyObject *descr = read_obj(&this_instr[6].cache); @@ -3673,6 +3685,7 @@ attr = Py_NewRef(descr); } stack_pointer[-1] = attr; + stack_pointer += (((0) ? 1 : 0)); DISPATCH(); } @@ -3680,8 +3693,10 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -3713,6 +3728,7 @@ attr = Py_NewRef(descr); } stack_pointer[-1] = attr; + stack_pointer += (((0) ? 1 : 0)); DISPATCH(); } @@ -3720,6 +3736,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_PROPERTY); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); @@ -3727,7 +3744,6 @@ PyObject *fget = read_obj(&this_instr[6].cache); assert((oparg & 1) == 0); DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); - PyTypeObject *cls = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3752,9 +3768,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_SLOT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; PyObject *null = NULL; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -3774,9 +3792,10 @@ null = NULL; Py_DECREF(owner); } - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + /* Skip 5 cache entries */ + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += ((oparg & 1)); DISPATCH(); } @@ -3784,9 +3803,11 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 10; INSTRUCTION_STATS(LOAD_ATTR_WITH_HINT); + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); PyObject *owner; PyObject *attr; PyObject *null = NULL; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -3827,9 +3848,10 @@ null = NULL; Py_DECREF(owner); } - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + /* Skip 5 cache entries */ + stack_pointer[-1] = attr; + if (oparg & 1) stack_pointer[0] = null; + stack_pointer += ((oparg & 1)); DISPATCH(); } @@ -3844,8 +3866,8 @@ "__build_class__ not found"); if (true) goto error; } - STACK_GROW(1); - stack_pointer[-1] = bc; + stack_pointer[0] = bc; + stack_pointer += 1; DISPATCH(); } @@ -3856,8 +3878,8 @@ PyObject *value; value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); - STACK_GROW(1); - stack_pointer[-1] = value; + stack_pointer[0] = value; + stack_pointer += 1; DISPATCH(); } @@ -3873,8 +3895,8 @@ if (true) goto error; } Py_INCREF(value); - STACK_GROW(1); - stack_pointer[-1] = value; + stack_pointer[0] = value; + stack_pointer += 1; DISPATCH(); } @@ -3886,8 +3908,8 @@ value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); - STACK_GROW(1); - stack_pointer[-1] = value; + stack_pointer[0] = value; + stack_pointer += 1; DISPATCH(); } @@ -3899,8 +3921,8 @@ value = GETLOCAL(oparg); // do not use SETLOCAL here, it decrefs the old value GETLOCAL(oparg) = NULL; - STACK_GROW(1); - stack_pointer[-1] = value; + stack_pointer[0] = value; + stack_pointer += 1; DISPATCH(); } @@ -3912,8 +3934,8 @@ value = GETLOCAL(oparg); if (value == NULL) goto unbound_local_error; Py_INCREF(value); - STACK_GROW(1); - stack_pointer[-1] = value; + stack_pointer[0] = value; + stack_pointer += 1; DISPATCH(); } @@ -3929,9 +3951,9 @@ value2 = GETLOCAL(oparg2); Py_INCREF(value1); Py_INCREF(value2); - STACK_GROW(2); - stack_pointer[-2] = value1; - stack_pointer[-1] = value2; + stack_pointer[0] = value1; + stack_pointer[1] = value2; + stack_pointer += 2; DISPATCH(); } @@ -3984,8 +4006,8 @@ } if (v == NULL) { _PyEval_FormatExcCheckArg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); GOTO_ERROR(error); } } @@ -4001,7 +4023,6 @@ INSTRUCTION_STATS(LOAD_GLOBAL); PREDICTED(LOAD_GLOBAL); _Py_CODEUNIT *this_instr = next_instr - 5; - static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *res; PyObject *null = NULL; // _SPECIALIZE_LOAD_GLOBAL @@ -4026,14 +4047,14 @@ && PyDict_CheckExact(BUILTINS())) { res = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), - (PyDictObject *)BUILTINS(), - name); + (PyDictObject *)BUILTINS(), + name); if (res == NULL) { if (!_PyErr_Occurred(tstate)) { /* _PyDict_LoadGlobal() returns NULL without raising * an exception if the key doesn't exist */ _PyEval_FormatExcCheckArg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); + NAME_ERROR_MSG, name); } if (true) goto error; } @@ -4048,18 +4069,17 @@ if (PyMapping_GetOptionalItem(BUILTINS(), name, &res) < 0) goto error; if (res == NULL) { _PyEval_FormatExcCheckArg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); if (true) goto error; } } } null = NULL; } - STACK_GROW(1); - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + ((oparg & 1)); DISPATCH(); } @@ -4067,8 +4087,10 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(LOAD_GLOBAL_BUILTIN); + static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *res; PyObject *null = NULL; + /* Skip 1 cache entry */ // _GUARD_GLOBALS_VERSION { uint16_t version = read_u16(&this_instr[2].cache); @@ -4096,10 +4118,9 @@ STAT_INC(LOAD_GLOBAL, hit); null = NULL; } - STACK_GROW(1); - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + ((oparg & 1)); DISPATCH(); } @@ -4107,8 +4128,10 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(LOAD_GLOBAL_MODULE); + static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); PyObject *res; PyObject *null = NULL; + /* Skip 1 cache entry */ // _GUARD_GLOBALS_VERSION { uint16_t version = read_u16(&this_instr[2].cache); @@ -4117,6 +4140,7 @@ DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); assert(DK_IS_UNICODE(dict->ma_keys)); } + /* Skip 1 cache entry */ // _LOAD_GLOBAL_MODULE { uint16_t index = read_u16(&this_instr[4].cache); @@ -4128,10 +4152,9 @@ STAT_INC(LOAD_GLOBAL, hit); null = NULL; } - STACK_GROW(1); - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = res; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + stack_pointer[0] = res; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + ((oparg & 1)); DISPATCH(); } @@ -4147,8 +4170,8 @@ if (true) goto error; } Py_INCREF(locals); - STACK_GROW(1); - stack_pointer[-1] = locals; + stack_pointer[0] = locals; + stack_pointer += 1; DISPATCH(); } @@ -4177,14 +4200,14 @@ } if (v == NULL) { _PyEval_FormatExcCheckArg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); GOTO_ERROR(error); } } } - STACK_GROW(1); - stack_pointer[-1] = v; + stack_pointer[0] = v; + stack_pointer += 1; DISPATCH(); } @@ -4194,7 +4217,6 @@ INSTRUCTION_STATS(LOAD_SUPER_ATTR); PREDICTED(LOAD_SUPER_ATTR); _Py_CODEUNIT *this_instr = next_instr - 2; - static_assert(INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR == 1, "incorrect cache size"); PyObject *class; PyObject *global_super; PyObject *self; @@ -4224,8 +4246,8 @@ if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; int err = _Py_call_instrumentation_2args( - tstate, PY_MONITORING_EVENT_CALL, - frame, this_instr, global_super, arg); + tstate, PY_MONITORING_EVENT_CALL, + frame, this_instr, global_super, arg); if (err) goto pop_3_error; } // we make no attempt to optimize here; specializations should @@ -4258,10 +4280,9 @@ if (attr == NULL) goto pop_3_error; null = NULL; } - STACK_SHRINK(2); - STACK_GROW(((oparg & 1) ? 1 : 0)); - stack_pointer[-1 - (oparg & 1 ? 1 : 0)] = attr; - if (oparg & 1) { stack_pointer[-(oparg & 1 ? 1 : 0)] = null; } + stack_pointer[-3] = attr; + if (oparg & 1) stack_pointer[-2] = null; + stack_pointer += -2 + ((oparg & 1)); DISPATCH(); } @@ -4269,6 +4290,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(LOAD_SUPER_ATTR_ATTR); + static_assert(INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR == 1, "incorrect cache size"); PyObject *self; PyObject *class; PyObject *global_super; @@ -4286,8 +4308,8 @@ Py_DECREF(class); Py_DECREF(self); if (attr == NULL) goto pop_3_error; - STACK_SHRINK(2); - stack_pointer[-1] = attr; + stack_pointer[-3] = attr; + stack_pointer += -2 + (((0) ? 1 : 0)); DISPATCH(); } @@ -4295,6 +4317,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(LOAD_SUPER_ATTR_METHOD); + static_assert(INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR == 1, "incorrect cache size"); PyObject *self; PyObject *class; PyObject *global_super; @@ -4324,9 +4347,9 @@ Py_DECREF(self); self_or_null = NULL; } - STACK_SHRINK(1); - stack_pointer[-2] = attr; - stack_pointer[-1] = self_or_null; + stack_pointer[-3] = attr; + stack_pointer[-2] = self_or_null; + stack_pointer += -1; DISPATCH(); } @@ -4352,17 +4375,14 @@ PyObject *codeobj; PyObject *func; codeobj = stack_pointer[-1]; - PyFunctionObject *func_obj = (PyFunctionObject *) - PyFunction_New(codeobj, GLOBALS()); - + PyFunction_New(codeobj, GLOBALS()); Py_DECREF(codeobj); if (func_obj == NULL) { GOTO_ERROR(error); } - _PyFunction_SetVersion( - func_obj, ((PyCodeObject *)codeobj)->co_version); + func_obj, ((PyCodeObject *)codeobj)->co_version); func = (PyObject *)func_obj; stack_pointer[-1] = func; DISPATCH(); @@ -4382,7 +4402,7 @@ /* 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; - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -4409,10 +4429,11 @@ } else { if (_PyErr_Occurred(tstate)) goto pop_3_error; + // Error! attrs = Py_None; // Failure! } - STACK_SHRINK(2); - stack_pointer[-1] = attrs; + stack_pointer[-3] = attrs; + stack_pointer += -2; DISPATCH(); } @@ -4428,8 +4449,8 @@ // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = _PyEval_MatchKeys(tstate, subject, keys); if (values_or_none == NULL) goto error; - STACK_GROW(1); - stack_pointer[-1] = values_or_none; + stack_pointer[0] = values_or_none; + stack_pointer += 1; DISPATCH(); } @@ -4442,8 +4463,8 @@ subject = stack_pointer[-1]; int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - STACK_GROW(1); - stack_pointer[-1] = res; + stack_pointer[0] = res; + stack_pointer += 1; DISPATCH(); } @@ -4456,8 +4477,8 @@ subject = stack_pointer[-1]; int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - STACK_GROW(1); - stack_pointer[-1] = res; + stack_pointer[0] = res; + stack_pointer += 1; DISPATCH(); } @@ -4476,7 +4497,7 @@ exc_value = stack_pointer[-1]; _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -4492,7 +4513,7 @@ this_instr[1].cache = (this_instr[1].cache << 1) | flag; #endif JUMPBY(oparg * flag); - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -4524,7 +4545,7 @@ #endif JUMPBY(oparg * flag); } - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -4556,7 +4577,7 @@ #endif JUMPBY(oparg * flag); } - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -4572,7 +4593,7 @@ this_instr[1].cache = (this_instr[1].cache << 1) | flag; #endif JUMPBY(oparg * flag); - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -4583,7 +4604,7 @@ PyObject *value; value = stack_pointer[-1]; Py_DECREF(value); - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -4603,9 +4624,9 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - STACK_GROW(1); - stack_pointer[-2] = prev_exc; - stack_pointer[-1] = new_exc; + stack_pointer[-1] = prev_exc; + stack_pointer[0] = new_exc; + stack_pointer += 1; DISPATCH(); } @@ -4615,8 +4636,8 @@ INSTRUCTION_STATS(PUSH_NULL); PyObject *res; res = NULL; - STACK_GROW(1); - stack_pointer[-1] = res; + stack_pointer[0] = res; + stack_pointer += 1; DISPATCH(); } @@ -4625,29 +4646,29 @@ next_instr += 1; INSTRUCTION_STATS(RAISE_VARARGS); PyObject **args; - args = stack_pointer - oparg; + args = &stack_pointer[-oparg]; TIER_ONE_ONLY PyObject *cause = NULL, *exc = NULL; switch (oparg) { - case 2: + case 2: cause = args[1]; /* fall through */ - case 1: + case 1: exc = args[0]; /* fall through */ - case 0: + case 0: if (do_raise(tstate, exc, cause)) { assert(oparg == 0); monitor_reraise(tstate, frame, this_instr); goto exception_unwind; } break; - default: + default: _PyErr_SetString(tstate, PyExc_SystemError, "bad RAISE_VARARGS oparg"); break; } - if (true) { STACK_SHRINK(oparg); goto error; } + if (true) { stack_pointer += -oparg; goto error; } } TARGET(RERAISE) { @@ -4657,7 +4678,7 @@ PyObject *exc; PyObject **values; exc = stack_pointer[-1]; - values = stack_pointer - 1 - oparg; + values = &stack_pointer[-1 - oparg]; TIER_ONE_ONLY assert(oparg >= 0 && oparg <= 2); if (oparg) { @@ -4693,12 +4714,11 @@ INSTRUCTION_STATS(RESUME); PREDICTED(RESUME); _Py_CODEUNIT *this_instr = next_instr - 1; - static_assert(0 == 0, "incorrect cache size"); TIER_ONE_ONLY assert(frame == tstate->current_frame); uintptr_t global_version = - _Py_atomic_load_uintptr_relaxed(&tstate->interp->ceval.eval_breaker) & - ~_PY_EVAL_EVENTS_MASK; + _Py_atomic_load_uintptr_relaxed(&tstate->interp->ceval.eval_breaker) & + ~_PY_EVAL_EVENTS_MASK; uintptr_t code_version = _PyFrame_GetCode(frame)->_co_instrumentation_version; assert((code_version & 255) == 0); if (code_version != global_version) { @@ -4719,10 +4739,11 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(RESUME_CHECK); -#if defined(__EMSCRIPTEN__) + static_assert(0 == 0, "incorrect cache size"); + #if defined(__EMSCRIPTEN__) DEOPT_IF(_Py_emscripten_signal_clock == 0, RESUME); _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; -#endif + #endif uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->interp->ceval.eval_breaker); uintptr_t version = _PyFrame_GetCode(frame)->_co_instrumentation_version; assert((version & _PY_EVAL_EVENTS_MASK) == 0); @@ -4736,7 +4757,7 @@ INSTRUCTION_STATS(RETURN_CONST); PyObject *value; PyObject *retval; - // LOAD_CONST + // _LOAD_CONST { value = GETITEM(FRAME_CO_CONSTS, oparg); Py_INCREF(value); @@ -4744,11 +4765,11 @@ // _POP_FRAME retval = value; { - assert(EMPTY()); #if TIER_ONE assert(frame != &entry_frame); #endif - STORE_SP(); + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(EMPTY()); _Py_LeaveRecursiveCallPy(tstate); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; @@ -4757,12 +4778,12 @@ _PyFrame_StackPush(frame, retval); LOAD_SP(); LOAD_IP(frame->return_offset); - #if LLTRACE && TIER_ONE + #if LLTRACE && TIER_ONE lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); if (lltrace < 0) { goto exit_unwind; } - #endif + #endif } DISPATCH(); } @@ -4801,12 +4822,12 @@ INSTRUCTION_STATS(RETURN_VALUE); PyObject *retval; retval = stack_pointer[-1]; - STACK_SHRINK(1); - assert(EMPTY()); #if TIER_ONE assert(frame != &entry_frame); #endif - STORE_SP(); + stack_pointer += -1; + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(EMPTY()); _Py_LeaveRecursiveCallPy(tstate); // GH-99729: We need to unlink the frame *before* clearing it: _PyInterpreterFrame *dying = frame; @@ -4815,12 +4836,12 @@ _PyFrame_StackPush(frame, retval); LOAD_SP(); LOAD_IP(frame->return_offset); -#if LLTRACE && TIER_ONE + #if LLTRACE && TIER_ONE lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); if (lltrace < 0) { goto exit_unwind; } -#endif + #endif DISPATCH(); } @@ -4830,7 +4851,6 @@ INSTRUCTION_STATS(SEND); PREDICTED(SEND); _Py_CODEUNIT *this_instr = next_instr - 2; - static_assert(INLINE_CACHE_ENTRIES_SEND == 1, "incorrect cache size"); PyObject *receiver; PyObject *v; PyObject *retval; @@ -4897,6 +4917,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(SEND_GEN); + static_assert(INLINE_CACHE_ENTRIES_SEND == 1, "incorrect cache size"); PyObject *v; PyObject *receiver; v = stack_pointer[-1]; @@ -4955,7 +4976,7 @@ int err = PySet_Add(set, v); Py_DECREF(v); if (err) goto pop_1_error; - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -4971,28 +4992,28 @@ PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { case MAKE_FUNCTION_CLOSURE: - assert(func_obj->func_closure == NULL); - func_obj->func_closure = attr; - break; + assert(func_obj->func_closure == NULL); + func_obj->func_closure = attr; + break; case MAKE_FUNCTION_ANNOTATIONS: - assert(func_obj->func_annotations == NULL); - func_obj->func_annotations = attr; - break; + assert(func_obj->func_annotations == NULL); + func_obj->func_annotations = attr; + break; case MAKE_FUNCTION_KWDEFAULTS: - assert(PyDict_CheckExact(attr)); - assert(func_obj->func_kwdefaults == NULL); - func_obj->func_kwdefaults = attr; - break; + assert(PyDict_CheckExact(attr)); + assert(func_obj->func_kwdefaults == NULL); + func_obj->func_kwdefaults = attr; + break; case MAKE_FUNCTION_DEFAULTS: - assert(PyTuple_CheckExact(attr)); - assert(func_obj->func_defaults == NULL); - func_obj->func_defaults = attr; - break; + assert(PyTuple_CheckExact(attr)); + assert(func_obj->func_defaults == NULL); + func_obj->func_defaults = attr; + break; default: - Py_UNREACHABLE(); + Py_UNREACHABLE(); } - STACK_SHRINK(1); - stack_pointer[-1] = func; + stack_pointer[-2] = func; + stack_pointer += -1; DISPATCH(); } @@ -5007,7 +5028,7 @@ int err = _PySet_Update(set, iterable); Py_DECREF(iterable); if (err < 0) goto pop_1_error; - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -5017,7 +5038,6 @@ INSTRUCTION_STATS(STORE_ATTR); PREDICTED(STORE_ATTR); _Py_CODEUNIT *this_instr = next_instr - 5; - static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); PyObject *owner; PyObject *v; // _SPECIALIZE_STORE_ATTR @@ -5045,7 +5065,7 @@ Py_DECREF(owner); if (err) goto pop_2_error; } - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -5053,8 +5073,10 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(STORE_ATTR_INSTANCE_VALUE); + static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); PyObject *owner; PyObject *value; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -5086,7 +5108,7 @@ } Py_DECREF(owner); } - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -5094,8 +5116,10 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(STORE_ATTR_SLOT); + static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); PyObject *owner; PyObject *value; + /* Skip 1 cache entry */ // _GUARD_TYPE_VERSION owner = stack_pointer[-1]; { @@ -5115,7 +5139,7 @@ Py_XDECREF(old_value); Py_DECREF(owner); } - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -5123,6 +5147,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 5; INSTRUCTION_STATS(STORE_ATTR_WITH_HINT); + static_assert(INLINE_CACHE_ENTRIES_STORE_ATTR == 4, "incorrect cache size"); PyObject *owner; PyObject *value; owner = stack_pointer[-1]; @@ -5167,7 +5192,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -5181,7 +5206,7 @@ PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -5192,7 +5217,7 @@ PyObject *value; value = stack_pointer[-1]; SETLOCAL(oparg, value); - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -5224,7 +5249,7 @@ uint32_t oparg2 = oparg & 15; SETLOCAL(oparg1, value1); SETLOCAL(oparg2, value2); - STACK_SHRINK(2); + stack_pointer += -2; DISPATCH(); } @@ -5238,7 +5263,7 @@ int err = PyDict_SetItem(GLOBALS(), name, v); Py_DECREF(v); if (err) goto pop_1_error; - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -5258,12 +5283,12 @@ if (true) goto pop_1_error; } if (PyDict_CheckExact(ns)) - err = PyDict_SetItem(ns, name, v); + err = PyDict_SetItem(ns, name, v); else - err = PyObject_SetItem(ns, name, v); + err = PyObject_SetItem(ns, name, v); Py_DECREF(v); if (err) goto pop_1_error; - STACK_SHRINK(1); + stack_pointer += -1; DISPATCH(); } @@ -5291,7 +5316,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - STACK_SHRINK(4); + stack_pointer += -4; DISPATCH(); } @@ -5301,7 +5326,6 @@ INSTRUCTION_STATS(STORE_SUBSCR); PREDICTED(STORE_SUBSCR); _Py_CODEUNIT *this_instr = next_instr - 2; - static_assert(INLINE_CACHE_ENTRIES_STORE_SUBSCR == 1, "incorrect cache size"); PyObject *sub; PyObject *container; PyObject *v; @@ -5331,7 +5355,7 @@ Py_DECREF(sub); if (err) goto pop_3_error; } - STACK_SHRINK(3); + stack_pointer += -3; DISPATCH(); } @@ -5339,6 +5363,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(STORE_SUBSCR_DICT); + static_assert(INLINE_CACHE_ENTRIES_STORE_SUBSCR == 1, "incorrect cache size"); PyObject *sub; PyObject *dict; PyObject *value; @@ -5350,7 +5375,7 @@ int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - STACK_SHRINK(3); + stack_pointer += -3; DISPATCH(); } @@ -5358,6 +5383,7 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(STORE_SUBSCR_LIST_INT); + static_assert(INLINE_CACHE_ENTRIES_STORE_SUBSCR == 1, "incorrect cache size"); PyObject *sub; PyObject *list; PyObject *value; @@ -5366,21 +5392,19 @@ value = stack_pointer[-3]; DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); - // Ensure nonnegative, zero-or-one-digit ints. 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); STAT_INC(STORE_SUBSCR, hit); - PyObject *old_value = PyList_GET_ITEM(list, index); PyList_SET_ITEM(list, index, value); assert(old_value != NULL); Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - STACK_SHRINK(3); + stack_pointer += -3; DISPATCH(); } @@ -5404,7 +5428,6 @@ INSTRUCTION_STATS(TO_BOOL); PREDICTED(TO_BOOL); _Py_CODEUNIT *this_instr = next_instr - 4; - static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value; PyObject *res; // _SPECIALIZE_TO_BOOL @@ -5437,6 +5460,7 @@ _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(TO_BOOL_ALWAYS_TRUE); + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value; PyObject *res; value = stack_pointer[-1]; @@ -5455,6 +5479,7 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(TO_BOOL_BOOL); + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value; value = stack_pointer[-1]; DEOPT_IF(!PyBool_Check(value), TO_BOOL); @@ -5466,6 +5491,7 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(TO_BOOL_INT); + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value; PyObject *res; value = stack_pointer[-1]; @@ -5487,6 +5513,7 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(TO_BOOL_LIST); + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value; PyObject *res; value = stack_pointer[-1]; @@ -5502,6 +5529,7 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(TO_BOOL_NONE); + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value; PyObject *res; value = stack_pointer[-1]; @@ -5517,6 +5545,7 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(TO_BOOL_STR); + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); PyObject *value; PyObject *res; value = stack_pointer[-1]; @@ -5587,7 +5616,7 @@ int res = _PyEval_UnpackIterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); Py_DECREF(seq); if (res == 0) goto pop_1_error; - STACK_GROW((oparg & 0xFF) + (oparg >> 8)); + stack_pointer += (oparg >> 8) + (oparg & 0xFF); DISPATCH(); } @@ -5597,7 +5626,6 @@ INSTRUCTION_STATS(UNPACK_SEQUENCE); PREDICTED(UNPACK_SEQUENCE); _Py_CODEUNIT *this_instr = next_instr - 2; - static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq; // _SPECIALIZE_UNPACK_SEQUENCE seq = stack_pointer[-1]; @@ -5623,8 +5651,7 @@ Py_DECREF(seq); if (res == 0) goto pop_1_error; } - STACK_SHRINK(1); - STACK_GROW(oparg); + stack_pointer += -1 + oparg; DISPATCH(); } @@ -5632,10 +5659,11 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(UNPACK_SEQUENCE_LIST); + static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq; PyObject **values; seq = stack_pointer[-1]; - values = stack_pointer - 1; + values = &stack_pointer[-1]; DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -5644,8 +5672,7 @@ *values++ = Py_NewRef(items[i]); } Py_DECREF(seq); - STACK_SHRINK(1); - STACK_GROW(oparg); + stack_pointer += -1 + oparg; DISPATCH(); } @@ -5653,10 +5680,11 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(UNPACK_SEQUENCE_TUPLE); + static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq; PyObject **values; seq = stack_pointer[-1]; - values = stack_pointer - 1; + values = &stack_pointer[-1]; DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); @@ -5665,8 +5693,7 @@ *values++ = Py_NewRef(items[i]); } Py_DECREF(seq); - STACK_SHRINK(1); - STACK_GROW(oparg); + stack_pointer += -1 + oparg; DISPATCH(); } @@ -5674,10 +5701,11 @@ frame->instr_ptr = next_instr; next_instr += 2; INSTRUCTION_STATS(UNPACK_SEQUENCE_TWO_TUPLE); + static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq; PyObject **values; seq = stack_pointer[-1]; - values = stack_pointer - 1; + values = &stack_pointer[-1]; DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); assert(oparg == 2); @@ -5685,8 +5713,7 @@ values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); Py_DECREF(seq); - STACK_SHRINK(1); - STACK_GROW(oparg); + stack_pointer += -1 + oparg; DISPATCH(); } @@ -5708,9 +5735,8 @@ - exit_func: FOURTH = the context.__exit__ bound method We call FOURTH(type(TOP), TOP, GetTraceback(TOP)). Then we push the __exit__ return value. - */ + */ PyObject *exc, *tb; - assert(val && PyExceptionInstance_Check(val)); exc = PyExceptionInstance_Class(val); tb = PyException_GetTraceback(val); @@ -5724,10 +5750,10 @@ (void)lasti; // Shut up compiler warning if asserts are off PyObject *stack[4] = {NULL, exc, val, tb}; res = PyObject_Vectorcall(exit_func, stack + 1, - 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - STACK_GROW(1); - stack_pointer[-1] = res; + stack_pointer[0] = res; + stack_pointer += 1; DISPATCH(); } @@ -5759,5 +5785,4 @@ LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); goto resume_frame; } - #undef TIER_ONE diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py new file mode 100644 index 000000000000000..027f9861a1c0ebc --- /dev/null +++ b/Tools/cases_generator/analyzer.py @@ -0,0 +1,456 @@ +from dataclasses import dataclass +import lexer +import parser +from typing import Optional + + +@dataclass +class Properties: + escapes: bool + infallible: bool + deopts: bool + oparg: bool + jumps: bool + ends_with_eval_breaker: bool + needs_this: bool + always_exits: bool + stores_sp: bool + + def dump(self, indent: str) -> None: + print(indent, end="") + text = ", ".join([f"{key}: {value}" for (key, value) in self.__dict__.items()]) + print(indent, text, sep="") + + @staticmethod + def from_list(properties: list["Properties"]) -> "Properties": + return Properties( + escapes=any(p.escapes for p in properties), + infallible=all(p.infallible for p in properties), + deopts=any(p.deopts for p in properties), + oparg=any(p.oparg for p in properties), + jumps=any(p.jumps for p in properties), + ends_with_eval_breaker=any(p.ends_with_eval_breaker for p in properties), + needs_this=any(p.needs_this for p in properties), + always_exits=any(p.always_exits for p in properties), + stores_sp=any(p.stores_sp for p in properties), + ) + + +SKIP_PROPERTIES = Properties( + escapes=False, + infallible=True, + deopts=False, + oparg=False, + jumps=False, + ends_with_eval_breaker=False, + needs_this=False, + always_exits=False, + stores_sp=False, +) + + +@dataclass +class Skip: + "Unused cache entry" + size: int + + @property + def name(self) -> str: + return f"unused/{self.size}" + + @property + def properties(self) -> Properties: + return SKIP_PROPERTIES + + +@dataclass +class StackItem: + name: str + type: str | None + condition: str | None + size: str + peek: bool = False + + def __str__(self) -> str: + cond = f" if ({self.condition})" if self.condition else "" + size = f"[{self.size}]" if self.size != "1" else "" + type = "" if self.type is None else f"{self.type} " + return f"{type}{self.name}{size}{cond} {self.peek}" + + def is_array(self) -> bool: + return self.type == "PyObject **" + + +@dataclass +class StackEffect: + inputs: list[StackItem] + outputs: list[StackItem] + + def __str__(self) -> str: + return f"({', '.join([str(i) for i in self.inputs])} -- {', '.join([str(i) for i in self.outputs])})" + + +@dataclass +class CacheEntry: + name: str + size: int + + def __str__(self) -> str: + return f"{self.name}/{self.size}" + + +@dataclass +class Uop: + name: str + context: parser.Context | None + annotations: list[str] + stack: StackEffect + caches: list[CacheEntry] + body: list[lexer.Token] + properties: Properties + _size: int = -1 + + def dump(self, indent: str) -> None: + print( + indent, self.name, ", ".join(self.annotations) if self.annotations else "" + ) + print(indent, self.stack, ", ".join([str(c) for c in self.caches])) + self.properties.dump(" " + indent) + + @property + def size(self) -> int: + if self._size < 0: + self._size = sum(c.size for c in self.caches) + return self._size + + +Part = Uop | Skip + + +@dataclass +class Instruction: + name: str + parts: list[Part] + _properties: Properties | None + is_target: bool = False + family: Optional["Family"] = None + + @property + def properties(self) -> Properties: + if self._properties is None: + self._properties = self._compute_properties() + return self._properties + + def _compute_properties(self) -> Properties: + return Properties.from_list([part.properties for part in self.parts]) + + def dump(self, indent: str) -> None: + print(indent, self.name, "=", ", ".join([part.name for part in self.parts])) + self.properties.dump(" " + indent) + + @property + def size(self) -> int: + return 1 + sum(part.size for part in self.parts) + + +@dataclass +class PseudoInstruction: + name: str + targets: list[Instruction] + flags: list[str] + + def dump(self, indent: str) -> None: + print(indent, self.name, "->", " or ".join([t.name for t in self.targets])) + + +@dataclass +class Family: + name: str + size: str + members: list[Instruction] + + def dump(self, indent: str) -> None: + print(indent, self.name, "= ", ", ".join([m.name for m in self.members])) + + +@dataclass +class Analysis: + instructions: dict[str, Instruction] + uops: dict[str, Uop] + families: dict[str, Family] + pseudos: dict[str, PseudoInstruction] + + +def analysis_error(message: str, tkn: lexer.Token) -> SyntaxError: + # To do -- support file and line output + # Construct a SyntaxError instance from message and token + return lexer.make_syntax_error(message, "", tkn.line, tkn.column, "") + + +def override_error( + name: str, + context: parser.Context | None, + prev_context: parser.Context | None, + token: lexer.Token, +) -> SyntaxError: + return analysis_error( + f"Duplicate definition of '{name}' @ {context} " + f"previous definition @ {prev_context}", + token, + ) + + +def convert_stack_item(item: parser.StackEffect) -> StackItem: + return StackItem(item.name, item.type, item.cond, (item.size or "1")) + + +def analyze_stack(op: parser.InstDef) -> StackEffect: + inputs: list[StackItem] = [ + convert_stack_item(i) for i in op.inputs if isinstance(i, parser.StackEffect) + ] + outputs: list[StackItem] = [convert_stack_item(i) for i in op.outputs] + for input, output in zip(inputs, outputs): + if input.name == output.name: + input.peek = output.peek = True + return StackEffect(inputs, outputs) + + +def analyze_caches(op: parser.InstDef) -> list[CacheEntry]: + caches: list[parser.CacheEffect] = [ + i for i in op.inputs if isinstance(i, parser.CacheEffect) + ] + return [CacheEntry(i.name, int(i.size)) for i in caches] + + +def variable_used(node: parser.InstDef, name: str) -> bool: + """Determine whether a variable with a given name is used in a node.""" + return any( + token.kind == "IDENTIFIER" and token.text == name for token in node.tokens + ) + + +def is_infallible(op: parser.InstDef) -> bool: + return not ( + variable_used(op, "ERROR_IF") + or variable_used(op, "error") + or variable_used(op, "pop_1_error") + or variable_used(op, "exception_unwind") + or variable_used(op, "resume_with_error") + ) + + +from flags import makes_escaping_api_call + +EXITS = { + "DISPATCH", + "GO_TO_INSTRUCTION", + "Py_UNREACHABLE", + "DISPATCH_INLINED", + "DISPATCH_GOTO", +} + + +def eval_breaker_at_end(op: parser.InstDef) -> bool: + return op.tokens[-5].text == "CHECK_EVAL_BREAKER" + + +def always_exits(op: parser.InstDef) -> bool: + depth = 0 + tkn_iter = iter(op.tokens) + for tkn in tkn_iter: + if tkn.kind == "LBRACE": + depth += 1 + elif tkn.kind == "RBRACE": + depth -= 1 + elif depth > 1: + continue + elif tkn.kind == "GOTO" or tkn.kind == "RETURN": + return True + elif tkn.kind == "KEYWORD": + if tkn.text in EXITS: + return True + elif tkn.kind == "IDENTIFIER": + if tkn.text in EXITS: + return True + if tkn.text == "DEOPT_IF" or tkn.text == "ERROR_IF": + next(tkn_iter) # '(' + t = next(tkn_iter) + if t.text == "true": + return True + return False + + +def compute_properties(op: parser.InstDef) -> Properties: + return Properties( + escapes=makes_escaping_api_call(op), + infallible=is_infallible(op), + deopts=variable_used(op, "DEOPT_IF"), + oparg=variable_used(op, "oparg"), + jumps=variable_used(op, "JUMPBY"), + ends_with_eval_breaker=eval_breaker_at_end(op), + needs_this=variable_used(op, "this_instr"), + always_exits=always_exits(op), + stores_sp=variable_used(op, "STORE_SP"), + ) + + +def make_uop(name: str, op: parser.InstDef) -> Uop: + return Uop( + name=name, + context=op.context, + annotations=op.annotations, + stack=analyze_stack(op), + caches=analyze_caches(op), + body=op.block.tokens, + properties=compute_properties(op), + ) + + +def add_op(op: parser.InstDef, uops: dict[str, Uop]) -> None: + assert op.kind == "op" + if op.name in uops: + if "override" not in op.annotations: + raise override_error( + op.name, op.context, uops[op.name].context, op.tokens[0] + ) + uops[op.name] = make_uop(op.name, op) + + +def add_instruction( + name: str, parts: list[Part], instructions: dict[str, Instruction] +) -> None: + instructions[name] = Instruction(name, parts, None) + + +def desugar_inst( + inst: parser.InstDef, instructions: dict[str, Instruction], uops: dict[str, Uop] +) -> None: + assert inst.kind == "inst" + name = inst.name + uop = make_uop("_" + inst.name, inst) + uops[inst.name] = uop + add_instruction(name, [uop], instructions) + + +def add_macro( + macro: parser.Macro, instructions: dict[str, Instruction], uops: dict[str, Uop] +) -> None: + parts: list[Uop | Skip] = [] + for part in macro.uops: + match part: + case parser.OpName(): + if part.name not in uops: + analysis_error(f"No Uop named {part.name}", macro.tokens[0]) + parts.append(uops[part.name]) + case parser.CacheEffect(): + parts.append(Skip(part.size)) + case _: + assert False + assert parts + add_instruction(macro.name, parts, instructions) + + +def add_family( + pfamily: parser.Family, + instructions: dict[str, Instruction], + families: dict[str, Family], +) -> None: + family = Family( + pfamily.name, + pfamily.size, + [instructions[member_name] for member_name in pfamily.members], + ) + for member in family.members: + member.family = family + # The head of the family is an implicit jump target for DEOPTs + instructions[family.name].is_target = True + families[family.name] = family + + +def add_pseudo( + pseudo: parser.Pseudo, + instructions: dict[str, Instruction], + pseudos: dict[str, PseudoInstruction], +) -> None: + pseudos[pseudo.name] = PseudoInstruction( + pseudo.name, + [instructions[target] for target in pseudo.targets], + pseudo.flags, + ) + + +def analyze_forest(forest: list[parser.AstNode]) -> Analysis: + instructions: dict[str, Instruction] = {} + uops: dict[str, Uop] = {} + families: dict[str, Family] = {} + pseudos: dict[str, PseudoInstruction] = {} + for node in forest: + match node: + case parser.InstDef(name): + if node.kind == "inst": + desugar_inst(node, instructions, uops) + else: + assert node.kind == "op" + add_op(node, uops) + case parser.Macro(): + pass + case parser.Family(): + pass + case parser.Pseudo(): + pass + case _: + assert False + for node in forest: + if isinstance(node, parser.Macro): + add_macro(node, instructions, uops) + for node in forest: + match node: + case parser.Family(): + add_family(node, instructions, families) + case parser.Pseudo(): + add_pseudo(node, instructions, pseudos) + case _: + pass + for uop in uops.values(): + tkn_iter = iter(uop.body) + for tkn in tkn_iter: + if tkn.kind == "IDENTIFIER" and tkn.text == "GO_TO_INSTRUCTION": + if next(tkn_iter).kind != "LPAREN": + continue + target = next(tkn_iter) + if target.kind != "IDENTIFIER": + continue + if target.text in instructions: + instructions[target.text].is_target = True + # Hack + instructions["BINARY_OP_INPLACE_ADD_UNICODE"].family = families["BINARY_OP"] + return Analysis(instructions, uops, families, pseudos) + + +def analyze_files(filenames: list[str]) -> Analysis: + return analyze_forest(parser.parse_files(filenames)) + + +def dump_analysis(analysis: Analysis) -> None: + print("Uops:") + for u in analysis.uops.values(): + u.dump(" ") + print("Instructions:") + for i in analysis.instructions.values(): + i.dump(" ") + print("Families:") + for f in analysis.families.values(): + f.dump(" ") + print("Pseudos:") + for p in analysis.pseudos.values(): + p.dump(" ") + + +if __name__ == "__main__": + import sys + + if len(sys.argv) < 2: + print("No input") + else: + filenames = sys.argv[1:] + dump_analysis(analyze_files(filenames)) diff --git a/Tools/cases_generator/cwriter.py b/Tools/cases_generator/cwriter.py new file mode 100644 index 000000000000000..0b7edd03fd9e47c --- /dev/null +++ b/Tools/cases_generator/cwriter.py @@ -0,0 +1,111 @@ +from lexer import Token +from typing import TextIO + + +class CWriter: + "A writer that understands tokens and how to format C code" + + last_token: Token | None + + def __init__(self, out: TextIO, indent: int, line_directives: bool): + self.out = out + self.base_column = indent * 4 + self.indents = [i * 4 for i in range(indent + 1)] + self.line_directives = line_directives + self.last_token = None + self.newline = True + + def set_position(self, tkn: Token) -> None: + if self.last_token is not None: + if self.last_token.line < tkn.line: + self.out.write("\n") + if self.line_directives: + self.out.write(f'#line {tkn.line} "{tkn.filename}"\n') + self.out.write(" " * self.indents[-1]) + else: + gap = tkn.column - self.last_token.end_column + self.out.write(" " * gap) + elif self.newline: + self.out.write(" " * self.indents[-1]) + self.last_token = tkn + self.newline = False + + def emit_at(self, txt: str, where: Token) -> None: + self.set_position(where) + self.out.write(txt) + + def maybe_dedent(self, txt: str) -> None: + parens = txt.count("(") - txt.count(")") + if parens < 0: + self.indents.pop() + elif "}" in txt or is_label(txt): + self.indents.pop() + + def maybe_indent(self, txt: str) -> None: + parens = txt.count("(") - txt.count(")") + if parens > 0 and self.last_token: + offset = self.last_token.end_column - 1 + if offset <= self.indents[-1] or offset > 40: + offset = self.indents[-1] + 4 + self.indents.append(offset) + elif "{" in txt or is_label(txt): + self.indents.append(self.indents[-1] + 4) + + def emit_text(self, txt: str) -> None: + self.out.write(txt) + + def emit_multiline_comment(self, tkn: Token) -> None: + self.set_position(tkn) + lines = tkn.text.splitlines(True) + first = True + for line in lines: + text = line.lstrip() + if first: + spaces = 0 + else: + spaces = self.indents[-1] + if text.startswith("*"): + spaces += 1 + else: + spaces += 3 + first = False + self.out.write(" " * spaces) + self.out.write(text) + + def emit_token(self, tkn: Token) -> None: + if tkn.kind == "COMMENT" and "\n" in tkn.text: + return self.emit_multiline_comment(tkn) + self.maybe_dedent(tkn.text) + self.set_position(tkn) + self.emit_text(tkn.text) + self.maybe_indent(tkn.text) + + def emit_str(self, txt: str) -> None: + self.maybe_dedent(txt) + if self.newline and txt: + if txt[0] != "\n": + self.out.write(" " * self.indents[-1]) + self.newline = False + self.emit_text(txt) + if txt.endswith("\n"): + self.newline = True + self.maybe_indent(txt) + self.last_token = None + + def emit(self, txt: str | Token) -> None: + if isinstance(txt, Token): + self.emit_token(txt) + elif isinstance(txt, str): + self.emit_str(txt) + else: + assert False + + def start_line(self) -> None: + if not self.newline: + self.out.write("\n") + self.newline = True + self.last_token = None + + +def is_label(txt: str) -> bool: + return not txt.startswith("//") and txt.endswith(":") diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 1f94c1fedb2ac7b..4b7f028970bd0c9 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -883,7 +883,6 @@ def main() -> None: return # These raise OSError if output can't be written - a.write_instructions(args.output, args.emit_line_directives) a.assign_opcode_ids() a.write_opcode_ids(args.opcode_ids_h, args.opcode_targets_h) diff --git a/Tools/cases_generator/lexer.py b/Tools/cases_generator/lexer.py index 1185c8557859397..c3c2954a42083fa 100644 --- a/Tools/cases_generator/lexer.py +++ b/Tools/cases_generator/lexer.py @@ -112,7 +112,7 @@ def choice(*opts: str) -> str: char = r"\'.\'" # TODO: escape sequence CHARACTER = "CHARACTER" -comment_re = r"//.*|/\*([^*]|\*[^/])*\*/" +comment_re = r"(//.*)|/\*([^*]|\*[^/])*\*/" COMMENT = "COMMENT" newline = r"\n" @@ -234,6 +234,7 @@ def make_syntax_error( @dataclass(slots=True) class Token: + filename: str kind: str text: str begin: tuple[int, int] @@ -261,7 +262,7 @@ def width(self) -> int: def replaceText(self, txt: str) -> "Token": assert isinstance(txt, str) - return Token(self.kind, txt, self.begin, self.end) + return Token(self.filename, self.kind, txt, self.begin, self.end) def __repr__(self) -> str: b0, b1 = self.begin @@ -272,7 +273,7 @@ def __repr__(self) -> str: return f"{self.kind}({self.text!r}, {b0}:{b1}, {e0}:{e1})" -def tokenize(src: str, line: int = 1, filename: str | None = None) -> Iterator[Token]: +def tokenize(src: str, line: int = 1, filename: str = "") -> Iterator[Token]: linestart = -1 for m in matcher.finditer(src): start, end = m.span() @@ -323,7 +324,7 @@ def tokenize(src: str, line: int = 1, filename: str | None = None) -> Iterator[T else: begin = line, start - linestart if kind != "\n": - yield Token(kind, text, begin, (line, start - linestart + len(text))) + yield Token(filename, kind, text, begin, (line, start - linestart + len(text))) def to_text(tkns: list[Token], dedent: int = 0) -> str: diff --git a/Tools/cases_generator/mypy.ini b/Tools/cases_generator/mypy.ini index e7175e263350b21..8e5a31851c596e7 100644 --- a/Tools/cases_generator/mypy.ini +++ b/Tools/cases_generator/mypy.ini @@ -11,3 +11,5 @@ strict = True strict_concatenate = True enable_error_code = ignore-without-code,redundant-expr,truthy-bool,possibly-undefined warn_unreachable = True +allow_redefinition = True +implicit_reexport = True diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py new file mode 100644 index 000000000000000..12173a611997007 --- /dev/null +++ b/Tools/cases_generator/parser.py @@ -0,0 +1,55 @@ +from parsing import ( + InstDef, + Macro, + Pseudo, + Family, + Parser, + Context, + CacheEffect, + StackEffect, + OpName, + AstNode, +) +from formatting import prettify_filename + + +BEGIN_MARKER = "// BEGIN BYTECODES //" +END_MARKER = "// END BYTECODES //" + + +def parse_files(filenames: list[str]) -> list[AstNode]: + result: list[AstNode] = [] + for filename in filenames: + with open(filename) as file: + src = file.read() + + psr = Parser(src, filename=prettify_filename(filename)) + + # Skip until begin marker + while tkn := psr.next(raw=True): + if tkn.text == BEGIN_MARKER: + break + else: + raise psr.make_syntax_error( + f"Couldn't find {BEGIN_MARKER!r} in {psr.filename}" + ) + start = psr.getpos() + + # Find end marker, then delete everything after it + while tkn := psr.next(raw=True): + if tkn.text == END_MARKER: + break + del psr.tokens[psr.getpos() - 1 :] + + # Parse from start + psr.setpos(start) + thing_first_token = psr.peek() + while node := psr.definition(): + assert node is not None + result.append(node) # type: ignore[arg-type] + if not psr.eof(): + psr.backup() + raise psr.make_syntax_error( + f"Extra stuff at the end of {filename}", psr.next(True) + ) + return result diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py index 7800adf16794bba..60c185dcef58e9a 100644 --- a/Tools/cases_generator/parsing.py +++ b/Tools/cases_generator/parsing.py @@ -141,10 +141,11 @@ class Pseudo(Node): flags: list[str] # instr flags to set on the pseudo instruction targets: list[str] # opcodes this can be replaced by +AstNode = InstDef | Macro | Pseudo | Family class Parser(PLexer): @contextual - def definition(self) -> InstDef | Macro | Pseudo | Family | None: + def definition(self) -> AstNode | None: if macro := self.macro_def(): return macro if family := self.family_def(): diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py new file mode 100644 index 000000000000000..9cd8e1a3b2edf84 --- /dev/null +++ b/Tools/cases_generator/stack.py @@ -0,0 +1,81 @@ +import sys +from analyzer import StackItem +from dataclasses import dataclass +from formatting import maybe_parenthesize + + +def var_size(var: StackItem) -> str: + if var.condition: + # Special case simplification + if var.condition == "oparg & 1" and var.size == "1": + return f"({var.condition})" + else: + return f"(({var.condition}) ? {var.size} : 0)" + else: + return var.size + + +class StackOffset: + "The stack offset of the virtual base of the stack from the physical stack pointer" + + def __init__(self) -> None: + self.popped: list[str] = [] + self.pushed: list[str] = [] + + def pop(self, item: StackItem) -> None: + self.popped.append(var_size(item)) + + def push(self, item: StackItem) -> None: + self.pushed.append(var_size(item)) + + def simplify(self) -> None: + "Remove matching values from both the popped and pushed list" + if not self.popped or not self.pushed: + return + # Sort the list so the lexically largest element is last. + popped = sorted(self.popped) + pushed = sorted(self.pushed) + self.popped = [] + self.pushed = [] + while popped and pushed: + pop = popped.pop() + push = pushed.pop() + if pop == push: + pass + elif pop > push: + # if pop > push, there can be no element in pushed matching pop. + self.popped.append(pop) + pushed.append(push) + else: + self.pushed.append(push) + popped.append(pop) + self.popped.extend(popped) + self.pushed.extend(pushed) + + def to_c(self) -> str: + self.simplify() + int_offset = 0 + symbol_offset = "" + for item in self.popped: + try: + int_offset -= int(item) + except ValueError: + symbol_offset += f" - {maybe_parenthesize(item)}" + for item in self.pushed: + try: + int_offset += int(item) + except ValueError: + symbol_offset += f" + {maybe_parenthesize(item)}" + if symbol_offset and not int_offset: + res = symbol_offset + else: + res = f"{int_offset}{symbol_offset}" + if res.startswith(" + "): + res = res[3:] + if res.startswith(" - "): + res = "-" + res[3:] + return res + + def clear(self) -> None: + self.popped = [] + self.pushed = [] diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py new file mode 100644 index 000000000000000..eba926435d24151 --- /dev/null +++ b/Tools/cases_generator/tier1_generator.py @@ -0,0 +1,417 @@ +"""Generate the main interpreter switch. +Reads the instruction definitions from bytecodes.c. +Writes the cases to generated_cases.c.h, which is #included in ceval.c. +""" + +import argparse +import os.path +import sys + +from analyzer import ( + Analysis, + Instruction, + Uop, + Part, + analyze_files, + Skip, + StackItem, + analysis_error, +) +from cwriter import CWriter +from typing import TextIO, Iterator +from lexer import Token +from stack import StackOffset + + +HERE = os.path.dirname(__file__) +ROOT = os.path.join(HERE, "../..") +THIS = os.path.relpath(__file__, ROOT).replace(os.path.sep, "/") + +DEFAULT_INPUT = os.path.relpath(os.path.join(ROOT, "Python/bytecodes.c")) +DEFAULT_OUTPUT = os.path.relpath(os.path.join(ROOT, "Python/generated_cases.c.h")) + + +def write_header(filename: str, outfile: TextIO) -> None: + outfile.write( + f"""// This file is generated by {THIS} +// from: +// {filename} +// Do not edit! + +#ifdef TIER_TWO + #error "This file is for Tier 1 only" +#endif +#define TIER_ONE 1 +""" + ) + + +FOOTER = "#undef TIER_ONE\n" + + +class SizeMismatch(Exception): + pass + + +class Stack: + def __init__(self) -> None: + self.top_offset = StackOffset() + self.base_offset = StackOffset() + self.peek_offset = StackOffset() + self.variables: list[StackItem] = [] + self.defined: set[str] = set() + + def pop(self, var: StackItem) -> str: + self.top_offset.pop(var) + if not var.peek: + self.peek_offset.pop(var) + indirect = "&" if var.is_array() else "" + if self.variables: + popped = self.variables.pop() + if popped.size != var.size: + raise SizeMismatch( + f"Size mismatch when popping '{popped.name}' from stack to assign to {var.name}. " + f"Expected {var.size} got {popped.size}" + ) + if popped.name == var.name: + return "" + elif popped.name == "unused": + self.defined.add(var.name) + return ( + f"{var.name} = {indirect}stack_pointer[{self.top_offset.to_c()}];\n" + ) + elif var.name == "unused": + return "" + else: + self.defined.add(var.name) + return f"{var.name} = {popped.name};\n" + self.base_offset.pop(var) + if var.name == "unused": + return "" + else: + self.defined.add(var.name) + assign = f"{var.name} = {indirect}stack_pointer[{self.base_offset.to_c()}];" + if var.condition: + return f"if ({var.condition}) {{ {assign} }}\n" + return f"{assign}\n" + + def push(self, var: StackItem) -> str: + self.variables.append(var) + if var.is_array() and var.name not in self.defined and var.name != "unused": + c_offset = self.top_offset.to_c() + self.top_offset.push(var) + self.defined.add(var.name) + return f"{var.name} = &stack_pointer[{c_offset}];\n" + else: + self.top_offset.push(var) + return "" + + def flush(self, out: CWriter) -> None: + for var in self.variables: + if not var.peek: + if var.name != "unused" and not var.is_array(): + if var.condition: + out.emit(f" if ({var.condition}) ") + out.emit( + f"stack_pointer[{self.base_offset.to_c()}] = {var.name};\n" + ) + self.base_offset.push(var) + if self.base_offset.to_c() != self.top_offset.to_c(): + print("base", self.base_offset.to_c(), "top", self.top_offset.to_c()) + assert False + number = self.base_offset.to_c() + if number != "0": + out.emit(f"stack_pointer += {number};\n") + self.variables = [] + self.base_offset.clear() + self.top_offset.clear() + self.peek_offset.clear() + + def as_comment(self) -> str: + return f"/* Variables: {[v.name for v in self.variables]}. Base offset: {self.base_offset.to_c()}. Top offset: {self.top_offset.to_c()} */" + + +def declare_variables(inst: Instruction, out: CWriter) -> None: + variables = {"unused"} + for uop in inst.parts: + if isinstance(uop, Uop): + for var in reversed(uop.stack.inputs): + if var.name not in variables: + type = var.type if var.type else "PyObject *" + variables.add(var.name) + if var.condition: + out.emit(f"{type}{var.name} = NULL;\n") + else: + out.emit(f"{type}{var.name};\n") + for var in uop.stack.outputs: + if var.name not in variables: + variables.add(var.name) + type = var.type if var.type else "PyObject *" + if var.condition: + out.emit(f"{type}{var.name} = NULL;\n") + else: + out.emit(f"{type}{var.name};\n") + + +def emit_to(out: CWriter, tkn_iter: Iterator[Token], end: str) -> None: + parens = 0 + for tkn in tkn_iter: + if tkn.kind == end and parens == 0: + return + if tkn.kind == "LPAREN": + parens += 1 + if tkn.kind == "RPAREN": + parens -= 1 + out.emit(tkn) + + +def replace_deopt( + out: CWriter, + tkn: Token, + tkn_iter: Iterator[Token], + uop: Uop, + unused: Stack, + inst: Instruction, +) -> None: + out.emit_at("DEOPT_IF", tkn) + out.emit(next(tkn_iter)) + emit_to(out, tkn_iter, "RPAREN") + next(tkn_iter) # Semi colon + out.emit(", ") + assert inst.family is not None + out.emit(inst.family.name) + out.emit(");\n") + + +def replace_error( + out: CWriter, + tkn: Token, + tkn_iter: Iterator[Token], + uop: Uop, + stack: Stack, + inst: Instruction, +) -> None: + out.emit_at("if ", tkn) + out.emit(next(tkn_iter)) + emit_to(out, tkn_iter, "COMMA") + label = next(tkn_iter).text + next(tkn_iter) # RPAREN + next(tkn_iter) # Semi colon + out.emit(") ") + c_offset = stack.peek_offset.to_c() + try: + offset = -int(c_offset) + close = ";\n" + except ValueError: + offset = None + out.emit(f"{{ stack_pointer += {c_offset}; ") + close = "; }\n" + out.emit("goto ") + if offset: + out.emit(f"pop_{offset}_") + out.emit(label) + out.emit(close) + + +def replace_decrefs( + out: CWriter, + tkn: Token, + tkn_iter: Iterator[Token], + uop: Uop, + stack: Stack, + inst: Instruction, +) -> None: + next(tkn_iter) + next(tkn_iter) + next(tkn_iter) + out.emit_at("", tkn) + for var in uop.stack.inputs: + if var.name == "unused" or var.name == "null" or var.peek: + continue + if var.size != "1": + out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n") + out.emit(f"Py_DECREF({var.name}[_i]);\n") + out.emit("}\n") + elif var.condition: + out.emit(f"Py_XDECREF({var.name});\n") + else: + out.emit(f"Py_DECREF({var.name});\n") + + +def replace_store_sp( + out: CWriter, + tkn: Token, + tkn_iter: Iterator[Token], + uop: Uop, + stack: Stack, + inst: Instruction, +) -> None: + next(tkn_iter) + next(tkn_iter) + next(tkn_iter) + out.emit_at("", tkn) + stack.flush(out) + out.emit("_PyFrame_SetStackPointer(frame, stack_pointer);\n") + + +def replace_check_eval_breaker( + out: CWriter, + tkn: Token, + tkn_iter: Iterator[Token], + uop: Uop, + stack: Stack, + inst: Instruction, +) -> None: + next(tkn_iter) + next(tkn_iter) + next(tkn_iter) + if not uop.properties.ends_with_eval_breaker: + out.emit_at("CHECK_EVAL_BREAKER();", tkn) + + +REPLACEMENT_FUNCTIONS = { + "DEOPT_IF": replace_deopt, + "ERROR_IF": replace_error, + "DECREF_INPUTS": replace_decrefs, + "CHECK_EVAL_BREAKER": replace_check_eval_breaker, + "STORE_SP": replace_store_sp, +} + + +# Move this to formatter +def emit_tokens(out: CWriter, uop: Uop, stack: Stack, inst: Instruction) -> None: + tkns = uop.body[1:-1] + if not tkns: + return + tkn_iter = iter(tkns) + out.start_line() + for tkn in tkn_iter: + if tkn.kind == "IDENTIFIER" and tkn.text in REPLACEMENT_FUNCTIONS: + REPLACEMENT_FUNCTIONS[tkn.text](out, tkn, tkn_iter, uop, stack, inst) + else: + out.emit(tkn) + + +def write_uop( + uop: Part, out: CWriter, offset: int, stack: Stack, inst: Instruction, braces: bool +) -> int: + # out.emit(stack.as_comment() + "\n") + if isinstance(uop, Skip): + entries = "entries" if uop.size > 1 else "entry" + out.emit(f"/* Skip {uop.size} cache {entries} */\n") + return offset + uop.size + try: + out.start_line() + if braces: + out.emit(f"// {uop.name}\n") + for var in reversed(uop.stack.inputs): + out.emit(stack.pop(var)) + if braces: + out.emit("{\n") + if not uop.properties.stores_sp: + for i, var in enumerate(uop.stack.outputs): + out.emit(stack.push(var)) + for cache in uop.caches: + if cache.name != "unused": + if cache.size == 4: + type = "PyObject *" + reader = "read_obj" + else: + type = f"uint{cache.size*16}_t " + reader = f"read_u{cache.size*16}" + out.emit( + f"{type}{cache.name} = {reader}(&this_instr[{offset}].cache);\n" + ) + offset += cache.size + emit_tokens(out, uop, stack, inst) + if uop.properties.stores_sp: + for i, var in enumerate(uop.stack.outputs): + out.emit(stack.push(var)) + if braces: + out.start_line() + out.emit("}\n") + # out.emit(stack.as_comment() + "\n") + return offset + except SizeMismatch as ex: + raise analysis_error(ex.args[0], uop.body[0]) + + +def uses_this(inst: Instruction) -> bool: + if inst.properties.needs_this: + return True + for uop in inst.parts: + if isinstance(uop, Skip): + continue + for cache in uop.caches: + if cache.name != "unused": + return True + return False + + +def generate_tier1( + filenames: str, analysis: Analysis, outfile: TextIO, lines: bool +) -> None: + write_header(filenames, outfile) + out = CWriter(outfile, 2, lines) + out.emit("\n") + for name, inst in sorted(analysis.instructions.items()): + needs_this = uses_this(inst) + out.emit("\n") + out.emit(f"TARGET({name}) {{\n") + if needs_this and not inst.is_target: + out.emit(f"_Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr;\n") + else: + out.emit(f"frame->instr_ptr = next_instr;\n") + out.emit(f"next_instr += {inst.size};\n") + out.emit(f"INSTRUCTION_STATS({name});\n") + if inst.is_target: + out.emit(f"PREDICTED({name});\n") + if needs_this: + out.emit(f"_Py_CODEUNIT *this_instr = next_instr - {inst.size};\n") + if inst.family is not None: + out.emit( + f"static_assert({inst.family.size} == {inst.size-1}" + ', "incorrect cache size");\n' + ) + declare_variables(inst, out) + offset = 1 # The instruction itself + stack = Stack() + for part in inst.parts: + # Only emit braces if more than one uop + offset = write_uop(part, out, offset, stack, inst, len(inst.parts) > 1) + out.start_line() + if not inst.parts[-1].properties.always_exits: + stack.flush(out) + if inst.parts[-1].properties.ends_with_eval_breaker: + out.emit("CHECK_EVAL_BREAKER();\n") + out.emit("DISPATCH();\n") + out.start_line() + out.emit("}") + out.emit("\n") + outfile.write(FOOTER) + + +arg_parser = argparse.ArgumentParser( + description="Generate the code for the interpreter switch.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, +) + +arg_parser.add_argument( + "-o", "--output", type=str, help="Generated code", default=DEFAULT_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)" +) + +if __name__ == "__main__": + args = arg_parser.parse_args() + if len(args.input) == 0: + args.input.append(DEFAULT_INPUT) + data = analyze_files(args.input) + with open(args.output, "w") as outfile: + generate_tier1(args.input, data, outfile, args.emit_line_directives) From 9c3458e05865093dd55d7608810a9d0ef0765978 Mon Sep 17 00:00:00 2001 From: andrewluotechnologies <44252973+andrewluotechnologies@users.noreply.github.com> Date: Thu, 7 Dec 2023 04:56:01 -0800 Subject: [PATCH 78/87] gh-112125: Fix None.__ne__(None) returning NotImplemented instead of False (#112504) --- Include/internal/pycore_typeobject.h | 2 ++ Lib/test/test_builtin.py | 5 +++++ .../2023-12-07-13-19-55.gh-issue-112125.4ADN7i.rst | 1 + Objects/object.c | 2 +- Objects/typeobject.c | 6 ++++++ 5 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-12-07-13-19-55.gh-issue-112125.4ADN7i.rst diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index bbf8544b09f0fb7..f983de560496318 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -135,6 +135,8 @@ extern PyObject* _Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int *suppress_missing_attribute); extern PyObject* _Py_type_getattro(PyTypeObject *type, PyObject *name); +extern PyObject* _Py_BaseObject_RichCompare(PyObject* self, PyObject* other, int op); + extern PyObject* _Py_slot_tp_getattro(PyObject *self, PyObject *name); extern PyObject* _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name); diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 558715383c82ee1..5e66d58fd2cb18c 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -627,6 +627,11 @@ def __dir__(self): # test that object has a __dir__() self.assertEqual(sorted([].__dir__()), dir([])) + def test___ne__(self): + self.assertFalse(None.__ne__(None)) + self.assertTrue(None.__ne__(0)) + self.assertTrue(None.__ne__("abc")) + def test_divmod(self): self.assertEqual(divmod(12, 7), (1, 5)) self.assertEqual(divmod(-12, 7), (-2, 2)) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-07-13-19-55.gh-issue-112125.4ADN7i.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-07-13-19-55.gh-issue-112125.4ADN7i.rst new file mode 100644 index 000000000000000..52cd45029fb8c71 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-12-07-13-19-55.gh-issue-112125.4ADN7i.rst @@ -0,0 +1 @@ +Fix None.__ne__(None) returning NotImplemented instead of False diff --git a/Objects/object.c b/Objects/object.c index d145674cb3ba34d..cdb7a08a7828fb7 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2026,7 +2026,7 @@ PyTypeObject _PyNone_Type = { 0, /*tp_doc */ 0, /*tp_traverse */ 0, /*tp_clear */ - 0, /*tp_richcompare */ + _Py_BaseObject_RichCompare, /*tp_richcompare */ 0, /*tp_weaklistoffset */ 0, /*tp_iter */ 0, /*tp_iternext */ diff --git a/Objects/typeobject.c b/Objects/typeobject.c index aa00e04ad5e11b0..08f5f47d5867291 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5625,6 +5625,12 @@ object_richcompare(PyObject *self, PyObject *other, int op) return res; } +PyObject* +_Py_BaseObject_RichCompare(PyObject* self, PyObject* other, int op) +{ + return object_richcompare(self, other, op); +} + static PyObject * object_get_class(PyObject *self, void *closure) { From 7576534f4a230cc8f9b0f13ef2e521eeaa9e9ead Mon Sep 17 00:00:00 2001 From: Christopher Chavez Date: Thu, 7 Dec 2023 07:24:11 -0600 Subject: [PATCH 79/87] bpo-42519: Remove outdated sentence in comment (#112822) Update objimpl.h --- Include/objimpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/objimpl.h b/Include/objimpl.h index 967e2776767756e..ff5fa7a8c1d3d8d 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -35,7 +35,7 @@ Functions and macros for modules that implement new object types. fields, this also fills in the ob_size field. - PyObject_Free(op) releases the memory allocated for an object. It does not - run a destructor -- it only frees the memory. PyObject_Free is identical. + run a destructor -- it only frees the memory. - PyObject_Init(op, typeobj) and PyObject_InitVar(op, typeobj, n) don't allocate memory. Instead of a 'type' parameter, they take a pointer to a From 9f67042f28bf886a9bf30fed6795d26cff255f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Langa?= Date: Thu, 7 Dec 2023 14:29:15 +0100 Subject: [PATCH 80/87] gh-110190: Temporarily skip new test introduced in gh-112604 on PPC64LE (#112818) --- Lib/test/test_ctypes/test_structures.py | 98 +++++++++++++------------ 1 file changed, 53 insertions(+), 45 deletions(-) diff --git a/Lib/test/test_ctypes/test_structures.py b/Lib/test/test_ctypes/test_structures.py index 771205ffb32ecca..57ae9240b3c165b 100644 --- a/Lib/test/test_ctypes/test_structures.py +++ b/Lib/test/test_ctypes/test_structures.py @@ -1,4 +1,5 @@ import _ctypes_test +import platform import struct import sys import unittest @@ -494,51 +495,6 @@ class Test3B(Test3A): ('more_data', c_float * 2), ] - class Test3C1(Structure): - _fields_ = [ - ("data", c_double * 4) - ] - - class DataType4(Array): - _type_ = c_double - _length_ = 4 - - class Test3C2(Structure): - _fields_ = [ - ("data", DataType4) - ] - - class Test3C3(Structure): - _fields_ = [ - ("x", c_double), - ("y", c_double), - ("z", c_double), - ("t", c_double) - ] - - class Test3D1(Structure): - _fields_ = [ - ("data", c_double * 5) - ] - - class DataType5(Array): - _type_ = c_double - _length_ = 5 - - class Test3D2(Structure): - _fields_ = [ - ("data", DataType5) - ] - - class Test3D3(Structure): - _fields_ = [ - ("x", c_double), - ("y", c_double), - ("z", c_double), - ("t", c_double), - ("u", c_double) - ] - # Load the shared library dll = CDLL(_ctypes_test.__file__) @@ -587,6 +543,58 @@ class Test3D3(Structure): self.assertAlmostEqual(s.more_data[0], -3.0, places=6) self.assertAlmostEqual(s.more_data[1], -2.0, places=6) + @unittest.skipIf( + 'ppc64le' in platform.uname().machine, + "gh-110190: currently fails on ppc64le", + ) + def test_array_in_struct_registers(self): + dll = CDLL(_ctypes_test.__file__) + + class Test3C1(Structure): + _fields_ = [ + ("data", c_double * 4) + ] + + class DataType4(Array): + _type_ = c_double + _length_ = 4 + + class Test3C2(Structure): + _fields_ = [ + ("data", DataType4) + ] + + class Test3C3(Structure): + _fields_ = [ + ("x", c_double), + ("y", c_double), + ("z", c_double), + ("t", c_double) + ] + + class Test3D1(Structure): + _fields_ = [ + ("data", c_double * 5) + ] + + class DataType5(Array): + _type_ = c_double + _length_ = 5 + + class Test3D2(Structure): + _fields_ = [ + ("data", DataType5) + ] + + class Test3D3(Structure): + _fields_ = [ + ("x", c_double), + ("y", c_double), + ("z", c_double), + ("t", c_double), + ("u", c_double) + ] + # Tests for struct Test3C expected = (1.0, 2.0, 3.0, 4.0) func = dll._testfunc_array_in_struct_set_defaults_3C From 2d76be251d0aee89f76e6fa5a63fa1ad3f2b76cf Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 7 Dec 2023 08:47:55 -0500 Subject: [PATCH 81/87] gh-111962: Make dtoa thread-safe in `--disable-gil` builds. (#112049) This updates `dtoa.c` to avoid using the Bigint free-list in --disable-gil builds and to pre-computes the needed powers of 5 during interpreter initialization. * gh-111962: Make dtoa thread-safe in `--disable-gil` builds. This avoids using the Bigint free-list in `--disable-gil` builds and pre-computes the needed powers of 5 during interpreter initialization. * Fix size of cached powers of 5 array. We need the powers of 5 up to 5**512 because we only jump straight to underflow when the exponent is less than -512 (or larger than 308). * Rename Py_NOGIL to Py_GIL_DISABLED * Changes from review * Fix assertion placement --- Include/internal/pycore_dtoa.h | 16 ++++--- Python/dtoa.c | 78 +++++++++++++++++++++++----------- Python/pylifecycle.c | 6 +++ 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/Include/internal/pycore_dtoa.h b/Include/internal/pycore_dtoa.h index ac62a4d300720af..c5cfdf4ce8f823f 100644 --- a/Include/internal/pycore_dtoa.h +++ b/Include/internal/pycore_dtoa.h @@ -35,6 +35,9 @@ struct _dtoa_state { /* The size of the Bigint freelist */ #define Bigint_Kmax 7 +/* The size of the cached powers of 5 array */ +#define Bigint_Pow5size 8 + #ifndef PRIVATE_MEM #define PRIVATE_MEM 2304 #endif @@ -42,9 +45,10 @@ struct _dtoa_state { ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) struct _dtoa_state { - /* p5s is a linked list of powers of 5 of the form 5**(2**i), i >= 2 */ + // p5s is an array of powers of 5 of the form: + // 5**(2**(i+2)) for 0 <= i < Bigint_Pow5size + struct Bigint *p5s[Bigint_Pow5size]; // XXX This should be freed during runtime fini. - struct Bigint *p5s; struct Bigint *freelist[Bigint_Kmax+1]; double preallocated[Bigint_PREALLOC_SIZE]; double *preallocated_next; @@ -57,9 +61,6 @@ struct _dtoa_state { #endif // !Py_USING_MEMORY_DEBUGGER -/* These functions are used by modules compiled as C extension like math: - they must be exported. */ - extern double _Py_dg_strtod(const char *str, char **ptr); extern char* _Py_dg_dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve); @@ -67,6 +68,11 @@ extern void _Py_dg_freedtoa(char *s); #endif // _PY_SHORT_FLOAT_REPR == 1 + +extern PyStatus _PyDtoa_Init(PyInterpreterState *interp); +extern void _PyDtoa_Fini(PyInterpreterState *interp); + + #ifdef __cplusplus } #endif diff --git a/Python/dtoa.c b/Python/dtoa.c index 5dfc0e179cbc348..6e3162f80bdae1e 100644 --- a/Python/dtoa.c +++ b/Python/dtoa.c @@ -309,7 +309,7 @@ BCinfo { // struct Bigint is defined in pycore_dtoa.h. typedef struct Bigint Bigint; -#ifndef Py_USING_MEMORY_DEBUGGER +#if !defined(Py_GIL_DISABLED) && !defined(Py_USING_MEMORY_DEBUGGER) /* Memory management: memory is allocated from, and returned to, Kmax+1 pools of memory, where pool k (0 <= k <= Kmax) is for Bigints b with b->maxwds == @@ -428,7 +428,7 @@ Bfree(Bigint *v) } } -#endif /* Py_USING_MEMORY_DEBUGGER */ +#endif /* !defined(Py_GIL_DISABLED) && !defined(Py_USING_MEMORY_DEBUGGER) */ #define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \ y->wds*sizeof(Long) + 2*sizeof(int)) @@ -673,10 +673,17 @@ mult(Bigint *a, Bigint *b) static Bigint * pow5mult(Bigint *b, int k) { - Bigint *b1, *p5, *p51; + Bigint *b1, *p5, **p5s; int i; static const int p05[3] = { 5, 25, 125 }; + // For double-to-string conversion, the maximum value of k is limited by + // DBL_MAX_10_EXP (308), the maximum decimal base-10 exponent for binary64. + // For string-to-double conversion, the extreme case is constrained by our + // hardcoded exponent limit before we underflow of -512, adjusted by + // STRTOD_DIGLIM-DBL_DIG-1, giving a maximum of k=535. + assert(0 <= k && k < 1024); + if ((i = k & 3)) { b = multadd(b, p05[i-1], 0); if (b == NULL) @@ -686,18 +693,11 @@ pow5mult(Bigint *b, int k) if (!(k >>= 2)) return b; PyInterpreterState *interp = _PyInterpreterState_GET(); - p5 = interp->dtoa.p5s; - if (!p5) { - /* first time */ - p5 = i2b(625); - if (p5 == NULL) { - Bfree(b); - return NULL; - } - interp->dtoa.p5s = p5; - p5->next = 0; - } + p5s = interp->dtoa.p5s; for(;;) { + assert(p5s != interp->dtoa.p5s + Bigint_Pow5size); + p5 = *p5s; + p5s++; if (k & 1) { b1 = mult(b, p5); Bfree(b); @@ -707,17 +707,6 @@ pow5mult(Bigint *b, int k) } if (!(k >>= 1)) break; - p51 = p5->next; - if (!p51) { - p51 = mult(p5,p5); - if (p51 == NULL) { - Bfree(b); - return NULL; - } - p51->next = 0; - p5->next = p51; - } - p5 = p51; } return b; } @@ -2811,3 +2800,42 @@ _Py_dg_dtoa(double dd, int mode, int ndigits, } #endif // _PY_SHORT_FLOAT_REPR == 1 + +PyStatus +_PyDtoa_Init(PyInterpreterState *interp) +{ +#if _PY_SHORT_FLOAT_REPR == 1 && !defined(Py_USING_MEMORY_DEBUGGER) + Bigint **p5s = interp->dtoa.p5s; + + // 5**4 = 625 + Bigint *p5 = i2b(625); + if (p5 == NULL) { + return PyStatus_NoMemory(); + } + p5s[0] = p5; + + // compute 5**8, 5**16, 5**32, ..., 5**512 + for (Py_ssize_t i = 1; i < Bigint_Pow5size; i++) { + p5 = mult(p5, p5); + if (p5 == NULL) { + return PyStatus_NoMemory(); + } + p5s[i] = p5; + } + +#endif + return PyStatus_Ok(); +} + +void +_PyDtoa_Fini(PyInterpreterState *interp) +{ +#if _PY_SHORT_FLOAT_REPR == 1 && !defined(Py_USING_MEMORY_DEBUGGER) + Bigint **p5s = interp->dtoa.p5s; + for (Py_ssize_t i = 0; i < Bigint_Pow5size; i++) { + Bigint *p5 = p5s[i]; + p5s[i] = NULL; + Bfree(p5); + } +#endif +} diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 95a72eb47048f25..20bfe1a0b75b291 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -820,6 +820,11 @@ pycore_interp_init(PyThreadState *tstate) return status; } + status = _PyDtoa_Init(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + // The GC must be initialized before the first GC collection. status = _PyGC_Init(interp); if (_PyStatus_EXCEPTION(status)) { @@ -1776,6 +1781,7 @@ finalize_interp_clear(PyThreadState *tstate) _PyXI_Fini(tstate->interp); _PyExc_ClearExceptionGroupType(tstate->interp); _Py_clear_generic_types(tstate->interp); + _PyDtoa_Fini(tstate->interp); /* Clear interpreter state and all thread states */ _PyInterpreterState_Clear(tstate); From 21221c398f6d89b2d9295895d8a2fd71d28138fa Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Thu, 7 Dec 2023 10:01:58 -0600 Subject: [PATCH 82/87] gh-112302: Add Software Bill-of-Materials (SBOM) tracking for dependencies (#112303) --- .github/CODEOWNERS | 4 + .github/workflows/mypy.yml | 2 + Makefile.pre.in | 6 +- ...-12-06-14-06-59.gh-issue-112302.3bl20f.rst | 2 + Misc/sbom.spdx.json | 2294 +++++++++++++++++ Tools/build/generate_sbom.py | 179 ++ Tools/build/mypy.ini | 13 + 7 files changed, 2499 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2023-12-06-14-06-59.gh-issue-112302.3bl20f.rst create mode 100644 Misc/sbom.spdx.json create mode 100644 Tools/build/generate_sbom.py create mode 100644 Tools/build/mypy.ini diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1925363cbeb46e1..aa6d937d9cbc31f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -190,3 +190,7 @@ Doc/howto/clinic.rst @erlend-aasland # WebAssembly /Tools/wasm/ @brettcannon + +# SBOM +/Misc/sbom.spdx.json @sethmlarson +/Tools/build/generate_sbom.py @sethmlarson diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 72ae67aa02aa968..792903a90a4880b 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -9,6 +9,7 @@ on: paths: - ".github/workflows/mypy.yml" - "Lib/test/libregrtest/**" + - "Tools/build/generate_sbom.py" - "Tools/cases_generator/**" - "Tools/clinic/**" - "Tools/peg_generator/**" @@ -34,6 +35,7 @@ jobs: matrix: target: [ "Lib/test/libregrtest", + "Tools/build/", "Tools/cases_generator", "Tools/clinic", "Tools/peg_generator", diff --git a/Makefile.pre.in b/Makefile.pre.in index 6ac68d59c8c47f1..db85b11ef01b2c4 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1359,7 +1359,7 @@ regen-unicodedata: regen-all: regen-cases regen-typeslots \ regen-token regen-ast regen-keyword regen-sre regen-frozen \ regen-pegen-metaparser regen-pegen regen-test-frozenmain \ - regen-test-levenshtein regen-global-objects + regen-test-levenshtein regen-global-objects regen-sbom @echo @echo "Note: make regen-stdlib-module-names, make regen-limited-abi, " @echo "make regen-configure and make regen-unicodedata should be run manually" @@ -2651,6 +2651,10 @@ autoconf: regen-configure: $(srcdir)/Tools/build/regen-configure.sh +.PHONY: regen-sbom +regen-sbom: + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_sbom.py + # Create a tags file for vi tags:: ctags -w $(srcdir)/Include/*.h $(srcdir)/Include/cpython/*.h $(srcdir)/Include/internal/*.h diff --git a/Misc/NEWS.d/next/Security/2023-12-06-14-06-59.gh-issue-112302.3bl20f.rst b/Misc/NEWS.d/next/Security/2023-12-06-14-06-59.gh-issue-112302.3bl20f.rst new file mode 100644 index 000000000000000..65e4dc3762d3c03 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2023-12-06-14-06-59.gh-issue-112302.3bl20f.rst @@ -0,0 +1,2 @@ +Created a Software Bill-of-Materials document and tooling for tracking +dependencies. diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json new file mode 100644 index 000000000000000..09355640db888ea --- /dev/null +++ b/Misc/sbom.spdx.json @@ -0,0 +1,2294 @@ +{ + "SPDXID": "SPDXRef-DOCUMENT", + "files": [ + { + "SPDXID": "SPDXRef-FILE-Modules-expat-COPYING", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "39e6f567a10e36b2e77727e98e60bbcb3eb3af0b" + }, + { + "algorithm": "SHA256", + "checksumValue": "122f2c27000472a201d337b9b31f7eb2b52d091b02857061a8880371612d9534" + } + ], + "fileName": "Modules/expat/COPYING" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-ascii.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "b0235fa3cf845a7d68e8e66dd344d5e32e8951b5" + }, + { + "algorithm": "SHA256", + "checksumValue": "42f8b392c70366743eacbc60ce021389ccaa333598dd49eef6ee5c93698ca205" + } + ], + "fileName": "Modules/expat/ascii.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-asciitab.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "cbb53d16ca1f35ee9c9e296116efd222ae611ed9" + }, + { + "algorithm": "SHA256", + "checksumValue": "1cc0ae749019fc0e488cd1cf245f6beaa6d4f7c55a1fc797e5aa40a408bc266b" + } + ], + "fileName": "Modules/expat/asciitab.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-expat.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "ab7bb32514d170592dfb3f76e41bbdc075a4e7e0" + }, + { + "algorithm": "SHA256", + "checksumValue": "f521acdad222644365b0e81a33bcd6939a98c91b225c47582cc84bd73d96febc" + } + ], + "fileName": "Modules/expat/expat.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-expat-config.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "73627287302ee3e84347c4fe21f37a9cb828bc3b" + }, + { + "algorithm": "SHA256", + "checksumValue": "f17e59f9d95eeb05694c02508aa284d332616c22cbe2e6a802d8a0710310eaab" + } + ], + "fileName": "Modules/expat/expat_config.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-expat-external.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "b70ce53fdc25ae482681ae2f6623c3c8edc9c1b7" + }, + { + "algorithm": "SHA256", + "checksumValue": "86afb425ec9999eb4f1ec9ab2fb41c58c4aa5cb9bf934b8c94264670fc5a961d" + } + ], + "fileName": "Modules/expat/expat_external.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-iasciitab.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "1b0e9014c0baa4c6254d2b5e6a67c70148309c34" + }, + { + "algorithm": "SHA256", + "checksumValue": "ad8b01e9f323cc4208bcd22241df383d7e8641fe3c8b3415aa513de82531f89f" + } + ], + "fileName": "Modules/expat/iasciitab.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-internal.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "2790d37e7de2f13dccc4f4fb352cbdf9ed6abaa2" + }, + { + "algorithm": "SHA256", + "checksumValue": "d2efe5a1018449968a689f444cca432e3d5875aba6ad08ee18ca235d64f41bb9" + } + ], + "fileName": "Modules/expat/internal.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-latin1tab.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "d335ecca380e331a0ea7dc33838a4decd93ec1e4" + }, + { + "algorithm": "SHA256", + "checksumValue": "eab66226da100372e01e42e1cbcd8ac2bbbb5c1b5f95d735289cc85c7a8fc2ba" + } + ], + "fileName": "Modules/expat/latin1tab.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-nametab.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "cf2bc9626c945826602ba9170786e9a2a44645e4" + }, + { + "algorithm": "SHA256", + "checksumValue": "67dcf415d37a4b692a6a8bb46f990c02d83f2ef3d01a65cd61c8594a084246f2" + } + ], + "fileName": "Modules/expat/nametab.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-pyexpatns.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "baa44fe4581895d42e8d5e83d8ce6a69b1c34dbe" + }, + { + "algorithm": "SHA256", + "checksumValue": "33a7b9ac8bf4571e23272cdf644c6f9808bd44c66b149e3c41ab3870d1888609" + } + ], + "fileName": "Modules/expat/pyexpatns.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-siphash.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "2b984f806f10fbfbf72d8d1b7ba2992413c15299" + }, + { + "algorithm": "SHA256", + "checksumValue": "fbce56cd680e690043bbf572188cc2d0a25dbfc0d47ac8cb98eb3de768d4e694" + } + ], + "fileName": "Modules/expat/siphash.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-utf8tab.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "b77c8fcfb551553c81d6fbd94c798c8aa04ad021" + }, + { + "algorithm": "SHA256", + "checksumValue": "8cd26bd461d334d5e1caedb3af4518d401749f2fc66d56208542b29085159c18" + } + ], + "fileName": "Modules/expat/utf8tab.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-winconfig.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "e774ae6ee9391aa6ffb8f775fb74e48f4b428959" + }, + { + "algorithm": "SHA256", + "checksumValue": "3c71cea9a6174718542331971a35db317902b2433be9d8dd1cb24239b635c0cc" + } + ], + "fileName": "Modules/expat/winconfig.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-xmlparse.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "b580e827e16baa6b035586ffcd4d90301e5a353f" + }, + { + "algorithm": "SHA256", + "checksumValue": "483518bbd69338eefc706cd7fc0b6039df2d3e347f64097989059ed6d2385a1e" + } + ], + "fileName": "Modules/expat/xmlparse.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-xmlrole.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "5ef21312af73deb2428be3fe97a65244608e76de" + }, + { + "algorithm": "SHA256", + "checksumValue": "6fcf8c72ac0112c1b98bd2039c632a66b4c3dc516ce7c1f981390951121ef3c0" + } + ], + "fileName": "Modules/expat/xmlrole.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-xmlrole.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "c1a4ea6356643d0820edb9c024c20ad2aaf562dc" + }, + { + "algorithm": "SHA256", + "checksumValue": "2b5d674be6ef20c7e3f69295176d75e68c5616e4dfce0a186fdd5e2ed8315f7a" + } + ], + "fileName": "Modules/expat/xmlrole.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-xmltok.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "e6d66ae9fd61d7950c62c5d87693c30a707e8577" + }, + { + "algorithm": "SHA256", + "checksumValue": "1110f651bdccfa765ad3d6f3857a35887ab35fc0fe7f3f3488fde2b238b482e3" + } + ], + "fileName": "Modules/expat/xmltok.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-xmltok.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "9c2a544875fd08ba9c2397296c97263518a410aa" + }, + { + "algorithm": "SHA256", + "checksumValue": "4299a03828b98bfe47ec6809f6e279252954a9a911dc7e0f19551bd74e3af971" + } + ], + "fileName": "Modules/expat/xmltok.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-xmltok-impl.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "aa96882de8e3d1d3083124b595aa911efe44e5ad" + }, + { + "algorithm": "SHA256", + "checksumValue": "0fbcba7931707c60301305dab78d2298d96447d0a5513926d8b18135228c0818" + } + ], + "fileName": "Modules/expat/xmltok_impl.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-xmltok-impl.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "788332fe8040bed71172cddedb69abd848cc62f7" + }, + { + "algorithm": "SHA256", + "checksumValue": "f05ad4fe5e98429a7349ff04f57192cac58c324601f2a2e5e697ab0bc05d36d5" + } + ], + "fileName": "Modules/expat/xmltok_impl.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-expat-xmltok-ns.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "2d82d0a1201f78d478b30d108ff8fc27ee3e2672" + }, + { + "algorithm": "SHA256", + "checksumValue": "6ce6d03193279078d55280150fe91e7370370b504a6c123a79182f28341f3e90" + } + ], + "fileName": "Modules/expat/xmltok_ns.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-MD5.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "f77449b2b4eb99f1da0938633cc558baf9c444fb" + }, + { + "algorithm": "SHA256", + "checksumValue": "0f252967debca5b35362ca53951ea16ca8bb97a19a1d24f6695f44d50010859e" + } + ], + "fileName": "Modules/_hacl/Hacl_Hash_MD5.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-MD5.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "c24e6779a91c840f3d65d24abbce225b608b676e" + }, + { + "algorithm": "SHA256", + "checksumValue": "9cd062e782801013e3cacaba583e44e1b5e682e217d20208d5323354d42011f1" + } + ], + "fileName": "Modules/_hacl/Hacl_Hash_MD5.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA1.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "560f6ff541b5eff480ea047b147f4212bb0db7ed" + }, + { + "algorithm": "SHA256", + "checksumValue": "0ade3ab264e912d7b4e5cdcf773db8c63e4440540d295922d74b06bcfc74c77a" + } + ], + "fileName": "Modules/_hacl/Hacl_Hash_SHA1.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA1.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "853b77d45379146faaeac5fe899b28db386ad13c" + }, + { + "algorithm": "SHA256", + "checksumValue": "b13eb14f91582703819235ea7c8f807bb93e4f1e6b695499dc1d86021dc39e72" + } + ], + "fileName": "Modules/_hacl/Hacl_Hash_SHA1.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA2.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "667120b6100c946cdaa442f1173c723339923071" + }, + { + "algorithm": "SHA256", + "checksumValue": "b189459b863341a3a9c5c78c0208b6554a2f2ac26e0748fbd4432a91db21fae6" + } + ], + "fileName": "Modules/_hacl/Hacl_Hash_SHA2.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA2.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "81db38b0b920e63ec33c7109d1144c35cf091da0" + }, + { + "algorithm": "SHA256", + "checksumValue": "631c9ba19c1c2c835bb63d3f2f22b8d76fb535edfed3c254ff2a52f12af3fe61" + } + ], + "fileName": "Modules/_hacl/Hacl_Hash_SHA2.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA3.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "9c832b98a2f2a68202d2da016fb718965d7b7602" + }, + { + "algorithm": "SHA256", + "checksumValue": "38d350d1184238966cfa821a59ae00343f362182b6c2fbea7f2651763d757fb7" + } + ], + "fileName": "Modules/_hacl/Hacl_Hash_SHA3.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA3.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "ecc766fb6f7ee85e902b593b61b41e5a728fca34" + }, + { + "algorithm": "SHA256", + "checksumValue": "bae290a94366a2460f51e8468144baaade91d9048db111e10d2e2ffddc3f98cf" + } + ], + "fileName": "Modules/_hacl/Hacl_Hash_SHA3.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-Hacl-Streaming-Types.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "ab7b4d9465a2765a07f8d5bccace7182b28ed1b8" + }, + { + "algorithm": "SHA256", + "checksumValue": "26913613f3b4f8ffff0a3e211a5ebc849159094e5e11de0a31fcb95b6105b74c" + } + ], + "fileName": "Modules/_hacl/Hacl_Streaming_Types.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-include-krml-FStar-UInt128-Verified.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "2ea61d6a236147462045f65c20311819d74db80c" + }, + { + "algorithm": "SHA256", + "checksumValue": "2c22b4d49ba06d6a3053cdc66405bd5ae953a28fcfed1ab164e8f5e0f6e2fb8b" + } + ], + "fileName": "Modules/_hacl/include/krml/FStar_UInt128_Verified.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-include-krml-FStar-UInt-8-16-32-64.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "1a647d841180ac8ca667afa968c353425e81ad0d" + }, + { + "algorithm": "SHA256", + "checksumValue": "e5d1c5854833bec7ea02e227ec35bd7b49c5fb9e0f339efa0dd83e1595f722d4" + } + ], + "fileName": "Modules/_hacl/include/krml/FStar_UInt_8_16_32_64.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-include-krml-fstar-uint128-struct-endianness.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "1987119a563a8fdc5966286e274f716dbcea77ee" + }, + { + "algorithm": "SHA256", + "checksumValue": "fe57e1bc5ce3224d106e36cb8829b5399c63a68a70b0ccd0c91d82a4565c8869" + } + ], + "fileName": "Modules/_hacl/include/krml/fstar_uint128_struct_endianness.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-include-krml-internal-target.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "903c9eb76b01f3a95c04c3bc841c2fb71dea5403" + }, + { + "algorithm": "SHA256", + "checksumValue": "08ec602c7f90a1540389c0cfc95769fa7fec251e7ca143ef83c0b9f7afcf89a7" + } + ], + "fileName": "Modules/_hacl/include/krml/internal/target.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-include-krml-lowstar-endianness.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "964e09bd99ff2366afd6193b59863fc925e7fb05" + }, + { + "algorithm": "SHA256", + "checksumValue": "3734c7942bec9a434e16df069fa45bdcb84b130f14417bc5f7bfe8546272d9f5" + } + ], + "fileName": "Modules/_hacl/include/krml/lowstar_endianness.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-include-krml-types.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "df8e0ed74a5970d09d3cc4c6e7c6c7a4c4e5015c" + }, + { + "algorithm": "SHA256", + "checksumValue": "de7444c345caa4c47902c4380500356a3ee7e199d2aab84fd8c4960410154f3d" + } + ], + "fileName": "Modules/_hacl/include/krml/types.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-internal-Hacl-Hash-MD5.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "5dd4ee3c835a0d176a6e9fecbe9752fd1474ff41" + }, + { + "algorithm": "SHA256", + "checksumValue": "d82ef594cba44203576d67b047240316bb3c542912ebb7034afa1e07888cec56" + } + ], + "fileName": "Modules/_hacl/internal/Hacl_Hash_MD5.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-internal-Hacl-Hash-SHA1.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "515b3082eb7c30597773e1c63ec46688f6da3634" + }, + { + "algorithm": "SHA256", + "checksumValue": "10aacf847006b8e0dfb64d5c327443f954db6718b4aec712fb3268230df6a752" + } + ], + "fileName": "Modules/_hacl/internal/Hacl_Hash_SHA1.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-internal-Hacl-Hash-SHA2.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "a044ec12b70ba97b67e9a312827d6270452a20ca" + }, + { + "algorithm": "SHA256", + "checksumValue": "a1426b54fa7273ba5b50817c25b2b26fc85c4d1befb14092cd27dc4c99439463" + } + ], + "fileName": "Modules/_hacl/internal/Hacl_Hash_SHA2.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-internal-Hacl-Hash-SHA3.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "cfb7b520c39a73cb84c541d370455f92b998781f" + }, + { + "algorithm": "SHA256", + "checksumValue": "fd41997f9e96b3c9a3337b1b51fab965a1e21b0c16f353d156f1a1fa00709fbf" + } + ], + "fileName": "Modules/_hacl/internal/Hacl_Hash_SHA3.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-hacl-python-hacl-namespaces.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "f5c7b3ed911af6c8d582e8b3714b0c36195dc994" + }, + { + "algorithm": "SHA256", + "checksumValue": "07de72398b12957e014e97b9ac197bceef12d6d6505c2bfe8b23ee17b94ec5fa" + } + ], + "fileName": "Modules/_hacl/python_hacl_namespaces.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2-config.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "ff5e3ae2360adf7279a9c54d12a1d32e16a1f223" + }, + { + "algorithm": "SHA256", + "checksumValue": "1eb919e885244e43cdf7b2104ad30dc9271513478c0026f6bfb4bad6e2f0ab42" + } + ], + "fileName": "Modules/_blake2/impl/blake2-config.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2-impl.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "28b947b43bdc680b9f4335712bb2a5f2d5d32623" + }, + { + "algorithm": "SHA256", + "checksumValue": "4277092643b289f1d36d32cf0fd2efc30ead8bdd99342e5da3b3609dd8ea7d86" + } + ], + "fileName": "Modules/_blake2/impl/blake2-impl.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "caa3da7953109d0d2961e3b686d2d285c484b901" + }, + { + "algorithm": "SHA256", + "checksumValue": "2f6c9d0ecf70be474f2853b52394993625a32960e0a64eae147ef97a3a5c1460" + } + ], + "fileName": "Modules/_blake2/impl/blake2.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2b-load-sse2.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "029a98f87a178936d9e5211c7798b3e0fc622f94" + }, + { + "algorithm": "SHA256", + "checksumValue": "b392a6e7b43813a05609e994db5fc3552c5912bd482efc781daa0778eb56ab4e" + } + ], + "fileName": "Modules/_blake2/impl/blake2b-load-sse2.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2b-load-sse41.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "fb466dd72344170d09e311e5ea12de99ce071357" + }, + { + "algorithm": "SHA256", + "checksumValue": "cc3072c92164142bf2f9dda4e6c08db61be68ec15a95442415e861090d08f6a2" + } + ], + "fileName": "Modules/_blake2/impl/blake2b-load-sse41.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2b-ref.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "4c0d79128cf891a95b1f668031d55c0c6d2e0270" + }, + { + "algorithm": "SHA256", + "checksumValue": "07b257d44e9cc2d95d4911629c92138feafd16d63fef0a5fa7b38914dfd82349" + } + ], + "fileName": "Modules/_blake2/impl/blake2b-ref.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2b-round.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "4c7418e2026417c9c6736fcd305a31f23e05a661" + }, + { + "algorithm": "SHA256", + "checksumValue": "fa34a60c2d198a0585033f43fd4003f4ba279c9ebcabdf5d6650def0e6d1e914" + } + ], + "fileName": "Modules/_blake2/impl/blake2b-round.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2b.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "6fa074693aa7305018dfa8db48010a8ef1050ad4" + }, + { + "algorithm": "SHA256", + "checksumValue": "c8c6dd861ac193d4a0e836242ff44900f83423f86d2c2940c8c4c1e41fbd5812" + } + ], + "fileName": "Modules/_blake2/impl/blake2b.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2s-load-sse2.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "ad3f79b6cbe3fd812722114a0d5d08064e69e4d0" + }, + { + "algorithm": "SHA256", + "checksumValue": "57f1ac6c09f4a50d95811529062220eab4f29cec3805bc6081dec00426c6df62" + } + ], + "fileName": "Modules/_blake2/impl/blake2s-load-sse2.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2s-load-sse41.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "51c32d79f419f3d2eb9875cd9a7f5c0d7892f8a8" + }, + { + "algorithm": "SHA256", + "checksumValue": "ecc9e09adcbe098629eafd305596bed8d7004be1d83f326995def42bbde93b23" + } + ], + "fileName": "Modules/_blake2/impl/blake2s-load-sse41.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2s-load-xop.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "2749a7ba0104b765d4f56f13faf70b6eb89cf203" + }, + { + "algorithm": "SHA256", + "checksumValue": "8bc95595cec4c50f5d70f2b330d3798de07cc784e8890791b3328890e602d5c5" + } + ], + "fileName": "Modules/_blake2/impl/blake2s-load-xop.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2s-ref.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "883fcfe85f9063819f21b1100296d1f9eb55bac1" + }, + { + "algorithm": "SHA256", + "checksumValue": "9715c00d0f11587a139b07fa26678e6d26e44d3d4910b96158d158da2b022bfb" + } + ], + "fileName": "Modules/_blake2/impl/blake2s-ref.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2s-round.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "5d9f69adda40ed163b287b9ed4cedb35b88f2daa" + }, + { + "algorithm": "SHA256", + "checksumValue": "65d90111c89c43bb18a9e1d1a4fdbd9f85bebd1ff00129335b85995d0f30ee8b" + } + ], + "fileName": "Modules/_blake2/impl/blake2s-round.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-blake2-impl-blake2s.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "d2691353fa54ac6ffcd7c0a294984dc9d7968ef7" + }, + { + "algorithm": "SHA256", + "checksumValue": "cfd7948c9fd50e9f9c62f8a93b20a254d1d510a862d1092af4f187b7c1a859a3" + } + ], + "fileName": "Modules/_blake2/impl/blake2s.c" + }, + { + "SPDXID": "SPDXRef-FILE-Lib-ctypes-macholib-init-.py", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "0fbc026a9771d9675e7094790b5b945334d3cb53" + }, + { + "algorithm": "SHA256", + "checksumValue": "1e77c01eec8f167ed10b754f153c0c743c8e5196ae9c81dffc08f129ab56dbfd" + } + ], + "fileName": "Lib/ctypes/macholib/__init__.py" + }, + { + "SPDXID": "SPDXRef-FILE-Lib-ctypes-macholib-dyld.py", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "4a78ebd73ce4167c722689781a15fe0b4578e967" + }, + { + "algorithm": "SHA256", + "checksumValue": "eb8e7b17f1533bc3e86e23e8695f7a5e4b7a99ef1b1575d10af54f389161b655" + } + ], + "fileName": "Lib/ctypes/macholib/dyld.py" + }, + { + "SPDXID": "SPDXRef-FILE-Lib-ctypes-macholib-dylib.py", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "f339420cc01bd01f8d0da19b6102f099075e8bcd" + }, + { + "algorithm": "SHA256", + "checksumValue": "f19ee056b18165cc6735efab0b4ca3508be9405b9646c38113316c15e8278a6f" + } + ], + "fileName": "Lib/ctypes/macholib/dylib.py" + }, + { + "SPDXID": "SPDXRef-FILE-Lib-ctypes-macholib-framework.py", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "0b219f58467d7f193fa1de0c1b118485840d855b" + }, + { + "algorithm": "SHA256", + "checksumValue": "302439e40d9cbdd61b8b7cffd0b7e1278a6811b635044ee366a36e0d991f62da" + } + ], + "fileName": "Lib/ctypes/macholib/framework.py" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-README.txt", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "bda6e0bd6121f7069b420bdc0bc7c49414d948d1" + }, + { + "algorithm": "SHA256", + "checksumValue": "89926cd0fe6cfb33a2b5b7416c101e9b5d42b0d639d348e0871acf6ffc8258a3" + } + ], + "fileName": "Modules/_decimal/libmpdec/README.txt" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-basearith.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "33757ce2ec0c93c1b5e03c45a495563a00e498ae" + }, + { + "algorithm": "SHA256", + "checksumValue": "ad498362c31a5b99ab19fce320ac540cf14c5c4ec09478f0ad3858da1428113d" + } + ], + "fileName": "Modules/_decimal/libmpdec/basearith.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-basearith.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "bf03919412c068e6969e7ac48850f91bfcd3b2b1" + }, + { + "algorithm": "SHA256", + "checksumValue": "2eaac88a71b9bcf3144396c12dcfeced573e0e550a0050d75b9ed3903248596d" + } + ], + "fileName": "Modules/_decimal/libmpdec/basearith.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-bench.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "c925b7f26754ae182aaa461d51802e8b6a2bb5e9" + }, + { + "algorithm": "SHA256", + "checksumValue": "007e38542ec8d9d8805fe243b5390d79211b9360e2797a20079e833e68ad9e45" + } + ], + "fileName": "Modules/_decimal/libmpdec/bench.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-bench-full.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "cb22686269685a53a17afdea9ed984714e399d9d" + }, + { + "algorithm": "SHA256", + "checksumValue": "1b9e892d4b268deea835ec8906f20a1e5d25e037b2e698edcd34315613f3608c" + } + ], + "fileName": "Modules/_decimal/libmpdec/bench_full.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-bits.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "fc91c2450cdf1e785d1347411662294c3945eb27" + }, + { + "algorithm": "SHA256", + "checksumValue": "ce7741e58ea761a24250c0bfa10058cec8c4fd220dca70a41de3927a2e4f5376" + } + ], + "fileName": "Modules/_decimal/libmpdec/bits.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-constants.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "7187c18916b0a546ec19b4fc4bec43d0d9fb5fc2" + }, + { + "algorithm": "SHA256", + "checksumValue": "cd430b8657cf8a616916e02f9bd5ca044d5fc19e69333f5d427e1fdb90b0864b" + } + ], + "fileName": "Modules/_decimal/libmpdec/constants.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-constants.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "af9cbd016fb0ef0b30ced49c0aa4ce2ca3c20125" + }, + { + "algorithm": "SHA256", + "checksumValue": "19dc46df04abb7ee08e9a403f87c8aac8d4a077efcce314c597f8b73e22884f2" + } + ], + "fileName": "Modules/_decimal/libmpdec/constants.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-context.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "666162870230bebd3f2383020d908806fd03909e" + }, + { + "algorithm": "SHA256", + "checksumValue": "9a265d366f31894aad78bca7fcdc1457bc4a3aa3887ca231b7d78e41f79541c0" + } + ], + "fileName": "Modules/_decimal/libmpdec/context.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-convolute.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "0545547a8b37b922fbe2574fbad8fc3bf16f1d33" + }, + { + "algorithm": "SHA256", + "checksumValue": "66fe27b9bb37039cad5be32b105ed509e5aefa15c1957a9058af8ee23cddc97a" + } + ], + "fileName": "Modules/_decimal/libmpdec/convolute.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-convolute.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "05ff0936c5bb08f40d460f5843004a1cc0751d9b" + }, + { + "algorithm": "SHA256", + "checksumValue": "c00d17450c2b8e1d7f1eb8a084f7e6a68f257a453f8701600e860bf357c531d7" + } + ], + "fileName": "Modules/_decimal/libmpdec/convolute.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-crt.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "fe8176849bc99a306332ba25caa4e91bfa3c6f7d" + }, + { + "algorithm": "SHA256", + "checksumValue": "1f4e65c44864c3e911a6e91f33adec76765293e90553459e3ebce35a58898dba" + } + ], + "fileName": "Modules/_decimal/libmpdec/crt.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-crt.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "1930b9e0910014b3479aec4e940f02118d9e4a08" + }, + { + "algorithm": "SHA256", + "checksumValue": "7d31f1d0dd73b62964dab0f7a1724473bf87f1f95d8febf0b40c15430ae9a47c" + } + ], + "fileName": "Modules/_decimal/libmpdec/crt.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-difradix2.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "415c51e7d7f517b6366bec2a809610d0d38ada14" + }, + { + "algorithm": "SHA256", + "checksumValue": "0a9fef8a374f55277e9f6000b7277bb037b9763c32b156c29950422b057498bd" + } + ], + "fileName": "Modules/_decimal/libmpdec/difradix2.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-difradix2.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "d8a998c3bee4c3d9059ba7bf9ae6a8b64649c2ba" + }, + { + "algorithm": "SHA256", + "checksumValue": "5c6766496224de657400995b58b64db3e7084004bf00daebdd7e08d0c5995243" + } + ], + "fileName": "Modules/_decimal/libmpdec/difradix2.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-README.txt", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "158f6ad18edf348efa4fdd7cf61114c77c1d22e9" + }, + { + "algorithm": "SHA256", + "checksumValue": "7b0da2758097a2688f06b3c7ca46b2ebc8329addbd28bb4f5fe95626cc81f8a9" + } + ], + "fileName": "Modules/_decimal/libmpdec/examples/README.txt" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-compare.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "ef80ba26847287fb351ab0df0a78b5f08ba0b5b7" + }, + { + "algorithm": "SHA256", + "checksumValue": "452666ee4eb10a8cf0a926cb3bcf5e95b5c361fa129dbdfe27b654e6d640417e" + } + ], + "fileName": "Modules/_decimal/libmpdec/examples/compare.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-div.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "6ca3a369b3d1e140fdc93c4fdbedb724f7daf969" + }, + { + "algorithm": "SHA256", + "checksumValue": "6d369f5a24d0bb1e7cb6a4f8b0e97a273260e7668c8a540a8fcc92e039f7af2e" + } + ], + "fileName": "Modules/_decimal/libmpdec/examples/div.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-divmod.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "3872a28b4f77e07e1760256067ea338a8dd183f8" + }, + { + "algorithm": "SHA256", + "checksumValue": "5db54bae75ac3d7fa12f1bb0f7ce1bf797df86a81030e8c3ce44d3b1f9b958b7" + } + ], + "fileName": "Modules/_decimal/libmpdec/examples/divmod.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-multiply.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "25dbc94fd4ee5dec21061d2d40dd5d0f88849cb1" + }, + { + "algorithm": "SHA256", + "checksumValue": "22ed39b18fa740a27aacfd29a7bb40066be24500ba49b9b1f24e2af1e039fcd9" + } + ], + "fileName": "Modules/_decimal/libmpdec/examples/multiply.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-pow.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "13d3b7657dc2dc5000fea428f57963d520792ef7" + }, + { + "algorithm": "SHA256", + "checksumValue": "cd8c037649b3d4d6897c9acd2f92f3f9d5390433061d5e48623a5d526a3f4f9c" + } + ], + "fileName": "Modules/_decimal/libmpdec/examples/pow.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-powmod.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "1f7e6c3d3e38df52bbcec0f5a180a8f328679618" + }, + { + "algorithm": "SHA256", + "checksumValue": "e29614b43abf1856b656a84d6b67c22cc5dc7af8cbae8ddc7acf17022220ee12" + } + ], + "fileName": "Modules/_decimal/libmpdec/examples/powmod.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-shift.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "0bd9ce89c7987d1109eb7b0c8f1f9a1298e1422e" + }, + { + "algorithm": "SHA256", + "checksumValue": "203f2dbf11d115580cb3c7c524ac6ccca2a7b31d89545db1b6263381b5de2b6a" + } + ], + "fileName": "Modules/_decimal/libmpdec/examples/shift.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-sqrt.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "b401ba0814e17c9164c0df26e01cc0a355382f46" + }, + { + "algorithm": "SHA256", + "checksumValue": "f3dc2ce321833bbd4b3d1d9ea6fa2e0bcc1bfe1e39abb8d55be53e46c33949db" + } + ], + "fileName": "Modules/_decimal/libmpdec/examples/sqrt.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-fnt.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "060615ddef089a5a8f879a57e4968d920972a0e2" + }, + { + "algorithm": "SHA256", + "checksumValue": "a9f923524d53a9445769f27405375ec3d95fa804bb11db5ee249ae047f11cfce" + } + ], + "fileName": "Modules/_decimal/libmpdec/fnt.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-fnt.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "b205043ebeaf065b16505a299342a992654f19b0" + }, + { + "algorithm": "SHA256", + "checksumValue": "3b03e69adf78fde68c8f87d33595d557237581d33fc067e1039eed9e9f2cc44c" + } + ], + "fileName": "Modules/_decimal/libmpdec/fnt.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-fourstep.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "702c27599b43280c94906235d7e1a74193ba701b" + }, + { + "algorithm": "SHA256", + "checksumValue": "cf2e69b946ec14b087e523c0ff606553070d13c23e851fb0ba1df51a728017e6" + } + ], + "fileName": "Modules/_decimal/libmpdec/fourstep.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-fourstep.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "ee5291c265ef1f5ae373bc243a4d96975eb3e7b5" + }, + { + "algorithm": "SHA256", + "checksumValue": "dbaced03b52d0f880c377b86c943bcb36f24d557c99a5e9732df3ad5debb5917" + } + ], + "fileName": "Modules/_decimal/libmpdec/fourstep.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-io.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "12402bcf7f0161adb83f78163f41cc10a5e5de5f" + }, + { + "algorithm": "SHA256", + "checksumValue": "cba044c76b6bc3ae6cfa49df1121cad7552140157b9e61e11cbb6580cc5d74cf" + } + ], + "fileName": "Modules/_decimal/libmpdec/io.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-io.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "28c653cd40b1ce46575e41f5dbfda5f6dd0db4d1" + }, + { + "algorithm": "SHA256", + "checksumValue": "259eab89fe27914e0e39e61199094a357ac60d86b2aab613c909040ff64a4a0c" + } + ], + "fileName": "Modules/_decimal/libmpdec/io.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-REFERENCES.txt", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "218d1d7bedb335cd2c31eae89a15873c3139e13f" + }, + { + "algorithm": "SHA256", + "checksumValue": "a57e8bed93ded481ef264166aec2c49d1a7f3252f29a873ee41fff053cfd9c20" + } + ], + "fileName": "Modules/_decimal/libmpdec/literature/REFERENCES.txt" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-bignum.txt", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "f67eab2431336cf6eeafb30cdafd7e54c251def3" + }, + { + "algorithm": "SHA256", + "checksumValue": "dc34aa122c208ce79e3fc6baee8628094ffaf6a662862dd5647836241f6ebd79" + } + ], + "fileName": "Modules/_decimal/libmpdec/literature/bignum.txt" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-fnt.py", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "a58cfbcd8ea57d66ddfd11fb5a170138c8bbfb3a" + }, + { + "algorithm": "SHA256", + "checksumValue": "122de20eebf87274af2d02072251a94500e7df2d5ef29e81aeabeda991c079e3" + } + ], + "fileName": "Modules/_decimal/libmpdec/literature/fnt.py" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-matrix-transform.txt", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "9a947f6b660150cbd457c4458da2956a36c5824d" + }, + { + "algorithm": "SHA256", + "checksumValue": "592659e7192e3a939b797f5bc7455455834a285f5d8b643ccd780b5114914f73" + } + ], + "fileName": "Modules/_decimal/libmpdec/literature/matrix-transform.txt" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-mulmod-64.txt", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "69fe9afb8353b5a2b57917469c51c64ac518169d" + }, + { + "algorithm": "SHA256", + "checksumValue": "229a80ca940c594a32e3345412370cbc097043fe59c66a6153cbcf01e7837266" + } + ], + "fileName": "Modules/_decimal/libmpdec/literature/mulmod-64.txt" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-mulmod-ppro.txt", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "720d468a1f51098036c7a0c869810fff22ed9b79" + }, + { + "algorithm": "SHA256", + "checksumValue": "f3549fc73f697a087267c7b042e30a409e191cbba69a2c0902685e507fbae9f7" + } + ], + "fileName": "Modules/_decimal/libmpdec/literature/mulmod-ppro.txt" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-six-step.txt", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "6815ec3a39baebebe7b3f51d45d10c180a659f17" + }, + { + "algorithm": "SHA256", + "checksumValue": "bf15f73910a173c98fca9db56122b6cc71983668fa8b934c46ca21a57398ec54" + } + ], + "fileName": "Modules/_decimal/libmpdec/literature/six-step.txt" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-umodarith.lisp", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "c91ac4438e661ce78f86e981257546e5adff39ae" + }, + { + "algorithm": "SHA256", + "checksumValue": "783a1b4b9b7143677b0c3d30ffaf28aa0cb01956409031fa38ed8011970bdee0" + } + ], + "fileName": "Modules/_decimal/libmpdec/literature/umodarith.lisp" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-mpalloc.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "7e8dfb4b7a801b48c501969b001153203b14679e" + }, + { + "algorithm": "SHA256", + "checksumValue": "5ba2f4c80302e71fb216aa247c858e0bf6c8cfabffe7980ac17d4d023c0fef2b" + } + ], + "fileName": "Modules/_decimal/libmpdec/mpalloc.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-mpalloc.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "bccb6a6ae76fd7f6c8a9102a78958bcad7862950" + }, + { + "algorithm": "SHA256", + "checksumValue": "f7412521de38afb837fcabc2b1d48b971b86bfaa55f3f40d58ff9e46e92debd3" + } + ], + "fileName": "Modules/_decimal/libmpdec/mpalloc.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-mpdecimal.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "f4539afb1ace58c52d18ffd0cc7704f53ca55182" + }, + { + "algorithm": "SHA256", + "checksumValue": "4f89b8095e408a18deff79cfb605299e615bae747898eb105d8936064f7fb626" + } + ], + "fileName": "Modules/_decimal/libmpdec/mpdecimal.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-mpdecimal.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "4b80e25ac49b7e1ea0d1e84967ee32a3d111fc4c" + }, + { + "algorithm": "SHA256", + "checksumValue": "ea0b9c6b296c13aed6ecaa50b463e39a9c1bdc059b84f50507fd8247b2e660f9" + } + ], + "fileName": "Modules/_decimal/libmpdec/mpdecimal.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-mpsignal.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "5c7305a6db0fddf64c6d97e29d3b0c402e3d5d6e" + }, + { + "algorithm": "SHA256", + "checksumValue": "653171cf2549719478417db7e9800fa0f9d99c02dec6da6876329ccf2c07b93f" + } + ], + "fileName": "Modules/_decimal/libmpdec/mpsignal.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-numbertheory.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "d736b874c43777ca021dde5289ea718893f39219" + }, + { + "algorithm": "SHA256", + "checksumValue": "bdbf2e246f341a3ba3f6f9d8759e7cb222eb9b15f9ed1e7c9f6a59cbb9f8bc91" + } + ], + "fileName": "Modules/_decimal/libmpdec/numbertheory.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-numbertheory.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "d341508d8c6dd4c4cbd8b99afc8029945f9bbe0d" + }, + { + "algorithm": "SHA256", + "checksumValue": "2f7d5b40af508fa6ac86f5d62101fa3bf683c63b24aa87c9548e3fdd13abc57b" + } + ], + "fileName": "Modules/_decimal/libmpdec/numbertheory.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-sixstep.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "cbd05d68bb3940d0d7d0818b14cc03b090a4dd74" + }, + { + "algorithm": "SHA256", + "checksumValue": "7602aaf98ec9525bc4b3cab9631615e1be2efd9af894002ef4e3f5ec63924fcf" + } + ], + "fileName": "Modules/_decimal/libmpdec/sixstep.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-sixstep.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "4c059463ec4b4522562dab24760fc64c172c9eee" + }, + { + "algorithm": "SHA256", + "checksumValue": "a191366348b3d3dd49b9090ec5c77dbd77bb3a523c01ff32adafa137e5097ce7" + } + ], + "fileName": "Modules/_decimal/libmpdec/sixstep.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-transpose.c", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "cc5593ac9fdb60480cc23fc9d6f27d85670bd35f" + }, + { + "algorithm": "SHA256", + "checksumValue": "2d12fcae512143a9376c8a0d4c1ba3008e420e024497a7e7ec64c6bec23fcddc" + } + ], + "fileName": "Modules/_decimal/libmpdec/transpose.c" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-transpose.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "2f616425756b6cbdf7d189744870b98b613455bd" + }, + { + "algorithm": "SHA256", + "checksumValue": "fafeb2b901b2b41bf0df00be7d99b84df1a78e3cc1e582e09cbfc3b6d44d4abe" + } + ], + "fileName": "Modules/_decimal/libmpdec/transpose.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-typearith.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "b1e9341e173cc8e219ad4aa45fad36d92cce10d3" + }, + { + "algorithm": "SHA256", + "checksumValue": "25e0a0703b51744277834e6b2398d7b7d2c17f92bf30f8b6f949e0486ae2b346" + } + ], + "fileName": "Modules/_decimal/libmpdec/typearith.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-umodarith.h", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "46f6483fce136cd3cc2f7516ee119a487d86333e" + }, + { + "algorithm": "SHA256", + "checksumValue": "bfe1ddb2ca92906456b80745adcbe02c83cadac3ef69caa21bc09b7292cc152b" + } + ], + "fileName": "Modules/_decimal/libmpdec/umodarith.h" + }, + { + "SPDXID": "SPDXRef-FILE-Modules-decimal-libmpdec-vcdiv64.asm", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "d0cc1052fcba08b773d935b0ae2dc6b80d0f2f68" + }, + { + "algorithm": "SHA256", + "checksumValue": "aacc3e47ea8f41e8840c6c67f64ec96d54696a16889903098fa1aab56949a00f" + } + ], + "fileName": "Modules/_decimal/libmpdec/vcdiv64.asm" + }, + { + "SPDXID": "SPDXRef-FILE-Lib-ensurepip-bundled-pip-23.3.1-py3-none-any.whl", + "checksums": [ + { + "algorithm": "SHA1", + "checksumValue": "4b2baddc0673f73017e531648a9ee27e47925e7a" + }, + { + "algorithm": "SHA256", + "checksumValue": "55eb67bb6171d37447e82213be585b75fe2b12b359e993773aca4de9247a052b" + } + ], + "fileName": "Lib/ensurepip/_bundled/pip-23.3.1-py3-none-any.whl" + } + ], + "packages": [ + { + "SPDXID": "SPDXRef-PACKAGE-expat", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "6b902ab103843592be5e99504f846ec109c1abb692e85347587f237a4ffa1033" + } + ], + "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_5_0/expat-2.5.0.tar.gz", + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.5.0:*:*:*:*:*:*:*", + "referenceType": "cpe23Type" + } + ], + "licenseConcluded": "MIT", + "name": "expat", + "originator": "Organization: Expat development team", + "primaryPackagePurpose": "SOURCE", + "versionInfo": "2.5.0" + }, + { + "SPDXID": "SPDXRef-PACKAGE-hacl-star", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "c23ac158b238c368389dc86bfc315263e5c0e57785da74144aea2cab9a3d51a2" + } + ], + "downloadLocation": "https://github.com/hacl-star/hacl-star/archive/521af282fdf6d60227335120f18ae9309a4b8e8c.zip", + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:a:hacl-star:hacl-star:521af282fdf6d60227335120f18ae9309a4b8e8c:*:*:*:*:*:*:*", + "referenceType": "cpe23Type" + } + ], + "licenseConcluded": "Apache-2.0", + "name": "hacl-star", + "originator": "Organization: HACL* Developers", + "primaryPackagePurpose": "SOURCE", + "versionInfo": "521af282fdf6d60227335120f18ae9309a4b8e8c" + }, + { + "SPDXID": "SPDXRef-PACKAGE-libb2", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "53626fddce753c454a3fea581cbbc7fe9bbcf0bc70416d48fdbbf5d87ef6c72e" + } + ], + "downloadLocation": "https://github.com/BLAKE2/libb2/releases/download/v0.98.1/libb2-0.98.1.tar.gz", + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:a:blake2:libb2:0.98.1:*:*:*:*:*:*:*", + "referenceType": "cpe23Type" + } + ], + "licenseConcluded": "CC0-1.0", + "name": "libb2", + "originator": "Organization: BLAKE2 - fast secure hashing", + "primaryPackagePurpose": "SOURCE", + "versionInfo": "0.98.1" + }, + { + "SPDXID": "SPDXRef-PACKAGE-macholib", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "c76f268f5054024e962f2515a0e522baf85313064f6740d80375afc850787a38" + } + ], + "downloadLocation": "https://files.pythonhosted.org/packages/ec/57/f0a712efc3ed982cf4038a3cee172057303b9be914c32c93b2fbec27f785/macholib-1.0.tar.gz", + "externalRefs": [ + { + "referenceCategory": "PACKAGE_MANAGER", + "referenceLocator": "pkg:pypi/macholib@1.0", + "referenceType": "purl" + } + ], + "licenseConcluded": "MIT", + "name": "macholib", + "originator": "Person: Ronald Oussoren (ronaldoussoren@mac.com)", + "primaryPackagePurpose": "SOURCE", + "versionInfo": "1.0" + }, + { + "SPDXID": "SPDXRef-PACKAGE-mpdecimal", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "9f9cd4c041f99b5c49ffb7b59d9f12d95b683d88585608aa56a6307667b2b21f" + } + ], + "downloadLocation": "https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-2.5.1.tar.gz", + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:a:bytereef:mpdecimal:2.5.1:*:*:*:*:*:*:*", + "referenceType": "cpe23Type" + } + ], + "licenseConcluded": "BSD-2-Clause", + "name": "mpdecimal", + "originator": "Organization: bytereef.org", + "primaryPackagePurpose": "SOURCE", + "versionInfo": "2.5.1" + }, + { + "SPDXID": "SPDXRef-PACKAGE-pip", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be" + } + ], + "downloadLocation": "https://files.pythonhosted.org/packages/50/c2/e06851e8cc28dcad7c155f4753da8833ac06a5c704c109313b8d5a62968a/pip-23.2.1-py3-none-any.whl", + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:2.3:a:pypa:pip:23.2.1:*:*:*:*:*:*:*", + "referenceType": "cpe23Type" + }, + { + "referenceCategory": "PACKAGE_MANAGER", + "referenceLocator": "pkg:pypi/pip@23.2.1", + "referenceType": "purl" + } + ], + "licenseConcluded": "MIT", + "name": "pip", + "originator": "Organization: Python Packaging Authority", + "primaryPackagePurpose": "SOURCE", + "versionInfo": "23.2.1" + } + ], + "relationships": [ + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-COPYING", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-ascii.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-asciitab.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-expat.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-expat-config.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-expat-external.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-iasciitab.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-internal.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-latin1tab.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-nametab.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-pyexpatns.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-siphash.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-utf8tab.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-winconfig.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xmlparse.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xmlrole.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xmlrole.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xmltok.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xmltok.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xmltok-impl.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xmltok-impl.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-expat-xmltok-ns.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-expat" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-MD5.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-MD5.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA1.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA1.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA2.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA2.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA3.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-Hacl-Hash-SHA3.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-Hacl-Streaming-Types.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-include-krml-FStar-UInt128-Verified.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-include-krml-FStar-UInt-8-16-32-64.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-include-krml-fstar-uint128-struct-endianness.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-include-krml-internal-target.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-include-krml-lowstar-endianness.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-include-krml-types.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-internal-Hacl-Hash-MD5.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-internal-Hacl-Hash-SHA1.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-internal-Hacl-Hash-SHA2.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-internal-Hacl-Hash-SHA3.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-hacl-python-hacl-namespaces.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-hacl-star" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2-config.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2-impl.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2b-load-sse2.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2b-load-sse41.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2b-ref.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2b-round.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2b.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2s-load-sse2.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2s-load-sse41.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2s-load-xop.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2s-ref.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2s-round.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-blake2-impl-blake2s.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-libb2" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Lib-ctypes-macholib-init-.py", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-macholib" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Lib-ctypes-macholib-dyld.py", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-macholib" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Lib-ctypes-macholib-dylib.py", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-macholib" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Lib-ctypes-macholib-framework.py", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-macholib" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-README.txt", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-basearith.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-basearith.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-bench.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-bench-full.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-bits.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-constants.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-constants.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-context.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-convolute.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-convolute.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-crt.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-crt.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-difradix2.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-difradix2.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-README.txt", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-compare.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-div.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-divmod.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-multiply.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-pow.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-powmod.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-shift.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-examples-sqrt.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-fnt.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-fnt.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-fourstep.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-fourstep.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-io.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-io.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-REFERENCES.txt", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-bignum.txt", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-fnt.py", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-matrix-transform.txt", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-mulmod-64.txt", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-mulmod-ppro.txt", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-six-step.txt", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-literature-umodarith.lisp", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-mpalloc.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-mpalloc.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-mpdecimal.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-mpdecimal.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-mpsignal.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-numbertheory.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-numbertheory.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-sixstep.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-sixstep.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-transpose.c", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-transpose.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-typearith.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-umodarith.h", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Modules-decimal-libmpdec-vcdiv64.asm", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-mpdecimal" + }, + { + "relatedSpdxElement": "SPDXRef-FILE-Lib-ensurepip-bundled-pip-23.3.1-py3-none-any.whl", + "relationshipType": "CONTAINS", + "spdxElementId": "SPDXRef-PACKAGE-pip" + } + ], + "spdxVersion": "SPDX-2.3" +} \ No newline at end of file diff --git a/Tools/build/generate_sbom.py b/Tools/build/generate_sbom.py new file mode 100644 index 000000000000000..0089db81af9b9d7 --- /dev/null +++ b/Tools/build/generate_sbom.py @@ -0,0 +1,179 @@ +"""Tool for generating Software Bill of Materials (SBOM) for Python's dependencies""" + +import re +import hashlib +import json +import glob +import pathlib +import subprocess +import typing + +# Before adding a new entry to this list, double check that +# the license expression is a valid SPDX license expression: +# See: https://spdx.org/licenses +ALLOWED_LICENSE_EXPRESSIONS = { + "MIT", + "CC0-1.0", + "Apache-2.0", + "BSD-2-Clause", +} + +# Properties which are required for our purposes. +REQUIRED_PROPERTIES_PACKAGE = frozenset([ + "SPDXID", + "name", + "versionInfo", + "downloadLocation", + "checksums", + "licenseConcluded", + "externalRefs", + "originator", + "primaryPackagePurpose", +]) + + +class PackageFiles(typing.NamedTuple): + """Structure for describing the files of a package""" + include: list[str] + exclude: list[str] | None = None + + +# SBOMS don't have a method to specify the sources of files +# so we need to do that external to the SBOM itself. Add new +# values to 'exclude' if we create new files within tracked +# directories that aren't sourced from third-party packages. +PACKAGE_TO_FILES = { + "mpdecimal": PackageFiles( + include=["Modules/_decimal/libmpdec/**"] + ), + "expat": PackageFiles( + include=["Modules/expat/**"] + ), + "pip": PackageFiles( + include=["Lib/ensurepip/_bundled/pip-23.3.1-py3-none-any.whl"] + ), + "macholib": PackageFiles( + include=["Lib/ctypes/macholib/**"], + exclude=[ + "Lib/ctypes/macholib/README.ctypes", + "Lib/ctypes/macholib/fetch_macholib", + "Lib/ctypes/macholib/fetch_macholib.bat", + ], + ), + "libb2": PackageFiles( + include=["Modules/_blake2/impl/**"] + ), + "hacl-star": PackageFiles( + include=["Modules/_hacl/**"], + exclude=[ + "Modules/_hacl/refresh.sh", + "Modules/_hacl/README.md", + "Modules/_hacl/python_hacl_namespace.h", + ] + ), +} + + +def spdx_id(value: str) -> str: + """Encode a value into characters that are valid in an SPDX ID""" + return re.sub(r"[^a-zA-Z0-9.\-]+", "-", value) + + +def filter_gitignored_paths(paths: list[str]) -> list[str]: + """ + Filter out paths excluded by the gitignore file. + The output of 'git check-ignore --non-matching --verbose' looks + like this for non-matching (included) files: + + '::' + + And looks like this for matching (excluded) files: + + '.gitignore:9:*.a Tools/lib.a' + """ + # Filter out files in gitignore. + # Non-matching files show up as '::' + git_check_ignore_proc = subprocess.run( + ["git", "check-ignore", "--verbose", "--non-matching", *paths], + check=False, + stdout=subprocess.PIPE, + ) + # 1 means matches, 0 means no matches. + assert git_check_ignore_proc.returncode in (0, 1) + + # Return the list of paths sorted + git_check_ignore_lines = git_check_ignore_proc.stdout.decode().splitlines() + return sorted([line.split()[-1] for line in git_check_ignore_lines if line.startswith("::")]) + + +def main() -> None: + root_dir = pathlib.Path(__file__).parent.parent.parent + sbom_path = root_dir / "Misc/sbom.spdx.json" + sbom_data = json.loads(sbom_path.read_bytes()) + + # Make a bunch of assertions about the SBOM data to ensure it's consistent. + assert {package["name"] for package in sbom_data["packages"]} == set(PACKAGE_TO_FILES) + for package in sbom_data["packages"]: + + # Properties and ID must be properly formed. + assert set(package.keys()) == REQUIRED_PROPERTIES_PACKAGE + assert package["SPDXID"] == spdx_id(f"SPDXRef-PACKAGE-{package['name']}") + + # Version must be in the download and external references. + version = package["versionInfo"] + assert version in package["downloadLocation"] + assert all(version in ref["referenceLocator"] for ref in package["externalRefs"]) + + # License must be on the approved list for SPDX. + assert package["licenseConcluded"] in ALLOWED_LICENSE_EXPRESSIONS, package["licenseConcluded"] + + # Regenerate file information from current data. + sbom_files = [] + sbom_relationships = [] + + # We call 'sorted()' here a lot to avoid filesystem scan order issues. + for name, files in sorted(PACKAGE_TO_FILES.items()): + package_spdx_id = spdx_id(f"SPDXRef-PACKAGE-{name}") + exclude = files.exclude or () + for include in sorted(files.include): + + # Find all the paths and then filter them through .gitignore. + paths = glob.glob(include, root_dir=root_dir, recursive=True) + paths = filter_gitignored_paths(paths) + assert paths, include # Make sure that every value returns something! + + for path in paths: + # Skip directories and excluded files + if not (root_dir / path).is_file() or path in exclude: + continue + + # SPDX requires SHA1 to be used for files, but we provide SHA256 too. + data = (root_dir / path).read_bytes() + checksum_sha1 = hashlib.sha1(data).hexdigest() + checksum_sha256 = hashlib.sha256(data).hexdigest() + + file_spdx_id = spdx_id(f"SPDXRef-FILE-{path}") + sbom_files.append({ + "SPDXID": file_spdx_id, + "fileName": path, + "checksums": [ + {"algorithm": "SHA1", "checksumValue": checksum_sha1}, + {"algorithm": "SHA256", "checksumValue": checksum_sha256}, + ], + }) + + # Tie each file back to its respective package. + sbom_relationships.append({ + "spdxElementId": package_spdx_id, + "relatedSpdxElement": file_spdx_id, + "relationshipType": "CONTAINS", + }) + + # Update the SBOM on disk + sbom_data["files"] = sbom_files + sbom_data["relationships"] = sbom_relationships + sbom_path.write_text(json.dumps(sbom_data, indent=2, sort_keys=True)) + + +if __name__ == "__main__": + main() diff --git a/Tools/build/mypy.ini b/Tools/build/mypy.ini new file mode 100644 index 000000000000000..cf1dac7fde5ac5a --- /dev/null +++ b/Tools/build/mypy.ini @@ -0,0 +1,13 @@ +[mypy] +files = Tools/build/generate_sbom.py +pretty = True + +# Make sure Python can still be built +# using Python 3.10 for `PYTHON_FOR_REGEN`... +python_version = 3.10 + +# ...And be strict: +strict = True +strict_concatenate = True +enable_error_code = ignore-without-code,redundant-expr,truthy-bool,possibly-undefined +warn_unreachable = True From 81c16cd94ec38d61aa478b9a452436dc3b1b524d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20L=C3=B8vborg?= Date: Thu, 7 Dec 2023 17:04:06 +0100 Subject: [PATCH 83/87] gh-91133: tempfile.TemporaryDirectory: fix symlink bug in cleanup (GH-99930) Co-authored-by: Serhiy Storchaka --- Lib/tempfile.py | 27 +++-- Lib/test/test_tempfile.py | 111 +++++++++++++++++- ...2-12-01-16-57-44.gh-issue-91133.LKMVCV.rst | 2 + 3 files changed, 125 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-12-01-16-57-44.gh-issue-91133.LKMVCV.rst diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 55403ad1faf46d8..9a5e7d01c2379b0 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -270,6 +270,22 @@ def _mkstemp_inner(dir, pre, suf, flags, output_type): raise FileExistsError(_errno.EEXIST, "No usable temporary file name found") +def _dont_follow_symlinks(func, path, *args): + # Pass follow_symlinks=False, unless not supported on this platform. + if func in _os.supports_follow_symlinks: + func(path, *args, follow_symlinks=False) + elif _os.name == 'nt' or not _os.path.islink(path): + func(path, *args) + +def _resetperms(path): + try: + chflags = _os.chflags + except AttributeError: + pass + else: + _dont_follow_symlinks(chflags, path, 0) + _dont_follow_symlinks(_os.chmod, path, 0o700) + # User visible interfaces. @@ -876,17 +892,10 @@ def __init__(self, suffix=None, prefix=None, dir=None, def _rmtree(cls, name, ignore_errors=False): def onexc(func, path, exc): if isinstance(exc, PermissionError): - def resetperms(path): - try: - _os.chflags(path, 0) - except AttributeError: - pass - _os.chmod(path, 0o700) - try: if path != name: - resetperms(_os.path.dirname(path)) - resetperms(path) + _resetperms(_os.path.dirname(path)) + _resetperms(path) try: _os.unlink(path) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index f4aef887799ed4a..2729bec7a21c71d 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1673,6 +1673,103 @@ def test_cleanup_with_symlink_to_a_directory(self): "were deleted") d2.cleanup() + @os_helper.skip_unless_symlink + def test_cleanup_with_symlink_modes(self): + # cleanup() should not follow symlinks when fixing mode bits (#91133) + with self.do_create(recurse=0) as d2: + file1 = os.path.join(d2, 'file1') + open(file1, 'wb').close() + dir1 = os.path.join(d2, 'dir1') + os.mkdir(dir1) + for mode in range(8): + mode <<= 6 + with self.subTest(mode=format(mode, '03o')): + def test(target, target_is_directory): + d1 = self.do_create(recurse=0) + symlink = os.path.join(d1.name, 'symlink') + os.symlink(target, symlink, + target_is_directory=target_is_directory) + try: + os.chmod(symlink, mode, follow_symlinks=False) + except NotImplementedError: + pass + try: + os.chmod(symlink, mode) + except FileNotFoundError: + pass + os.chmod(d1.name, mode) + d1.cleanup() + self.assertFalse(os.path.exists(d1.name)) + + with self.subTest('nonexisting file'): + test('nonexisting', target_is_directory=False) + with self.subTest('nonexisting dir'): + test('nonexisting', target_is_directory=True) + + with self.subTest('existing file'): + os.chmod(file1, mode) + old_mode = os.stat(file1).st_mode + test(file1, target_is_directory=False) + new_mode = os.stat(file1).st_mode + self.assertEqual(new_mode, old_mode, + '%03o != %03o' % (new_mode, old_mode)) + + with self.subTest('existing dir'): + os.chmod(dir1, mode) + old_mode = os.stat(dir1).st_mode + test(dir1, target_is_directory=True) + new_mode = os.stat(dir1).st_mode + self.assertEqual(new_mode, old_mode, + '%03o != %03o' % (new_mode, old_mode)) + + @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.chflags') + @os_helper.skip_unless_symlink + def test_cleanup_with_symlink_flags(self): + # cleanup() should not follow symlinks when fixing flags (#91133) + flags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK + self.check_flags(flags) + + with self.do_create(recurse=0) as d2: + file1 = os.path.join(d2, 'file1') + open(file1, 'wb').close() + dir1 = os.path.join(d2, 'dir1') + os.mkdir(dir1) + def test(target, target_is_directory): + d1 = self.do_create(recurse=0) + symlink = os.path.join(d1.name, 'symlink') + os.symlink(target, symlink, + target_is_directory=target_is_directory) + try: + os.chflags(symlink, flags, follow_symlinks=False) + except NotImplementedError: + pass + try: + os.chflags(symlink, flags) + except FileNotFoundError: + pass + os.chflags(d1.name, flags) + d1.cleanup() + self.assertFalse(os.path.exists(d1.name)) + + with self.subTest('nonexisting file'): + test('nonexisting', target_is_directory=False) + with self.subTest('nonexisting dir'): + test('nonexisting', target_is_directory=True) + + with self.subTest('existing file'): + os.chflags(file1, flags) + old_flags = os.stat(file1).st_flags + test(file1, target_is_directory=False) + new_flags = os.stat(file1).st_flags + self.assertEqual(new_flags, old_flags) + + with self.subTest('existing dir'): + os.chflags(dir1, flags) + old_flags = os.stat(dir1).st_flags + test(dir1, target_is_directory=True) + new_flags = os.stat(dir1).st_flags + self.assertEqual(new_flags, old_flags) + @support.cpython_only def test_del_on_collection(self): # A TemporaryDirectory is deleted when garbage collected @@ -1845,10 +1942,7 @@ def test_modes(self): d.cleanup() self.assertFalse(os.path.exists(d.name)) - @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.chflags') - def test_flags(self): - flags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK - + def check_flags(self, flags): # skip the test if these flags are not supported (ex: FreeBSD 13) filename = os_helper.TESTFN try: @@ -1857,13 +1951,18 @@ def test_flags(self): os.chflags(filename, flags) except OSError as exc: # "OSError: [Errno 45] Operation not supported" - self.skipTest(f"chflags() doesn't support " - f"UF_IMMUTABLE|UF_NOUNLINK: {exc}") + self.skipTest(f"chflags() doesn't support flags " + f"{flags:#b}: {exc}") else: os.chflags(filename, 0) finally: os_helper.unlink(filename) + @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.chflags') + def test_flags(self): + flags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK + self.check_flags(flags) + d = self.do_create(recurse=3, dirs=2, files=2) with d: # Change files and directories flags recursively. diff --git a/Misc/NEWS.d/next/Library/2022-12-01-16-57-44.gh-issue-91133.LKMVCV.rst b/Misc/NEWS.d/next/Library/2022-12-01-16-57-44.gh-issue-91133.LKMVCV.rst new file mode 100644 index 000000000000000..7991048fc48e039 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-01-16-57-44.gh-issue-91133.LKMVCV.rst @@ -0,0 +1,2 @@ +Fix a bug in :class:`tempfile.TemporaryDirectory` cleanup, which now no longer +dereferences symlinks when working around file system permission errors. From ba18893555bbf69b1da262aaf85d65e4b67e8955 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 7 Dec 2023 18:32:10 +0200 Subject: [PATCH 84/87] gh-87319: Simplify TemporaryDirectory cleanup using os.path.isjunction() (GH-112791) --- Lib/tempfile.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 9a5e7d01c2379b0..4d99f91e1f53b7d 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -41,7 +41,6 @@ import io as _io import os as _os import shutil as _shutil -import stat as _stat import errno as _errno from random import Random as _Random import sys as _sys @@ -909,18 +908,7 @@ def onexc(func, path, exc): # raise NotADirectoryError and mask the PermissionError. # So we must re-raise the current PermissionError if # path is not a directory. - try: - st = _os.lstat(path) - except OSError: - if ignore_errors: - return - raise - if (_stat.S_ISLNK(st.st_mode) or - not _stat.S_ISDIR(st.st_mode) or - (hasattr(st, 'st_file_attributes') and - st.st_file_attributes & _stat.FILE_ATTRIBUTE_REPARSE_POINT and - st.st_reparse_tag == _stat.IO_REPARSE_TAG_MOUNT_POINT) - ): + if not _os.path.isdir(path) or _os.path.isjunction(path): if ignore_errors: return raise From b2923a61a10dc2717f4662b590cc9f6d181c6983 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 7 Dec 2023 19:21:36 +0200 Subject: [PATCH 85/87] gh-79325: Fix recursion error in TemporaryDirectory cleanup on Windows (GH-112762) --- Lib/tempfile.py | 10 ++++++++-- Lib/test/test_tempfile.py | 11 +++++++++++ .../2023-12-05-18-57-53.gh-issue-79325.P2vMVK.rst | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-12-05-18-57-53.gh-issue-79325.P2vMVK.rst diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 4d99f91e1f53b7d..cbfc172a789b251 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -888,9 +888,14 @@ def __init__(self, suffix=None, prefix=None, dir=None, ignore_errors=self._ignore_cleanup_errors, delete=self._delete) @classmethod - def _rmtree(cls, name, ignore_errors=False): + def _rmtree(cls, name, ignore_errors=False, repeated=False): def onexc(func, path, exc): if isinstance(exc, PermissionError): + if repeated and path == name: + if ignore_errors: + return + raise + try: if path != name: _resetperms(_os.path.dirname(path)) @@ -912,7 +917,8 @@ def onexc(func, path, exc): if ignore_errors: return raise - cls._rmtree(path, ignore_errors=ignore_errors) + cls._rmtree(path, ignore_errors=ignore_errors, + repeated=(path == name)) except FileNotFoundError: pass elif isinstance(exc, FileNotFoundError): diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 2729bec7a21c71d..b64b6a4f2baeb57 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1651,6 +1651,17 @@ def test_explicit_cleanup_correct_error(self): with self.assertRaises(PermissionError): temp_dir.cleanup() + @unittest.skipUnless(os.name == "nt", "Only on Windows.") + def test_cleanup_with_used_directory(self): + with tempfile.TemporaryDirectory() as working_dir: + temp_dir = self.do_create(dir=working_dir) + subdir = os.path.join(temp_dir.name, "subdir") + os.mkdir(subdir) + with os_helper.change_cwd(subdir): + # Previously raised RecursionError on some OSes + # (e.g. Windows). See bpo-35144. + with self.assertRaises(PermissionError): + temp_dir.cleanup() @os_helper.skip_unless_symlink def test_cleanup_with_symlink_to_a_directory(self): diff --git a/Misc/NEWS.d/next/Library/2023-12-05-18-57-53.gh-issue-79325.P2vMVK.rst b/Misc/NEWS.d/next/Library/2023-12-05-18-57-53.gh-issue-79325.P2vMVK.rst new file mode 100644 index 000000000000000..f3c32d27b5fe661 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-05-18-57-53.gh-issue-79325.P2vMVK.rst @@ -0,0 +1,2 @@ +Fix an infinite recursion error in :func:`tempfile.TemporaryDirectory` +cleanup on Windows. From a955fd68d6451bd42199110c978e99b3d2959db2 Mon Sep 17 00:00:00 2001 From: AN Long Date: Fri, 8 Dec 2023 01:26:29 +0800 Subject: [PATCH 86/87] gh-112278: Disable WMI queries on Windows after they time out (GH-112658) --- Lib/platform.py | 32 +++++++++++-------- ...-12-03-19-22-37.gh-issue-112278.FiloCE.rst | 2 ++ PC/_wmimodule.cpp | 25 +++++++++++++-- 3 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-12-03-19-22-37.gh-issue-112278.FiloCE.rst diff --git a/Lib/platform.py b/Lib/platform.py index 7bb222088d50616..75aa55510858fd4 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -118,6 +118,10 @@ import sys import functools import itertools +try: + import _wmi +except ImportError: + _wmi = None ### Globals & Constants @@ -312,24 +316,26 @@ def _syscmd_ver(system='', release='', version='', version = _norm_version(version) return system, release, version -try: - import _wmi -except ImportError: - def _wmi_query(*keys): + +def _wmi_query(table, *keys): + global _wmi + if not _wmi: raise OSError("not supported") -else: - def _wmi_query(table, *keys): - table = { - "OS": "Win32_OperatingSystem", - "CPU": "Win32_Processor", - }[table] + table = { + "OS": "Win32_OperatingSystem", + "CPU": "Win32_Processor", + }[table] + try: data = _wmi.exec_query("SELECT {} FROM {}".format( ",".join(keys), table, )).split("\0") - split_data = (i.partition("=") for i in data) - dict_data = {i[0]: i[2] for i in split_data} - return (dict_data[k] for k in keys) + except OSError: + _wmi = None + raise OSError("not supported") + split_data = (i.partition("=") for i in data) + dict_data = {i[0]: i[2] for i in split_data} + return (dict_data[k] for k in keys) _WIN32_CLIENT_RELEASES = [ diff --git a/Misc/NEWS.d/next/Windows/2023-12-03-19-22-37.gh-issue-112278.FiloCE.rst b/Misc/NEWS.d/next/Windows/2023-12-03-19-22-37.gh-issue-112278.FiloCE.rst new file mode 100644 index 000000000000000..0350d105d97375a --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-12-03-19-22-37.gh-issue-112278.FiloCE.rst @@ -0,0 +1,2 @@ +Reduce the time cost for some functions in :mod:`platform` on Windows if +current user has no permission to the WMI. diff --git a/PC/_wmimodule.cpp b/PC/_wmimodule.cpp index fdf09ec6ec6f634..215350acfb0d8ec 100644 --- a/PC/_wmimodule.cpp +++ b/PC/_wmimodule.cpp @@ -44,6 +44,7 @@ struct _query_data { LPCWSTR query; HANDLE writePipe; HANDLE readPipe; + HANDLE connectEvent; }; @@ -86,6 +87,9 @@ _query_thread(LPVOID param) NULL, NULL, 0, NULL, 0, 0, &services ); } + if (!SetEvent(data->connectEvent)) { + hr = HRESULT_FROM_WIN32(GetLastError()); + } if (SUCCEEDED(hr)) { hr = CoSetProxyBlanket( services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, @@ -231,7 +235,8 @@ _wmi_exec_query_impl(PyObject *module, PyObject *query) Py_BEGIN_ALLOW_THREADS - if (!CreatePipe(&data.readPipe, &data.writePipe, NULL, 0)) { + data.connectEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!data.connectEvent || !CreatePipe(&data.readPipe, &data.writePipe, NULL, 0)) { err = GetLastError(); } else { hThread = CreateThread(NULL, 0, _query_thread, (LPVOID*)&data, 0, NULL); @@ -243,6 +248,21 @@ _wmi_exec_query_impl(PyObject *module, PyObject *query) } } + // gh-112278: If current user doesn't have permission to query the WMI, the + // function IWbemLocator::ConnectServer will hang for 5 seconds, and there + // is no way to specify the timeout. So we use an Event object to simulate + // a timeout. + switch (WaitForSingleObject(data.connectEvent, 100)) { + case WAIT_OBJECT_0: + break; + case WAIT_TIMEOUT: + err = WAIT_TIMEOUT; + break; + default: + err = GetLastError(); + break; + } + while (!err) { if (ReadFile( data.readPipe, @@ -265,7 +285,7 @@ _wmi_exec_query_impl(PyObject *module, PyObject *query) } // Allow the thread some time to clean up - switch (WaitForSingleObject(hThread, 1000)) { + switch (WaitForSingleObject(hThread, 100)) { case WAIT_OBJECT_0: // Thread ended cleanly if (!GetExitCodeThread(hThread, (LPDWORD)&err)) { @@ -286,6 +306,7 @@ _wmi_exec_query_impl(PyObject *module, PyObject *query) } CloseHandle(hThread); + CloseHandle(data.connectEvent); hThread = NULL; Py_END_ALLOW_THREADS From bf0beae6a05f3266606a21e22a4d803abbb8d731 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Thu, 7 Dec 2023 19:41:27 +0100 Subject: [PATCH 87/87] gh-110017: Disable test_signal.test_stress_modifying_handlers on macOS (#112834) Test test_stress_modifying_handlers in test_signal can crash the interpreter due to a bug in macOS. Filed as FB13453490 with Apple. --- Lib/test/test_signal.py | 1 + .../next/macOS/2023-12-07-15-53-16.gh-issue-110017.UMYzMR.rst | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/macOS/2023-12-07-15-53-16.gh-issue-110017.UMYzMR.rst diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index f2ae28c38dd72d7..acb7e9d4c6074d1 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -1318,6 +1318,7 @@ def handler(signum, frame): # Python handler self.assertEqual(len(sigs), N, "Some signals were lost") + @unittest.skipIf(sys.platform == "darwin", "crashes due to system bug (FB13453490)") @unittest.skipUnless(hasattr(signal, "SIGUSR1"), "test needs SIGUSR1") @threading_helper.requires_working_threading() diff --git a/Misc/NEWS.d/next/macOS/2023-12-07-15-53-16.gh-issue-110017.UMYzMR.rst b/Misc/NEWS.d/next/macOS/2023-12-07-15-53-16.gh-issue-110017.UMYzMR.rst new file mode 100644 index 000000000000000..eab1746f1ae3f73 --- /dev/null +++ b/Misc/NEWS.d/next/macOS/2023-12-07-15-53-16.gh-issue-110017.UMYzMR.rst @@ -0,0 +1,2 @@ +Disable a signal handling stress test on macOS due to a bug in macOS +(FB13453490).
  • O3=@lHik4kW(~$h5zRB&Vr@ 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