'NoneType' in contextmanager prevent proper RuntimeError to be raised

Cameron Simpson cs at zip.com.au
Wed May 20 19:58:25 EDT 2015


On 20May2015 16:20, Daniel Gonçalves <daniel.base4 at gmail.com> wrote:
>When you decorate a function with contextmanager that didn't yield you got an AttributeError instead of a proper RuntimeError "generator didn't yield". For example:
>
>>>> @contextlib.contextmanager
>>>> def foo():
>...     pass
>...
>>>> with foo():
>...     do_something()
>...
>Traceback (most recent call last):
>  File "<stdin>", line 1, in <module>
>  File "/usr/lib/python2.7/contextlib.py", line 17, in __enter__
>    return self.gen.next()
>AttributeError: 'NoneType' object has no attribute 'next'
>
>The proper exception should be a RuntimerError with the "generator didn't yield" message. At least for Python version 2.7.6.

Unfortunately no.

Your function foo() is _not_ a generator because it does not have a yield 
statement. Therefore it is a normal funcion which returns None (because it also 
lacks a return statement).

contextlib.contextmanager works by _calling_ the inner foo(). It expected to 
get a generator back. But your foo() returns None, _not_ a generator.

hence the error message: contextlib.contextmanager tries to use the return 
value with next(), which of course fails with exactly the exception one might 
expect.

To get "generator didn't yield" you need to actually have a generator. Eg:

  @contextlib.contextmanager
  def foo():
    if false:
      yield

Untested, though.

Cheers,
Cameron Simpson <cs at zip.com.au>



More information about the Python-list mailing list