diff options
author | Benjamin Peterson <benjamin@python.org> | 2010-10-12 23:06:22 (GMT) |
---|---|---|
committer | Benjamin Peterson <benjamin@python.org> | 2010-10-12 23:06:22 (GMT) |
commit | 582162e42ba4c944fa96c15a99de29ea96ea9ca3 (patch) | |
tree | cf2d9057a3ede1221810619875d1976ae36bcd02 | |
parent | 93f5cd42e7a2cc99a7a9670e7d0ea7db2290fcf3 (diff) | |
download | cpython-582162e42ba4c944fa96c15a99de29ea96ea9ca3.zip cpython-582162e42ba4c944fa96c15a99de29ea96ea9ca3.tar.gz cpython-582162e42ba4c944fa96c15a99de29ea96ea9ca3.tar.bz2 |
Merged revisions 85392 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/py3k
........
r85392 | benjamin.peterson | 2010-10-12 17:57:59 -0500 (Tue, 12 Oct 2010) | 1 line
prefer clearing global objects to obscure module.__dict__ bugs #10068
........
-rw-r--r-- | Doc/reference/datamodel.rst | 7 | ||||
-rw-r--r-- | Lib/test/test_module.py | 17 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Objects/moduleobject.c | 5 |
4 files changed, 27 insertions, 5 deletions
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 3d1d26d..9643f2b 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -654,6 +654,13 @@ Modules Special read-only attribute: :attr:`__dict__` is the module's namespace as a dictionary object. + .. impl-detail:: + + Because of the way CPython clears module dictionaries, the module + dictionary will be cleared when the module falls out of scope even if the + dictionary still has live references. To avoid this, copy the dictionary + or keep the module around while using its dictionary directly. + .. index:: single: __name__ (module attribute) single: __doc__ (module attribute) diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py index 21ddc9a..7734fb0 100644 --- a/Lib/test/test_module.py +++ b/Lib/test/test_module.py @@ -1,6 +1,6 @@ # Test the module type import unittest -from test.support import run_unittest +from test.support import run_unittest, gc_collect import sys ModuleType = type(sys) @@ -55,14 +55,29 @@ class ModuleTests(unittest.TestCase): {"__name__": "foo", "__doc__": "foodoc", "bar": 42}) self.assertTrue(foo.__dict__ is d) + @unittest.expectedFailure def test_dont_clear_dict(self): # See issue 7140. def f(): foo = ModuleType("foo") foo.bar = 4 return foo + gc_collect() self.assertEqual(f().__dict__["bar"], 4) + def test_clear_dict_in_ref_cycle(self): + destroyed = [] + m = ModuleType("foo") + m.destroyed = destroyed + s = """class A: + def __del__(self): + destroyed.append(1) +a = A()""" + exec(s, m.__dict__) + del m + gc_collect() + self.assertEqual(destroyed, [1]) + def test_main(): run_unittest(ModuleTests) @@ -46,6 +46,9 @@ Core and Builtins - Issue #83755: Implicit set-to-frozenset conversion was not thread-safe. +- Issue #10068: Global objects which have reference cycles with their module's + dict are now cleared again. This causes issue #7140 to appear again. + - Issue #9416: Fix some issues with complex formatting where the output with no type specifier failed to match the str output: diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index def3781..5dd9c01 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -312,10 +312,7 @@ module_dealloc(PyModuleObject *m) if (m->md_def && m->md_def->m_free) m->md_def->m_free(m); if (m->md_dict != NULL) { - /* If we are the only ones holding a reference, we can clear - the dictionary. */ - if (Py_REFCNT(m->md_dict) == 1) - _PyModule_Clear((PyObject *)m); + _PyModule_Clear((PyObject *)m); Py_DECREF(m->md_dict); } if (m->md_state != NULL) |