[Python-Dev] Creating APIs that work as both decorators and context managers

Michael Foord fuzzyman at voidspace.org.uk
Fri Jun 25 20:35:35 CEST 2010


Hello all,

I've put a recipe up on the Python cookbook for creating APIs that work 
as both decorators and context managers and wonder if it would be 
considered a useful addition to the functools module.

http://code.activestate.com/recipes/577273-decorator-and-context-manager-from-a-single-api/

I wrote this after writing almost identical code the second time for 
"patch" in the mock module. (The patch decorator can be used as a 
decorator or as a context manager and I was writing a new variant.) Both 
py.test and django have similar code in places, so it is not an uncommon 
pattern.

It is only 40 odd lines (ignore the ugly Python 2 & 3 compatibility 
hack), so I'm fine with it living on the cookbook - but it is at least 
slightly fiddly to write and has the added niceness of providing the 
optional exception handling semantics of __exit__ for decorators as well.

Example use (really hope email doesn't swallow the whitespace - my 
apologies in advance if it does):

from context import Context

class mycontext(Context):
     def __init__(self, *args):
         """Normal initialiser"""

     def start(self):
         """
         Called on entering the with block or starting the decorated 
function.

         If used in a with statement whatever this method returns will 
be the
         context manager.
         """

     def finish(self, *exc):
         """
         Called on exit. Arguments and return value of this method have
         the same meaning as the __exit__ method of a normal context
         manager.
         """

@mycontext('some', 'args')
def function():
     pass

with mycontext('some', 'args') as something:
     pass

I'm not entirely happy with the name of the class or the start and 
finish methods, so open to suggestions there. start and finish *could* 
be __enter__ and __exit__ - but that would make the class you implement 
*look* like a normal context manager and I thought it was better to 
distinguish them. Perhaps before and after?

All the best,

Michael Foord

-- 
http://www.ironpythoninaction.com/
http://www.voidspace.org.uk/blog

READ CAREFULLY. By accepting and reading this email you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies ("BOGUS AGREEMENTS") that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.	


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20100625/33717a14/attachment.html>


More information about the Python-Dev mailing list