[Zope-dev] Re: "hasattr" geddon

Shane Hathaway shane at hathawaymix.org
Sun Jul 11 19:28:12 EDT 2004


On Saturday 10 July 2004 15:55 pm, Tim Peters wrote:
> [Shane Hathaway]
>
> > Here is what often happens in Zope:
> >
> > def setFoo(self, value):
> >  try:
> >    self.foo = value
> >  except:
> >    LOG("Oops", ERROR, "Some error happened", error=sys.exc_info())
> >  self.change_count += 1
> >  self.get_indexes().update(self)
> >
> > Some piece of code has a legitimate reason to catch but log all
> > exceptions. Some other piece of code updates indexes.  The database has
> > now committed a partial transaction.
>
> I need more words -- I don't see a commit() in that code, and I don't
> know what "partial transaction" might mean (in ZODB you can commit a
> transaction, or abort it -- there's no facility I know of for a
> partial commit (or a partial abort, for that matter)).

Commit occurs later, in the publisher.  It is a partial transaction because 
the first part was implicitly aborted.  The change to "self.foo" was aborted, 
while the change to self.change_count and the indexes was not.

> > Even worse, this can happen within the indexes, making the indexes
> > inconsistent with themselves.
>
> Sorry, since I didn't understand the first part, I'm way lost here.
>
> > Once a conflict error has occurred on any object, the rest of the
> > transaction is on shaky grounds.
>
> Which is why the current ZODB releases intend to prevent committing a
> transaction if a conflict error occurred during the transaction.  It
> shouldn't matter to this ZODB machinery if the application suppressed
> the original conflict error(s), ZODB remembers that it raised
> ReadConflictError regardless (via the Connection._conflicts
> set-implemented-as-a-dict).

Well, you described what I'm asking for: "prevent committing a transaction if 
a conflict error occurred during the transaction".  I don't believe it's 
doing that, though.  If a conflict occurs on any object (read conflict or 
write conflict), ZODB should prevent any attempt to commit even if no one 
tries to change that object a second time.

> Dieter already wrote it <wink>.  Zope/ZODB's use of Python's machinery
> is sometimes so far from the goals Guido had in mind that Zope is
> alone in wanting a Python change.  For example, I don't know of other
> apps where calling hasattr() can have disastrous consequences.

I think it's wrong that hasattr can have disastrous consequences.  I think 
Zope is more wrong than hasattr.  However, I don't like hasattr now because I 
had no idea that it hides errors.

> That's certainly not needed for "ordinary" uses, like
>
>      if hasattr(errno, "WSAEWOULDBLOCK"):    # Windows
>
> Uses of hasattr() on base Python objects and modules is safe (as I
> believe it is in *almost* all applications outside our part of the
> Python world).

In your example, imagine that errno has a __getattribute__ hook that tries to 
interface with C code.  Imagine some kind of linker error occurs and a 
meaningful error results, but hasattr swallows it.  Wouldn't you like to know 
about the linker error rather than receive a possibly wrong answer?

Shane


More information about the Zope-Dev mailing list