Rename @with_template and class Wrapper to @contextmanager and class
ContextManager. Mark open issues as resolved.
This commit is contained in:
parent
050ac22ecc
commit
f2d367de26
46
pep-0343.txt
46
pep-0343.txt
|
@ -111,7 +111,7 @@ Motivation and Summary
|
||||||
example, it was impossible to do this for the opening example.
|
example, it was impossible to do this for the opening example.
|
||||||
The idea was to define the template like this:
|
The idea was to define the template like this:
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def opening(filename):
|
def opening(filename):
|
||||||
f = open(filename)
|
f = open(filename)
|
||||||
try:
|
try:
|
||||||
|
@ -258,7 +258,7 @@ Generator Decorator
|
||||||
that makes it possible to use a generator that yields exactly once
|
that makes it possible to use a generator that yields exactly once
|
||||||
to control a with-statement. Here's a sketch of such a decorator:
|
to control a with-statement. Here's a sketch of such a decorator:
|
||||||
|
|
||||||
class Wrapper(object):
|
class ContextManager(object):
|
||||||
|
|
||||||
def __init__(self, gen):
|
def __init__(self, gen):
|
||||||
self.gen = gen
|
self.gen = gen
|
||||||
|
@ -285,16 +285,16 @@ Generator Decorator
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("generator caught exception")
|
raise RuntimeError("generator caught exception")
|
||||||
|
|
||||||
def with_template(func):
|
def contextmanager(func):
|
||||||
def helper(*args, **kwds):
|
def helper(*args, **kwds):
|
||||||
return Wrapper(func(*args, **kwds))
|
return ContextManager(func(*args, **kwds))
|
||||||
return helper
|
return helper
|
||||||
|
|
||||||
This decorator could be used as follows:
|
This decorator could be used as follows:
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def opening(filename):
|
def opening(filename):
|
||||||
f = open(filename) # IOError here is untouched by Wrapper
|
f = open(filename) # IOError is untouched by ContextManager
|
||||||
try:
|
try:
|
||||||
yield f
|
yield f
|
||||||
finally:
|
finally:
|
||||||
|
@ -332,18 +332,20 @@ Optional Extensions
|
||||||
is entered).
|
is entered).
|
||||||
|
|
||||||
OTOH such mistakes are easily diagnosed; for example, the
|
OTOH such mistakes are easily diagnosed; for example, the
|
||||||
with_template decorator above raises RuntimeError when the second
|
contextmanager decorator above raises RuntimeError when the second
|
||||||
with-statement calls f.__enter__() again.
|
with-statement calls f.__enter__() again.
|
||||||
|
|
||||||
Open Issues
|
Resolved Open Issues
|
||||||
|
|
||||||
Discussion on python-dev has revealed some open issues. I list
|
Discussion on python-dev revealed some open issues. I list them
|
||||||
them here, with my preferred resolution and its motivation. The
|
here, with my preferred resolution and its motivation. The PEP
|
||||||
PEP as currently written reflects this preferred resolution.
|
has been accepted without these being challenged, so the issues
|
||||||
|
are now resolved.
|
||||||
|
|
||||||
1. The __exit__() method of the with_template decorator class catches
|
1. The __exit__() method of the contextmanager decorator class
|
||||||
StopIteration and considers it equivalent to re-raising the exception
|
catches StopIteration and considers it equivalent to re-raising
|
||||||
passed to throw(). Is allowing StopIteration right here?
|
the exception passed to throw(). Is allowing StopIteration
|
||||||
|
right here?
|
||||||
|
|
||||||
This is so that a generator doing cleanup depending on the
|
This is so that a generator doing cleanup depending on the
|
||||||
exception thrown (like the transactional() example below) can
|
exception thrown (like the transactional() example below) can
|
||||||
|
@ -368,7 +370,7 @@ Examples
|
||||||
1. A template for ensuring that a lock, acquired at the start of a
|
1. A template for ensuring that a lock, acquired at the start of a
|
||||||
block, is released when the block is left:
|
block, is released when the block is left:
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def locking(lock):
|
def locking(lock):
|
||||||
lock.acquire()
|
lock.acquire()
|
||||||
try:
|
try:
|
||||||
|
@ -390,7 +392,7 @@ Examples
|
||||||
2. A template for opening a file that ensures the file is closed
|
2. A template for opening a file that ensures the file is closed
|
||||||
when the block is left:
|
when the block is left:
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def opening(filename, mode="r"):
|
def opening(filename, mode="r"):
|
||||||
f = open(filename, mode)
|
f = open(filename, mode)
|
||||||
try:
|
try:
|
||||||
|
@ -407,7 +409,7 @@ Examples
|
||||||
3. A template for committing or rolling back a database
|
3. A template for committing or rolling back a database
|
||||||
transaction:
|
transaction:
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def transactional(db):
|
def transactional(db):
|
||||||
db.begin()
|
db.begin()
|
||||||
try:
|
try:
|
||||||
|
@ -433,7 +435,7 @@ Examples
|
||||||
|
|
||||||
5. Redirect stdout temporarily:
|
5. Redirect stdout temporarily:
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def redirecting_stdout(new_stdout):
|
def redirecting_stdout(new_stdout):
|
||||||
save_stdout = sys.stdout
|
save_stdout = sys.stdout
|
||||||
sys.stdout = new_stdout
|
sys.stdout = new_stdout
|
||||||
|
@ -454,7 +456,7 @@ Examples
|
||||||
|
|
||||||
6. A variant on opening() that also returns an error condition:
|
6. A variant on opening() that also returns an error condition:
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def opening_w_error(filename, mode="r"):
|
def opening_w_error(filename, mode="r"):
|
||||||
try:
|
try:
|
||||||
f = open(filename, mode)
|
f = open(filename, mode)
|
||||||
|
@ -491,7 +493,7 @@ Examples
|
||||||
|
|
||||||
import decimal
|
import decimal
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def extra_precision(places=2):
|
def extra_precision(places=2):
|
||||||
c = decimal.getcontext()
|
c = decimal.getcontext()
|
||||||
saved_prec = c.prec
|
saved_prec = c.prec
|
||||||
|
@ -520,7 +522,7 @@ Examples
|
||||||
|
|
||||||
9. Here's a more general Decimal-context-switching template:
|
9. Here's a more general Decimal-context-switching template:
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def decimal_context(newctx=None):
|
def decimal_context(newctx=None):
|
||||||
oldctx = decimal.getcontext()
|
oldctx = decimal.getcontext()
|
||||||
if newctx is None:
|
if newctx is None:
|
||||||
|
@ -545,7 +547,7 @@ Examples
|
||||||
|
|
||||||
10. A generic "object-closing" template:
|
10. A generic "object-closing" template:
|
||||||
|
|
||||||
@with_template
|
@contextmanager
|
||||||
def closing(obj):
|
def closing(obj):
|
||||||
try:
|
try:
|
||||||
yield obj
|
yield obj
|
||||||
|
|
Loading…
Reference in New Issue