Skip to content

Commit 4d6c0c0

Browse files
authored
bpo-45871: Refactor except matcher validation into a separate function so that it can be reused. Add missing unit test. (GH-29711)
1 parent 0e1c2f3 commit 4d6c0c0

File tree

2 files changed

+48
-23
lines changed

2 files changed

+48
-23
lines changed

Lib/test/test_exceptions.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2401,6 +2401,21 @@ def test_incorrect_constructor(self):
24012401
self.assertRaises(TypeError, SyntaxError, "bad bad", args)
24022402

24032403

2404+
class TestInvalidExceptionMatcher(unittest.TestCase):
2405+
def test_except_star_invalid_exception_type(self):
2406+
with self.assertRaises(TypeError):
2407+
try:
2408+
raise ValueError
2409+
except 42:
2410+
pass
2411+
2412+
with self.assertRaises(TypeError):
2413+
try:
2414+
raise ValueError
2415+
except (ValueError, 42):
2416+
pass
2417+
2418+
24042419
class PEP626Tests(unittest.TestCase):
24052420

24062421
def lineno_after_raise(self, f, *expected):

Python/ceval.c

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ static int import_all_from(PyThreadState *, PyObject *, PyObject *);
9393
static void format_exc_check_arg(PyThreadState *, PyObject *, const char *, PyObject *);
9494
static void format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg);
9595
static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg);
96+
static int check_except_type_valid(PyThreadState *tstate, PyObject* right);
9697
static void format_kwargs_error(PyThreadState *, PyObject *func, PyObject *kwargs);
9798
static void format_awaitable_error(PyThreadState *, PyTypeObject *, int, int);
9899
static int get_exception_handler(PyCodeObject *, int, int*, int*, int*);
@@ -3715,31 +3716,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
37153716
}
37163717

37173718
TARGET(JUMP_IF_NOT_EXC_MATCH) {
3718-
const char *cannot_catch_msg = "catching classes that do not "
3719-
"inherit from BaseException is not "
3720-
"allowed";
37213719
PyObject *right = POP();
37223720
PyObject *left = TOP();
3723-
if (PyTuple_Check(right)) {
3724-
Py_ssize_t i, length;
3725-
length = PyTuple_GET_SIZE(right);
3726-
for (i = 0; i < length; i++) {
3727-
PyObject *exc = PyTuple_GET_ITEM(right, i);
3728-
if (!PyExceptionClass_Check(exc)) {
3729-
_PyErr_SetString(tstate, PyExc_TypeError,
3730-
cannot_catch_msg);
3731-
Py_DECREF(right);
3732-
goto error;
3733-
}
3734-
}
3735-
}
3736-
else {
3737-
if (!PyExceptionClass_Check(right)) {
3738-
_PyErr_SetString(tstate, PyExc_TypeError,
3739-
cannot_catch_msg);
3740-
Py_DECREF(right);
3741-
goto error;
3742-
}
3721+
if (check_except_type_valid(tstate, right) < 0) {
3722+
Py_DECREF(right);
3723+
goto error;
37433724
}
37443725
int res = PyErr_GivenExceptionMatches(left, right);
37453726
Py_DECREF(right);
@@ -6892,6 +6873,35 @@ import_all_from(PyThreadState *tstate, PyObject *locals, PyObject *v)
68926873
return err;
68936874
}
68946875

6876+
6877+
#define CANNOT_CATCH_MSG "catching classes that do not inherit from "\
6878+
"BaseException is not allowed"
6879+
6880+
static int
6881+
check_except_type_valid(PyThreadState *tstate, PyObject* right)
6882+
{
6883+
if (PyTuple_Check(right)) {
6884+
Py_ssize_t i, length;
6885+
length = PyTuple_GET_SIZE(right);
6886+
for (i = 0; i < length; i++) {
6887+
PyObject *exc = PyTuple_GET_ITEM(right, i);
6888+
if (!PyExceptionClass_Check(exc)) {
6889+
_PyErr_SetString(tstate, PyExc_TypeError,
6890+
CANNOT_CATCH_MSG);
6891+
return -1;
6892+
}
6893+
}
6894+
}
6895+
else {
6896+
if (!PyExceptionClass_Check(right)) {
6897+
_PyErr_SetString(tstate, PyExc_TypeError,
6898+
CANNOT_CATCH_MSG);
6899+
return -1;
6900+
}
6901+
}
6902+
return 0;
6903+
}
6904+
68956905
static int
68966906
check_args_iterable(PyThreadState *tstate, PyObject *func, PyObject *args)
68976907
{

0 commit comments

Comments
 (0)