[Python-Dev] context manager - generator interaction?

Guido van Rossum guido at python.org
Thu Apr 5 22:10:06 CEST 2007

Isn't this violating the rule that a try/except should only enclose
the smallest expression where the exception is expected?

BTW this is probably more appropriate for c.l.py -- even if there's a
change to the language to come out of the discussion, it should be
held there until the use case is well established. But my suspicion is
that you get what you ask for with an overly-wide try block.


On 4/5/07, Bob Sidebotham <bob.sidebotham at gmail.com> wrote:
> The interaction shown below feels like a bug, or at least very much a
> trap for the unwary. It's some sort of interaction between a context
> manager and a generator, both of which can raise StopIteration. The
> code is excised from a real application, so it's a bit artificial
> looking. Nevertheless, it represents an entirely natural evolution of
> some code (whereby the call to a context manager was added deep within
> the code). Since it seems to work with open as the context manager,
> but not with my own null context manager defined with
> context_manager(), it feels like this is probably a bug in
> contextmanager().
> I did look in the archives, and it's possible this has been raised
> before, but I wasn't clear on that. So apologies in advance if this is
> already understood.
> This is using the stock distribution of python 2.5 on Linux 2.4.
> Comments?
> Bob Sidebotham
> bash-2.05b$ cat test.py
> from __future__ import with_statement
> def gen():
>     return# Should cause stop iteration
>     yield # Just to make this a generator, for this example
> # This works as expected.
> try:
>     gen().next() # Should immediately raise StopIteration
> except StopIteration:
>     print "Part 1: should reach here!"
> else:
>     print "Part 1: shouldn't reach here!"
> # Now try the same thing, but with a context manager wrapping the
> generator call.
> # This also works as expected.
> try:
>     with open("/etc/passwd") as pw:
>         gen().next()
> except StopIteration:
>     print "Part 2: should reach here!"
> else:
>     print "Part 2: shouldn't reach here!"
> # Finally, try this with our own home grown null context manager.
> # This does not work as expected.
> from contextlib import contextmanager
> @contextmanager
> def ctxt():
>     yield
> try:
>     with ctxt():
>         gen().next()
> except StopIteration:
>     print "Part 3: should reach here!"
> else:
>     print "Part 3: shouldn't reach here!"
> bash-2.05b$ python test.py
> Part 1: should reach here!
> Part 2: should reach here!
> Part 3: shouldn't reach here!
> bash-2.05b$
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org

--Guido van Rossum (home page: http://www.python.org/~guido/)

More information about the Python-Dev mailing list