[Python-checkins] r54875 - in python/trunk: Lib/test/test_descr.py Objects/typeobject.c

armin.rigo python-checkins at python.org
Thu Apr 19 16:44:54 CEST 2007


Author: armin.rigo
Date: Thu Apr 19 16:44:48 2007
New Revision: 54875
Modified:
 python/trunk/Lib/test/test_descr.py
 python/trunk/Objects/typeobject.c
Log:
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.
Modified: python/trunk/Lib/test/test_descr.py
==============================================================================
--- python/trunk/Lib/test/test_descr.py	(original)
+++ python/trunk/Lib/test/test_descr.py	Thu Apr 19 16:44:48 2007
@@ -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 @@
 verify(someclass != object)
 
 def errors():
- """Test that type can't be placed after an instance of type in bases.
+ if verbose: print "Testing errors..."
 
- >>> 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
- """
+ 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 @@
 slots()
 slotspecials()
 dynamics()
+ errors()
 classmethods()
 classmethods_in_c()
 staticmethods()
@@ -4399,9 +4376,6 @@
 notimplemented()
 test_assign_slice()
 
- from test import test_descr
- run_doctest(test_descr, verbosity=True)
-
 if verbose: print "All OK"
 
 if __name__ == "__main__":
Modified: python/trunk/Objects/typeobject.c
==============================================================================
--- python/trunk/Objects/typeobject.c	(original)
+++ python/trunk/Objects/typeobject.c	Thu Apr 19 16:44:48 2007
@@ -127,7 +127,6 @@
 	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 @@
 	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 @@
 		}
 	}
 
-
- 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 @@
 
 
 /* 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 @@
 		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 @@
 	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 @@
 		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 @@
 					 &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)


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /