[Zope-Coders] Zope test results

Chris McDonough chrism@zope.com
11 Jun 2002 23:12:15 -0400


This is actually not a Transience bug but a bug in either
OFS.ObjectManager or ZODB (depending on your point of view) exposed by
the Transience test suite and the recent changes to ZODB.

Here's what happens:

- the test suite uses the _setObject method of the root Zope
  object (the Application object), which subclasses from
  OFS.ObjectManager.ObjectManager.  This method is typically used
  to set subobjects of a "folderish" Zope objects.  This method
  sets up the _p_jar of the subobject that is passed in as the
  object manager's _p_jar if the subobject has no _p_jar.  There
  is a comment in the code as to why this is done:

  # Prepare the _p_jar attribute immediately. _getCopy() may need it.

  That doesn't help me too much, but at least I know I had some
  inspiration for doing it in my own code. ;-)

- as a result, a new persistent object (let's call it "A") is registered
  with the data manager and has its _p_jar set to the objectmanager's
  _p_jar.  Although it has a _p_jar, its _p_oid is None.

- a subobject "B" is attached to object "A", which
  (because object "A" has a _p_jar) causes "A" to be registered
  with the data manager.

- when get_transaction().abort() is called, the registered objects
  are processed in order.  Object "A" (which has no oid) is
  the offender.

Here's a debug session that shows this (I changed Transaction.register
to print registrations as they happened, and they show up in the output)
:

          Zope debugging session for /home/chrism/projects/BackTalk
          The root application object is bound to name 'app'.
          To let other people see your changes, you must:
            get_transaction().commit()
          To see other people's changes, you must:
            app._p_jar.sync()
registered {'folder': <Folder instance at 88d8680>}
registered <TransientObjectContainer at session_data>
>>> from OFS.SimpleItem import SimpleItem  
>>> a = SimpleItem()
>>> b = SimpleItem()
>>> app._setObject('a', a)
registered <Application instance at 88c0760>
'a'
>>> app.a.b = b           
registered <SimpleItem at 0x8719a78>
>>> a._p_oid
>>> b._p_oid
>>> get_transaction().abort()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "ZODB/Transaction.py", line 111, in abort
    j.abort(o, self)
  File "/home/chrism/software/Trunk/lib/python/ZODB/Connection.py", line
227, in abort
    self._cache.invalidate(object._p_oid)
TypeError: len() of unsized object

I'm not sure whether ObjectManager should be fixed or ZODB that should
be fixed or both.  I didn't dig too much into the rationale for setting
up the subobject's _p_jar immediately, does anybody have a good handle
on how this helps the copy machinery?


On Mon, 2002-06-10 at 18:04, Jeremy Hylton wrote:
> >>>>> "BG" == background  <background@shane.zope.com> writes:
> 
>   BG> ERROR: testAddNotification
>   BG> (testTimeoutRelated.TestNotifications)
>   BG> ----------------------------------------------------------------------
>   BG> Traceback (most recent call last):
>   BG>   File "testTimeoutRelated.py", line 70, in tearDown File
>   BG>   "/home/background/zopetest/lib/python/ZODB/Transaction.py",
>   BG>   line 111, in abort
>   BG>     j.abort(o, self)
>   BG>   File
>   BG>   "/home/background/zopetest/lib/python/ZODB/Connection.py",
>   BG>   line 227, in abort
>   BG>     self._cache.invalidate(object._p_oid)
>   BG> TypeError: len() of unsized object
>   BG> ======================================================================
>   BG> ERROR: testDelNotification
>   BG> (testTimeoutRelated.TestNotifications)
>   BG> ----------------------------------------------------------------------
>   BG> Traceback (most recent call last):
>   BG>   File "testTimeoutRelated.py", line 70, in tearDown File
>   BG>   "/home/background/zopetest/lib/python/ZODB/Transaction.py",
>   BG>   line 111, in abort
>   BG>     j.abort(o, self)
>   BG>   File
>   BG>   "/home/background/zopetest/lib/python/ZODB/Connection.py",
>   BG>   line 227, in abort
>   BG>     self._cache.invalidate(object._p_oid)
>   BG> TypeError: len() of unsized object
>   BG> ----------------------------------------------------------------------
>   BG> Ran 1456 tests in 298.544s
> 
> Someone caused these errors when he changed the cPickleCache so that
> it doesn't accept None as an argument to invalidate().  It's clear
> that something is wrong, but I'm not sure what the fix is.
> 
> It would be possible to add a test to abort() in Connection, so that
> it didn't call invalidate if _p_oid is None.  If the object's oid is
> None, then it isn't in the cache.  (It's also clear that the old
> behavior of clearing the entire cache isn't intended.)  
> 
> How did an object with no oid get registered with this data manager?
> I don't understand Transience product well enough to guess.  It's
> possible that there is a bug that needs to be fixed there.
> 
> Jeremy
> 
> 
> 
> _______________________________________________
> Zope-Coders mailing list
> Zope-Coders@zope.org
> http://lists.zope.org/mailman/listinfo/zope-coders