PageRenderTime 58ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/External.LCA_RESTRICTED/Languages/IronPython/27/Lib/test/test_weakref.py

http://github.com/IronLanguages/main
Python | 1510 lines | 1101 code | 192 blank | 217 comment | 58 complexity | 461d32f5f4e6613854d13eec68829548 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file