3232for the documentation.
3333"""
3434
35- __version__ = '3.3.3 '
35+ __version__ = '3.4.0 '
3636
37- __all__ = ["decorator" , "FunctionMaker" , "partial " ]
37+ __all__ = ["decorator" , "FunctionMaker" , "contextmanager " ]
3838
3939import sys , re , inspect
40-
41- try :
42- from functools import partial
43- except ImportError : # for Python version < 2.5
44- class partial (object ):
45- "A simple replacement of functools.partial"
46- def __init__ (self , func , * args , ** kw ):
47- self .func = func
48- self .args = args
49- self .keywords = kw
50- def __call__ (self , * otherargs , ** otherkw ):
51- kw = self .keywords .copy ()
52- kw .update (otherkw )
53- return self .func (* (self .args + otherargs ), ** kw )
54-
5540if sys .version >= '3' :
5641 from inspect import getfullargspec
42+ def get_init (cls ):
43+ return cls .__init__
5744else :
5845 class getfullargspec (object ):
5946 "A quick and dirty replacement for getfullargspec for Python 2.X"
@@ -67,6 +54,8 @@ def __iter__(self):
6754 yield self .varargs
6855 yield self .varkw
6956 yield self .defaults
57+ def get_init (cls ):
58+ return cls .__init__ .__func__
7059
7160DEF = re .compile ('\s*def\s*([_\w][_\w\d]*)\s*\(' )
7261
@@ -100,17 +89,21 @@ def __init__(self, func=None, name=None, signature=None,
10089 inspect .formatargspec (
10190 formatvalue = lambda val : "" , * argspec )[1 :- 1 ]
10291 else : # Python 3 way
103- self .signature = self .shortsignature = ', ' .join (self .args )
92+ allargs = list (self .args )
93+ allshortargs = list (self .args )
10494 if self .varargs :
105- self .signature += ', *' + self .varargs
106- self .shortsignature += ', *' + self .varargs
107- if self .kwonlyargs :
108- for a in self .kwonlyargs :
109- self .signature += ', %s=None' % a
110- self .shortsignature += ', %s=%s' % (a , a )
95+ allargs .append ('*' + self .varargs )
96+ allshortargs .append ('*' + self .varargs )
97+ elif self .kwonlyargs :
98+ allargs .append ('*' ) # single star syntax
99+ for a in self .kwonlyargs :
100+ allargs .append ('%s=None' % a )
101+ allshortargs .append ('%s=%s' % (a , a ))
111102 if self .varkw :
112- self .signature += ', **' + self .varkw
113- self .shortsignature += ', **' + self .varkw
103+ allargs .append ('**' + self .varkw )
104+ allshortargs .append ('**' + self .varkw )
105+ self .signature = ', ' .join (allargs )
106+ self .shortsignature = ', ' .join (allshortargs )
114107 self .dict = func .__dict__ .copy ()
115108 # func=None happens when decorating a caller
116109 if name :
@@ -135,7 +128,7 @@ def update(self, func, **kw):
135128 func .__name__ = self .name
136129 func .__doc__ = getattr (self , 'doc' , None )
137130 func .__dict__ = getattr (self , 'dict' , {})
138- func .func_defaults = getattr (self , 'defaults' , ())
131+ func .__defaults__ = getattr (self , 'defaults' , ())
139132 func .__kwdefaults__ = getattr (self , 'kwonlydefaults' , None )
140133 func .__annotations__ = getattr (self , 'annotations' , None )
141134 callermodule = sys ._getframe (3 ).f_globals .get ('__name__' , '?' )
@@ -160,10 +153,10 @@ def make(self, src_templ, evaldict=None, addsource=False, **attrs):
160153 try :
161154 code = compile (src , '<string>' , 'single' )
162155 # print >> sys.stderr, 'Compiling %s' % src
163- exec code in evaldict
156+ exec ( code , evaldict )
164157 except :
165- print >> sys . stderr , 'Error in generated code:'
166- print >> sys .stderr , src
158+ print ( 'Error in generated code:' , file = sys . stderr )
159+ print ( src , file = sys .stderr )
167160 raise
168161 func = evaldict [name ]
169162 if addsource :
@@ -199,22 +192,60 @@ def decorator(caller, func=None):
199192 decorator(caller, func) decorates a function using a caller.
200193 """
201194 if func is not None : # returns a decorated function
202- evaldict = func .func_globals .copy ()
195+ evaldict = func .__globals__ .copy ()
203196 evaldict ['_call_' ] = caller
204197 evaldict ['_func_' ] = func
205198 return FunctionMaker .create (
206199 func , "return _call_(_func_, %(shortsignature)s)" ,
207200 evaldict , undecorated = func , __wrapped__ = func )
208201 else : # returns a decorator
209- if isinstance (caller , partial ):
210- return partial (decorator , caller )
211- # otherwise assume caller is a function
212- first = inspect .getargspec (caller )[0 ][0 ] # first arg
213- evaldict = caller .func_globals .copy ()
202+ if inspect .isclass (caller ):
203+ name = caller .__name__ .lower ()
204+ callerfunc = get_init (caller )
205+ doc = 'decorator(%s) converts functions/generators into ' \
206+ 'factories of %s objects' % (caller .__name__ , caller .__name__ )
207+ fun = getfullargspec (callerfunc ).args [1 ] # second arg
208+ elif inspect .isfunction (caller ):
209+ name = '_lambda_' if caller .__name__ == '<lambda>' \
210+ else caller .__name__
211+ callerfunc = caller
212+ doc = caller .__doc__
213+ fun = getfullargspec (callerfunc ).args [0 ] # first arg
214+ else : # assume caller is an object with a __call__ method
215+ name = caller .__class__ .__name__ .lower ()
216+ callerfunc = caller .__call__ .__func__
217+ doc = caller .__call__ .__doc__
218+ fun = getfullargspec (callerfunc ).args [1 ] # second arg
219+ evaldict = callerfunc .__globals__ .copy ()
214220 evaldict ['_call_' ] = caller
215221 evaldict ['decorator' ] = decorator
216222 return FunctionMaker .create (
217- '%s(%s)' % (caller . __name__ , first ),
218- 'return decorator(_call_, %s)' % first ,
223+ '%s(%s)' % (name , fun ),
224+ 'return decorator(_call_, %s)' % fun ,
219225 evaldict , undecorated = caller , __wrapped__ = caller ,
220- doc = caller .__doc__ , module = caller .__module__ )
226+ doc = doc , module = caller .__module__ )
227+
228+ ######################### contextmanager ########################
229+
230+ def __call__ (self , func ):
231+ 'Context manager decorator'
232+ return FunctionMaker .create (
233+ func , "with _self_: return _func_(%(shortsignature)s)" ,
234+ dict (_self_ = self , _func_ = func ), __wrapped__ = func )
235+
236+ try : # Python >= 3.2
237+
238+ from contextlib import _GeneratorContextManager
239+ ContextManager = type (
240+ 'ContextManager' , (_GeneratorContextManager ,), dict (__call__ = __call__ ))
241+
242+ except ImportError : # Python >= 2.5
243+
244+ from contextlib import GeneratorContextManager
245+ def __init__ (self , f , * a , ** k ):
246+ return GeneratorContextManager .__init__ (self , f (* a , ** k ))
247+ ContextManager = type (
248+ 'ContextManager' , (GeneratorContextManager ,),
249+ dict (__call__ = __call__ , __init__ = __init__ ))
250+
251+ contextmanager = decorator (ContextManager )
0 commit comments