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 <pyt...@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 -- https://mail.python.org/mailman/listinfo/python-list