Skip to content

Commit 373c741

Browse files
committed
Fix for SF bug #642358: only provide a new with a __dict__ or
__weaklist__ descriptor if we added __dict__ or __weaklist__, respectively. With unit test.
1 parent 145a4a0 commit 373c741

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

‎Lib/test/test_descr.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3686,6 +3686,19 @@ class E(C):
36863686
vereq(E(1) / C(1), "C.__div__")
36873687
vereq(C(1) / E(1), "C.__div__") # This one would fail
36883688

3689+
def dict_type_with_metaclass():
3690+
if verbose:
3691+
print "Testing type of __dict__ when __metaclass__ set..."
3692+
3693+
class B(object):
3694+
pass
3695+
class M(type):
3696+
pass
3697+
class C:
3698+
# In 2.3a1, C.__dict__ was a real dict rather than a dict proxy
3699+
__metaclass__ = M
3700+
veris(type(C.__dict__), type(B.__dict__))
3701+
36893702

36903703
def test_main():
36913704
do_this_first()
@@ -3771,6 +3784,7 @@ def test_main():
37713784
test_mutable_bases_catch_mro_conflict()
37723785
mutable_names()
37733786
subclass_right_op()
3787+
dict_type_with_metaclass()
37743788

37753789
if verbose: print "All OK"
37763790

‎Objects/typeobject.c‎

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,16 +1353,28 @@ subtype_getweakref(PyObject *obj, void *context)
13531353
return result;
13541354
}
13551355

1356-
static PyGetSetDef subtype_getsets[] = {
1357-
/* Not all objects have these attributes!
1358-
The descriptor's __get__ method may raise AttributeError. */
1356+
/* Three variants on the subtype_getsets list. */
1357+
1358+
static PyGetSetDef subtype_getsets_full[] = {
13591359
{"__dict__", subtype_dict, subtype_setdict,
13601360
PyDoc_STR("dictionary for instance variables (if defined)")},
13611361
{"__weakref__", subtype_getweakref, NULL,
13621362
PyDoc_STR("list of weak references to the object (if defined)")},
13631363
{0}
13641364
};
13651365

1366+
static PyGetSetDef subtype_getsets_dict_only[] = {
1367+
{"__dict__", subtype_dict, subtype_setdict,
1368+
PyDoc_STR("dictionary for instance variables (if defined)")},
1369+
{0}
1370+
};
1371+
1372+
static PyGetSetDef subtype_getsets_weakref_only[] = {
1373+
{"__weakref__", subtype_getweakref, NULL,
1374+
PyDoc_STR("list of weak references to the object (if defined)")},
1375+
{0}
1376+
};
1377+
13661378
/* bozo: __getstate__ that raises TypeError */
13671379

13681380
static PyObject *
@@ -1810,7 +1822,15 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
18101822
type->tp_basicsize = slotoffset;
18111823
type->tp_itemsize = base->tp_itemsize;
18121824
type->tp_members = et->members;
1813-
type->tp_getset = subtype_getsets;
1825+
1826+
if (type->tp_weaklistoffset && type->tp_dictoffset)
1827+
type->tp_getset = subtype_getsets_full;
1828+
else if (type->tp_weaklistoffset && !type->tp_dictoffset)
1829+
type->tp_getset = subtype_getsets_weakref_only;
1830+
else if (!type->tp_weaklistoffset && type->tp_dictoffset)
1831+
type->tp_getset = subtype_getsets_dict_only;
1832+
else
1833+
type->tp_getset = NULL;
18141834

18151835
/* Special case some slots */
18161836
if (type->tp_dictoffset != 0 || nslots > 0) {

0 commit comments

Comments
 (0)