diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index b7175166a6f009..e7805ba143c584 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -358,7 +358,7 @@ an error value). .. c:function:: int PyErr_ResourceWarning(PyObject *source, Py_ssize_t stack_level, const char *format, ...) Function similar to :c:func:`PyErr_WarnFormat`, but *category* is - :exc:`ResourceWarning` and pass *source* to :func:`warnings.WarningMessage`. + :exc:`ResourceWarning` and it passes *source* to :func:`warnings.WarningMessage`. .. versionadded:: 3.6 diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index c34b1174a5913d..badea5a01362a5 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1091,6 +1091,32 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. versionadded:: 3.8 +.. c:type:: PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *frame, int throwflag) + + Type of a frame evaluation function. + + The *throwflag* parameter is used by the ``throw()`` method of generators: + if non-zero, handle the current exception. + + .. versionchanged:: 3.9 + The function now takes a *tstate* parameter. + +.. c:function:: _PyFrameEvalFunction _PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp) + + Get the frame evaluation function. + + See the :pep:`523` "Adding a frame evaluation API to CPython". + + .. versionadded:: 3.9 + +.. c:function:: void _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, _PyFrameEvalFunction eval_frame); + + Set the frame evaluation function. + + See the :pep:`523` "Adding a frame evaluation API to CPython". + + .. versionadded:: 3.9 + .. c:function:: PyObject* PyThreadState_GetDict() diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 9948539b01c586..0b61fb8f0deb95 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -356,7 +356,7 @@ running. sys --- -Add a new :attr:`sys.platlitdir` attribute: name of the platform-specific +Add a new :attr:`sys.platlibdir` attribute: name of the platform-specific library directory. It is used to build the path of platform-specific dynamic libraries and the path of the standard library. It is equal to ``"lib"`` on most platforms. On Fedora and SuSE, it is equal to ``"lib64"`` on 64-bit @@ -407,7 +407,7 @@ Build and C API Changes ======================= * Add ``--with-platlibdir`` option to the ``configure`` script: name of the - platform-specific library directory, stored in the new :attr:`sys.platlitdir` + platform-specific library directory, stored in the new :attr:`sys.platlibdir` attribute. See :attr:`sys.platlibdir` attribute for more information. (Contributed by Jan Matějek, Matěj Cepl, Charalampos Stratakis and Victor Stinner in :issue:`1294959`.) @@ -487,6 +487,10 @@ Build and C API Changes (Contributed by Victor Stinner in :issue:`38644` and :issue:`39542`.) +* ``PyInterpreterState.eval_frame`` (:pep:`523`) now requires a new mandatory + *tstate* parameter (``PyThreadState*``). + (Contributed by Victor Stinner in :issue:`38500`.) + Deprecated ========== diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index e601304589f762..f03b53ade92983 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -21,7 +21,7 @@ PyAPI_FUNC(PyObject *) _PyEval_GetBuiltinId(_Py_Identifier *); flag was set, else return 0. */ PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf); -PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(struct _frame *f, int exc); +PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, struct _frame *f, int exc); PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds); PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void); diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index d1792575c97378..fbb0899186f607 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -186,6 +186,16 @@ PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_); +/* Frame evaluation API */ + +typedef PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, struct _frame *, int); + +PyAPI_FUNC(_PyFrameEvalFunction) _PyInterpreterState_GetEvalFrameFunc( + PyInterpreterState *interp); +PyAPI_FUNC(void) _PyInterpreterState_SetEvalFrameFunc( + PyInterpreterState *interp, + _PyFrameEvalFunction eval_frame); + /* cross-interpreter data */ struct _xid; diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 70ce0ee5f70d34..23d80916fde389 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -40,7 +40,7 @@ void _PyEval_Fini(void); static inline PyObject* _PyEval_EvalFrame(PyThreadState *tstate, struct _frame *f, int throwflag) { - return tstate->interp->eval_frame(f, throwflag); + return tstate->interp->eval_frame(tstate, f, throwflag); } extern PyObject *_PyEval_EvalCode( diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index b5f509547207dd..0a835463625580 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -54,8 +54,6 @@ struct _ceval_runtime_state { /* interpreter state */ -typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int); - #define _PY_NSMALLPOSINTS 257 #define _PY_NSMALLNEGINTS 5 diff --git a/Lib/_aix_support.py b/Lib/_aix_support.py index 2c5cd3297de30d..45504934063df8 100644 --- a/Lib/_aix_support.py +++ b/Lib/_aix_support.py @@ -1,35 +1,20 @@ """Shared AIX support functions.""" import sys -from sysconfig import get_config_var +import sysconfig -# subprocess is not necessarily available early in the build process -# if not available, the config_vars are also definitely not available -# supply substitutes to bootstrap the build try: import subprocess - _have_subprocess = True - _tmp_bd = get_config_var("AIX_BUILDDATE") - _bgt = get_config_var("BUILD_GNU_TYPE") except ImportError: # pragma: no cover - _have_subprocess = False - _tmp_bd = None - _bgt = "powerpc-ibm-aix6.1.7.0" - -# if get_config_var("AIX_BUILDDATE") was unknown, provide a substitute, -# impossible builddate to specify 'unknown' -_MISSING_BD = 9898 -try: - _bd = int(_tmp_bd) -except TypeError: - _bd = _MISSING_BD - -# Infer the ABI bitwidth from maxsize (assuming 64 bit as the default) -_sz = 32 if sys.maxsize == (2**31-1) else 64 + # _aix_support is used in distutils by setup.py to build C extensions, + # before subprocess dependencies like _posixsubprocess are available. + import _bootsubprocess as subprocess def _aix_tag(vrtl, bd): # type: (List[int], int) -> str + # Infer the ABI bitwidth from maxsize (assuming 64 bit as the default) + _sz = 32 if sys.maxsize == (2**31-1) else 64 # vrtl[version, release, technology_level] return "aix-{:1x}{:1d}{:02d}-{:04d}-{}".format(vrtl[0], vrtl[1], vrtl[2], bd, _sz) @@ -48,17 +33,12 @@ def _aix_bosmp64(): The fileset bos.mp64 is the AIX kernel. It's VRMF and builddate reflect the current ABI levels of the runtime environment. """ - if _have_subprocess: - # We expect all AIX systems to have lslpp installed in this location - out = subprocess.check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) - out = out.decode("utf-8").strip().split(":") # type: ignore - # Use str() and int() to help mypy see types - return str(out[2]), int(out[-1]) - else: - from os import uname - - osname, host, release, version, machine = uname() - return "{}.{}.0.0".format(version, release), _MISSING_BD + # We expect all AIX systems to have lslpp installed in this location + out = subprocess.check_output(["/usr/bin/lslpp", "-Lqc", "bos.mp64"]) + out = out.decode("utf-8") + out = out.strip().split(":") # type: ignore + # Use str() and int() to help mypy see types + return (str(out[2]), int(out[-1])) def aix_platform(): @@ -87,8 +67,10 @@ def aix_platform(): # extract vrtl from the BUILD_GNU_TYPE as an int def _aix_bgt(): # type: () -> List[int] - assert _bgt - return _aix_vrtl(vrmf=_bgt) + gnu_type = sysconfig.get_config_var("BUILD_GNU_TYPE") + if not gnu_type: + raise ValueError("BUILD_GNU_TYPE is not defined") + return _aix_vrtl(vrmf=gnu_type) def aix_buildtag(): @@ -96,4 +78,12 @@ def aix_buildtag(): """ Return the platform_tag of the system Python was built on. """ - return _aix_tag(_aix_bgt(), _bd) + # AIX_BUILDDATE is defined by configure with: + # lslpp -Lcq bos.mp64 | awk -F: '{ print $NF }' + build_date = sysconfig.get_config_var("AIX_BUILDDATE") + try: + build_date = int(build_date) + except (ValueError, TypeError): + raise ValueError(f"AIX_BUILDDATE is not defined or invalid: " + f"{build_date!r}") + return _aix_tag(_aix_bgt(), build_date) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 2ddca06b8b568a..d440bcf7e0faa1 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -2754,6 +2754,10 @@ def test_memoryview_cast_1D_ND(self): # be 1D, at least one format must be 'c', 'b' or 'B'. for _tshape in gencastshapes(): for char in fmtdict['@']: + # Casts to _Bool are undefined if the source contains values + # other than 0 or 1. + if char == "?": + continue tfmt = ('', '@')[randrange(2)] + char tsize = struct.calcsize(tfmt) n = prod(_tshape) * tsize diff --git a/Misc/NEWS.d/next/Build/2020-02-06-18-08-25.bpo-1294959.AZPg4R.rst b/Misc/NEWS.d/next/Build/2020-02-06-18-08-25.bpo-1294959.AZPg4R.rst index 1642e6929bcef4..a90d6300f33bad 100644 --- a/Misc/NEWS.d/next/Build/2020-02-06-18-08-25.bpo-1294959.AZPg4R.rst +++ b/Misc/NEWS.d/next/Build/2020-02-06-18-08-25.bpo-1294959.AZPg4R.rst @@ -1,5 +1,5 @@ Add ``--with-platlibdir`` option to the configure script: name of the -platform-specific library directory, stored in the new :attr:`sys.platlitdir` +platform-specific library directory, stored in the new :attr:`sys.platlibdir` attribute. It is used to build the path of platform-specific dynamic libraries and the path of the standard library. It is equal to ``"lib"`` on most platforms. On Fedora and SuSE, it is equal to ``"lib64"`` on 64-bit platforms. diff --git a/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst b/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst new file mode 100644 index 00000000000000..f1ccfacd2c8f96 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2019-11-22-14-06-28.bpo-38500.nPEdjH.rst @@ -0,0 +1,5 @@ +Add a private API to get and set the frame evaluation function: add +:c:func:`_PyInterpreterState_GetEvalFrameFunc` and +:c:func:`_PyInterpreterState_SetEvalFrameFunc` C functions. +The :c:type:`_PyFrameEvalFunction` function type now takes a *tstate* +parameter. diff --git a/Misc/NEWS.d/next/C API/2020-03-12-00-27-26.bpo-39884.CGOJBO.rst b/Misc/NEWS.d/next/C API/2020-03-12-00-27-26.bpo-39884.CGOJBO.rst new file mode 100644 index 00000000000000..c65dfdc21244a9 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-03-12-00-27-26.bpo-39884.CGOJBO.rst @@ -0,0 +1,2 @@ +:c:func:`PyDescr_NewMethod` and :c:func:`PyCFunction_NewEx` now include the +method name in the SystemError "bad call flags" error message to ease debug. diff --git a/Misc/NEWS.d/next/Library/2020-03-12-21-59-47.bpo-39936.Ca9IKe.rst b/Misc/NEWS.d/next/Library/2020-03-12-21-59-47.bpo-39936.Ca9IKe.rst new file mode 100644 index 00000000000000..8d3b6fd974b795 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-03-12-21-59-47.bpo-39936.Ca9IKe.rst @@ -0,0 +1,5 @@ +AIX: Fix _aix_support module when the subprocess is not available, when +building Python from scratch. It now uses new private _bootsubprocess +module, rather than having two implementations depending if subprocess is +available or not. So _aix_support.aix_platform() result is now the same if +subprocess is available or not. diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index d0a381deabf5d8..fd0e4edcddfdbe 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2133,12 +2133,8 @@ defdict_repr(defdictobject *dd) static PyObject* defdict_or(PyObject* left, PyObject* right) { - int left_is_self = PyObject_IsInstance(left, (PyObject*)&defdict_type); - if (left_is_self < 0) { - return NULL; - } PyObject *self, *other; - if (left_is_self) { + if (PyObject_TypeCheck(left, &defdict_type)) { self = left; other = right; } diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index d06ba6c6ff3509..1a9e1c0b667d39 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -623,7 +623,7 @@ nfd_nfkd(PyObject *self, PyObject *input, int k) } static int -find_nfc_index(PyObject *self, struct reindex* nfc, Py_UCS4 code) +find_nfc_index(const struct reindex* nfc, Py_UCS4 code) { unsigned int index; for (index = 0; nfc[index].start; index++) { @@ -709,7 +709,7 @@ nfc_nfkc(PyObject *self, PyObject *input, int k) } /* code is still input[i] here */ - f = find_nfc_index(self, nfc_first, code); + f = find_nfc_index(nfc_first, code); if (f == -1) { output[o++] = code; i++; @@ -732,7 +732,7 @@ nfc_nfkc(PyObject *self, PyObject *input, int k) continue; } } - l = find_nfc_index(self, nfc_last, code1); + l = find_nfc_index(nfc_last, code1); /* i1 cannot be combined with i. If i1 is a starter, we don't need to look further. Otherwise, record the combining class. */ @@ -757,7 +757,7 @@ nfc_nfkc(PyObject *self, PyObject *input, int k) assert(cskipped < 20); skipped[cskipped++] = i1; i1++; - f = find_nfc_index(self, nfc_first, output[o]); + f = find_nfc_index(nfc_first, output[o]); if (f == -1) break; } diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 4ebbb74151a232..b448ec642683c2 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -888,7 +888,8 @@ PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method) vectorcall = method_vectorcall_O; break; default: - PyErr_SetString(PyExc_SystemError, "bad call flags"); + PyErr_Format(PyExc_SystemError, + "%s() method: bad call flags", method->ml_name); return NULL; } diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 0d4570534b1ae5..16abded3854664 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -56,7 +56,8 @@ PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) vectorcall = cfunction_vectorcall_O; break; default: - PyErr_SetString(PyExc_SystemError, "bad call flags"); + PyErr_Format(PyExc_SystemError, + "%s() method: bad call flags", ml->ml_name); return NULL; } diff --git a/Python/ceval.c b/Python/ceval.c index 380212a71aaf75..ccd1c06a39cfd9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -725,9 +725,7 @@ PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals) PyObject * PyEval_EvalFrame(PyFrameObject *f) { - /* This is for backward compatibility with extension modules that - used this API; core interpreter code should call - PyEval_EvalFrameEx() */ + /* Function kept for backward compatibility */ PyThreadState *tstate = _PyThreadState_GET(); return _PyEval_EvalFrame(tstate, f, 0); } @@ -740,8 +738,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } PyObject* _Py_HOT_FUNCTION -_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) +_PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) { + ensure_tstate_not_null(__func__, tstate); + #ifdef DXPAIRS int lastopcode = 0; #endif @@ -756,9 +756,6 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) _Py_atomic_int * const eval_breaker = &ceval->eval_breaker; PyCodeObject *co; - PyThreadState * const tstate = _PyRuntimeState_GetThreadState(runtime); - ensure_tstate_not_null(__func__, tstate); - /* when tracing we set things up so that not (instr_lb <= current_bytecode_offset < instr_ub) @@ -1181,7 +1178,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) goto error; #ifdef Py_DEBUG - /* PyEval_EvalFrameEx() must not be called with an exception set, + /* _PyEval_EvalFrameDefault() must not be called with an exception set, because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!_PyErr_Occurred(tstate)); @@ -3702,7 +3699,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) f->f_executing = 0; tstate->frame = f->f_back; - return _Py_CheckFunctionResult(tstate, NULL, retval, "PyEval_EvalFrameEx"); + return _Py_CheckFunctionResult(tstate, NULL, retval, __func__); } static void diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index bc32eff436e68b..e63ecf70f35c1d 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -65,7 +65,7 @@ extern grammar _PyParser_Grammar; /* From graminit.c */ /* Forward declarations */ static PyStatus add_main_module(PyInterpreterState *interp); static PyStatus init_import_site(void); -static PyStatus init_set_builtins_open(PyThreadState *tstate); +static PyStatus init_set_builtins_open(void); static PyStatus init_sys_streams(PyThreadState *tstate); static PyStatus init_signals(PyThreadState *tstate); static void call_py_exitfuncs(PyThreadState *tstate); @@ -1025,7 +1025,7 @@ init_interp_main(PyThreadState *tstate) return status; } - status = init_set_builtins_open(tstate); + status = init_set_builtins_open(); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -1888,7 +1888,7 @@ create_stdio(const PyConfig *config, PyObject* io, /* Set builtins.open to io.OpenWrapper */ static PyStatus -init_set_builtins_open(PyThreadState *tstate) +init_set_builtins_open(void) { PyObject *iomod = NULL, *wrapper; PyObject *bimod = NULL; @@ -2056,9 +2056,8 @@ _Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp, Return 1 if the traceback was displayed, 0 otherwise. */ static int -_Py_FatalError_PrintExc(int fd) +_Py_FatalError_PrintExc(PyThreadState *tstate) { - PyThreadState *tstate = _PyThreadState_GET(); PyObject *ferr, *res; PyObject *exception, *v, *tb; int has_tb; @@ -2220,7 +2219,7 @@ fatal_error(const char *prefix, const char *msg, int status) int has_tstate_and_gil = (tss_tstate != NULL && tss_tstate == tstate); if (has_tstate_and_gil) { /* If an exception is set, print the exception with its traceback */ - if (!_Py_FatalError_PrintExc(fd)) { + if (!_Py_FatalError_PrintExc(tss_tstate)) { /* No exception is set, or an exception is set without traceback */ _Py_FatalError_DumpTracebacks(fd, interp, tss_tstate); } diff --git a/Python/pystate.c b/Python/pystate.c index 504f5f456dd2a5..9cf6bea1a027d1 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1722,6 +1722,20 @@ _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry) } +_PyFrameEvalFunction +_PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp) +{ + return interp->eval_frame; +} + + +void +_PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp, + _PyFrameEvalFunction eval_frame) +{ + interp->eval_frame = eval_frame; +} + #ifdef __cplusplus } #endif