]> granicus.if.org Git - python/commitdiff
Revert r53997 as per
authorArmin Rigo <arigo@tunes.org>
Thu, 19 Apr 2007 14:44:48 +0000 (14:44 +0000)
committerArmin Rigo <arigo@tunes.org>
Thu, 19 Apr 2007 14:44:48 +0000 (14:44 +0000)
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.

Lib/test/test_descr.py
Objects/typeobject.c

index eda96a6bd9991eead57f1794c6e5fd434d474956..00a1deaa9da089885ea5ef697188f5497a01a15a 100644 (file)
@@ -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__":
index 285bd67fccd24a7c575eb82b7c51aaee2236062e..a3b1476a8d50c416d5b59e447ab9bebceac8baf4 100644 (file)
@@ -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)