[Python-Dev] PEP 343 rewrite complete
Guido van Rossum
gvanrossum at gmail.com
Thu Jun 2 16:38:48 CEST 2005
[Arnold deVos, responding to himself]
> > This template eats eats the exception, which will cause a RuntimeError
> > in the proposed Wrapper, I think. A raise after rollback is needed.
No, the generator returns after rolling back, which causes throw() to
raise StopIteration, which is good enough for the wrapper as written.
> Actually, the Wrapper as written in the PEP does not raise RuntimeError
> if the generator catches a block's exception.
>
> Shouldn't the relevant clause in the Wrapper go like this:
>
> try:
> self.gen.throw(type, value, traceback)
> except type:
> return
> except StopIteration:
> raise RuntimeError("generator caught exception")
> else:
> raise RuntimeError("generator didn't stop")
I considered that, but decided that it should be okay for the
generator to respond to a throw() by returning (thus replacing the
exception thrown by StopIteration) since the call to __exit__() is
contained inside a finally-clause, so that when __exit__() returns
normally, the finally-clause will re-raise the original exception
anyway.
Note that there are currently no other use cases for throw() except
the with_template decorator and the close() method. Both allow the
generator to respond either by letting the exception pass through it
unchanged (after executing finally-clauses if present) or by simply
returning (which will raise StopIteration in the caller of throw()).
Erroneous behaviors are, in both cases, raising some other exception
or *yielding* another value. There may be *other* use cases for
yielding a value, for example, a future (looping) block-statement a la
PEP 343. Raising another exception is always an indication of a bug in
the generator.
> And the transaction template would go like this (re-raising the exception):
>
> @with_template
> def transactional(db):
> db.begin()
> try:
> yield None
> except:
> db.rollback()
> raise
> else:
> db.commit()
>
> At least this is what I gleaned from the earlier threads. It means that
> the template does not appear to supress an exception that it cannot
> actually supress.
I disagree (at the -0 to -0.5 level); given that the with_template
decorator allows StopIteration, I think that "appearing to suppress an
exception it doesn't actually suppress" is a minor sin -- the key
point is that the cleanup gets executed and doesn't raise a new
exception or reaches a yield-statement.
I'll summarize this discussion in the PEP.
--
--Guido van Rossum (home page: http://www.python.org/~guido/)
More information about the Python-Dev
mailing list