ContextDecorator via contextmanager: broken?

I

Ian Kelly

Python 3.2 has this lovely new contextlib.ContextDecorator mixin [1]
for context manager classes that allows you to apply the context
manager as a decorator. The docs for this feature include the note:

ContextDecorator is used by contextmanager(), so you get this
functionality automatically.

Sweet! So I tried this out:
.... def print_stuff():
.... print('Starting')
.... try:
.... yield 'Yielded'
.... finally:
.... print('Exiting')
........ def test():
.... print('The bit in the middle')
....Starting
The bit in the middle
Exiting

So far so good. There seems to be no straight-forward way for the
function to get access to the 'Yielded' value, but I suppose I can
live with that.

But then I tried calling the function again:
Traceback (most recent call last):
File "c:\python32\lib\contextlib.py", line 28, in __enter__
return next(self.gen)
StopIteration

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "c:\python32\lib\contextlib.py", line 15, in inner
with self:
File "c:\python32\lib\contextlib.py", line 30, in __enter__
raise RuntimeError("generator didn't yield")
RuntimeError: generator didn't yield

Whoops! The problem is that the same generator instance is used for
both function calls, and since the first call has already exhausted
the generator, the second call just fizzles. Now, you might think
that this can be salvaged by looping inside the generator. But that
doesn't work either:
.... def print_stuff():
.... while True:
.... print('Starting')
.... try:
.... yield
.... finally:
.... print('Exiting')
........ def test():
.... print('The bit in the middle')
....Starting
The bit in the middle
Exiting
Starting
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "c:\python32\lib\contextlib.py", line 16, in inner
return func(*args, **kwds)
File "c:\python32\lib\contextlib.py", line 39, in __exit__
raise RuntimeError("generator didn't stop")
RuntimeError: generator didn't stop

So as far as I can tell, generator-based context managers simply can't
be used as ContextDecorators. Furthermore, the documentation's claim
that they can is actually harmful, since they *appear* to work at
first. Or am I simply missing something here?

Cheers,
Ian

[1] http://docs.python.org/py3k/library/contextlib.html#contextlib.ContextDecorator
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top