From 52c36051bded16cf8616996e271a1aafbe2ec908 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Sat, 21 Aug 2010 03:03:22 +0000 Subject: Use weakrefs to hold onto classes #2521. This also causes the _weakref module to be built into the core. --- Lib/abc.py | 11 ++++++----- Lib/test/test_abc.py | 18 +++++++++++++++++- Misc/NEWS | 6 ++++++ Modules/Setup.dist | 1 + 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Lib/abc.py b/Lib/abc.py index 515ba08..02e48a1 100644 --- a/Lib/abc.py +++ b/Lib/abc.py @@ -5,6 +5,7 @@ import types +from _weakrefset import WeakSet # Instance of old-style class class _C: pass @@ -95,9 +96,9 @@ class ABCMeta(type): abstracts.add(name) cls.__abstractmethods__ = frozenset(abstracts) # Set up inheritance registry - cls._abc_registry = set() - cls._abc_cache = set() - cls._abc_negative_cache = set() + cls._abc_registry = WeakSet() + cls._abc_cache = WeakSet() + cls._abc_negative_cache = WeakSet() cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter return cls @@ -128,7 +129,7 @@ class ABCMeta(type): """Override for isinstance(instance, cls).""" # Inline the cache checking when it's simple. subclass = getattr(instance, '__class__', None) - if subclass in cls._abc_cache: + if subclass is not None and subclass in cls._abc_cache: return True subtype = type(instance) # Old-style instances @@ -152,7 +153,7 @@ class ABCMeta(type): # Check negative cache; may have to invalidate if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter: # Invalidate the negative cache - cls._abc_negative_cache = set() + cls._abc_negative_cache = WeakSet() cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter elif subclass in cls._abc_negative_cache: return False diff --git a/Lib/test/test_abc.py b/Lib/test/test_abc.py index b5af46b..6a8c3a1 100644 --- a/Lib/test/test_abc.py +++ b/Lib/test/test_abc.py @@ -3,7 +3,7 @@ """Unit tests for abc.py.""" -import unittest +import unittest, weakref from test import test_support import abc @@ -208,6 +208,22 @@ class TestABC(unittest.TestCase): C() self.assertEqual(B.counter, 1) + def test_cache_leak(self): + # See issue #2521. + class A(object): + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def f(self): + pass + class C(A): + def f(self): + A.f(self) + r = weakref.ref(C) + # Trigger cache. + C().f() + del C + test_support.gc_collect() + self.assertEqual(r(), None) def test_main(): test_support.run_unittest(TestABC) diff --git a/Misc/NEWS b/Misc/NEWS index 29bc276..349cc7f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -31,6 +31,9 @@ Core and Builtins Library ------- +- Issue #2521: Use weakrefs on for caching in the abc module, so that classes + are not held onto after they are deleted elsewhere. + - Issue #9626: the view methods for collections.OrderedDict() were returning the unordered versions inherited from dict. Those methods are now overridden to provide ordered views. @@ -188,6 +191,9 @@ Library Extension Modules ----------------- +- As a result of issue #2521, the _weakref module is now compiled into the + interpreter by default. + - Issue #9324: Add parameter validation to signal.signal on Windows in order to prevent crashes. diff --git a/Modules/Setup.dist b/Modules/Setup.dist index e76e0df..e2b0c59 100644 --- a/Modules/Setup.dist +++ b/Modules/Setup.dist @@ -118,6 +118,7 @@ pwd pwdmodule.c # this is needed to find out the user's home dir # if $HOME is not set _sre _sre.c # Fredrik Lundh's new regular expressions _codecs _codecsmodule.c # access to the builtin codecs and codec registry +_weakref _weakref.c # weak references # The zipimport module is always imported at startup. Having it as a # builtin module avoids some bootstrapping problems and reduces overhead. -- cgit v0.12