/Lib/test/test_weakref.py

http://unladen-swallow.googlecode.com/ · Python · 1227 lines · 876 code · 177 blank · 174 comment · 31 complexity · bbbf9b9e02f53255a9be72e4f244359d MD5 · raw file

  1. import gc
  2. import sys
  3. import unittest
  4. import UserList
  5. import weakref
  6. import operator
  7. from test import test_support
  8. # Used in ReferencesTestCase.test_ref_created_during_del() .
  9. ref_from_del = None
  10. class C:
  11. def method(self):
  12. pass
  13. class Callable:
  14. bar = None
  15. def __call__(self, x):
  16. self.bar = x
  17. def create_function():
  18. def f(): pass
  19. return f
  20. def create_bound_method():
  21. return C().method
  22. def create_unbound_method():
  23. return C.method
  24. class TestBase(unittest.TestCase):
  25. def setUp(self):
  26. self.cbcalled = 0
  27. def callback(self, ref):
  28. self.cbcalled += 1
  29. class ReferencesTestCase(TestBase):
  30. def test_basic_ref(self):
  31. self.check_basic_ref(C)
  32. self.check_basic_ref(create_function)
  33. self.check_basic_ref(create_bound_method)
  34. self.check_basic_ref(create_unbound_method)
  35. # Just make sure the tp_repr handler doesn't raise an exception.
  36. # Live reference:
  37. o = C()
  38. wr = weakref.ref(o)
  39. `wr`
  40. # Dead reference:
  41. del o
  42. `wr`
  43. def test_basic_callback(self):
  44. self.check_basic_callback(C)
  45. self.check_basic_callback(create_function)
  46. self.check_basic_callback(create_bound_method)
  47. self.check_basic_callback(create_unbound_method)
  48. def test_multiple_callbacks(self):
  49. o = C()
  50. ref1 = weakref.ref(o, self.callback)
  51. ref2 = weakref.ref(o, self.callback)
  52. del o
  53. self.assert_(ref1() is None,
  54. "expected reference to be invalidated")
  55. self.assert_(ref2() is None,
  56. "expected reference to be invalidated")
  57. self.assert_(self.cbcalled == 2,
  58. "callback not called the right number of times")
  59. def test_multiple_selfref_callbacks(self):
  60. # Make sure all references are invalidated before callbacks are called
  61. #
  62. # What's important here is that we're using the first
  63. # reference in the callback invoked on the second reference
  64. # (the most recently created ref is cleaned up first). This
  65. # tests that all references to the object are invalidated
  66. # before any of the callbacks are invoked, so that we only
  67. # have one invocation of _weakref.c:cleanup_helper() active
  68. # for a particular object at a time.
  69. #
  70. def callback(object, self=self):
  71. self.ref()
  72. c = C()
  73. self.ref = weakref.ref(c, callback)
  74. ref1 = weakref.ref(c, callback)
  75. del c
  76. def test_proxy_ref(self):
  77. o = C()
  78. o.bar = 1
  79. ref1 = weakref.proxy(o, self.callback)
  80. ref2 = weakref.proxy(o, self.callback)
  81. del o
  82. def check(proxy):
  83. proxy.bar
  84. self.assertRaises(weakref.ReferenceError, check, ref1)
  85. self.assertRaises(weakref.ReferenceError, check, ref2)
  86. self.assertRaises(weakref.ReferenceError, bool, weakref.proxy(C()))
  87. self.assert_(self.cbcalled == 2)
  88. def check_basic_ref(self, factory):
  89. o = factory()
  90. ref = weakref.ref(o)
  91. self.assert_(ref() is not None,
  92. "weak reference to live object should be live")
  93. o2 = ref()
  94. self.assert_(o is o2,
  95. "<ref>() should return original object if live")
  96. def check_basic_callback(self, factory):
  97. self.cbcalled = 0
  98. o = factory()
  99. ref = weakref.ref(o, self.callback)
  100. del o
  101. self.assert_(self.cbcalled == 1,
  102. "callback did not properly set 'cbcalled'")
  103. self.assert_(ref() is None,
  104. "ref2 should be dead after deleting object reference")
  105. def test_ref_reuse(self):
  106. o = C()
  107. ref1 = weakref.ref(o)
  108. # create a proxy to make sure that there's an intervening creation
  109. # between these two; it should make no difference
  110. proxy = weakref.proxy(o)
  111. ref2 = weakref.ref(o)
  112. self.assert_(ref1 is ref2,
  113. "reference object w/out callback should be re-used")
  114. o = C()
  115. proxy = weakref.proxy(o)
  116. ref1 = weakref.ref(o)
  117. ref2 = weakref.ref(o)
  118. self.assert_(ref1 is ref2,
  119. "reference object w/out callback should be re-used")
  120. self.assert_(weakref.getweakrefcount(o) == 2,
  121. "wrong weak ref count for object")
  122. del proxy
  123. self.assert_(weakref.getweakrefcount(o) == 1,
  124. "wrong weak ref count for object after deleting proxy")
  125. def test_proxy_reuse(self):
  126. o = C()
  127. proxy1 = weakref.proxy(o)
  128. ref = weakref.ref(o)
  129. proxy2 = weakref.proxy(o)
  130. self.assert_(proxy1 is proxy2,
  131. "proxy object w/out callback should have been re-used")
  132. def test_basic_proxy(self):
  133. o = C()
  134. self.check_proxy(o, weakref.proxy(o))
  135. L = UserList.UserList()
  136. p = weakref.proxy(L)
  137. self.failIf(p, "proxy for empty UserList should be false")
  138. p.append(12)
  139. self.assertEqual(len(L), 1)
  140. self.failUnless(p, "proxy for non-empty UserList should be true")
  141. p[:] = [2, 3]
  142. self.assertEqual(len(L), 2)
  143. self.assertEqual(len(p), 2)
  144. self.failUnless(3 in p,
  145. "proxy didn't support __contains__() properly")
  146. p[1] = 5
  147. self.assertEqual(L[1], 5)
  148. self.assertEqual(p[1], 5)
  149. L2 = UserList.UserList(L)
  150. p2 = weakref.proxy(L2)
  151. self.assertEqual(p, p2)
  152. ## self.assertEqual(repr(L2), repr(p2))
  153. L3 = UserList.UserList(range(10))
  154. p3 = weakref.proxy(L3)
  155. self.assertEqual(L3[:], p3[:])
  156. self.assertEqual(L3[5:], p3[5:])
  157. self.assertEqual(L3[:5], p3[:5])
  158. self.assertEqual(L3[2:5], p3[2:5])
  159. def test_proxy_index(self):
  160. class C:
  161. def __index__(self):
  162. return 10
  163. o = C()
  164. p = weakref.proxy(o)
  165. self.assertEqual(operator.index(p), 10)
  166. def test_proxy_div(self):
  167. class C:
  168. def __floordiv__(self, other):
  169. return 42
  170. def __ifloordiv__(self, other):
  171. return 21
  172. o = C()
  173. p = weakref.proxy(o)
  174. self.assertEqual(p // 5, 42)
  175. p //= 5
  176. self.assertEqual(p, 21)
  177. # The PyWeakref_* C API is documented as allowing either NULL or
  178. # None as the value for the callback, where either means "no
  179. # callback". The "no callback" ref and proxy objects are supposed
  180. # to be shared so long as they exist by all callers so long as
  181. # they are active. In Python 2.3.3 and earlier, this guarantee
  182. # was not honored, and was broken in different ways for
  183. # PyWeakref_NewRef() and PyWeakref_NewProxy(). (Two tests.)
  184. def test_shared_ref_without_callback(self):
  185. self.check_shared_without_callback(weakref.ref)
  186. def test_shared_proxy_without_callback(self):
  187. self.check_shared_without_callback(weakref.proxy)
  188. def check_shared_without_callback(self, makeref):
  189. o = Object(1)
  190. p1 = makeref(o, None)
  191. p2 = makeref(o, None)
  192. self.assert_(p1 is p2, "both callbacks were None in the C API")
  193. del p1, p2
  194. p1 = makeref(o)
  195. p2 = makeref(o, None)
  196. self.assert_(p1 is p2, "callbacks were NULL, None in the C API")
  197. del p1, p2
  198. p1 = makeref(o)
  199. p2 = makeref(o)
  200. self.assert_(p1 is p2, "both callbacks were NULL in the C API")
  201. del p1, p2
  202. p1 = makeref(o, None)
  203. p2 = makeref(o)
  204. self.assert_(p1 is p2, "callbacks were None, NULL in the C API")
  205. def test_callable_proxy(self):
  206. o = Callable()
  207. ref1 = weakref.proxy(o)
  208. self.check_proxy(o, ref1)
  209. self.assert_(type(ref1) is weakref.CallableProxyType,
  210. "proxy is not of callable type")
  211. ref1('twinkies!')
  212. self.assert_(o.bar == 'twinkies!',
  213. "call through proxy not passed through to original")
  214. ref1(x='Splat.')
  215. self.assert_(o.bar == 'Splat.',
  216. "call through proxy not passed through to original")
  217. # expect due to too few args
  218. self.assertRaises(TypeError, ref1)
  219. # expect due to too many args
  220. self.assertRaises(TypeError, ref1, 1, 2, 3)
  221. def check_proxy(self, o, proxy):
  222. o.foo = 1
  223. self.assert_(proxy.foo == 1,
  224. "proxy does not reflect attribute addition")
  225. o.foo = 2
  226. self.assert_(proxy.foo == 2,
  227. "proxy does not reflect attribute modification")
  228. del o.foo
  229. self.assert_(not hasattr(proxy, 'foo'),
  230. "proxy does not reflect attribute removal")
  231. proxy.foo = 1
  232. self.assert_(o.foo == 1,
  233. "object does not reflect attribute addition via proxy")
  234. proxy.foo = 2
  235. self.assert_(
  236. o.foo == 2,
  237. "object does not reflect attribute modification via proxy")
  238. del proxy.foo
  239. self.assert_(not hasattr(o, 'foo'),
  240. "object does not reflect attribute removal via proxy")
  241. def test_proxy_deletion(self):
  242. # Test clearing of SF bug #762891
  243. class Foo:
  244. result = None
  245. def __delitem__(self, accessor):
  246. self.result = accessor
  247. g = Foo()
  248. f = weakref.proxy(g)
  249. del f[0]
  250. self.assertEqual(f.result, 0)
  251. def test_proxy_bool(self):
  252. # Test clearing of SF bug #1170766
  253. class List(list): pass
  254. lyst = List()
  255. self.assertEqual(bool(weakref.proxy(lyst)), bool(lyst))
  256. def test_getweakrefcount(self):
  257. o = C()
  258. ref1 = weakref.ref(o)
  259. ref2 = weakref.ref(o, self.callback)
  260. self.assert_(weakref.getweakrefcount(o) == 2,
  261. "got wrong number of weak reference objects")
  262. proxy1 = weakref.proxy(o)
  263. proxy2 = weakref.proxy(o, self.callback)
  264. self.assert_(weakref.getweakrefcount(o) == 4,
  265. "got wrong number of weak reference objects")
  266. del ref1, ref2, proxy1, proxy2
  267. self.assert_(weakref.getweakrefcount(o) == 0,
  268. "weak reference objects not unlinked from"
  269. " referent when discarded.")
  270. # assumes ints do not support weakrefs
  271. self.assert_(weakref.getweakrefcount(1) == 0,
  272. "got wrong number of weak reference objects for int")
  273. def test_getweakrefs(self):
  274. o = C()
  275. ref1 = weakref.ref(o, self.callback)
  276. ref2 = weakref.ref(o, self.callback)
  277. del ref1
  278. self.assert_(weakref.getweakrefs(o) == [ref2],
  279. "list of refs does not match")
  280. o = C()
  281. ref1 = weakref.ref(o, self.callback)
  282. ref2 = weakref.ref(o, self.callback)
  283. del ref2
  284. self.assert_(weakref.getweakrefs(o) == [ref1],
  285. "list of refs does not match")
  286. del ref1
  287. self.assert_(weakref.getweakrefs(o) == [],
  288. "list of refs not cleared")
  289. # assumes ints do not support weakrefs
  290. self.assert_(weakref.getweakrefs(1) == [],
  291. "list of refs does not match for int")
  292. def test_newstyle_number_ops(self):
  293. class F(float):
  294. pass
  295. f = F(2.0)
  296. p = weakref.proxy(f)
  297. self.assert_(p + 1.0 == 3.0)
  298. self.assert_(1.0 + p == 3.0) # this used to SEGV
  299. def test_callbacks_protected(self):
  300. # Callbacks protected from already-set exceptions?
  301. # Regression test for SF bug #478534.
  302. class BogusError(Exception):
  303. pass
  304. data = {}
  305. def remove(k):
  306. del data[k]
  307. def encapsulate():
  308. f = lambda : ()
  309. data[weakref.ref(f, remove)] = None
  310. raise BogusError
  311. try:
  312. encapsulate()
  313. except BogusError:
  314. pass
  315. else:
  316. self.fail("exception not properly restored")
  317. try:
  318. encapsulate()
  319. except BogusError:
  320. pass
  321. else:
  322. self.fail("exception not properly restored")
  323. def test_sf_bug_840829(self):
  324. # "weakref callbacks and gc corrupt memory"
  325. # subtype_dealloc erroneously exposed a new-style instance
  326. # already in the process of getting deallocated to gc,
  327. # causing double-deallocation if the instance had a weakref
  328. # callback that triggered gc.
  329. # If the bug exists, there probably won't be an obvious symptom
  330. # in a release build. In a debug build, a segfault will occur
  331. # when the second attempt to remove the instance from the "list
  332. # of all objects" occurs.
  333. import gc
  334. class C(object):
  335. pass
  336. c = C()
  337. wr = weakref.ref(c, lambda ignore: gc.collect())
  338. del c
  339. # There endeth the first part. It gets worse.
  340. del wr
  341. c1 = C()
  342. c1.i = C()
  343. wr = weakref.ref(c1.i, lambda ignore: gc.collect())
  344. c2 = C()
  345. c2.c1 = c1
  346. del c1 # still alive because c2 points to it
  347. # Now when subtype_dealloc gets called on c2, it's not enough just
  348. # that c2 is immune from gc while the weakref callbacks associated
  349. # with c2 execute (there are none in this 2nd half of the test, btw).
  350. # subtype_dealloc goes on to call the base classes' deallocs too,
  351. # so any gc triggered by weakref callbacks associated with anything
  352. # torn down by a base class dealloc can also trigger double
  353. # deallocation of c2.
  354. del c2
  355. def test_callback_in_cycle_1(self):
  356. import gc
  357. class J(object):
  358. pass
  359. class II(object):
  360. def acallback(self, ignore):
  361. self.J
  362. I = II()
  363. I.J = J
  364. I.wr = weakref.ref(J, I.acallback)
  365. # Now J and II are each in a self-cycle (as all new-style class
  366. # objects are, since their __mro__ points back to them). I holds
  367. # both a weak reference (I.wr) and a strong reference (I.J) to class
  368. # J. I is also in a cycle (I.wr points to a weakref that references
  369. # I.acallback). When we del these three, they all become trash, but
  370. # the cycles prevent any of them from getting cleaned up immediately.
  371. # Instead they have to wait for cyclic gc to deduce that they're
  372. # trash.
  373. #
  374. # gc used to call tp_clear on all of them, and the order in which
  375. # it does that is pretty accidental. The exact order in which we
  376. # built up these things manages to provoke gc into running tp_clear
  377. # in just the right order (I last). Calling tp_clear on II leaves
  378. # behind an insane class object (its __mro__ becomes NULL). Calling
  379. # tp_clear on J breaks its self-cycle, but J doesn't get deleted
  380. # just then because of the strong reference from I.J. Calling
  381. # tp_clear on I starts to clear I's __dict__, and just happens to
  382. # clear I.J first -- I.wr is still intact. That removes the last
  383. # reference to J, which triggers the weakref callback. The callback
  384. # tries to do "self.J", and instances of new-style classes look up
  385. # attributes ("J") in the class dict first. The class (II) wants to
  386. # search II.__mro__, but that's NULL. The result was a segfault in
  387. # a release build, and an assert failure in a debug build.
  388. del I, J, II
  389. gc.collect()
  390. def test_callback_in_cycle_2(self):
  391. import gc
  392. # This is just like test_callback_in_cycle_1, except that II is an
  393. # old-style class. The symptom is different then: an instance of an
  394. # old-style class looks in its own __dict__ first. 'J' happens to
  395. # get cleared from I.__dict__ before 'wr', and 'J' was never in II's
  396. # __dict__, so the attribute isn't found. The difference is that
  397. # the old-style II doesn't have a NULL __mro__ (it doesn't have any
  398. # __mro__), so no segfault occurs. Instead it got:
  399. # test_callback_in_cycle_2 (__main__.ReferencesTestCase) ...
  400. # Exception exceptions.AttributeError:
  401. # "II instance has no attribute 'J'" in <bound method II.acallback
  402. # of <?.II instance at 0x00B9B4B8>> ignored
  403. class J(object):
  404. pass
  405. class II:
  406. def acallback(self, ignore):
  407. self.J
  408. I = II()
  409. I.J = J
  410. I.wr = weakref.ref(J, I.acallback)
  411. del I, J, II
  412. gc.collect()
  413. def test_callback_in_cycle_3(self):
  414. import gc
  415. # This one broke the first patch that fixed the last two. In this
  416. # case, the objects reachable from the callback aren't also reachable
  417. # from the object (c1) *triggering* the callback: you can get to
  418. # c1 from c2, but not vice-versa. The result was that c2's __dict__
  419. # got tp_clear'ed by the time the c2.cb callback got invoked.
  420. class C:
  421. def cb(self, ignore):
  422. self.me
  423. self.c1
  424. self.wr
  425. c1, c2 = C(), C()
  426. c2.me = c2
  427. c2.c1 = c1
  428. c2.wr = weakref.ref(c1, c2.cb)
  429. del c1, c2
  430. gc.collect()
  431. def test_callback_in_cycle_4(self):
  432. import gc
  433. # Like test_callback_in_cycle_3, except c2 and c1 have different
  434. # classes. c2's class (C) isn't reachable from c1 then, so protecting
  435. # objects reachable from the dying object (c1) isn't enough to stop
  436. # c2's class (C) from getting tp_clear'ed before c2.cb is invoked.
  437. # The result was a segfault (C.__mro__ was NULL when the callback
  438. # tried to look up self.me).
  439. class C(object):
  440. def cb(self, ignore):
  441. self.me
  442. self.c1
  443. self.wr
  444. class D:
  445. pass
  446. c1, c2 = D(), C()
  447. c2.me = c2
  448. c2.c1 = c1
  449. c2.wr = weakref.ref(c1, c2.cb)
  450. del c1, c2, C, D
  451. gc.collect()
  452. def test_callback_in_cycle_resurrection(self):
  453. import gc
  454. # Do something nasty in a weakref callback: resurrect objects
  455. # from dead cycles. For this to be attempted, the weakref and
  456. # its callback must also be part of the cyclic trash (else the
  457. # objects reachable via the callback couldn't be in cyclic trash
  458. # to begin with -- the callback would act like an external root).
  459. # But gc clears trash weakrefs with callbacks early now, which
  460. # disables the callbacks, so the callbacks shouldn't get called
  461. # at all (and so nothing actually gets resurrected).
  462. alist = []
  463. class C(object):
  464. def __init__(self, value):
  465. self.attribute = value
  466. def acallback(self, ignore):
  467. alist.append(self.c)
  468. common = C(0)
  469. c1, c2 = C(common), C(common)
  470. c1.c = c2
  471. c2.c = c1
  472. c1.wr = weakref.ref(c2, c1.acallback)
  473. c2.wr = weakref.ref(c1, c2.acallback)
  474. def common_went_away(ignore):
  475. alist.append("common went away")
  476. wr = weakref.ref(common, common_went_away)
  477. del c1, c2, common # make them all trash
  478. self.assertEqual(alist, []) # del isn't enough to reclaim anything
  479. gc.collect()
  480. # c1.wr and c2.wr were part of the cyclic trash, so should have
  481. # been cleared without their callbacks executing. OTOH, the weakref
  482. # to common is bound to a function local (wr), and wasn't trash, so that
  483. # callback should have been invoked when common went away.
  484. self.assertEqual(alist, ["common went away"])
  485. # The remaining weakref should be dead now (its callback ran).
  486. self.assertEqual(wr(), None)
  487. del alist[:]
  488. gc.collect()
  489. self.assertEqual(alist, [])
  490. def test_callbacks_on_callback(self):
  491. import gc
  492. # Set up weakref callbacks *on* weakref callbacks.
  493. alist = []
  494. def safe_callback(ignore):
  495. alist.append("safe_callback called")
  496. class C(object):
  497. def cb(self, ignore):
  498. alist.append("cb called")
  499. c, d = C(), C()
  500. c.other = d
  501. d.other = c
  502. callback = c.cb
  503. c.wr = weakref.ref(d, callback) # this won't trigger
  504. d.wr = weakref.ref(callback, d.cb) # ditto
  505. external_wr = weakref.ref(callback, safe_callback) # but this will
  506. self.assert_(external_wr() is callback)
  507. # The weakrefs attached to c and d should get cleared, so that
  508. # C.cb is never called. But external_wr isn't part of the cyclic
  509. # trash, and no cyclic trash is reachable from it, so safe_callback
  510. # should get invoked when the bound method object callback (c.cb)
  511. # -- which is itself a callback, and also part of the cyclic trash --
  512. # gets reclaimed at the end of gc.
  513. del callback, c, d, C
  514. self.assertEqual(alist, []) # del isn't enough to clean up cycles
  515. gc.collect()
  516. self.assertEqual(alist, ["safe_callback called"])
  517. self.assertEqual(external_wr(), None)
  518. del alist[:]
  519. gc.collect()
  520. self.assertEqual(alist, [])
  521. def test_gc_during_ref_creation(self):
  522. self.check_gc_during_creation(weakref.ref)
  523. def test_gc_during_proxy_creation(self):
  524. self.check_gc_during_creation(weakref.proxy)
  525. def check_gc_during_creation(self, makeref):
  526. thresholds = gc.get_threshold()
  527. gc.set_threshold(1, 1, 1)
  528. gc.collect()
  529. class A:
  530. pass
  531. def callback(*args):
  532. pass
  533. referenced = A()
  534. a = A()
  535. a.a = a
  536. a.wr = makeref(referenced)
  537. try:
  538. # now make sure the object and the ref get labeled as
  539. # cyclic trash:
  540. a = A()
  541. weakref.ref(referenced, callback)
  542. finally:
  543. gc.set_threshold(*thresholds)
  544. def test_ref_created_during_del(self):
  545. # Bug #1377858
  546. # A weakref created in an object's __del__() would crash the
  547. # interpreter when the weakref was cleaned up since it would refer to
  548. # non-existent memory. This test should not segfault the interpreter.
  549. class Target(object):
  550. def __del__(self):
  551. global ref_from_del
  552. ref_from_del = weakref.ref(self)
  553. w = Target()
  554. def test_init(self):
  555. # Issue 3634
  556. # <weakref to class>.__init__() doesn't check errors correctly
  557. r = weakref.ref(Exception)
  558. self.assertRaises(TypeError, r.__init__, 0, 0, 0, 0, 0)
  559. # No exception should be raised here
  560. gc.collect()
  561. class SubclassableWeakrefTestCase(TestBase):
  562. def test_subclass_refs(self):
  563. class MyRef(weakref.ref):
  564. def __init__(self, ob, callback=None, value=42):
  565. self.value = value
  566. super(MyRef, self).__init__(ob, callback)
  567. def __call__(self):
  568. self.called = True
  569. return super(MyRef, self).__call__()
  570. o = Object("foo")
  571. mr = MyRef(o, value=24)
  572. self.assert_(mr() is o)
  573. self.assert_(mr.called)
  574. self.assertEqual(mr.value, 24)
  575. del o
  576. self.assert_(mr() is None)
  577. self.assert_(mr.called)
  578. def test_subclass_refs_dont_replace_standard_refs(self):
  579. class MyRef(weakref.ref):
  580. pass
  581. o = Object(42)
  582. r1 = MyRef(o)
  583. r2 = weakref.ref(o)
  584. self.assert_(r1 is not r2)
  585. self.assertEqual(weakref.getweakrefs(o), [r2, r1])
  586. self.assertEqual(weakref.getweakrefcount(o), 2)
  587. r3 = MyRef(o)
  588. self.assertEqual(weakref.getweakrefcount(o), 3)
  589. refs = weakref.getweakrefs(o)
  590. self.assertEqual(len(refs), 3)
  591. self.assert_(r2 is refs[0])
  592. self.assert_(r1 in refs[1:])
  593. self.assert_(r3 in refs[1:])
  594. def test_subclass_refs_dont_conflate_callbacks(self):
  595. class MyRef(weakref.ref):
  596. pass
  597. o = Object(42)
  598. r1 = MyRef(o, id)
  599. r2 = MyRef(o, str)
  600. self.assert_(r1 is not r2)
  601. refs = weakref.getweakrefs(o)
  602. self.assert_(r1 in refs)
  603. self.assert_(r2 in refs)
  604. def test_subclass_refs_with_slots(self):
  605. class MyRef(weakref.ref):
  606. __slots__ = "slot1", "slot2"
  607. def __new__(type, ob, callback, slot1, slot2):
  608. return weakref.ref.__new__(type, ob, callback)
  609. def __init__(self, ob, callback, slot1, slot2):
  610. self.slot1 = slot1
  611. self.slot2 = slot2
  612. def meth(self):
  613. return self.slot1 + self.slot2
  614. o = Object(42)
  615. r = MyRef(o, None, "abc", "def")
  616. self.assertEqual(r.slot1, "abc")
  617. self.assertEqual(r.slot2, "def")
  618. self.assertEqual(r.meth(), "abcdef")
  619. self.failIf(hasattr(r, "__dict__"))
  620. def test_subclass_refs_with_cycle(self):
  621. # Bug #3110
  622. # An instance of a weakref subclass can have attributes.
  623. # If such a weakref holds the only strong reference to the object,
  624. # deleting the weakref will delete the object. In this case,
  625. # the callback must not be called, because the ref object is
  626. # being deleted.
  627. class MyRef(weakref.ref):
  628. pass
  629. # Use a local callback, for "regrtest -R::"
  630. # to detect refcounting problems
  631. def callback(w):
  632. self.cbcalled += 1
  633. o = C()
  634. r1 = MyRef(o, callback)
  635. r1.o = o
  636. del o
  637. del r1 # Used to crash here
  638. self.assertEqual(self.cbcalled, 0)
  639. # Same test, with two weakrefs to the same object
  640. # (since code paths are different)
  641. o = C()
  642. r1 = MyRef(o, callback)
  643. r2 = MyRef(o, callback)
  644. r1.r = r2
  645. r2.o = o
  646. del o
  647. del r2
  648. del r1 # Used to crash here
  649. self.assertEqual(self.cbcalled, 0)
  650. class Object:
  651. def __init__(self, arg):
  652. self.arg = arg
  653. def __repr__(self):
  654. return "<Object %r>" % self.arg
  655. class MappingTestCase(TestBase):
  656. COUNT = 10
  657. def test_weak_values(self):
  658. #
  659. # This exercises d.copy(), d.items(), d[], del d[], len(d).
  660. #
  661. dict, objects = self.make_weak_valued_dict()
  662. for o in objects:
  663. self.assert_(weakref.getweakrefcount(o) == 1,
  664. "wrong number of weak references to %r!" % o)
  665. self.assert_(o is dict[o.arg],
  666. "wrong object returned by weak dict!")
  667. items1 = dict.items()
  668. items2 = dict.copy().items()
  669. items1.sort()
  670. items2.sort()
  671. self.assert_(items1 == items2,
  672. "cloning of weak-valued dictionary did not work!")
  673. del items1, items2
  674. self.assert_(len(dict) == self.COUNT)
  675. del objects[0]
  676. self.assert_(len(dict) == (self.COUNT - 1),
  677. "deleting object did not cause dictionary update")
  678. del objects, o
  679. self.assert_(len(dict) == 0,
  680. "deleting the values did not clear the dictionary")
  681. # regression on SF bug #447152:
  682. dict = weakref.WeakValueDictionary()
  683. self.assertRaises(KeyError, dict.__getitem__, 1)
  684. dict[2] = C()
  685. self.assertRaises(KeyError, dict.__getitem__, 2)
  686. def test_weak_keys(self):
  687. #
  688. # This exercises d.copy(), d.items(), d[] = v, d[], del d[],
  689. # len(d), d.has_key().
  690. #
  691. dict, objects = self.make_weak_keyed_dict()
  692. for o in objects:
  693. self.assert_(weakref.getweakrefcount(o) == 1,
  694. "wrong number of weak references to %r!" % o)
  695. self.assert_(o.arg is dict[o],
  696. "wrong object returned by weak dict!")
  697. items1 = dict.items()
  698. items2 = dict.copy().items()
  699. self.assert_(set(items1) == set(items2),
  700. "cloning of weak-keyed dictionary did not work!")
  701. del items1, items2
  702. self.assert_(len(dict) == self.COUNT)
  703. del objects[0]
  704. self.assert_(len(dict) == (self.COUNT - 1),
  705. "deleting object did not cause dictionary update")
  706. del objects, o
  707. self.assert_(len(dict) == 0,
  708. "deleting the keys did not clear the dictionary")
  709. o = Object(42)
  710. dict[o] = "What is the meaning of the universe?"
  711. self.assert_(dict.has_key(o))
  712. self.assert_(not dict.has_key(34))
  713. def test_weak_keyed_iters(self):
  714. dict, objects = self.make_weak_keyed_dict()
  715. self.check_iters(dict)
  716. # Test keyrefs()
  717. refs = dict.keyrefs()
  718. self.assertEqual(len(refs), len(objects))
  719. objects2 = list(objects)
  720. for wr in refs:
  721. ob = wr()
  722. self.assert_(dict.has_key(ob))
  723. self.assert_(ob in dict)
  724. self.assertEqual(ob.arg, dict[ob])
  725. objects2.remove(ob)
  726. self.assertEqual(len(objects2), 0)
  727. # Test iterkeyrefs()
  728. objects2 = list(objects)
  729. self.assertEqual(len(list(dict.iterkeyrefs())), len(objects))
  730. for wr in dict.iterkeyrefs():
  731. ob = wr()
  732. self.assert_(dict.has_key(ob))
  733. self.assert_(ob in dict)
  734. self.assertEqual(ob.arg, dict[ob])
  735. objects2.remove(ob)
  736. self.assertEqual(len(objects2), 0)
  737. def test_weak_valued_iters(self):
  738. dict, objects = self.make_weak_valued_dict()
  739. self.check_iters(dict)
  740. # Test valuerefs()
  741. refs = dict.valuerefs()
  742. self.assertEqual(len(refs), len(objects))
  743. objects2 = list(objects)
  744. for wr in refs:
  745. ob = wr()
  746. self.assertEqual(ob, dict[ob.arg])
  747. self.assertEqual(ob.arg, dict[ob.arg].arg)
  748. objects2.remove(ob)
  749. self.assertEqual(len(objects2), 0)
  750. # Test itervaluerefs()
  751. objects2 = list(objects)
  752. self.assertEqual(len(list(dict.itervaluerefs())), len(objects))
  753. for wr in dict.itervaluerefs():
  754. ob = wr()
  755. self.assertEqual(ob, dict[ob.arg])
  756. self.assertEqual(ob.arg, dict[ob.arg].arg)
  757. objects2.remove(ob)
  758. self.assertEqual(len(objects2), 0)
  759. def check_iters(self, dict):
  760. # item iterator:
  761. items = dict.items()
  762. for item in dict.iteritems():
  763. items.remove(item)
  764. self.assert_(len(items) == 0, "iteritems() did not touch all items")
  765. # key iterator, via __iter__():
  766. keys = dict.keys()
  767. for k in dict:
  768. keys.remove(k)
  769. self.assert_(len(keys) == 0, "__iter__() did not touch all keys")
  770. # key iterator, via iterkeys():
  771. keys = dict.keys()
  772. for k in dict.iterkeys():
  773. keys.remove(k)
  774. self.assert_(len(keys) == 0, "iterkeys() did not touch all keys")
  775. # value iterator:
  776. values = dict.values()
  777. for v in dict.itervalues():
  778. values.remove(v)
  779. self.assert_(len(values) == 0,
  780. "itervalues() did not touch all values")
  781. def test_make_weak_keyed_dict_from_dict(self):
  782. o = Object(3)
  783. dict = weakref.WeakKeyDictionary({o:364})
  784. self.assert_(dict[o] == 364)
  785. def test_make_weak_keyed_dict_from_weak_keyed_dict(self):
  786. o = Object(3)
  787. dict = weakref.WeakKeyDictionary({o:364})
  788. dict2 = weakref.WeakKeyDictionary(dict)
  789. self.assert_(dict[o] == 364)
  790. def make_weak_keyed_dict(self):
  791. dict = weakref.WeakKeyDictionary()
  792. objects = map(Object, range(self.COUNT))
  793. for o in objects:
  794. dict[o] = o.arg
  795. return dict, objects
  796. def make_weak_valued_dict(self):
  797. dict = weakref.WeakValueDictionary()
  798. objects = map(Object, range(self.COUNT))
  799. for o in objects:
  800. dict[o.arg] = o
  801. return dict, objects
  802. def check_popitem(self, klass, key1, value1, key2, value2):
  803. weakdict = klass()
  804. weakdict[key1] = value1
  805. weakdict[key2] = value2
  806. self.assert_(len(weakdict) == 2)
  807. k, v = weakdict.popitem()
  808. self.assert_(len(weakdict) == 1)
  809. if k is key1:
  810. self.assert_(v is value1)
  811. else:
  812. self.assert_(v is value2)
  813. k, v = weakdict.popitem()
  814. self.assert_(len(weakdict) == 0)
  815. if k is key1:
  816. self.assert_(v is value1)
  817. else:
  818. self.assert_(v is value2)
  819. def test_weak_valued_dict_popitem(self):
  820. self.check_popitem(weakref.WeakValueDictionary,
  821. "key1", C(), "key2", C())
  822. def test_weak_keyed_dict_popitem(self):
  823. self.check_popitem(weakref.WeakKeyDictionary,
  824. C(), "value 1", C(), "value 2")
  825. def check_setdefault(self, klass, key, value1, value2):
  826. self.assert_(value1 is not value2,
  827. "invalid test"
  828. " -- value parameters must be distinct objects")
  829. weakdict = klass()
  830. o = weakdict.setdefault(key, value1)
  831. self.assert_(o is value1)
  832. self.assert_(weakdict.has_key(key))
  833. self.assert_(weakdict.get(key) is value1)
  834. self.assert_(weakdict[key] is value1)
  835. o = weakdict.setdefault(key, value2)
  836. self.assert_(o is value1)
  837. self.assert_(weakdict.has_key(key))
  838. self.assert_(weakdict.get(key) is value1)
  839. self.assert_(weakdict[key] is value1)
  840. def test_weak_valued_dict_setdefault(self):
  841. self.check_setdefault(weakref.WeakValueDictionary,
  842. "key", C(), C())
  843. def test_weak_keyed_dict_setdefault(self):
  844. self.check_setdefault(weakref.WeakKeyDictionary,
  845. C(), "value 1", "value 2")
  846. def check_update(self, klass, dict):
  847. #
  848. # This exercises d.update(), len(d), d.keys(), d.has_key(),
  849. # d.get(), d[].
  850. #
  851. weakdict = klass()
  852. weakdict.update(dict)
  853. self.assert_(len(weakdict) == len(dict))
  854. for k in weakdict.keys():
  855. self.assert_(dict.has_key(k),
  856. "mysterious new key appeared in weak dict")
  857. v = dict.get(k)
  858. self.assert_(v is weakdict[k])
  859. self.assert_(v is weakdict.get(k))
  860. for k in dict.keys():
  861. self.assert_(weakdict.has_key(k),
  862. "original key disappeared in weak dict")
  863. v = dict[k]
  864. self.assert_(v is weakdict[k])
  865. self.assert_(v is weakdict.get(k))
  866. def test_weak_valued_dict_update(self):
  867. self.check_update(weakref.WeakValueDictionary,
  868. {1: C(), 'a': C(), C(): C()})
  869. def test_weak_keyed_dict_update(self):
  870. self.check_update(weakref.WeakKeyDictionary,
  871. {C(): 1, C(): 2, C(): 3})
  872. def test_weak_keyed_delitem(self):
  873. d = weakref.WeakKeyDictionary()
  874. o1 = Object('1')
  875. o2 = Object('2')
  876. d[o1] = 'something'
  877. d[o2] = 'something'
  878. self.assert_(len(d) == 2)
  879. del d[o1]
  880. self.assert_(len(d) == 1)
  881. self.assert_(d.keys() == [o2])
  882. def test_weak_valued_delitem(self):
  883. d = weakref.WeakValueDictionary()
  884. o1 = Object('1')
  885. o2 = Object('2')
  886. d['something'] = o1
  887. d['something else'] = o2
  888. self.assert_(len(d) == 2)
  889. del d['something']
  890. self.assert_(len(d) == 1)
  891. self.assert_(d.items() == [('something else', o2)])
  892. def test_weak_keyed_bad_delitem(self):
  893. d = weakref.WeakKeyDictionary()
  894. o = Object('1')
  895. # An attempt to delete an object that isn't there should raise
  896. # KeyError. It didn't before 2.3.
  897. self.assertRaises(KeyError, d.__delitem__, o)
  898. self.assertRaises(KeyError, d.__getitem__, o)
  899. # If a key isn't of a weakly referencable type, __getitem__ and
  900. # __setitem__ raise TypeError. __delitem__ should too.
  901. self.assertRaises(TypeError, d.__delitem__, 13)
  902. self.assertRaises(TypeError, d.__getitem__, 13)
  903. self.assertRaises(TypeError, d.__setitem__, 13, 13)
  904. def test_weak_keyed_cascading_deletes(self):
  905. # SF bug 742860. For some reason, before 2.3 __delitem__ iterated
  906. # over the keys via self.data.iterkeys(). If things vanished from
  907. # the dict during this (or got added), that caused a RuntimeError.
  908. d = weakref.WeakKeyDictionary()
  909. mutate = False
  910. class C(object):
  911. def __init__(self, i):
  912. self.value = i
  913. def __hash__(self):
  914. return hash(self.value)
  915. def __eq__(self, other):
  916. if mutate:
  917. # Side effect that mutates the dict, by removing the
  918. # last strong reference to a key.
  919. del objs[-1]
  920. return self.value == other.value
  921. objs = [C(i) for i in range(4)]
  922. for o in objs:
  923. d[o] = o.value
  924. del o # now the only strong references to keys are in objs
  925. # Find the order in which iterkeys sees the keys.
  926. objs = d.keys()
  927. # Reverse it, so that the iteration implementation of __delitem__
  928. # has to keep looping to find the first object we delete.
  929. objs.reverse()
  930. # Turn on mutation in C.__eq__. The first time thru the loop,
  931. # under the iterkeys() business the first comparison will delete
  932. # the last item iterkeys() would see, and that causes a
  933. # RuntimeError: dictionary changed size during iteration
  934. # when the iterkeys() loop goes around to try comparing the next
  935. # key. After this was fixed, it just deletes the last object *our*
  936. # "for o in obj" loop would have gotten to.
  937. mutate = True
  938. count = 0
  939. for o in objs:
  940. count += 1
  941. del d[o]
  942. self.assertEqual(len(d), 0)
  943. self.assertEqual(count, 2)
  944. from test import mapping_tests
  945. class WeakValueDictionaryTestCase(mapping_tests.BasicTestMappingProtocol):
  946. """Check that WeakValueDictionary conforms to the mapping protocol"""
  947. __ref = {"key1":Object(1), "key2":Object(2), "key3":Object(3)}
  948. type2test = weakref.WeakValueDictionary
  949. def _reference(self):
  950. return self.__ref.copy()
  951. class WeakKeyDictionaryTestCase(mapping_tests.BasicTestMappingProtocol):
  952. """Check that WeakKeyDictionary conforms to the mapping protocol"""
  953. __ref = {Object("key1"):1, Object("key2"):2, Object("key3"):3}
  954. type2test = weakref.WeakKeyDictionary
  955. def _reference(self):
  956. return self.__ref.copy()
  957. libreftest = """ Doctest for examples in the library reference: weakref.rst
  958. >>> import weakref
  959. >>> class Dict(dict):
  960. ... pass
  961. ...
  962. >>> obj = Dict(red=1, green=2, blue=3) # this object is weak referencable
  963. >>> r = weakref.ref(obj)
  964. >>> print r() is obj
  965. True
  966. >>> import weakref
  967. >>> class Object:
  968. ... pass
  969. ...
  970. >>> o = Object()
  971. >>> r = weakref.ref(o)
  972. >>> o2 = r()
  973. >>> o is o2
  974. True
  975. >>> del o, o2
  976. >>> print r()
  977. None
  978. >>> import weakref
  979. >>> class ExtendedRef(weakref.ref):
  980. ... def __init__(self, ob, callback=None, **annotations):
  981. ... super(ExtendedRef, self).__init__(ob, callback)
  982. ... self.__counter = 0
  983. ... for k, v in annotations.iteritems():
  984. ... setattr(self, k, v)
  985. ... def __call__(self):
  986. ... '''Return a pair containing the referent and the number of
  987. ... times the reference has been called.
  988. ... '''
  989. ... ob = super(ExtendedRef, self).__call__()
  990. ... if ob is not None:
  991. ... self.__counter += 1
  992. ... ob = (ob, self.__counter)
  993. ... return ob
  994. ...
  995. >>> class A: # not in docs from here, just testing the ExtendedRef
  996. ... pass
  997. ...
  998. >>> a = A()
  999. >>> r = ExtendedRef(a, foo=1, bar="baz")
  1000. >>> r.foo
  1001. 1
  1002. >>> r.bar
  1003. 'baz'
  1004. >>> r()[1]
  1005. 1
  1006. >>> r()[1]
  1007. 2
  1008. >>> r()[0] is a
  1009. True
  1010. >>> import weakref
  1011. >>> _id2obj_dict = weakref.WeakValueDictionary()
  1012. >>> def remember(obj):
  1013. ... oid = id(obj)
  1014. ... _id2obj_dict[oid] = obj
  1015. ... return oid
  1016. ...
  1017. >>> def id2obj(oid):
  1018. ... return _id2obj_dict[oid]
  1019. ...
  1020. >>> a = A() # from here, just testing
  1021. >>> a_id = remember(a)
  1022. >>> id2obj(a_id) is a
  1023. True
  1024. >>> del a
  1025. >>> try:
  1026. ... id2obj(a_id)
  1027. ... except KeyError:
  1028. ... print 'OK'
  1029. ... else:
  1030. ... print 'WeakValueDictionary error'
  1031. OK
  1032. """
  1033. __test__ = {'libreftest' : libreftest}
  1034. def test_main():
  1035. test_support.run_unittest(
  1036. ReferencesTestCase,
  1037. MappingTestCase,
  1038. WeakValueDictionaryTestCase,
  1039. WeakKeyDictionaryTestCase,
  1040. SubclassableWeakrefTestCase,
  1041. )
  1042. test_support.run_doctest(sys.modules[__name__])
  1043. if __name__ == "__main__":
  1044. test_main()