Change the PEP to add that __exit__() must re-raise the exception
passed in, if any. This appears to be a deviation from how the PEP was originally seen; but I think it's essential to be able to make a simple promise about generators decorated with @contextmanager. Added the transition plan and the __future__ statement. Also some miscellaneous cleanup.
This commit is contained in:
parent
12bffcefbe
commit
f038797f00
59
pep-0343.txt
59
pep-0343.txt
|
@ -227,21 +227,22 @@ Specification: The 'with' Statement
|
|||
|
||||
ctx = (EXPR).__context__()
|
||||
exit = exc.__exit__ # Not calling it yet
|
||||
res = ctx.__enter__()
|
||||
value = ctx.__enter__()
|
||||
exc = (None, None, None)
|
||||
try:
|
||||
try:
|
||||
VAR = res # Only if "as VAR" is present
|
||||
VAR = value # Only if "as VAR" is present
|
||||
BLOCK
|
||||
except:
|
||||
exc = sys.exc_info()
|
||||
raise
|
||||
exc = None
|
||||
exit(*sys.exc_info())
|
||||
finally:
|
||||
if exc:
|
||||
exit(*exc)
|
||||
|
||||
Here, the lowercase variables are internal variables and not
|
||||
accessible to the user; they will most likely be implemented as
|
||||
special registers or stack positions.
|
||||
Here, the lowercase variables (ctx, exit, value, exc) are internal
|
||||
variables and not accessible to the user; they will most likely be
|
||||
implemented as special registers or stack positions.
|
||||
|
||||
The details of the above translation are intended to prescribe the
|
||||
exact semantics. If any of the relevant methods are not found as
|
||||
|
@ -264,20 +265,32 @@ Specification: The 'with' Statement
|
|||
object each time its __context__ method is invoked.
|
||||
|
||||
If the "as VAR" part of the syntax is omitted, the "VAR =" part of
|
||||
the translation is omitted (but abc.__enter__() is still called).
|
||||
the translation is omitted (but ctx.__enter__() is still called).
|
||||
|
||||
The calling convention for abc.__exit__() is as follows. If the
|
||||
The calling convention for ctx.__exit__() is as follows. If the
|
||||
finally-suite was reached through normal completion of BLOCK or
|
||||
through a non-local goto (a break, continue or return statement in
|
||||
BLOCK), abc.__exit__() is called with three None arguments. If
|
||||
BLOCK), ctx.__exit__() is called with three None arguments. If
|
||||
the finally-suite was reached through an exception raised in
|
||||
BLOCK, abc.__exit__() is called with three arguments representing
|
||||
BLOCK, ctx.__exit__() is called with three arguments representing
|
||||
the exception type, value, and traceback.
|
||||
|
||||
The motivation for this API to __exit__(), as opposed to the
|
||||
argument-less __exit__() from PEP 310, was given by the
|
||||
transactional() use case, example 3 below. The template in that
|
||||
example must commit or roll back the transaction depending on
|
||||
IMPORTANT: if ctx.__exit__() is passed exception information, it
|
||||
*must* re-raise the exception, unless it wants the exception to be
|
||||
ignored. That is, if ctx.__exit__() returns normally, execution
|
||||
continues at the next statement after the with-statement, even if
|
||||
an exception happened inside the with-statement. However, if the
|
||||
with-statement was left via a non-local goto (break, continue or
|
||||
return), this non-local return is resumed when ctx.__exit__()
|
||||
returns normally. The motivation for this detail is to make a
|
||||
try/except block in a context manager created from a decorated
|
||||
generator behave exactly as if the body of the generator were
|
||||
expanded in-line at the place of the with-statement.
|
||||
|
||||
The motivation for passing the exception details to __exit__(), as
|
||||
opposed to the argument-less __exit__() from PEP 310, was given by
|
||||
the transactional() use case, example 3 below. The template in
|
||||
that example must commit or roll back the transaction depending on
|
||||
whether an exception occurred or not. Rather than just having a
|
||||
boolean flag indicating whether an exception occurred, we pass the
|
||||
complete exception information, for the benefit of an
|
||||
|
@ -291,6 +304,20 @@ Specification: The 'with' Statement
|
|||
non-local goto should be considered unexceptional for the purposes
|
||||
of a database transaction roll-back decision.
|
||||
|
||||
Transition Plan
|
||||
|
||||
In Python 2.5, the new syntax will only be recognized if a future
|
||||
statement is present:
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
This will make both 'with' and 'as' keywords. Without the future
|
||||
statement, using 'with' or 'as' as an identifier will cause a
|
||||
DeprecationWarning to be issued.
|
||||
|
||||
In Python 2.6, the new syntax will always be recognized; 'with'
|
||||
and 'as' are always keywords.
|
||||
|
||||
Generator Decorator
|
||||
|
||||
With PEP 342 accepted, it is possible to write a decorator
|
||||
|
@ -394,6 +421,7 @@ Optional Extensions
|
|||
- threading.Lock
|
||||
- threading.RLock
|
||||
- threading.Condition
|
||||
- threading.Semaphore and threading.BoundedSemaphore
|
||||
|
||||
Standard Terminology
|
||||
|
||||
|
@ -598,6 +626,7 @@ Examples
|
|||
yield None
|
||||
except:
|
||||
db.rollback()
|
||||
raise
|
||||
else:
|
||||
db.commit()
|
||||
|
||||
|
|
Loading…
Reference in New Issue