mirror of
https://github.com/python/cpython.git
synced 2025-08-01 07:33:08 +00:00
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.
This commit is contained in:
parent
bd53870d89
commit
c0ba52d3fd
2 changed files with 89 additions and 177 deletions
|
@ -1,6 +1,6 @@
|
||||||
# Test enhancements related to descriptors and new-style classes
|
# 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
|
from copy import deepcopy
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
@ -1466,89 +1466,65 @@ def dynamics():
|
||||||
verify(someclass != object)
|
verify(someclass != object)
|
||||||
|
|
||||||
def errors():
|
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):
|
try:
|
||||||
... pass
|
class C(list, dict):
|
||||||
Traceback (most recent call last):
|
pass
|
||||||
TypeError: Error when calling the metaclass bases
|
except TypeError:
|
||||||
multiple bases have instance lay-out conflict
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "inheritance from both list and dict should be illegal")
|
||||||
|
|
||||||
>>> class C(object, None):
|
try:
|
||||||
... pass
|
class C(object, None):
|
||||||
Traceback (most recent call last):
|
pass
|
||||||
TypeError: Error when calling the metaclass bases
|
except TypeError:
|
||||||
bases must be types
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "inheritance from non-type should be illegal")
|
||||||
|
class Classic:
|
||||||
|
pass
|
||||||
|
|
||||||
>>> class C(type(len)):
|
try:
|
||||||
... pass
|
class C(type(len)):
|
||||||
Traceback (most recent call last):
|
pass
|
||||||
TypeError: Error when calling the metaclass bases
|
except TypeError:
|
||||||
type 'builtin_function_or_method' is not an acceptable base type
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "inheritance from CFunction should be illegal")
|
||||||
|
|
||||||
>>> class Classic:
|
try:
|
||||||
... def __init__(*args): pass
|
class C(object):
|
||||||
>>> class C(object):
|
__slots__ = 1
|
||||||
... __metaclass__ = Classic
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "__slots__ = 1 should be illegal")
|
||||||
|
|
||||||
>>> class C(object):
|
try:
|
||||||
... __slots__ = 1
|
class C(object):
|
||||||
Traceback (most recent call last):
|
__slots__ = [1]
|
||||||
TypeError: Error when calling the metaclass bases
|
except TypeError:
|
||||||
'int' object is not iterable
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "__slots__ = [1] should be illegal")
|
||||||
|
|
||||||
>>> class C(object):
|
class M1(type):
|
||||||
... __slots__ = [1]
|
pass
|
||||||
Traceback (most recent call last):
|
class M2(type):
|
||||||
TypeError: Error when calling the metaclass bases
|
pass
|
||||||
__slots__ items must be strings, not 'int'
|
class A1(object):
|
||||||
|
__metaclass__ = M1
|
||||||
>>> class A(object):
|
class A2(object):
|
||||||
... pass
|
__metaclass__ = M2
|
||||||
|
try:
|
||||||
>>> class B(A, type):
|
class B(A1, A2):
|
||||||
... pass
|
pass
|
||||||
Traceback (most recent call last):
|
except TypeError:
|
||||||
TypeError: Error when calling the metaclass bases
|
pass
|
||||||
metaclass conflict: type must occur in bases before other non-classic base classes
|
else:
|
||||||
|
verify(0, "finding the most derived metaclass should have failed")
|
||||||
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
|
|
||||||
"""
|
|
||||||
|
|
||||||
def classmethods():
|
def classmethods():
|
||||||
if verbose: print "Testing class methods..."
|
if verbose: print "Testing class methods..."
|
||||||
|
@ -4331,6 +4307,7 @@ def test_main():
|
||||||
slots()
|
slots()
|
||||||
slotspecials()
|
slotspecials()
|
||||||
dynamics()
|
dynamics()
|
||||||
|
errors()
|
||||||
classmethods()
|
classmethods()
|
||||||
classmethods_in_c()
|
classmethods_in_c()
|
||||||
staticmethods()
|
staticmethods()
|
||||||
|
@ -4399,9 +4376,6 @@ def test_main():
|
||||||
notimplemented()
|
notimplemented()
|
||||||
test_assign_slice()
|
test_assign_slice()
|
||||||
|
|
||||||
from test import test_descr
|
|
||||||
run_doctest(test_descr, verbosity=True)
|
|
||||||
|
|
||||||
if verbose: print "All OK"
|
if verbose: print "All OK"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -127,7 +127,6 @@ type_get_bases(PyTypeObject *type, void *context)
|
||||||
return type->tp_bases;
|
return type->tp_bases;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyTypeObject *most_derived_metaclass(PyTypeObject *, PyObject *);
|
|
||||||
static PyTypeObject *best_base(PyObject *);
|
static PyTypeObject *best_base(PyObject *);
|
||||||
static int mro_internal(PyTypeObject *);
|
static int mro_internal(PyTypeObject *);
|
||||||
static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *);
|
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;
|
Py_ssize_t i;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
PyObject *ob, *temp;
|
PyObject *ob, *temp;
|
||||||
PyTypeObject *new_base, *old_base, *metatype;
|
PyTypeObject *new_base, *old_base;
|
||||||
PyObject *old_bases, *old_mro;
|
PyObject *old_bases, *old_mro;
|
||||||
|
|
||||||
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
|
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);
|
new_base = best_base(value);
|
||||||
|
|
||||||
if (!new_base) {
|
if (!new_base) {
|
||||||
|
@ -1367,14 +1355,7 @@ mro_internal(PyTypeObject *type)
|
||||||
|
|
||||||
|
|
||||||
/* Calculate the best base amongst multiple base classes.
|
/* Calculate the best base amongst multiple base classes.
|
||||||
This is the first one that's on the path to the "solid base".
|
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static PyTypeObject *
|
static PyTypeObject *
|
||||||
best_base(PyObject *bases)
|
best_base(PyObject *bases)
|
||||||
|
@ -1392,7 +1373,12 @@ best_base(PyObject *bases)
|
||||||
base_proto = PyTuple_GET_ITEM(bases, i);
|
base_proto = PyTuple_GET_ITEM(bases, i);
|
||||||
if (PyClass_Check(base_proto))
|
if (PyClass_Check(base_proto))
|
||||||
continue;
|
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;
|
base_i = (PyTypeObject *)base_proto;
|
||||||
if (base_i->tp_dict == NULL) {
|
if (base_i->tp_dict == NULL) {
|
||||||
if (PyType_Ready(base_i) < 0)
|
if (PyType_Ready(base_i) < 0)
|
||||||
|
@ -1445,8 +1431,6 @@ extra_ivars(PyTypeObject *type, PyTypeObject *base)
|
||||||
return t_size != b_size;
|
return t_size != b_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the type object that will determine the layout of the instance. */
|
|
||||||
|
|
||||||
static PyTypeObject *
|
static PyTypeObject *
|
||||||
solid_base(PyTypeObject *type)
|
solid_base(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
|
@ -1462,71 +1446,6 @@ solid_base(PyTypeObject *type)
|
||||||
return base;
|
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 void object_dealloc(PyObject *);
|
||||||
static int object_init(PyObject *, PyObject *, PyObject *);
|
static int object_init(PyObject *, PyObject *, PyObject *);
|
||||||
static int update_slot(PyTypeObject *, PyObject *);
|
static int update_slot(PyTypeObject *, PyObject *);
|
||||||
|
@ -1760,18 +1679,37 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
||||||
&PyDict_Type, &dict))
|
&PyDict_Type, &dict))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
winner = most_derived_metaclass(metatype, bases);
|
/* Determine the proper metatype to deal with this,
|
||||||
if (winner == NULL)
|
and check for metatype conflicts while we're at it.
|
||||||
return NULL;
|
Note that if some other metatype wins to contract,
|
||||||
if (winner != metatype) {
|
it's possible that its instances are not types. */
|
||||||
if (winner->tp_new != type_new) /* Pass it to the winner */ {
|
nbases = PyTuple_GET_SIZE(bases);
|
||||||
return winner->tp_new(winner, args, kwds);
|
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 */
|
||||||
|
return winner->tp_new(winner, args, kwds);
|
||||||
metatype = winner;
|
metatype = winner;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adjust for empty tuple bases */
|
/* Adjust for empty tuple bases */
|
||||||
nbases = PyTuple_GET_SIZE(bases);
|
|
||||||
if (nbases == 0) {
|
if (nbases == 0) {
|
||||||
bases = PyTuple_Pack(1, &PyBaseObject_Type);
|
bases = PyTuple_Pack(1, &PyBaseObject_Type);
|
||||||
if (bases == NULL)
|
if (bases == NULL)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue