A better contextlib.contextmanager

M

Michele Simionato

Python 3.2 enhanced contextlib.contextmanager so that it is possible to
use a context manager as a decorator. For instance, given the
contextmanager factory below

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

it is possibile to use it to generate decorators:

@before_after()
def hello(user):
print('hello', user)

This is equivalent to the more traditional

def hello(user):
with before_after():
print('hello', user)

but it has the advantage of saving a level of indentation and we all
know that flat is better than nested. Cool, but there are three issues:

1. I am using Python 2.7, not Python 3.2, so contextmanager has not such feature
2. The contextmanager decorator is losing the signature of the before_after factory:

Help on function before_after in module __main__:

before_after(*args, **kwds)
3. before_after() decorators do not preserve the signature of the decorated function either.

Since I am the author of the decorator module I have easily found out a recipe to solve both issues. Here it is:

from decorator import decorator, FunctionMaker
from contextlib import GeneratorContextManager

class GeneratorCM(GeneratorContextManager):
def __call__(self, func):
return FunctionMaker.create(
func, "with _cm_: return _func_(%(shortsignature)s)",
dict(_cm_=self, _func_=func), __wrapped__=func)

@decorator
def contextmanager(func, *args, **kwds):
return GeneratorCM(func(*args, **kwds))

before_after() objects obtained by using this version of
contextmanager become signature-preserving decorators. I am not going
to explain how FunctionMaker performs its magic (hint: it uses eval),
but I am asking a question instead: should I add this feature to the
next release of the decorator module? Do people use the
context-manager-as-decorator functionality? It is quite handy in unit
tests and actually I think it came from the unittest2 module. But I am
reluctant to complicate the API of the module, which currently is
really really small and such has been for many years.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top