'NoneType' in contextmanager prevent proper RuntimeError to be raised

Daniel Gonçalves daniel at base4.com.br
Wed May 20 20:08:07 EDT 2015


>From the "Lib/contextlib.py":

    class GeneratorContextManager(object):
        """Helper for @contextmanager decorator."""

        def __init__(self, gen):
            self.gen = gen

        def __enter__(self):
            try:
                return self.gen.next()
            except StopIteration:
                raise RuntimeError("generator didn't yield")

The line "raise RuntimerError(...)" never gets reached, since self.gen is None.

So you end up with an AttributeError: 'NoneType' object has no
attribute 'next', instead of the proper RuntimeError, making it harder
to debug.

Anyways, I know that it's strange to have a contextmanager that didn't yield.

I just stumbled upon this, by accident, and I think the way it's
implemented looks wrong :)

2015-05-20 20:44 GMT-03:00 MRAB <python at mrabarnett.plus.com>:
> On 2015-05-21 00:20, Daniel Gonçalves 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.
>>
> If it doesn't contain a 'yield', it's not a generator, it's a function.
>



-- 
Daniel Gonçalves
Base4 Sistemas Ltda ME
www.base4.com.br



More information about the Python-list mailing list