Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #7417

ContextDecorator via contextmanager: broken?

Path csiph.com!x330-a1.tempe.blueboxinc.net!newsfeed.hal-mli.net!feeder1.hal-mli.net!weretis.net!feeder1.news.weretis.net!feeder.erje.net!newsfeed.xs4all.nl!newsfeed6.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail
Return-Path <ian.g.kelly@gmail.com>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.001
X-Spam-Evidence '*H*': 1.00; '*S*': 0.00; 'context': 0.04; 'value,': 0.04; '3.2': 0.05; 'instance': 0.05; 'suppose': 0.05; 'exception,': 0.07; 'python': 0.08; 'finally:': 0.09; 'subject:broken': 0.09; '>>>': 0.12; 'def': 0.12; 'exception': 0.12; '*appear*': 0.16; '39,': 0.16; 'looping': 0.16; 'test()': 0.16; 'test():': 0.16; '16,': 0.16; 'traceback': 0.16; '(most': 0.16; 'yield': 0.19; 'cheers,': 0.19; 'seems': 0.21; 'here?': 0.23; 'last):': 0.23; 'received:209.85.161.46': 0.23; 'received :mail-fx0-f46.google.com': 0.23; "doesn't": 0.25; 'function': 0.25; 'classes': 0.26; 'received:209.85.161': 0.26; 'tried': 0.27; 'message-id:@mail.gmail.com': 0.28; 'raise': 0.28; 'problem': 0.28; 'skip:" 30': 0.29; 'subject:?': 0.29; 'good.': 0.29; 'bit': 0.30; 'second': 0.30; 'exiting': 0.30; 'url:library': 0.31; 'calling': 0.31; "didn't": 0.31; "can't": 0.32; 'apply': 0.32; 'to:addr:python-list': 0.33; 'handling': 0.33; 'actually': 0.33; 'starting': 0.33; 'file': 0.34; '[1]': 0.34; 'first.': 0.34; 'there': 0.35; '"",': 0.35; 'skip:@ 10': 0.35; 'try:': 0.35; 'received:google.com': 0.37; 'something': 0.37; 'received:209.85': 0.37; 'url:docs': 0.37; 'another': 0.37; 'think': 0.38; 'url:python': 0.38; 'url:org': 0.38; 'but': 0.38; 'docs': 0.38; 'subject:: ': 0.38; 'received:209': 0.39; 'to:addr:python.org': 0.39; 'allows': 0.40; 'feature': 0.40; 'missing': 0.40; 'simply': 0.60; 'stop': 0.62; 'note:': 0.63; 'subject:skip:C 10': 0.72; 'claim': 0.76; '30,': 0.84; 'calls,': 0.84; 'generator,': 0.84; 'lovely': 0.84; 'self:': 0.84
DKIM-Signature v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:from:date:message-id:subject:to :content-type; bh=K/3uPb8qXVy+GnYG1WtnkpoGyt58aD9EDuhaig2IFWU=; b=LmuM/nnwA36yRuowgXnCZyos/YW0bzuE2Vcsmj28NgDUIaTWzEYZ8DoNA2AvEw00j5 kFC3mbFlnKYBIVbcPKrswYex5/AaVsYoasmY305TJfd5WIvEEKK1N/mgA9s32P/oHF7s A0xtPMF6ybfCrppJqYtI9gHUHFlD24yfTQtME=
DomainKey-Signature a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:from:date:message-id:subject:to:content-type; b=o80LUurIN4kpXf0D1AoiTPkbQdKsuITnDrgROMzfCoGzVvJKi2kx49aweJmpVuM1Aw o0xkwvBn8CBJMoQjih2NDigvAY2YfPnotMCQiLtDZNk+GHPnqiDL6codon1rW9wwml7T IZ91+ITVt+Yhc+Jv7Es1oI4AvnXzGiiQ7+MEQ=
MIME-Version 1.0
From Ian Kelly <ian.g.kelly@gmail.com>
Date Fri, 10 Jun 2011 16:57:51 -0600
Subject ContextDecorator via contextmanager: broken?
To Python <python-list@python.org>
Content-Type text/plain; charset=ISO-8859-1
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.12
Precedence list
List-Id General discussion list for the Python programming language <python-list.python.org>
List-Unsubscribe <http://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive <http://mail.python.org/pipermail/python-list>
List-Post <mailto:python-list@python.org>
List-Help <mailto:python-list-request@python.org?subject=help>
List-Subscribe <http://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe>
Newsgroups comp.lang.python
Message-ID <mailman.114.1307746701.11593.python-list@python.org> (permalink)
Lines 89
NNTP-Posting-Host 82.94.164.166
X-Trace 1307746702 news.xs4all.nl 49184 [::ffff:82.94.164.166]:46182
X-Complaints-To abuse@xs4all.nl
Xref x330-a1.tempe.blueboxinc.net comp.lang.python:7417

Show key headers only | View raw


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:

>>> @contextmanager
... def print_stuff():
...   print('Starting')
...   try:
...     yield 'Yielded'
...   finally:
...     print('Exiting')
...
>>> @print_stuff()
... def test():
...   print('The bit in the middle')
...
>>> test()
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:

>>> test()
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:

>>> @contextmanager
... def print_stuff():
...   while True:
...     print('Starting')
...     try:
...       yield
...     finally:
...       print('Exiting')
...
>>> @print_stuff()
... def test():
...   print('The bit in the middle')
...
>>> test()
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

Back to comp.lang.python | Previous | Next | Find similar | Unroll thread


Thread

ContextDecorator via contextmanager: broken? Ian Kelly <ian.g.kelly@gmail.com> - 2011-06-10 16:57 -0600

csiph-web