diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -2,6 +2,7 @@ from test.support import run_unittest, run_with_locale import collections +import weakref import locale import sys import types @@ -1135,6 +1136,14 @@ with self.assertRaises(TypeError): ns['spam'] + def test_weakref(self): + ns1 = types.SimpleNamespace() + ns2 = types.SimpleNamespace() + ns2_proxy = weakref.proxy(ns2) + + self.assertIsNone(ns1.__weakref__) + self.assertEqual(ns2.__weakref__, ns2_proxy) + def test_main(): run_unittest(TypesTests, MappingProxyTests, ClassCreationTests, diff --git a/Objects/namespaceobject.c b/Objects/namespaceobject.c --- a/Objects/namespaceobject.c +++ b/Objects/namespaceobject.c @@ -7,11 +7,14 @@ typedef struct { PyObject_HEAD PyObject *ns_dict; + PyObject *ns_weakreflist; } _PyNamespaceObject; static PyMemberDef namespace_members[] = { {"__dict__", T_OBJECT, offsetof(_PyNamespaceObject, ns_dict), READONLY}, + {"__weakref__", T_OBJECT, offsetof(_PyNamespaceObject, ns_weakreflist), + READONLY}, {NULL} }; @@ -32,6 +35,8 @@ return NULL; } + ns->ns_weakreflist = NULL; + PyObject_GC_Track(ns); return (PyObject *)ns; } @@ -59,6 +64,9 @@ static void namespace_dealloc(_PyNamespaceObject *ns) { + if (ns->ns_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *)ns); + PyObject_GC_UnTrack(ns); Py_CLEAR(ns->ns_dict); Py_TYPE(ns)->tp_free((PyObject *)ns); @@ -165,45 +173,45 @@ PyTypeObject _PyNamespace_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - "namespace", /* tp_name */ - sizeof(_PyNamespaceObject), /* tp_size */ - 0, /* tp_itemsize */ - (destructor)namespace_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - (reprfunc)namespace_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - PyObject_GenericSetAttr, /* tp_setattro */ - 0, /* tp_as_buffer */ + "namespace", /* tp_name */ + sizeof(_PyNamespaceObject), /* tp_size */ + 0, /* tp_itemsize */ + (destructor)namespace_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc)namespace_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - namespace_doc, /* tp_doc */ - (traverseproc)namespace_traverse, /* tp_traverse */ - (inquiry)namespace_clear, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - namespace_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(_PyNamespaceObject, ns_dict), /* tp_dictoffset */ - (initproc)namespace_init, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - (newfunc)namespace_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ + Py_TPFLAGS_BASETYPE, /* tp_flags */ + namespace_doc, /* tp_doc */ + (traverseproc)namespace_traverse, /* tp_traverse */ + (inquiry)namespace_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(_PyNamespaceObject, ns_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + namespace_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(_PyNamespaceObject, ns_dict), /* tp_dictoffset */ + (initproc)namespace_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + (newfunc)namespace_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ };