Skip to content

gh-106320: Remove private _PyErr_ChainExceptions() #108713

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Include/cpython/initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ PyAPI_FUNC(PyStatus) PyStatus_Exit(int exitcode);
PyAPI_FUNC(int) PyStatus_IsError(PyStatus err);
PyAPI_FUNC(int) PyStatus_IsExit(PyStatus err);
PyAPI_FUNC(int) PyStatus_Exception(PyStatus err);
PyAPI_FUNC(PyObject *) _PyErr_SetFromPyStatus(PyStatus status);

/* --- PyWideStringList ------------------------------------------------ */

Expand Down
5 changes: 0 additions & 5 deletions Include/cpython/pyerrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,6 @@ typedef PyOSErrorObject PyEnvironmentErrorObject;
typedef PyOSErrorObject PyWindowsErrorObject;
#endif

/* Context manipulation (PEP 3134) */

Py_DEPRECATED(3.12) PyAPI_FUNC(void) _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *);
PyAPI_FUNC(void) _PyErr_ChainExceptions1(PyObject *);

/* In exceptions.c */

PyAPI_FUNC(PyObject*) PyUnstable_Exc_PrepReraiseStar(
Expand Down
4 changes: 4 additions & 0 deletions Include/internal/pycore_initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ struct pyruntimestate;
#define _PyStatus_UPDATE_FUNC(err) \
do { (err).func = _PyStatus_GET_FUNC(); } while (0)

// Export for '_testinternalcapi' shared extension
PyAPI_FUNC(PyObject *) _PyErr_SetFromPyStatus(PyStatus status);


/* --- PyWideStringList ------------------------------------------------ */

#define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL}
Expand Down
7 changes: 7 additions & 0 deletions Include/internal/pycore_pyerrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,13 @@ PyAPI_FUNC(Py_ssize_t) _Py_UTF8_Edit_Cost(PyObject *str_a, PyObject *str_b,

void _PyErr_FormatNote(const char *format, ...);

/* Context manipulation (PEP 3134) */

Py_DEPRECATED(3.12) extern void _PyErr_ChainExceptions(PyObject *, PyObject *, PyObject *);

// Export for '_zoneinfo' shared extension
PyAPI_FUNC(void) _PyErr_ChainExceptions1(PyObject *);

#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1821,11 +1821,11 @@ def run_in_subinterp_with_config(code, *, own_gil=None, **config):
module is enabled.
"""
_check_tracemalloc()
import _testcapi
import _testinternalcapi
if own_gil is not None:
assert 'gil' not in config, (own_gil, config)
config['gil'] = 2 if own_gil else 1
return _testcapi.run_in_subinterp_with_config(code, **config)
return _testinternalcapi.run_in_subinterp_with_config(code, **config)


def _check_tracemalloc():
Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_import/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1805,12 +1805,12 @@ def check_compatible_fresh(self, name, *, strict=False, isolated=False):
check_multi_interp_extensions=strict,
)
_, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f'''
import _testcapi, sys
import _testinternalcapi, sys
assert (
{name!r} in sys.builtin_module_names or
{name!r} not in sys.modules
), repr({name!r})
ret = _testcapi.run_in_subinterp_with_config(
ret = _testinternalcapi.run_in_subinterp_with_config(
{self.import_script(name, "sys.stdout.fileno()")!r},
**{kwargs},
)
Expand All @@ -1829,9 +1829,9 @@ def check_incompatible_fresh(self, name, *, isolated=False):
check_multi_interp_extensions=True,
)
_, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f'''
import _testcapi, sys
import _testinternalcapi, sys
assert {name!r} not in sys.modules, {name!r}
ret = _testcapi.run_in_subinterp_with_config(
ret = _testinternalcapi.run_in_subinterp_with_config(
{self.import_script(name, "sys.stdout.fileno()")!r},
**{kwargs},
)
Expand Down
1 change: 1 addition & 0 deletions Modules/_io/_iomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Python.h"
#include "pycore_abstract.h" // _PyNumber_Index()
#include "pycore_initconfig.h" // _PyStatus_OK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_pystate.h" // _PyInterpreterState_GET()

#include "_iomodule.h"
Expand Down
1 change: 1 addition & 0 deletions Modules/_io/fileio.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Python.h"
#include "pycore_fileutils.h" // _Py_BEGIN_SUPPRESS_IPH
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()

#include <stdbool.h>
#ifdef HAVE_SYS_TYPES_H
Expand Down
2 changes: 2 additions & 0 deletions Modules/_io/iobase.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_object.h" // _PyType_HasFeature()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()

#include <stddef.h> // offsetof()
#include "_iomodule.h"

Expand Down
3 changes: 2 additions & 1 deletion Modules/_io/textio.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
#include "Python.h"
#include "pycore_call.h" // _PyObject_CallMethod()
#include "pycore_codecs.h" // _PyCodecInfo_GetIncrementalDecoder()
#include "pycore_fileutils.h" // _Py_GetLocaleEncoding()
#include "pycore_interp.h" // PyInterpreterState.fs_codec
#include "pycore_long.h" // _PyLong_GetZero()
#include "pycore_fileutils.h" // _Py_GetLocaleEncoding()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_pystate.h" // _PyInterpreterState_GET()

#include "_iomodule.h"
Expand Down
2 changes: 2 additions & 0 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
#include "blob.h"
#include "prepare_protocol.h"
#include "util.h"

#include "pycore_import.h" // _PyImport_GetModuleAttrString()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing()
#include "pycore_weakref.h" // _PyWeakref_IS_DEAD()

Expand Down
1 change: 1 addition & 0 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "Python.h"
#include "pycore_fileutils.h" // _PyIsSelectable_fd()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_weakref.h" // _PyWeakref_GET_REF()

/* Include symbols from _socket module */
Expand Down
101 changes: 0 additions & 101 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1434,104 +1434,6 @@ run_in_subinterp(PyObject *self, PyObject *args)
return PyLong_FromLong(r);
}

/* To run some code in a sub-interpreter. */
static PyObject *
run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
{
const char *code;
int use_main_obmalloc = -1;
int allow_fork = -1;
int allow_exec = -1;
int allow_threads = -1;
int allow_daemon_threads = -1;
int check_multi_interp_extensions = -1;
int gil = -1;
int r;
PyThreadState *substate, *mainstate;
/* only initialise 'cflags.cf_flags' to test backwards compatibility */
PyCompilerFlags cflags = {0};

static char *kwlist[] = {"code",
"use_main_obmalloc",
"allow_fork",
"allow_exec",
"allow_threads",
"allow_daemon_threads",
"check_multi_interp_extensions",
"gil",
NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"s$ppppppi:run_in_subinterp_with_config", kwlist,
&code, &use_main_obmalloc,
&allow_fork, &allow_exec,
&allow_threads, &allow_daemon_threads,
&check_multi_interp_extensions,
&gil)) {
return NULL;
}
if (use_main_obmalloc < 0) {
PyErr_SetString(PyExc_ValueError, "missing use_main_obmalloc");
return NULL;
}
if (allow_fork < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_fork");
return NULL;
}
if (allow_exec < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_exec");
return NULL;
}
if (allow_threads < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_threads");
return NULL;
}
if (gil < 0) {
PyErr_SetString(PyExc_ValueError, "missing gil");
return NULL;
}
if (allow_daemon_threads < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_daemon_threads");
return NULL;
}
if (check_multi_interp_extensions < 0) {
PyErr_SetString(PyExc_ValueError, "missing check_multi_interp_extensions");
return NULL;
}

mainstate = PyThreadState_Get();

PyThreadState_Swap(NULL);

const PyInterpreterConfig config = {
.use_main_obmalloc = use_main_obmalloc,
.allow_fork = allow_fork,
.allow_exec = allow_exec,
.allow_threads = allow_threads,
.allow_daemon_threads = allow_daemon_threads,
.check_multi_interp_extensions = check_multi_interp_extensions,
.gil = gil,
};
PyStatus status = Py_NewInterpreterFromConfig(&substate, &config);
if (PyStatus_Exception(status)) {
/* Since no new thread state was created, there is no exception to
propagate; raise a fresh one after swapping in the old thread
state. */
PyThreadState_Swap(mainstate);
_PyErr_SetFromPyStatus(status);
PyObject *exc = PyErr_GetRaisedException();
PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed");
_PyErr_ChainExceptions1(exc);
return NULL;
}
assert(substate != NULL);
r = PyRun_SimpleStringFlags(code, &cflags);
Py_EndInterpreter(substate);

PyThreadState_Swap(mainstate);

return PyLong_FromLong(r);
}

static void
_xid_capsule_destructor(PyObject *capsule)
{
Expand Down Expand Up @@ -3376,9 +3278,6 @@ static PyMethodDef TestMethods[] = {
{"crash_no_current_thread", crash_no_current_thread, METH_NOARGS},
{"test_current_tstate_matches", test_current_tstate_matches, METH_NOARGS},
{"run_in_subinterp", run_in_subinterp, METH_VARARGS},
{"run_in_subinterp_with_config",
_PyCFunction_CAST(run_in_subinterp_with_config),
METH_VARARGS | METH_KEYWORDS},
{"get_crossinterp_data", get_crossinterp_data, METH_VARARGS},
{"restore_crossinterp_data", restore_crossinterp_data, METH_VARARGS},
{"create_cfunction", create_cfunction, METH_NOARGS},
Expand Down
103 changes: 103 additions & 0 deletions Modules/_testinternalcapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy()
#include "pycore_object.h" // _PyObject_IsFreed()
#include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost()
#include "pycore_pystate.h" // _PyThreadState_GET()

Expand Down Expand Up @@ -1593,6 +1594,105 @@ dict_getitem_knownhash(PyObject *self, PyObject *args)
}


/* To run some code in a sub-interpreter. */
static PyObject *
run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
{
const char *code;
int use_main_obmalloc = -1;
int allow_fork = -1;
int allow_exec = -1;
int allow_threads = -1;
int allow_daemon_threads = -1;
int check_multi_interp_extensions = -1;
int gil = -1;
int r;
PyThreadState *substate, *mainstate;
/* only initialise 'cflags.cf_flags' to test backwards compatibility */
PyCompilerFlags cflags = {0};

static char *kwlist[] = {"code",
"use_main_obmalloc",
"allow_fork",
"allow_exec",
"allow_threads",
"allow_daemon_threads",
"check_multi_interp_extensions",
"gil",
NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
"s$ppppppi:run_in_subinterp_with_config", kwlist,
&code, &use_main_obmalloc,
&allow_fork, &allow_exec,
&allow_threads, &allow_daemon_threads,
&check_multi_interp_extensions,
&gil)) {
return NULL;
}
if (use_main_obmalloc < 0) {
PyErr_SetString(PyExc_ValueError, "missing use_main_obmalloc");
return NULL;
}
if (allow_fork < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_fork");
return NULL;
}
if (allow_exec < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_exec");
return NULL;
}
if (allow_threads < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_threads");
return NULL;
}
if (gil < 0) {
PyErr_SetString(PyExc_ValueError, "missing gil");
return NULL;
}
if (allow_daemon_threads < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_daemon_threads");
return NULL;
}
if (check_multi_interp_extensions < 0) {
PyErr_SetString(PyExc_ValueError, "missing check_multi_interp_extensions");
return NULL;
}

mainstate = PyThreadState_Get();

PyThreadState_Swap(NULL);

const PyInterpreterConfig config = {
.use_main_obmalloc = use_main_obmalloc,
.allow_fork = allow_fork,
.allow_exec = allow_exec,
.allow_threads = allow_threads,
.allow_daemon_threads = allow_daemon_threads,
.check_multi_interp_extensions = check_multi_interp_extensions,
.gil = gil,
};
PyStatus status = Py_NewInterpreterFromConfig(&substate, &config);
if (PyStatus_Exception(status)) {
/* Since no new thread state was created, there is no exception to
propagate; raise a fresh one after swapping in the old thread
state. */
PyThreadState_Swap(mainstate);
_PyErr_SetFromPyStatus(status);
PyObject *exc = PyErr_GetRaisedException();
PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed");
_PyErr_ChainExceptions1(exc);
return NULL;
}
assert(substate != NULL);
r = PyRun_SimpleStringFlags(code, &cflags);
Py_EndInterpreter(substate);

PyThreadState_Swap(mainstate);

return PyLong_FromLong(r);
}


static PyMethodDef module_functions[] = {
{"get_configs", get_configs, METH_NOARGS},
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
Expand Down Expand Up @@ -1659,6 +1759,9 @@ static PyMethodDef module_functions[] = {
{"get_object_dict_values", get_object_dict_values, METH_O},
{"hamt", new_hamt, METH_NOARGS},
{"dict_getitem_knownhash", dict_getitem_knownhash, METH_VARARGS},
{"run_in_subinterp_with_config",
_PyCFunction_CAST(run_in_subinterp_with_config),
METH_VARARGS | METH_KEYWORDS},
{NULL, NULL} /* sentinel */
};

Expand Down
6 changes: 6 additions & 0 deletions Modules/_xxsubinterpretersmodule.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/* interpreters module */
/* low-level access to interpreter primitives */

#ifndef Py_BUILD_CORE_BUILTIN
# define Py_BUILD_CORE_MODULE 1
#endif

#include "Python.h"
#include "pycore_initconfig.h" // _PyErr_SetFromPyStatus()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include "interpreteridobject.h"


Expand Down
Loading