mirror of
https://github.com/python/cpython.git
synced 2025-10-31 21:51:50 +00:00
bpo-31588: Validate return value of __prepare__() methods (GH-3764)
Class execution requires that __prepare__() methods return a proper execution namespace. Check for that immediately after calling __prepare__(), rather than passing it through to the code execution machinery and potentially triggering SystemError (in debug builds) or a cryptic TypeError (in release builds). Patch by Oren Milman.
This commit is contained in:
parent
236329ed9f
commit
5837d0418f
3 changed files with 31 additions and 0 deletions
|
|
@ -864,6 +864,28 @@ def __prepare__(*args):
|
||||||
self.assertIs(ns, expected_ns)
|
self.assertIs(ns, expected_ns)
|
||||||
self.assertEqual(len(kwds), 0)
|
self.assertEqual(len(kwds), 0)
|
||||||
|
|
||||||
|
def test_bad___prepare__(self):
|
||||||
|
# __prepare__() must return a mapping.
|
||||||
|
class BadMeta(type):
|
||||||
|
@classmethod
|
||||||
|
def __prepare__(*args):
|
||||||
|
return None
|
||||||
|
with self.assertRaisesRegex(TypeError,
|
||||||
|
r'^BadMeta\.__prepare__\(\) must '
|
||||||
|
r'return a mapping, not NoneType$'):
|
||||||
|
class Foo(metaclass=BadMeta):
|
||||||
|
pass
|
||||||
|
# Also test the case in which the metaclass is not a type.
|
||||||
|
class BadMeta:
|
||||||
|
@classmethod
|
||||||
|
def __prepare__(*args):
|
||||||
|
return None
|
||||||
|
with self.assertRaisesRegex(TypeError,
|
||||||
|
r'^<metaclass>\.__prepare__\(\) must '
|
||||||
|
r'return a mapping, not NoneType$'):
|
||||||
|
class Bar(metaclass=BadMeta()):
|
||||||
|
pass
|
||||||
|
|
||||||
def test_metaclass_derivation(self):
|
def test_metaclass_derivation(self):
|
||||||
# issue1294232: correct metaclass calculation
|
# issue1294232: correct metaclass calculation
|
||||||
new_calls = [] # to check the order of __new__ calls
|
new_calls = [] # to check the order of __new__ calls
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
Raise a `TypeError` with a helpful error message when class creation fails
|
||||||
|
due to a metaclass with a bad ``__prepare__()`` method. Patch by Oren Milman.
|
||||||
|
|
@ -157,6 +157,13 @@ builtin___build_class__(PyObject *self, PyObject **args, Py_ssize_t nargs,
|
||||||
Py_DECREF(bases);
|
Py_DECREF(bases);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (!PyMapping_Check(ns)) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"%.200s.__prepare__() must return a mapping, not %.200s",
|
||||||
|
isclass ? ((PyTypeObject *)meta)->tp_name : "<metaclass>",
|
||||||
|
Py_TYPE(ns)->tp_name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
cell = PyEval_EvalCodeEx(PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), ns,
|
cell = PyEval_EvalCodeEx(PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), ns,
|
||||||
NULL, 0, NULL, 0, NULL, 0, NULL,
|
NULL, 0, NULL, 0, NULL, 0, NULL,
|
||||||
PyFunction_GET_CLOSURE(func));
|
PyFunction_GET_CLOSURE(func));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue