[Python-checkins] python/dist/src/Lib/test test_gc.py,1.25,1.26

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Sat, 05 Apr 2003 16:11:41 -0800


Update of /cvsroot/python/python/dist/src/Lib/test
In directory sc8-pr-cvs1:/tmp/cvs-serv11222/python/Lib/test

Modified Files:
	test_gc.py 
Log Message:
Reworked move_finalizer_reachable() to create two distinct lists:
externally unreachable objects with finalizers, and externally unreachable
objects without finalizers reachable from such objects.  This allows us
to call has_finalizer() at most once per object, and so limit the pain of
nasty getattr hooks.  This fixes the failing "boom 2" example Jeremy
posted (a non-printing variant of which is now part of test_gc), via never
triggering the nasty part of its __getattr__ method.


Index: test_gc.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/test/test_gc.py,v
retrieving revision 1.25
retrieving revision 1.26
diff -C2 -d -r1.25 -r1.26
*** test_gc.py	5 Apr 2003 17:46:04 -0000	1.25
--- test_gc.py	6 Apr 2003 00:11:38 -0000	1.26
***************
*** 254,258 ****
      gc.disable()
  
! class C:
      def __getattr__(self, someattribute):
          del self.attr
--- 254,258 ----
      gc.disable()
  
! class Boom:
      def __getattr__(self, someattribute):
          del self.attr
***************
*** 260,265 ****
  
  def test_boom():
!     a = C()
!     b = C()
      a.attr = b
      b.attr = a
--- 260,265 ----
  
  def test_boom():
!     a = Boom()
!     b = Boom()
      a.attr = b
      b.attr = a
***************
*** 268,272 ****
      garbagelen = len(gc.garbage)
      del a, b
!     # a<->b are in a trash cycle now.  Collection will invoke C.__getattr__
      # (to see whether a and b have __del__ methods), and __getattr__ deletes
      # the internal "attr" attributes as a side effect.  That causes the
--- 268,272 ----
      garbagelen = len(gc.garbage)
      del a, b
!     # a<->b are in a trash cycle now.  Collection will invoke Boom.__getattr__
      # (to see whether a and b have __del__ methods), and __getattr__ deletes
      # the internal "attr" attributes as a side effect.  That causes the
***************
*** 277,280 ****
--- 277,307 ----
      expect(len(gc.garbage), garbagelen, "boom")
  
+ class Boom2:
+     def __init__(self):
+         self.x = 0
+ 
+     def __getattr__(self, someattribute):
+         self.x += 1
+         if self.x > 1:
+             del self.attr
+         raise AttributeError
+ 
+ def test_boom2():
+     a = Boom2()
+     b = Boom2()
+     a.attr = b
+     b.attr = a
+ 
+     gc.collect()
+     garbagelen = len(gc.garbage)
+     del a, b
+     # Much like test_boom(), except that __getattr__ doesn't break the
+     # cycle until the second time gc checks for __del__.  As of 2.3b1,
+     # there isn't a second time, so this simply cleans up the trash cycle.
+     # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get reclaimed
+     # this way.
+     expect(gc.collect(), 4, "boom2")
+     expect(len(gc.garbage), garbagelen, "boom2")
+ 
  def test_all():
      gc.collect() # Delete 2nd generation garbage
***************
*** 296,299 ****
--- 323,327 ----
      run_test("trashcan", test_trashcan)
      run_test("boom", test_boom)
+     run_test("boom2", test_boom2)
  
  def test():