micheles/decorator

`decorator.contextmanager` instances do not work properly as decorators

apizarro-paypal opened this issue ยท 2 comments

Functions decorated with a decorator/context-manager built with decorator.contextmanager fail when invoked more than once.

I've experienced this in:

  • Python 3.5 with decorator v5.0.9.
  • Python 2.7 and 3.5 with decorator v4.4.1.

Repro code:

# from contextlib import contextmanager
# from contextlib2 import contextmanager
from decorator import contextmanager


@contextmanager
def before_after(before, after):
    print(before)
    yield
    print(after)


ba = before_after('BEFORE', 'AFTER')


@ba
def hello():
    print('hello')


hello()
hello()

Output:

BEFORE
hello
AFTER
Traceback (most recent call last):
  File "/Users/apizarro/tmp/test.py", line 22, in <module>
    hello()
  File "/Users/apizarro/.pyenv/versions/3.5.10/lib/python3.5/site-packages/decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "/Users/apizarro/.pyenv/versions/3.5.10/lib/python3.5/site-packages/decorator.py", line 285, in caller
    with self:
  File "/Users/apizarro/.pyenv/versions/3.5.10/lib/python3.5/contextlib.py", line 61, in __enter__
    raise RuntimeError("generator didn't yield") from None
RuntimeError: generator didn't yield

This does not happen when using the regular contextmanager decorator from the standard library.

I am surprised that this was never reported in 10+ years. I will look at it.

@micheles Thank you so much for such a quick fix ๐Ÿ‘๐Ÿป . Would it be possible to get a backport of this fix for the 4.x series? (though I'd understand if it's no longer supported). My reason being that, I'm working on projects/libraries that must remain Python 2 and 3 compatible for a while longer.