home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / test_weakref.py < prev    next >
Text File  |  2003-12-30  |  30KB  |  862 lines

  1. import sys
  2. import unittest
  3. import UserList
  4. import weakref
  5.  
  6. from test import test_support
  7. from sets import Set
  8.  
  9.  
  10. class C:
  11.     def method(self):
  12.         pass
  13.  
  14.  
  15. class Callable:
  16.     bar = None
  17.  
  18.     def __call__(self, x):
  19.         self.bar = x
  20.  
  21.  
  22. def create_function():
  23.     def f(): pass
  24.     return f
  25.  
  26. def create_bound_method():
  27.     return C().method
  28.  
  29. def create_unbound_method():
  30.     return C.method
  31.  
  32.  
  33. class TestBase(unittest.TestCase):
  34.  
  35.     def setUp(self):
  36.         self.cbcalled = 0
  37.  
  38.     def callback(self, ref):
  39.         self.cbcalled += 1
  40.  
  41.  
  42. class ReferencesTestCase(TestBase):
  43.  
  44.     def test_basic_ref(self):
  45.         self.check_basic_ref(C)
  46.         self.check_basic_ref(create_function)
  47.         self.check_basic_ref(create_bound_method)
  48.         self.check_basic_ref(create_unbound_method)
  49.  
  50.         # Just make sure the tp_repr handler doesn't raise an exception.
  51.         # Live reference:
  52.         o = C()
  53.         wr = weakref.ref(o)
  54.         `wr`
  55.         # Dead reference:
  56.         del o
  57.         `wr`
  58.  
  59.     def test_basic_callback(self):
  60.         self.check_basic_callback(C)
  61.         self.check_basic_callback(create_function)
  62.         self.check_basic_callback(create_bound_method)
  63.         self.check_basic_callback(create_unbound_method)
  64.  
  65.     def test_multiple_callbacks(self):
  66.         o = C()
  67.         ref1 = weakref.ref(o, self.callback)
  68.         ref2 = weakref.ref(o, self.callback)
  69.         del o
  70.         self.assert_(ref1() is None,
  71.                      "expected reference to be invalidated")
  72.         self.assert_(ref2() is None,
  73.                      "expected reference to be invalidated")
  74.         self.assert_(self.cbcalled == 2,
  75.                      "callback not called the right number of times")
  76.  
  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.  
  95.     def test_proxy_ref(self):
  96.         o = C()
  97.         o.bar = 1
  98.         ref1 = weakref.proxy(o, self.callback)
  99.         ref2 = weakref.proxy(o, self.callback)
  100.         del o
  101.  
  102.         def check(proxy):
  103.             proxy.bar
  104.  
  105.         self.assertRaises(weakref.ReferenceError, check, ref1)
  106.         self.assertRaises(weakref.ReferenceError, check, ref2)
  107.         self.assert_(self.cbcalled == 2)
  108.  
  109.     def check_basic_ref(self, factory):
  110.         o = factory()
  111.         ref = weakref.ref(o)
  112.         self.assert_(ref() is not None,
  113.                      "weak reference to live object should be live")
  114.         o2 = ref()
  115.         self.assert_(o is o2,
  116.                      "<ref>() should return original object if live")
  117.  
  118.     def check_basic_callback(self, factory):
  119.         self.cbcalled = 0
  120.         o = factory()
  121.         ref = weakref.ref(o, self.callback)
  122.         del o
  123.         self.assert_(self.cbcalled == 1,
  124.                      "callback did not properly set 'cbcalled'")
  125.         self.assert_(ref() is None,
  126.                      "ref2 should be dead after deleting object reference")
  127.  
  128.     def test_ref_reuse(self):
  129.         o = C()
  130.         ref1 = weakref.ref(o)
  131.         # create a proxy to make sure that there's an intervening creation
  132.         # between these two; it should make no difference
  133.         proxy = weakref.proxy(o)
  134.         ref2 = weakref.ref(o)
  135.         self.assert_(ref1 is ref2,
  136.                      "reference object w/out callback should be re-used")
  137.  
  138.         o = C()
  139.         proxy = weakref.proxy(o)
  140.         ref1 = weakref.ref(o)
  141.         ref2 = weakref.ref(o)
  142.         self.assert_(ref1 is ref2,
  143.                      "reference object w/out callback should be re-used")
  144.         self.assert_(weakref.getweakrefcount(o) == 2,
  145.                      "wrong weak ref count for object")
  146.         del proxy
  147.         self.assert_(weakref.getweakrefcount(o) == 1,
  148.                      "wrong weak ref count for object after deleting proxy")
  149.  
  150.     def test_proxy_reuse(self):
  151.         o = C()
  152.         proxy1 = weakref.proxy(o)
  153.         ref = weakref.ref(o)
  154.         proxy2 = weakref.proxy(o)
  155.         self.assert_(proxy1 is proxy2,
  156.                      "proxy object w/out callback should have been re-used")
  157.  
  158.     def test_basic_proxy(self):
  159.         o = C()
  160.         self.check_proxy(o, weakref.proxy(o))
  161.  
  162.         L = UserList.UserList()
  163.         p = weakref.proxy(L)
  164.         self.failIf(p, "proxy for empty UserList should be false")
  165.         p.append(12)
  166.         self.assertEqual(len(L), 1)
  167.         self.failUnless(p, "proxy for non-empty UserList should be true")
  168.         p[:] = [2, 3]
  169.         self.assertEqual(len(L), 2)
  170.         self.assertEqual(len(p), 2)
  171.         self.failUnless(3 in p,
  172.                         "proxy didn't support __contains__() properly")
  173.         p[1] = 5
  174.         self.assertEqual(L[1], 5)
  175.         self.assertEqual(p[1], 5)
  176.         L2 = UserList.UserList(L)
  177.         p2 = weakref.proxy(L2)
  178.         self.assertEqual(p, p2)
  179.         ## self.assertEqual(`L2`, `p2`)
  180.         L3 = UserList.UserList(range(10))
  181.         p3 = weakref.proxy(L3)
  182.         self.assertEqual(L3[:], p3[:])
  183.         self.assertEqual(L3[5:], p3[5:])
  184.         self.assertEqual(L3[:5], p3[:5])
  185.         self.assertEqual(L3[2:5], p3[2:5])
  186.  
  187.     def test_callable_proxy(self):
  188.         o = Callable()
  189.         ref1 = weakref.proxy(o)
  190.  
  191.         self.check_proxy(o, ref1)
  192.  
  193.         self.assert_(type(ref1) is weakref.CallableProxyType,
  194.                      "proxy is not of callable type")
  195.         ref1('twinkies!')
  196.         self.assert_(o.bar == 'twinkies!',
  197.                      "call through proxy not passed through to original")
  198.         ref1(x='Splat.')
  199.         self.assert_(o.bar == 'Splat.',
  200.                      "call through proxy not passed through to original")
  201.  
  202.         # expect due to too few args
  203.         self.assertRaises(TypeError, ref1)
  204.  
  205.         # expect due to too many args
  206.         self.assertRaises(TypeError, ref1, 1, 2, 3)
  207.  
  208.     def check_proxy(self, o, proxy):
  209.         o.foo = 1
  210.         self.assert_(proxy.foo == 1,
  211.                      "proxy does not reflect attribute addition")
  212.         o.foo = 2
  213.         self.assert_(proxy.foo == 2,
  214.                      "proxy does not reflect attribute modification")
  215.         del o.foo
  216.         self.assert_(not hasattr(proxy, 'foo'),
  217.                      "proxy does not reflect attribute removal")
  218.  
  219.         proxy.foo = 1
  220.         self.assert_(o.foo == 1,
  221.                      "object does not reflect attribute addition via proxy")
  222.         proxy.foo = 2
  223.         self.assert_(
  224.             o.foo == 2,
  225.             "object does not reflect attribute modification via proxy")
  226.         del proxy.foo
  227.         self.assert_(not hasattr(o, 'foo'),
  228.                      "object does not reflect attribute removal via proxy")
  229.  
  230.     def test_proxy_deletion(self):
  231.         # Test clearing of SF bug #762891
  232.         class Foo:
  233.             result = None
  234.             def __delitem__(self, accessor):
  235.                 self.result = accessor
  236.         g = Foo()
  237.         f = weakref.proxy(g)
  238.         del f[0]
  239.         self.assertEqual(f.result, 0)
  240.  
  241.     def test_getweakrefcount(self):
  242.         o = C()
  243.         ref1 = weakref.ref(o)
  244.         ref2 = weakref.ref(o, self.callback)
  245.         self.assert_(weakref.getweakrefcount(o) == 2,
  246.                      "got wrong number of weak reference objects")
  247.  
  248.         proxy1 = weakref.proxy(o)
  249.         proxy2 = weakref.proxy(o, self.callback)
  250.         self.assert_(weakref.getweakrefcount(o) == 4,
  251.                      "got wrong number of weak reference objects")
  252.  
  253.     def test_getweakrefs(self):
  254.         o = C()
  255.         ref1 = weakref.ref(o, self.callback)
  256.         ref2 = weakref.ref(o, self.callback)
  257.         del ref1
  258.         self.assert_(weakref.getweakrefs(o) == [ref2],
  259.                      "list of refs does not match")
  260.  
  261.         o = C()
  262.         ref1 = weakref.ref(o, self.callback)
  263.         ref2 = weakref.ref(o, self.callback)
  264.         del ref2
  265.         self.assert_(weakref.getweakrefs(o) == [ref1],
  266.                      "list of refs does not match")
  267.  
  268.     def test_newstyle_number_ops(self):
  269.         class F(float):
  270.             pass
  271.         f = F(2.0)
  272.         p = weakref.proxy(f)
  273.         self.assert_(p + 1.0 == 3.0)
  274.         self.assert_(1.0 + p == 3.0)  # this used to SEGV
  275.  
  276.     def test_callbacks_protected(self):
  277.         # Callbacks protected from already-set exceptions?
  278.         # Regression test for SF bug #478534.
  279.         class BogusError(Exception):
  280.             pass
  281.         data = {}
  282.         def remove(k):
  283.             del data[k]
  284.         def encapsulate():
  285.             f = lambda : ()
  286.             data[weakref.ref(f, remove)] = None
  287.             raise BogusError
  288.         try:
  289.             encapsulate()
  290.         except BogusError:
  291.             pass
  292.         else:
  293.             self.fail("exception not properly restored")
  294.         try:
  295.             encapsulate()
  296.         except BogusError:
  297.             pass
  298.         else:
  299.             self.fail("exception not properly restored")
  300.  
  301.     def test_sf_bug_840829(self):
  302.         # "weakref callbacks and gc corrupt memory"
  303.         # subtype_dealloc erroneously exposed a new-style instance
  304.         # already in the process of getting deallocated to gc,
  305.         # causing double-deallocation if the instance had a weakref
  306.         # callback that triggered gc.
  307.         # If the bug exists, there probably won't be an obvious symptom
  308.         # in a release build.  In a debug build, a segfault will occur
  309.         # when the second attempt to remove the instance from the "list
  310.         # of all objects" occurs.
  311.  
  312.         import gc
  313.  
  314.         class C(object):
  315.             pass
  316.  
  317.         c = C()
  318.         wr = weakref.ref(c, lambda ignore: gc.collect())
  319.         del c
  320.  
  321.         # There endeth the first part.  It gets worse.
  322.         del wr
  323.  
  324.         c1 = C()
  325.         c1.i = C()
  326.         wr = weakref.ref(c1.i, lambda ignore: gc.collect())
  327.  
  328.         c2 = C()
  329.         c2.c1 = c1
  330.         del c1  # still alive because c2 points to it
  331.  
  332.         # Now when subtype_dealloc gets called on c2, it's not enough just
  333.         # that c2 is immune from gc while the weakref callbacks associated
  334.         # with c2 execute (there are none in this 2nd half of the test, btw).
  335.         # subtype_dealloc goes on to call the base classes' deallocs too,
  336.         # so any gc triggered by weakref callbacks associated with anything
  337.         # torn down by a base class dealloc can also trigger double
  338.         # deallocation of c2.
  339.         del c2
  340.  
  341.     def test_callback_in_cycle_1(self):
  342.         import gc
  343.  
  344.         class J(object):
  345.             pass
  346.  
  347.         class II(object):
  348.             def acallback(self, ignore):
  349.                 self.J
  350.  
  351.         I = II()
  352.         I.J = J
  353.         I.wr = weakref.ref(J, I.acallback)
  354.  
  355.         # Now J and II are each in a self-cycle (as all new-style class
  356.         # objects are, since their __mro__ points back to them).  I holds
  357.         # both a weak reference (I.wr) and a strong reference (I.J) to class
  358.         # J.  I is also in a cycle (I.wr points to a weakref that references
  359.         # I.acallback).  When we del these three, they all become trash, but
  360.         # the cycles prevent any of them from getting cleaned up immediately.
  361.         # Instead they have to wait for cyclic gc to deduce that they're
  362.         # trash.
  363.         #
  364.         # gc used to call tp_clear on all of them, and the order in which
  365.         # it does that is pretty accidental.  The exact order in which we
  366.         # built up these things manages to provoke gc into running tp_clear
  367.         # in just the right order (I last).  Calling tp_clear on II leaves
  368.         # behind an insane class object (its __mro__ becomes NULL).  Calling
  369.         # tp_clear on J breaks its self-cycle, but J doesn't get deleted
  370.         # just then because of the strong reference from I.J.  Calling
  371.         # tp_clear on I starts to clear I's __dict__, and just happens to
  372.         # clear I.J first -- I.wr is still intact.  That removes the last
  373.         # reference to J, which triggers the weakref callback.  The callback
  374.         # tries to do "self.J", and instances of new-style classes look up
  375.         # attributes ("J") in the class dict first.  The class (II) wants to
  376.         # search II.__mro__, but that's NULL.   The result was a segfault in
  377.         # a release build, and an assert failure in a debug build.
  378.         del I, J, II
  379.         gc.collect()
  380.  
  381.     def test_callback_in_cycle_2(self):
  382.         import gc
  383.  
  384.         # This is just like test_callback_in_cycle_1, except that II is an
  385.         # old-style class.  The symptom is different then:  an instance of an
  386.         # old-style class looks in its own __dict__ first.  'J' happens to
  387.         # get cleared from I.__dict__ before 'wr', and 'J' was never in II's
  388.         # __dict__, so the attribute isn't found.  The difference is that
  389.         # the old-style II doesn't have a NULL __mro__ (it doesn't have any
  390.         # __mro__), so no segfault occurs.  Instead it got:
  391.         #    test_callback_in_cycle_2 (__main__.ReferencesTestCase) ...
  392.         #    Exception exceptions.AttributeError:
  393.         #   "II instance has no attribute 'J'" in <bound method II.acallback
  394.         #       of <?.II instance at 0x00B9B4B8>> ignored
  395.  
  396.         class J(object):
  397.             pass
  398.  
  399.         class II:
  400.             def acallback(self, ignore):
  401.                 self.J
  402.  
  403.         I = II()
  404.         I.J = J
  405.         I.wr = weakref.ref(J, I.acallback)
  406.  
  407.         del I, J, II
  408.         gc.collect()
  409.  
  410.     def test_callback_in_cycle_3(self):
  411.         import gc
  412.  
  413.         # This one broke the first patch that fixed the last two.  In this
  414.         # case, the objects reachable from the callback aren't also reachable
  415.         # from the object (c1) *triggering* the callback:  you can get to
  416.         # c1 from c2, but not vice-versa.  The result was that c2's __dict__
  417.         # got tp_clear'ed by the time the c2.cb callback got invoked.
  418.  
  419.         class C:
  420.             def cb(self, ignore):
  421.                 self.me
  422.                 self.c1
  423.                 self.wr
  424.  
  425.         c1, c2 = C(), C()
  426.  
  427.         c2.me = c2
  428.         c2.c1 = c1
  429.         c2.wr = weakref.ref(c1, c2.cb)
  430.  
  431.         del c1, c2
  432.         gc.collect()
  433.  
  434.     def test_callback_in_cycle_4(self):
  435.         import gc
  436.  
  437.         # Like test_callback_in_cycle_3, except c2 and c1 have different
  438.         # classes.  c2's class (C) isn't reachable from c1 then, so protecting
  439.         # objects reachable from the dying object (c1) isn't enough to stop
  440.         # c2's class (C) from getting tp_clear'ed before c2.cb is invoked.
  441.         # The result was a segfault (C.__mro__ was NULL when the callback
  442.         # tried to look up self.me).
  443.  
  444.         class C(object):
  445.             def cb(self, ignore):
  446.                 self.me
  447.                 self.c1
  448.                 self.wr
  449.  
  450.         class D:
  451.             pass
  452.  
  453.         c1, c2 = D(), C()
  454.  
  455.         c2.me = c2
  456.         c2.c1 = c1
  457.         c2.wr = weakref.ref(c1, c2.cb)
  458.  
  459.         del c1, c2, C, D
  460.         gc.collect()
  461.  
  462.     def test_callback_in_cycle_resurrection(self):
  463.         import gc
  464.  
  465.         # Do something nasty in a weakref callback:  resurrect objects
  466.         # from dead cycles.  For this to be attempted, the weakref and
  467.         # its callback must also be part of the cyclic trash (else the
  468.         # objects reachable via the callback couldn't be in cyclic trash
  469.         # to begin with -- the callback would act like an external root).
  470.         # But gc clears trash weakrefs with callbacks early now, which
  471.         # disables the callbacks, so the callbacks shouldn't get called
  472.         # at all (and so nothing actually gets resurrected).
  473.  
  474.         alist = []
  475.         class C(object):
  476.             def __init__(self, value):
  477.                 self.attribute = value
  478.  
  479.             def acallback(self, ignore):
  480.                 alist.append(self.c)
  481.  
  482.         c1, c2 = C(1), C(2)
  483.         c1.c = c2
  484.         c2.c = c1
  485.         c1.wr = weakref.ref(c2, c1.acallback)
  486.         c2.wr = weakref.ref(c1, c2.acallback)
  487.  
  488.         def C_went_away(ignore):
  489.             alist.append("C went away")
  490.         wr = weakref.ref(C, C_went_away)
  491.  
  492.         del c1, c2, C   # make them all trash
  493.         self.assertEqual(alist, [])  # del isn't enough to reclaim anything
  494.  
  495.         gc.collect()
  496.         # c1.wr and c2.wr were part of the cyclic trash, so should have
  497.         # been cleared without their callbacks executing.  OTOH, the weakref
  498.         # to C is bound to a function local (wr), and wasn't trash, so that
  499.         # callback should have been invoked when C went away.
  500.         self.assertEqual(alist, ["C went away"])
  501.         # The remaining weakref should be dead now (its callback ran).
  502.         self.assertEqual(wr(), None)
  503.  
  504.         del alist[:]
  505.         gc.collect()
  506.         self.assertEqual(alist, [])
  507.  
  508.     def test_callbacks_on_callback(self):
  509.         import gc
  510.  
  511.         # Set up weakref callbacks *on* weakref callbacks.
  512.         alist = []
  513.         def safe_callback(ignore):
  514.             alist.append("safe_callback called")
  515.  
  516.         class C(object):
  517.             def cb(self, ignore):
  518.                 alist.append("cb called")
  519.  
  520.         c, d = C(), C()
  521.         c.other = d
  522.         d.other = c
  523.         callback = c.cb
  524.         c.wr = weakref.ref(d, callback)     # this won't trigger
  525.         d.wr = weakref.ref(callback, d.cb)  # ditto
  526.         external_wr = weakref.ref(callback, safe_callback)  # but this will
  527.         self.assert_(external_wr() is callback)
  528.  
  529.         # The weakrefs attached to c and d should get cleared, so that
  530.         # C.cb is never called.  But external_wr isn't part of the cyclic
  531.         # trash, and no cyclic trash is reachable from it, so safe_callback
  532.         # should get invoked when the bound method object callback (c.cb)
  533.         # -- which is itself a callback, and also part of the cyclic trash --
  534.         # gets reclaimed at the end of gc.
  535.  
  536.         del callback, c, d, C
  537.         self.assertEqual(alist, [])  # del isn't enough to clean up cycles
  538.         gc.collect()
  539.         self.assertEqual(alist, ["safe_callback called"])
  540.         self.assertEqual(external_wr(), None)
  541.  
  542.         del alist[:]
  543.         gc.collect()
  544.         self.assertEqual(alist, [])
  545.  
  546. class Object:
  547.     def __init__(self, arg):
  548.         self.arg = arg
  549.     def __repr__(self):
  550.         return "<Object %r>" % self.arg
  551.  
  552.  
  553. class MappingTestCase(TestBase):
  554.  
  555.     COUNT = 10
  556.  
  557.     def test_weak_values(self):
  558.         #
  559.         #  This exercises d.copy(), d.items(), d[], del d[], len(d).
  560.         #
  561.         dict, objects = self.make_weak_valued_dict()
  562.         for o in objects:
  563.             self.assert_(weakref.getweakrefcount(o) == 1,
  564.                          "wrong number of weak references to %r!" % o)
  565.             self.assert_(o is dict[o.arg],
  566.                          "wrong object returned by weak dict!")
  567.         items1 = dict.items()
  568.         items2 = dict.copy().items()
  569.         items1.sort()
  570.         items2.sort()
  571.         self.assert_(items1 == items2,
  572.                      "cloning of weak-valued dictionary did not work!")
  573.         del items1, items2
  574.         self.assert_(len(dict) == self.COUNT)
  575.         del objects[0]
  576.         self.assert_(len(dict) == (self.COUNT - 1),
  577.                      "deleting object did not cause dictionary update")
  578.         del objects, o
  579.         self.assert_(len(dict) == 0,
  580.                      "deleting the values did not clear the dictionary")
  581.         # regression on SF bug #447152:
  582.         dict = weakref.WeakValueDictionary()
  583.         self.assertRaises(KeyError, dict.__getitem__, 1)
  584.         dict[2] = C()
  585.         self.assertRaises(KeyError, dict.__getitem__, 2)
  586.  
  587.     def test_weak_keys(self):
  588.         #
  589.         #  This exercises d.copy(), d.items(), d[] = v, d[], del d[],
  590.         #  len(d), d.has_key().
  591.         #
  592.         dict, objects = self.make_weak_keyed_dict()
  593.         for o in objects:
  594.             self.assert_(weakref.getweakrefcount(o) == 1,
  595.                          "wrong number of weak references to %r!" % o)
  596.             self.assert_(o.arg is dict[o],
  597.                          "wrong object returned by weak dict!")
  598.         items1 = dict.items()
  599.         items2 = dict.copy().items()
  600.         self.assert_(Set(items1) == Set(items2),
  601.                      "cloning of weak-keyed dictionary did not work!")
  602.         del items1, items2
  603.         self.assert_(len(dict) == self.COUNT)
  604.         del objects[0]
  605.         self.assert_(len(dict) == (self.COUNT - 1),
  606.                      "deleting object did not cause dictionary update")
  607.         del objects, o
  608.         self.assert_(len(dict) == 0,
  609.                      "deleting the keys did not clear the dictionary")
  610.         o = Object(42)
  611.         dict[o] = "What is the meaning of the universe?"
  612.         self.assert_(dict.has_key(o))
  613.         self.assert_(not dict.has_key(34))
  614.  
  615.     def test_weak_keyed_iters(self):
  616.         dict, objects = self.make_weak_keyed_dict()
  617.         self.check_iters(dict)
  618.  
  619.     def test_weak_valued_iters(self):
  620.         dict, objects = self.make_weak_valued_dict()
  621.         self.check_iters(dict)
  622.  
  623.     def check_iters(self, dict):
  624.         # item iterator:
  625.         items = dict.items()
  626.         for item in dict.iteritems():
  627.             items.remove(item)
  628.         self.assert_(len(items) == 0, "iteritems() did not touch all items")
  629.  
  630.         # key iterator, via __iter__():
  631.         keys = dict.keys()
  632.         for k in dict:
  633.             keys.remove(k)
  634.         self.assert_(len(keys) == 0, "__iter__() did not touch all keys")
  635.  
  636.         # key iterator, via iterkeys():
  637.         keys = dict.keys()
  638.         for k in dict.iterkeys():
  639.             keys.remove(k)
  640.         self.assert_(len(keys) == 0, "iterkeys() did not touch all keys")
  641.  
  642.         # value iterator:
  643.         values = dict.values()
  644.         for v in dict.itervalues():
  645.             values.remove(v)
  646.         self.assert_(len(values) == 0,
  647.                      "itervalues() did not touch all values")
  648.  
  649.     def test_make_weak_keyed_dict_from_dict(self):
  650.         o = Object(3)
  651.         dict = weakref.WeakKeyDictionary({o:364})
  652.         self.assert_(dict[o] == 364)
  653.  
  654.     def test_make_weak_keyed_dict_from_weak_keyed_dict(self):
  655.         o = Object(3)
  656.         dict = weakref.WeakKeyDictionary({o:364})
  657.         dict2 = weakref.WeakKeyDictionary(dict)
  658.         self.assert_(dict[o] == 364)
  659.  
  660.     def make_weak_keyed_dict(self):
  661.         dict = weakref.WeakKeyDictionary()
  662.         objects = map(Object, range(self.COUNT))
  663.         for o in objects:
  664.             dict[o] = o.arg
  665.         return dict, objects
  666.  
  667.     def make_weak_valued_dict(self):
  668.         dict = weakref.WeakValueDictionary()
  669.         objects = map(Object, range(self.COUNT))
  670.         for o in objects:
  671.             dict[o.arg] = o
  672.         return dict, objects
  673.  
  674.     def check_popitem(self, klass, key1, value1, key2, value2):
  675.         weakdict = klass()
  676.         weakdict[key1] = value1
  677.         weakdict[key2] = value2
  678.         self.assert_(len(weakdict) == 2)
  679.         k, v = weakdict.popitem()
  680.         self.assert_(len(weakdict) == 1)
  681.         if k is key1:
  682.             self.assert_(v is value1)
  683.         else:
  684.             self.assert_(v is value2)
  685.         k, v = weakdict.popitem()
  686.         self.assert_(len(weakdict) == 0)
  687.         if k is key1:
  688.             self.assert_(v is value1)
  689.         else:
  690.             self.assert_(v is value2)
  691.  
  692.     def test_weak_valued_dict_popitem(self):
  693.         self.check_popitem(weakref.WeakValueDictionary,
  694.                            "key1", C(), "key2", C())
  695.  
  696.     def test_weak_keyed_dict_popitem(self):
  697.         self.check_popitem(weakref.WeakKeyDictionary,
  698.                            C(), "value 1", C(), "value 2")
  699.  
  700.     def check_setdefault(self, klass, key, value1, value2):
  701.         self.assert_(value1 is not value2,
  702.                      "invalid test"
  703.                      " -- value parameters must be distinct objects")
  704.         weakdict = klass()
  705.         o = weakdict.setdefault(key, value1)
  706.         self.assert_(o is value1)
  707.         self.assert_(weakdict.has_key(key))
  708.         self.assert_(weakdict.get(key) is value1)
  709.         self.assert_(weakdict[key] is value1)
  710.  
  711.         o = weakdict.setdefault(key, value2)
  712.         self.assert_(o is value1)
  713.         self.assert_(weakdict.has_key(key))
  714.         self.assert_(weakdict.get(key) is value1)
  715.         self.assert_(weakdict[key] is value1)
  716.  
  717.     def test_weak_valued_dict_setdefault(self):
  718.         self.check_setdefault(weakref.WeakValueDictionary,
  719.                               "key", C(), C())
  720.  
  721.     def test_weak_keyed_dict_setdefault(self):
  722.         self.check_setdefault(weakref.WeakKeyDictionary,
  723.                               C(), "value 1", "value 2")
  724.  
  725.     def check_update(self, klass, dict):
  726.         #
  727.         #  This exercises d.update(), len(d), d.keys(), d.has_key(),
  728.         #  d.get(), d[].
  729.         #
  730.         weakdict = klass()
  731.         weakdict.update(dict)
  732.         self.assert_(len(weakdict) == len(dict))
  733.         for k in weakdict.keys():
  734.             self.assert_(dict.has_key(k),
  735.                          "mysterious new key appeared in weak dict")
  736.             v = dict.get(k)
  737.             self.assert_(v is weakdict[k])
  738.             self.assert_(v is weakdict.get(k))
  739.         for k in dict.keys():
  740.             self.assert_(weakdict.has_key(k),
  741.                          "original key disappeared in weak dict")
  742.             v = dict[k]
  743.             self.assert_(v is weakdict[k])
  744.             self.assert_(v is weakdict.get(k))
  745.  
  746.     def test_weak_valued_dict_update(self):
  747.         self.check_update(weakref.WeakValueDictionary,
  748.                           {1: C(), 'a': C(), C(): C()})
  749.  
  750.     def test_weak_keyed_dict_update(self):
  751.         self.check_update(weakref.WeakKeyDictionary,
  752.                           {C(): 1, C(): 2, C(): 3})
  753.  
  754.     def test_weak_keyed_delitem(self):
  755.         d = weakref.WeakKeyDictionary()
  756.         o1 = Object('1')
  757.         o2 = Object('2')
  758.         d[o1] = 'something'
  759.         d[o2] = 'something'
  760.         self.assert_(len(d) == 2)
  761.         del d[o1]
  762.         self.assert_(len(d) == 1)
  763.         self.assert_(d.keys() == [o2])
  764.  
  765.     def test_weak_valued_delitem(self):
  766.         d = weakref.WeakValueDictionary()
  767.         o1 = Object('1')
  768.         o2 = Object('2')
  769.         d['something'] = o1
  770.         d['something else'] = o2
  771.         self.assert_(len(d) == 2)
  772.         del d['something']
  773.         self.assert_(len(d) == 1)
  774.         self.assert_(d.items() == [('something else', o2)])
  775.  
  776.     def test_weak_keyed_bad_delitem(self):
  777.         d = weakref.WeakKeyDictionary()
  778.         o = Object('1')
  779.         # An attempt to delete an object that isn't there should raise
  780.         # KeyError.  It didn't before 2.3.
  781.         self.assertRaises(KeyError, d.__delitem__, o)
  782.         self.assertRaises(KeyError, d.__getitem__, o)
  783.  
  784.         # If a key isn't of a weakly referencable type, __getitem__ and
  785.         # __setitem__ raise TypeError.  __delitem__ should too.
  786.         self.assertRaises(TypeError, d.__delitem__,  13)
  787.         self.assertRaises(TypeError, d.__getitem__,  13)
  788.         self.assertRaises(TypeError, d.__setitem__,  13, 13)
  789.  
  790.     def test_weak_keyed_cascading_deletes(self):
  791.         # SF bug 742860.  For some reason, before 2.3 __delitem__ iterated
  792.         # over the keys via self.data.iterkeys().  If things vanished from
  793.         # the dict during this (or got added), that caused a RuntimeError.
  794.  
  795.         d = weakref.WeakKeyDictionary()
  796.         mutate = False
  797.  
  798.         class C(object):
  799.             def __init__(self, i):
  800.                 self.value = i
  801.             def __hash__(self):
  802.                 return hash(self.value)
  803.             def __eq__(self, other):
  804.                 if mutate:
  805.                     # Side effect that mutates the dict, by removing the
  806.                     # last strong reference to a key.
  807.                     del objs[-1]
  808.                 return self.value == other.value
  809.  
  810.         objs = [C(i) for i in range(4)]
  811.         for o in objs:
  812.             d[o] = o.value
  813.         del o   # now the only strong references to keys are in objs
  814.         # Find the order in which iterkeys sees the keys.
  815.         objs = d.keys()
  816.         # Reverse it, so that the iteration implementation of __delitem__
  817.         # has to keep looping to find the first object we delete.
  818.         objs.reverse()
  819.  
  820.         # Turn on mutation in C.__eq__.  The first time thru the loop,
  821.         # under the iterkeys() business the first comparison will delete
  822.         # the last item iterkeys() would see, and that causes a
  823.         #     RuntimeError: dictionary changed size during iteration
  824.         # when the iterkeys() loop goes around to try comparing the next
  825.         # key.  After this was fixed, it just deletes the last object *our*
  826.         # "for o in obj" loop would have gotten to.
  827.         mutate = True
  828.         count = 0
  829.         for o in objs:
  830.             count += 1
  831.             del d[o]
  832.         self.assertEqual(len(d), 0)
  833.         self.assertEqual(count, 2)
  834.  
  835. from test_userdict import TestMappingProtocol
  836.  
  837. class WeakValueDictionaryTestCase(TestMappingProtocol):
  838.     """Check that WeakValueDictionary conforms to the mapping protocol"""
  839.     __ref = {"key1":Object(1), "key2":Object(2), "key3":Object(3)}
  840.     _tested_class = weakref.WeakValueDictionary
  841.     def _reference(self):
  842.         return self.__ref.copy()
  843.  
  844. class WeakKeyDictionaryTestCase(TestMappingProtocol):
  845.     """Check that WeakKeyDictionary conforms to the mapping protocol"""
  846.     __ref = {Object("key1"):1, Object("key2"):2, Object("key3"):3}
  847.     _tested_class = weakref.WeakKeyDictionary
  848.     def _reference(self):
  849.         return self.__ref.copy()
  850.  
  851. def test_main():
  852.     test_support.run_unittest(
  853.         ReferencesTestCase,
  854.         MappingTestCase,
  855.         WeakValueDictionaryTestCase,
  856.         WeakKeyDictionaryTestCase,
  857.         )
  858.  
  859.  
  860. if __name__ == "__main__":
  861.     test_main()
  862.