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