diff options
author | Armin Rigo <arigo@tunes.org> | 2007-04-19 14:44:48 (GMT) |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2007-04-19 14:44:48 (GMT) |
commit | c0ba52d3fd6a4d6211d5a1a4ffe96f1b96fffd74 (patch) | |
tree | 283cbfe475c55cd2010acfba4451dd6ec8678c70 | |
parent | bd53870d899fe3492fd4b1432df3f0ad24d0e287 (diff) | |
download | cpython-c0ba52d3fd6a4d6211d5a1a4ffe96f1b96fffd74.zip cpython-c0ba52d3fd6a4d6211d5a1a4ffe96f1b96fffd74.tar.gz cpython-c0ba52d3fd6a4d6211d5a1a4ffe96f1b96fffd74.tar.bz2 |
Revert r53997 as per
http://mail.python.org/pipermail/python-dev/2007-March/071796.html .
I've kept a couple of still-valid extra tests in test_descr, but didn't
bother to sort through the new comments and refactorings added in r53997
to see if some of them could be kept. If so, they could go in a
follow-up check-in.
-rw-r--r-- | Lib/test/test_descr.py | 148 | ||||
-rw-r--r-- | Objects/typeobject.c | 126 |
2 files changed, 93 insertions, 181 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index eda96a6..00a1dea 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1,6 +1,6 @@ # Test enhancements related to descriptors and new-style classes -from test.test_support import verify, vereq, verbose, TestFailed, TESTFN, get_original_stdout, run_doctest +from test.test_support import verify, vereq, verbose, TestFailed, TESTFN, get_original_stdout from copy import deepcopy import warnings @@ -1466,89 +1466,65 @@ def dynamics(): verify(someclass != object) def errors(): - """Test that type can't be placed after an instance of type in bases. - - >>> class C(list, dict): - ... pass - Traceback (most recent call last): - TypeError: Error when calling the metaclass bases - multiple bases have instance lay-out conflict - - >>> class C(object, None): - ... pass - Traceback (most recent call last): - TypeError: Error when calling the metaclass bases - bases must be types - - >>> class C(type(len)): - ... pass - Traceback (most recent call last): - TypeError: Error when calling the metaclass bases - type 'builtin_function_or_method' is not an acceptable base type - - >>> class Classic: - ... def __init__(*args): pass - >>> class C(object): - ... __metaclass__ = Classic - - >>> class C(object): - ... __slots__ = 1 - Traceback (most recent call last): - TypeError: Error when calling the metaclass bases - 'int' object is not iterable - - >>> class C(object): - ... __slots__ = [1] - Traceback (most recent call last): - TypeError: Error when calling the metaclass bases - __slots__ items must be strings, not 'int' - - >>> class A(object): - ... pass - - >>> class B(A, type): - ... pass - Traceback (most recent call last): - TypeError: Error when calling the metaclass bases - metaclass conflict: type must occur in bases before other non-classic base classes - - Create two different metaclasses in order to setup an error where - there is no inheritance relationship between the metaclass of a class - and the metaclass of its bases. - - >>> class M1(type): - ... pass - >>> class M2(type): - ... pass - >>> class A1(object): - ... __metaclass__ = M1 - >>> class A2(object): - ... __metaclass__ = M2 - >>> class B(A1, A2): - ... pass - Traceback (most recent call last): - TypeError: Error when calling the metaclass bases - metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases - >>> class B(A1): - ... pass - - Also check that assignment to bases is safe. - - >>> B.__bases__ = A1, A2 - Traceback (most recent call last): - TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases - >>> B.__bases__ = A2, - Traceback (most recent call last): - TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases - - >>> class M3(M1): - ... pass - >>> class C(object): - ... __metaclass__ = M3 - >>> B.__bases__ = C, - Traceback (most recent call last): - TypeError: assignment to __bases__ may not change metatype - """ + if verbose: print "Testing errors..." + + try: + class C(list, dict): + pass + except TypeError: + pass + else: + verify(0, "inheritance from both list and dict should be illegal") + + try: + class C(object, None): + pass + except TypeError: + pass + else: + verify(0, "inheritance from non-type should be illegal") + class Classic: + pass + + try: + class C(type(len)): + pass + except TypeError: + pass + else: + verify(0, "inheritance from CFunction should be illegal") + + try: + class C(object): + __slots__ = 1 + except TypeError: + pass + else: + verify(0, "__slots__ = 1 should be illegal") + + try: + class C(object): + __slots__ = [1] + except TypeError: + pass + else: + verify(0, "__slots__ = [1] should be illegal") + + class M1(type): + pass + class M2(type): + pass + class A1(object): + __metaclass__ = M1 + class A2(object): + __metaclass__ = M2 + try: + class B(A1, A2): + pass + except TypeError: + pass + else: + verify(0, "finding the most derived metaclass should have failed") def classmethods(): if verbose: print "Testing class methods..." @@ -4331,6 +4307,7 @@ def test_main(): slots() slotspecials() dynamics() + errors() classmethods() classmethods_in_c() staticmethods() @@ -4399,9 +4376,6 @@ def test_main(): notimplemented() test_assign_slice() - from test import test_descr - run_doctest(test_descr, verbosity=True) - if verbose: print "All OK" if __name__ == "__main__": diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 285bd67..a3b1476 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -127,7 +127,6 @@ type_get_bases(PyTypeObject *type, void *context) return type->tp_bases; } -static PyTypeObject *most_derived_metaclass(PyTypeObject *, PyObject *); static PyTypeObject *best_base(PyObject *); static int mro_internal(PyTypeObject *); static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); @@ -188,7 +187,7 @@ type_set_bases(PyTypeObject *type, PyObject *value, void *context) Py_ssize_t i; int r = 0; PyObject *ob, *temp; - PyTypeObject *new_base, *old_base, *metatype; + PyTypeObject *new_base, *old_base; PyObject *old_bases, *old_mro; if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { @@ -231,17 +230,6 @@ type_set_bases(PyTypeObject *type, PyObject *value, void *context) } } - - metatype = most_derived_metaclass(type->ob_type, value); - if (metatype == NULL) - return -1; - if (metatype != type->ob_type) { - PyErr_SetString(PyExc_TypeError, - "assignment to __bases__ may not change " - "metatype"); - return -1; - } - new_base = best_base(value); if (!new_base) { @@ -1367,14 +1355,7 @@ mro_internal(PyTypeObject *type) /* Calculate the best base amongst multiple base classes. - This is the first one that's on the path to the "solid base". - - Requires that all base classes be types or classic classes. - - Will return NULL with TypeError set if - 1) the base classes have conflicting layout instances, or - 2) all the bases are classic classes. -*/ + This is the first one that's on the path to the "solid base". */ static PyTypeObject * best_base(PyObject *bases) @@ -1392,7 +1373,12 @@ best_base(PyObject *bases) base_proto = PyTuple_GET_ITEM(bases, i); if (PyClass_Check(base_proto)) continue; - assert(PyType_Check(base_proto)); + if (!PyType_Check(base_proto)) { + PyErr_SetString( + PyExc_TypeError, + "bases must be types"); + return NULL; + } base_i = (PyTypeObject *)base_proto; if (base_i->tp_dict == NULL) { if (PyType_Ready(base_i) < 0) @@ -1445,8 +1431,6 @@ extra_ivars(PyTypeObject *type, PyTypeObject *base) return t_size != b_size; } -/* Return the type object that will determine the layout of the instance. */ - static PyTypeObject * solid_base(PyTypeObject *type) { @@ -1462,71 +1446,6 @@ solid_base(PyTypeObject *type) return base; } -/* Determine the proper metatype to deal with this, and check some - error cases while we're at it. Note that if some other metatype - wins to contract, it's possible that its instances are not types. - - Error cases of interest: 1. The metaclass is not a subclass of a - base class. 2. A non-type, non-classic base class appears before - type. -*/ - -static PyTypeObject * -most_derived_metaclass(PyTypeObject *metatype, PyObject *bases) -{ - Py_ssize_t nbases, i; - PyTypeObject *winner; - /* types_ordered: One of three states possible: - 0 type is in bases - 1 non-types also in bases - 2 type follows non-type in bases (error) - */ - int types_ordered = 0; - - nbases = PyTuple_GET_SIZE(bases); - winner = metatype; - for (i = 0; i < nbases; i++) { - PyObject *tmp = PyTuple_GET_ITEM(bases, i); - PyTypeObject *tmptype = tmp->ob_type; - if (tmptype == &PyClass_Type) - continue; /* Special case classic classes */ - if (!PyType_Check(tmp)) { - PyErr_SetString(PyExc_TypeError, - "bases must be types"); - return NULL; - } - if (PyObject_IsSubclass(tmp, (PyObject*)&PyType_Type)) { - if (types_ordered == 1) { - types_ordered = 2; - } - } - else if (!types_ordered) - types_ordered = 1; - if (winner == tmptype) - continue; - if (PyType_IsSubtype(winner, tmptype)) - continue; - if (PyType_IsSubtype(tmptype, winner)) { - winner = tmptype; - continue; - } - PyErr_SetString(PyExc_TypeError, - "metaclass conflict: " - "the metaclass of a derived class " - "must be a (non-strict) subclass " - "of the metaclasses of all its bases"); - return NULL; - } - if (types_ordered == 2) { - PyErr_SetString(PyExc_TypeError, - "metaclass conflict: " - "type must occur in bases before other " - "non-classic base classes"); - return NULL; - } - return winner; -} - static void object_dealloc(PyObject *); static int object_init(PyObject *, PyObject *, PyObject *); static int update_slot(PyTypeObject *, PyObject *); @@ -1760,18 +1679,37 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) &PyDict_Type, &dict)) return NULL; - winner = most_derived_metaclass(metatype, bases); - if (winner == NULL) + /* Determine the proper metatype to deal with this, + and check for metatype conflicts while we're at it. + Note that if some other metatype wins to contract, + it's possible that its instances are not types. */ + nbases = PyTuple_GET_SIZE(bases); + winner = metatype; + for (i = 0; i < nbases; i++) { + tmp = PyTuple_GET_ITEM(bases, i); + tmptype = tmp->ob_type; + if (tmptype == &PyClass_Type) + continue; /* Special case classic classes */ + if (PyType_IsSubtype(winner, tmptype)) + continue; + if (PyType_IsSubtype(tmptype, winner)) { + winner = tmptype; + continue; + } + PyErr_SetString(PyExc_TypeError, + "metaclass conflict: " + "the metaclass of a derived class " + "must be a (non-strict) subclass " + "of the metaclasses of all its bases"); return NULL; + } if (winner != metatype) { - if (winner->tp_new != type_new) /* Pass it to the winner */ { + if (winner->tp_new != type_new) /* Pass it to the winner */ return winner->tp_new(winner, args, kwds); - } metatype = winner; } /* Adjust for empty tuple bases */ - nbases = PyTuple_GET_SIZE(bases); if (nbases == 0) { bases = PyTuple_Pack(1, &PyBaseObject_Type); if (bases == NULL) |