Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
_interpreters.RunFailedError -> interpreters.RunFailedError
  • Loading branch information
ericsnowcurrently committed Nov 23, 2023
commit dfff3e30ffdf25511d472385bf804bb15f71173e
22 changes: 17 additions & 5 deletions Lib/test/support/interpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,27 @@

__all__ = [
'Interpreter', 'get_current', 'get_main', 'create', 'list_all',
'RunFailedError',
'SendChannel', 'RecvChannel',
'create_channel', 'list_all_channels', 'is_shareable',
'ChannelError', 'ChannelNotFoundError',
'ChannelEmptyError',
]


class RunFailedError(RuntimeError):

def __init__(self, excinfo):
msg = excinfo.formatted
if not msg:
if excinfo.type and snapshot.msg:
msg = f'{snapshot.type.__name__}: {snapshot.msg}'
else:
msg = snapshot.type.__name__ or snapshot.msg
super().__init__(msg)
self.snapshot = excinfo


def create(*, isolated=True):
"""Return a new (idle) Python interpreter."""
id = _interpreters.create(isolated=isolated)
Expand Down Expand Up @@ -110,11 +124,9 @@ def run(self, src_str, /, channels=None):
that time, the previous interpreter is allowed to run
in other threads.
"""
err = _interpreters.exec(self._id, src_str, channels)
if err is not None:
exc = RunFailedError(err.formatted)
exc.snapshot = err
raise exc
excinfo = _interpreters.exec(self._id, src_str, channels)
if excinfo is not None:
raise RunFailedError(excinfo)


def create_channel():
Expand Down
11 changes: 5 additions & 6 deletions Lib/test/test__xxsubinterpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,6 @@ def add_module(self, modname, text):
return script_helper.make_script(tempdir, modname, text)

def run_script(self, text, *, fails=False):
excwrapper = interpreters.RunFailedError
r, w = os.pipe()
try:
script = dedent(f"""
Expand Down Expand Up @@ -980,18 +979,18 @@ def _assert_run_failed(self, exctype, msg, script):
exctype_name = exctype.__name__

# Run the script.
exc = self.run_script(script, fails=True)
excinfo = self.run_script(script, fails=True)

# Check the wrapper exception.
self.assertEqual(exc.type.__name__, exctype_name)
self.assertEqual(excinfo.type.__name__, exctype_name)
if msg is None:
self.assertEqual(exc.formatted.split(':')[0],
self.assertEqual(excinfo.formatted.split(':')[0],
exctype_name)
else:
self.assertEqual(exc.formatted,
self.assertEqual(excinfo.formatted,
'{}: {}'.format(exctype_name, msg))

return exc
return excinfo

def assert_run_failed(self, exctype, script):
self._assert_run_failed(exctype, None, script)
Expand Down
5 changes: 5 additions & 0 deletions Lib/test/test_interpreters.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,11 @@ def test_success(self):

self.assertEqual(out, 'it worked!')

def test_failure(self):
interp = interpreters.create()
with self.assertRaises(interpreters.RunFailedError):
interp.run('raise Exception')

def test_in_thread(self):
interp = interpreters.create()
script, file = _captured_script('print("it worked!", end="")')
Expand Down
57 changes: 1 addition & 56 deletions Modules/_xxsubinterpretersmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,31 +28,11 @@ _get_current_interp(void)
return PyInterpreterState_Get();
}

static PyObject *
add_new_exception(PyObject *mod, const char *name, PyObject *base)
{
assert(!PyObject_HasAttrStringWithError(mod, name));
PyObject *exctype = PyErr_NewException(name, base, NULL);
if (exctype == NULL) {
return NULL;
}
int res = PyModule_AddType(mod, (PyTypeObject *)exctype);
if (res < 0) {
Py_DECREF(exctype);
return NULL;
}
return exctype;
}

#define ADD_NEW_EXCEPTION(MOD, NAME, BASE) \
add_new_exception(MOD, MODULE_NAME "." Py_STRINGIFY(NAME), BASE)


/* module state *************************************************************/

typedef struct {
/* exceptions */
PyObject *RunFailedError;
int _notused;
} module_state;

static inline module_state *
Expand All @@ -67,18 +47,12 @@ get_module_state(PyObject *mod)
static int
traverse_module_state(module_state *state, visitproc visit, void *arg)
{
/* exceptions */
Py_VISIT(state->RunFailedError);

return 0;
}

static int
clear_module_state(module_state *state)
{
/* exceptions */
Py_CLEAR(state->RunFailedError);

return 0;
}

Expand Down Expand Up @@ -177,30 +151,6 @@ get_code_str(PyObject *arg, Py_ssize_t *len_p, PyObject **bytes_p, int *flags_p)

/* interpreter-specific code ************************************************/

static int
exceptions_init(PyObject *mod)
{
module_state *state = get_module_state(mod);
if (state == NULL) {
return -1;
}

#define ADD(NAME, BASE) \
do { \
assert(state->NAME == NULL); \
state->NAME = ADD_NEW_EXCEPTION(mod, NAME, BASE); \
if (state->NAME == NULL) { \
return -1; \
} \
} while (0)

// An uncaught exception came out of interp_run_string().
ADD(RunFailedError, PyExc_RuntimeError);
#undef ADD

return 0;
}

static int
_run_script(PyObject *ns, const char *codestr, Py_ssize_t codestrlen, int flags)
{
Expand Down Expand Up @@ -770,11 +720,6 @@ The 'interpreters' module provides a more convenient interface.");
static int
module_exec(PyObject *mod)
{
/* Add exception types */
if (exceptions_init(mod) != 0) {
goto error;
}

// PyInterpreterID
if (PyModule_AddType(mod, &PyInterpreterID_Type) < 0) {
goto error;
Expand Down