mirror of https://github.com/python/cpython
Convert the weakref test suite to PyUNIT, and add tests that exercise weak
references on function objects and both bound and unbound methods.
This commit is contained in:
parent
84a5934f8a
commit
b0fefc5121
|
@ -1,25 +1 @@
|
||||||
test_weakref
|
test_weakref
|
||||||
Basic Weak References
|
|
||||||
-- Liveness and referent identity
|
|
||||||
-- Reference objects with callbacks
|
|
||||||
-- Proxy objects with callbacks
|
|
||||||
-- Re-use of weak reference objects
|
|
||||||
reference objects
|
|
||||||
proxy objects
|
|
||||||
clearing ref 2
|
|
||||||
clearing ref 1
|
|
||||||
clearing ref 2
|
|
||||||
clearing ref 1
|
|
||||||
|
|
||||||
Weak Valued Dictionaries
|
|
||||||
objects are stored in weak dict
|
|
||||||
weak dict test complete
|
|
||||||
|
|
||||||
Weak Keyed Dictionaries
|
|
||||||
objects are stored in weak dict
|
|
||||||
weak key dict test complete
|
|
||||||
|
|
||||||
Non-callable Proxy References
|
|
||||||
XXX -- tests not written!
|
|
||||||
|
|
||||||
Callable Proxy References
|
|
||||||
|
|
|
@ -1,137 +1,202 @@
|
||||||
import sys
|
import sys
|
||||||
|
import unittest
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
from test_support import TestFailed, verify
|
from test_support import run_unittest, verify
|
||||||
|
|
||||||
|
|
||||||
class C:
|
class C:
|
||||||
|
def method(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
print "Basic Weak References"
|
class Callable:
|
||||||
|
bar = None
|
||||||
|
|
||||||
print "-- Liveness and referent identity"
|
def __call__(self, x):
|
||||||
|
self.bar = x
|
||||||
|
|
||||||
|
|
||||||
|
def create_function():
|
||||||
|
def f(): pass
|
||||||
|
return f
|
||||||
|
|
||||||
|
def create_bound_method():
|
||||||
|
return C().method
|
||||||
|
|
||||||
|
def create_unbound_method():
|
||||||
|
return C.method
|
||||||
|
|
||||||
|
|
||||||
|
class TestBase(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.cbcalled = 0
|
||||||
|
|
||||||
|
def callback(self, ref):
|
||||||
|
self.cbcalled += 1
|
||||||
|
|
||||||
|
|
||||||
|
class ReferencesTestCase(TestBase):
|
||||||
|
|
||||||
|
def test_basic_ref(self):
|
||||||
|
self.check_basic_ref(C)
|
||||||
|
self.check_basic_ref(create_function)
|
||||||
|
self.check_basic_ref(create_bound_method)
|
||||||
|
self.check_basic_ref(create_unbound_method)
|
||||||
|
|
||||||
|
def test_basic_callback(self):
|
||||||
|
self.check_basic_callback(C)
|
||||||
|
self.check_basic_callback(create_function)
|
||||||
|
self.check_basic_callback(create_bound_method)
|
||||||
|
self.check_basic_callback(create_unbound_method)
|
||||||
|
|
||||||
|
def test_multiple_callbacks(self):
|
||||||
o = C()
|
o = C()
|
||||||
|
ref1 = weakref.ref(o, self.callback)
|
||||||
|
ref2 = weakref.ref(o, self.callback)
|
||||||
|
del o
|
||||||
|
self.assert_(ref1() is None,
|
||||||
|
"expected reference to be invalidated")
|
||||||
|
self.assert_(ref2() is None,
|
||||||
|
"expected reference to be invalidated")
|
||||||
|
self.assert_(self.cbcalled == 2,
|
||||||
|
"callback not called the right number of times")
|
||||||
|
|
||||||
|
def test_proxy_ref(self):
|
||||||
|
o = C()
|
||||||
|
o.bar = 1
|
||||||
|
ref1 = weakref.proxy(o, self.callback)
|
||||||
|
ref2 = weakref.proxy(o, self.callback)
|
||||||
|
del o
|
||||||
|
|
||||||
|
def check(proxy):
|
||||||
|
proxy.bar
|
||||||
|
|
||||||
|
self.assertRaises(weakref.ReferenceError, check, ref1)
|
||||||
|
self.assertRaises(weakref.ReferenceError, check, ref2)
|
||||||
|
self.assert_(self.cbcalled == 2)
|
||||||
|
|
||||||
|
def check_basic_ref(self, factory):
|
||||||
|
o = factory()
|
||||||
ref = weakref.ref(o)
|
ref = weakref.ref(o)
|
||||||
verify(ref() is not None, "weak reference to live object should be live")
|
self.assert_(ref() is not None,
|
||||||
|
"weak reference to live object should be live")
|
||||||
o2 = ref()
|
o2 = ref()
|
||||||
verify(ref() is not None, "weak ref should still be live")
|
self.assert_(o is o2,
|
||||||
verify(o is o2, "<ref>() should return original object if live")
|
"<ref>() should return original object if live")
|
||||||
del o, o2
|
|
||||||
del ref
|
|
||||||
|
|
||||||
cbcalled = 0
|
def check_basic_callback(self, factory):
|
||||||
def callback(o):
|
self.cbcalled = 0
|
||||||
global cbcalled
|
o = factory()
|
||||||
cbcalled = 1
|
ref = weakref.ref(o, self.callback)
|
||||||
|
|
||||||
o = C()
|
|
||||||
ref2 = weakref.ref(o, callback)
|
|
||||||
del o
|
del o
|
||||||
verify(cbcalled,
|
verify(self.cbcalled == 1,
|
||||||
"callback did not properly set 'cbcalled'")
|
"callback did not properly set 'cbcalled'")
|
||||||
verify(ref2() is None,
|
verify(ref() is None,
|
||||||
"ref2 should be dead after deleting object reference")
|
"ref2 should be dead after deleting object reference")
|
||||||
del ref2
|
|
||||||
|
|
||||||
|
|
||||||
print "-- Reference objects with callbacks"
|
|
||||||
o = C()
|
|
||||||
o.bar = 1
|
|
||||||
ref1 = weakref.ref(o, id)
|
|
||||||
ref2 = weakref.ref(o, id)
|
|
||||||
del o
|
|
||||||
verify(ref1() is None,
|
|
||||||
"expected reference to be invalidated")
|
|
||||||
verify(ref2() is None,
|
|
||||||
"expected reference to be invalidated")
|
|
||||||
|
|
||||||
|
|
||||||
print "-- Proxy objects with callbacks"
|
|
||||||
o = C()
|
|
||||||
o.bar = 1
|
|
||||||
ref1 = weakref.proxy(o, id)
|
|
||||||
ref2 = weakref.proxy(o, id)
|
|
||||||
del o
|
|
||||||
try:
|
|
||||||
ref1.bar
|
|
||||||
except weakref.ReferenceError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise TestFailed("expected ReferenceError exception")
|
|
||||||
try:
|
|
||||||
ref2.bar
|
|
||||||
except weakref.ReferenceError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise TestFailed("expected ReferenceError exception")
|
|
||||||
|
|
||||||
|
|
||||||
print "-- Re-use of weak reference objects"
|
|
||||||
print " reference objects"
|
|
||||||
|
|
||||||
|
def test_ref_reuse(self):
|
||||||
o = C()
|
o = C()
|
||||||
ref1 = weakref.ref(o)
|
ref1 = weakref.ref(o)
|
||||||
# create a proxy to make sure that there's an intervening creation
|
# create a proxy to make sure that there's an intervening creation
|
||||||
# between these two; it should make no difference
|
# between these two; it should make no difference
|
||||||
proxy = weakref.proxy(o)
|
proxy = weakref.proxy(o)
|
||||||
ref2 = weakref.ref(o)
|
ref2 = weakref.ref(o)
|
||||||
verify(ref1 is ref2,
|
self.assert_(ref1 is ref2,
|
||||||
"reference object w/out callback should have been re-used")
|
"reference object w/out callback should be re-used")
|
||||||
|
|
||||||
o = C()
|
o = C()
|
||||||
proxy = weakref.proxy(o)
|
proxy = weakref.proxy(o)
|
||||||
ref1 = weakref.ref(o)
|
ref1 = weakref.ref(o)
|
||||||
ref2 = weakref.ref(o)
|
ref2 = weakref.ref(o)
|
||||||
verify(ref1 is ref2,
|
self.assert_(ref1 is ref2,
|
||||||
"reference object w/out callback should have been re-used")
|
"reference object w/out callback should be re-used")
|
||||||
verify(weakref.getweakrefcount(o) == 2,
|
self.assert_(weakref.getweakrefcount(o) == 2,
|
||||||
"wrong weak ref count for object")
|
"wrong weak ref count for object")
|
||||||
del proxy
|
del proxy
|
||||||
verify(weakref.getweakrefcount(o) == 1,
|
self.assert_(weakref.getweakrefcount(o) == 1,
|
||||||
"wrong weak ref count for object after deleting proxy")
|
"wrong weak ref count for object after deleting proxy")
|
||||||
|
|
||||||
print " proxy objects"
|
def test_proxy_reuse(self):
|
||||||
|
|
||||||
o = C()
|
o = C()
|
||||||
ref3 = weakref.proxy(o)
|
proxy1 = weakref.proxy(o)
|
||||||
ref4 = weakref.proxy(o)
|
ref = weakref.ref(o)
|
||||||
verify(ref3 is ref4,
|
proxy2 = weakref.proxy(o)
|
||||||
|
self.assert_(proxy1 is proxy2,
|
||||||
"proxy object w/out callback should have been re-used")
|
"proxy object w/out callback should have been re-used")
|
||||||
|
|
||||||
|
def test_basic_proxy(self):
|
||||||
def clearing1(r):
|
|
||||||
print "clearing ref 1"
|
|
||||||
|
|
||||||
def clearing2(r):
|
|
||||||
print "clearing ref 2"
|
|
||||||
|
|
||||||
o = C()
|
o = C()
|
||||||
ref1 = weakref.ref(o, clearing1)
|
self.check_proxy(o, weakref.proxy(o))
|
||||||
ref2 = weakref.ref(o, clearing2)
|
|
||||||
verify(weakref.getweakrefcount(o) == 2,
|
def test_callable_proxy(self):
|
||||||
|
o = Callable()
|
||||||
|
ref1 = weakref.proxy(o)
|
||||||
|
|
||||||
|
self.check_proxy(o, ref1)
|
||||||
|
|
||||||
|
self.assert_(type(ref1) is weakref.CallableProxyType,
|
||||||
|
"proxy is not of callable type")
|
||||||
|
ref1('twinkies!')
|
||||||
|
self.assert_(o.bar == 'twinkies!',
|
||||||
|
"call through proxy not passed through to original")
|
||||||
|
|
||||||
|
# expect due to too few args
|
||||||
|
self.assertRaises(TypeError, ref1)
|
||||||
|
|
||||||
|
# expect due to too many args
|
||||||
|
self.assertRaises(TypeError, ref1, 1, 2, 3)
|
||||||
|
|
||||||
|
def check_proxy(self, o, proxy):
|
||||||
|
o.foo = 1
|
||||||
|
self.assert_(proxy.foo == 1,
|
||||||
|
"proxy does not reflect attribute addition")
|
||||||
|
o.foo = 2
|
||||||
|
self.assert_(proxy.foo == 2,
|
||||||
|
"proxy does not reflect attribute modification")
|
||||||
|
del o.foo
|
||||||
|
self.assert_(not hasattr(proxy, 'foo'),
|
||||||
|
"proxy does not reflect attribute removal")
|
||||||
|
|
||||||
|
proxy.foo = 1
|
||||||
|
self.assert_(o.foo == 1,
|
||||||
|
"object does not reflect attribute addition via proxy")
|
||||||
|
proxy.foo = 2
|
||||||
|
self.assert_(
|
||||||
|
o.foo == 2,
|
||||||
|
"object does not reflect attribute modification via proxy")
|
||||||
|
del proxy.foo
|
||||||
|
self.assert_(not hasattr(o, 'foo'),
|
||||||
|
"object does not reflect attribute removal via proxy")
|
||||||
|
|
||||||
|
def test_getweakrefcount(self):
|
||||||
|
o = C()
|
||||||
|
ref1 = weakref.ref(o)
|
||||||
|
ref2 = weakref.ref(o, self.callback)
|
||||||
|
self.assert_(weakref.getweakrefcount(o) == 2,
|
||||||
"got wrong number of weak reference objects")
|
"got wrong number of weak reference objects")
|
||||||
del o
|
|
||||||
|
|
||||||
|
proxy1 = weakref.proxy(o)
|
||||||
|
proxy2 = weakref.proxy(o, self.callback)
|
||||||
|
self.assert_(weakref.getweakrefcount(o) == 4,
|
||||||
|
"got wrong number of weak reference objects")
|
||||||
|
|
||||||
|
def test_getweakrefs(self):
|
||||||
o = C()
|
o = C()
|
||||||
ref1 = weakref.ref(o, clearing1)
|
ref1 = weakref.ref(o, self.callback)
|
||||||
ref2 = weakref.ref(o, clearing2)
|
ref2 = weakref.ref(o, self.callback)
|
||||||
del ref1
|
del ref1
|
||||||
verify(weakref.getweakrefs(o) == [ref2],
|
self.assert_(weakref.getweakrefs(o) == [ref2],
|
||||||
"list of refs does not match")
|
"list of refs does not match")
|
||||||
del o
|
|
||||||
|
|
||||||
o = C()
|
o = C()
|
||||||
ref1 = weakref.ref(o, clearing1)
|
ref1 = weakref.ref(o, self.callback)
|
||||||
ref2 = weakref.ref(o, clearing2)
|
ref2 = weakref.ref(o, self.callback)
|
||||||
del ref2
|
del ref2
|
||||||
verify(weakref.getweakrefs(o) == [ref1],
|
self.assert_(weakref.getweakrefs(o) == [ref1],
|
||||||
"list of refs does not match")
|
"list of refs does not match")
|
||||||
del o
|
|
||||||
|
|
||||||
print
|
|
||||||
print "Weak Valued Dictionaries"
|
|
||||||
|
|
||||||
class Object:
|
class Object:
|
||||||
def __init__(self, arg):
|
def __init__(self, arg):
|
||||||
|
@ -139,112 +204,63 @@ class Object:
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Object %r>" % self.arg
|
return "<Object %r>" % self.arg
|
||||||
|
|
||||||
|
|
||||||
|
class MappingTestCase(TestBase):
|
||||||
|
|
||||||
|
COUNT = 10
|
||||||
|
|
||||||
|
def test_weak_values(self):
|
||||||
dict = weakref.mapping()
|
dict = weakref.mapping()
|
||||||
objects = map(Object, range(10))
|
objects = map(Object, range(self.COUNT))
|
||||||
for o in objects:
|
for o in objects:
|
||||||
dict[o.arg] = o
|
dict[o.arg] = o
|
||||||
print "objects are stored in weak dict"
|
|
||||||
for o in objects:
|
for o in objects:
|
||||||
verify(weakref.getweakrefcount(o) == 1,
|
self.assert_(weakref.getweakrefcount(o) == 1,
|
||||||
"wrong number of weak references to %r!" % o)
|
"wrong number of weak references to %r!" % o)
|
||||||
verify(o is dict[o.arg],
|
self.assert_(o is dict[o.arg],
|
||||||
"wrong object returned by weak dict!")
|
"wrong object returned by weak dict!")
|
||||||
items1 = dict.items()
|
items1 = dict.items()
|
||||||
items2 = dict.copy().items()
|
items2 = dict.copy().items()
|
||||||
items1.sort()
|
items1.sort()
|
||||||
items2.sort()
|
items2.sort()
|
||||||
verify(items1 == items2,
|
self.assert_(items1 == items2,
|
||||||
"cloning of weak-valued dictionary did not work!")
|
"cloning of weak-valued dictionary did not work!")
|
||||||
del items1, items2
|
del items1, items2
|
||||||
dict.clear()
|
self.assert_(len(dict) == self.COUNT)
|
||||||
print "weak dict test complete"
|
del objects[0]
|
||||||
|
self.assert_(len(dict) == (self.COUNT - 1),
|
||||||
print
|
"deleting object did not cause dictionary update")
|
||||||
print "Weak Keyed Dictionaries"
|
del objects, o
|
||||||
|
self.assert_(len(dict) == 0,
|
||||||
|
"deleting the values did not clear the dictionary")
|
||||||
|
|
||||||
|
def test_weak_keys(self):
|
||||||
dict = weakref.mapping(weakkeys=1)
|
dict = weakref.mapping(weakkeys=1)
|
||||||
objects = map(Object, range(10))
|
objects = map(Object, range(self.COUNT))
|
||||||
for o in objects:
|
for o in objects:
|
||||||
dict[o] = o.arg
|
dict[o] = o.arg
|
||||||
print "objects are stored in weak dict"
|
|
||||||
for o in objects:
|
for o in objects:
|
||||||
verify(weakref.getweakrefcount(o) == 1,
|
self.assert_(weakref.getweakrefcount(o) == 1,
|
||||||
"wrong number of weak references to %r!" % o)
|
"wrong number of weak references to %r!" % o)
|
||||||
verify(o.arg is dict[o],
|
self.assert_(o.arg is dict[o],
|
||||||
"wrong object returned by weak dict!")
|
"wrong object returned by weak dict!")
|
||||||
items1 = dict.items()
|
items1 = dict.items()
|
||||||
items2 = dict.copy().items()
|
items2 = dict.copy().items()
|
||||||
items1.sort()
|
items1.sort()
|
||||||
items2.sort()
|
items2.sort()
|
||||||
verify(items1 == items2,
|
self.assert_(items1 == items2,
|
||||||
"cloning of weak-keyed dictionary did not work!")
|
"cloning of weak-keyed dictionary did not work!")
|
||||||
del items1, items2
|
del items1, items2
|
||||||
|
self.assert_(len(dict) == self.COUNT)
|
||||||
|
del objects[0]
|
||||||
|
self.assert_(len(dict) == (self.COUNT - 1),
|
||||||
|
"deleting object did not cause dictionary update")
|
||||||
del objects, o
|
del objects, o
|
||||||
verify(len(dict)==0, "deleting the keys did not clear the dictionary")
|
self.assert_(len(dict) == 0,
|
||||||
print "weak key dict test complete"
|
"deleting the keys did not clear the dictionary")
|
||||||
|
|
||||||
|
|
||||||
print
|
run_unittest(ReferencesTestCase)
|
||||||
print "Non-callable Proxy References"
|
run_unittest(MappingTestCase)
|
||||||
print "XXX -- tests not written!"
|
|
||||||
|
|
||||||
|
|
||||||
def test_proxy(o, proxy):
|
|
||||||
o.foo = 1
|
|
||||||
verify(proxy.foo == 1,
|
|
||||||
"proxy does not reflect attribute addition")
|
|
||||||
o.foo = 2
|
|
||||||
verify(proxy.foo == 2,
|
|
||||||
"proxy does not reflect attribute modification")
|
|
||||||
del o.foo
|
|
||||||
verify(not hasattr(proxy, 'foo'),
|
|
||||||
"proxy does not reflect attribute removal")
|
|
||||||
|
|
||||||
proxy.foo = 1
|
|
||||||
verify(o.foo == 1,
|
|
||||||
"object does not reflect attribute addition via proxy")
|
|
||||||
proxy.foo = 2
|
|
||||||
verify(o.foo == 2,
|
|
||||||
"object does not reflect attribute modification via proxy")
|
|
||||||
del proxy.foo
|
|
||||||
verify(not hasattr(o, 'foo'),
|
|
||||||
"object does not reflect attribute removal via proxy")
|
|
||||||
|
|
||||||
|
|
||||||
o = C()
|
|
||||||
test_proxy(o, weakref.proxy(o))
|
|
||||||
|
|
||||||
print
|
|
||||||
print "Callable Proxy References"
|
|
||||||
|
|
||||||
class Callable:
|
|
||||||
bar = None
|
|
||||||
def __call__(self, x):
|
|
||||||
self.bar = x
|
|
||||||
|
|
||||||
o = Callable()
|
|
||||||
ref1 = weakref.proxy(o)
|
|
||||||
|
|
||||||
test_proxy(o, ref1)
|
|
||||||
|
|
||||||
verify(type(ref1) is weakref.CallableProxyType,
|
|
||||||
"proxy is not of callable type")
|
|
||||||
ref1('twinkies!')
|
|
||||||
verify(o.bar == 'twinkies!',
|
|
||||||
"call through proxy not passed through to original")
|
|
||||||
|
|
||||||
try:
|
|
||||||
ref1()
|
|
||||||
except TypeError:
|
|
||||||
# expect due to too few args
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise TestFailed("did not catch expected TypeError -- too few args")
|
|
||||||
|
|
||||||
try:
|
|
||||||
ref1(1, 2, 3)
|
|
||||||
except TypeError:
|
|
||||||
# expect due to too many args
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise TestFailed("did not catch expected TypeError -- too many args")
|
|
||||||
|
|
Loading…
Reference in New Issue