Update this PEP to reflect the new design: exceptions are swallowed only
when __exit__ returns a true value.
This commit is contained in:
parent
03a9d2dab8
commit
f6659b5348
29
pep-0343.txt
29
pep-0343.txt
|
@ -236,7 +236,9 @@ Specification: The 'with' Statement
|
||||||
except:
|
except:
|
||||||
# The exceptional case is handled here
|
# The exceptional case is handled here
|
||||||
exc = False
|
exc = False
|
||||||
exit(*sys.exc_info())
|
if not exit(*sys.exc_info()):
|
||||||
|
raise
|
||||||
|
# The exception is swallowed if exit() returns true
|
||||||
finally:
|
finally:
|
||||||
# The normal and non-local-goto cases are handled here
|
# The normal and non-local-goto cases are handled here
|
||||||
if exc:
|
if exc:
|
||||||
|
@ -277,17 +279,21 @@ Specification: The 'with' Statement
|
||||||
BLOCK, ctx.__exit__() is called with three arguments representing
|
BLOCK, ctx.__exit__() is called with three arguments representing
|
||||||
the exception type, value, and traceback.
|
the exception type, value, and traceback.
|
||||||
|
|
||||||
IMPORTANT: if ctx.__exit__() is passed exception information, it
|
IMPORTANT: if ctx.__exit__() returns a "true" value, the exception
|
||||||
*must* re-raise the exception, unless it wants the exception to be
|
is "swallowed". That is, if it returns "true", execution
|
||||||
ignored. That is, if ctx.__exit__() returns normally, execution
|
|
||||||
continues at the next statement after the with-statement, even if
|
continues at the next statement after the with-statement, even if
|
||||||
an exception happened inside the with-statement. However, if the
|
an exception happened inside the with-statement. However, if the
|
||||||
with-statement was left via a non-local goto (break, continue or
|
with-statement was left via a non-local goto (break, continue or
|
||||||
return), this non-local return is resumed when ctx.__exit__()
|
return), this non-local return is resumed when ctx.__exit__()
|
||||||
returns normally. The motivation for this detail is to make a
|
returns regardless of the return value. The motivation for this
|
||||||
try/except block in a context manager created from a decorated
|
detail is to make it possible for ctx.__exit__() to swallow
|
||||||
generator behave exactly as if the body of the generator were
|
exceptions, without making it too easy (since the default return
|
||||||
expanded in-line at the place of the with-statement.
|
value, None, is false and this causes the exception to be
|
||||||
|
re-raised). The main use case for swallowing exceptions is to
|
||||||
|
make it possible to write the @contextmanager decorator so thatn
|
||||||
|
that a try/except block in a decorated generator behaves 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
|
The motivation for passing the exception details to __exit__(), as
|
||||||
opposed to the argument-less __exit__() from PEP 310, was given by
|
opposed to the argument-less __exit__() from PEP 310, was given by
|
||||||
|
@ -351,10 +357,9 @@ Generator Decorator
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self.gen.throw(type, value, traceback)
|
self.gen.throw(type, value, traceback)
|
||||||
except (type, StopIteration):
|
return True
|
||||||
return
|
except StopIteration:
|
||||||
else:
|
return True
|
||||||
raise RuntimeError("generator caught exception")
|
|
||||||
|
|
||||||
def contextmanager(func):
|
def contextmanager(func):
|
||||||
def helper(*args, **kwds):
|
def helper(*args, **kwds):
|
||||||
|
|
Loading…
Reference in New Issue