Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 582162e

Browse files
committed
Merged revisions 85392 via svnmerge from
svn+ssh://[email protected]/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 ........
1 parent 93f5cd4 commit 582162e

4 files changed

Lines changed: 27 additions & 5 deletions

File tree

Doc/reference/datamodel.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,13 @@ Modules
654654
Special read-only attribute: :attr:`__dict__` is the module's namespace as a
655655
dictionary object.
656656

657+
.. impl-detail::
658+
659+
Because of the way CPython clears module dictionaries, the module
660+
dictionary will be cleared when the module falls out of scope even if the
661+
dictionary still has live references. To avoid this, copy the dictionary
662+
or keep the module around while using its dictionary directly.
663+
657664
.. index::
658665
single: __name__ (module attribute)
659666
single: __doc__ (module attribute)

Lib/test/test_module.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Test the module type
22
import unittest
3-
from test.support import run_unittest
3+
from test.support import run_unittest, gc_collect
44

55
import sys
66
ModuleType = type(sys)
@@ -55,14 +55,29 @@ def test_reinit(self):
5555
{"__name__": "foo", "__doc__": "foodoc", "bar": 42})
5656
self.assertTrue(foo.__dict__ is d)
5757

58+
@unittest.expectedFailure
5859
def test_dont_clear_dict(self):
5960
# See issue 7140.
6061
def f():
6162
foo = ModuleType("foo")
6263
foo.bar = 4
6364
return foo
65+
gc_collect()
6466
self.assertEqual(f().__dict__["bar"], 4)
6567

68+
def test_clear_dict_in_ref_cycle(self):
69+
destroyed = []
70+
m = ModuleType("foo")
71+
m.destroyed = destroyed
72+
s = """class A:
73+
def __del__(self):
74+
destroyed.append(1)
75+
a = A()"""
76+
exec(s, m.__dict__)
77+
del m
78+
gc_collect()
79+
self.assertEqual(destroyed, [1])
80+
6681
def test_main():
6782
run_unittest(ModuleTests)
6883

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ Core and Builtins
4646

4747
- Issue #83755: Implicit set-to-frozenset conversion was not thread-safe.
4848

49+
- Issue #10068: Global objects which have reference cycles with their module's
50+
dict are now cleared again. This causes issue #7140 to appear again.
51+
4952
- Issue #9416: Fix some issues with complex formatting where the
5053
output with no type specifier failed to match the str output:
5154

Objects/moduleobject.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,7 @@ module_dealloc(PyModuleObject *m)
312312
if (m->md_def && m->md_def->m_free)
313313
m->md_def->m_free(m);
314314
if (m->md_dict != NULL) {
315-
/* If we are the only ones holding a reference, we can clear
316-
the dictionary. */
317-
if (Py_REFCNT(m->md_dict) == 1)
318-
_PyModule_Clear((PyObject *)m);
315+
_PyModule_Clear((PyObject *)m);
319316
Py_DECREF(m->md_dict);
320317
}
321318
if (m->md_state != NULL)

0 commit comments

Comments
 (0)