##// END OF EJS Templates
Typo in comment fixed
Doug Blank -
Show More
@@ -1,229 +1,229 b''
1 ########################## LICENCE ###############################
1 ########################## LICENCE ###############################
2
2
3 # Copyright (c) 2005-2012, Michele Simionato
3 # Copyright (c) 2005-2012, Michele Simionato
4 # All rights reserved.
4 # All rights reserved.
5
5
6 # Redistribution and use in source and binary forms, with or without
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are
7 # modification, are permitted provided that the following conditions are
8 # met:
8 # met:
9
9
10 # Redistributions of source code must retain the above copyright
10 # Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
11 # notice, this list of conditions and the following disclaimer.
12 # Redistributions in bytecode form must reproduce the above copyright
12 # Redistributions in bytecode form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in
13 # notice, this list of conditions and the following disclaimer in
14 # the documentation and/or other materials provided with the
14 # the documentation and/or other materials provided with the
15 # distribution.
15 # distribution.
16
16
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 # HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 # OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26 # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27 # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28 # DAMAGE.
28 # DAMAGE.
29
29
30 """
30 """
31 Decorator module, see http://pypi.python.org/pypi/decorator
31 Decorator module, see http://pypi.python.org/pypi/decorator
32 for the documentation.
32 for the documentation.
33
33
34 NOTE: this is an IPython-patched version to work on IronPython. See
34 NOTE: this is an IPython-patched version to work on IronPython. See
35 FIXED comment below.
35 FIXED comment below.
36 """
36 """
37 from __future__ import print_function
37 from __future__ import print_function
38
38
39 __version__ = '3.3.3'
39 __version__ = '3.3.3'
40
40
41 __all__ = ["decorator", "FunctionMaker", "partial"]
41 __all__ = ["decorator", "FunctionMaker", "partial"]
42
42
43 import sys, re, inspect
43 import sys, re, inspect
44
44
45 try:
45 try:
46 from functools import partial
46 from functools import partial
47 except ImportError: # for Python version < 2.5
47 except ImportError: # for Python version < 2.5
48 class partial(object):
48 class partial(object):
49 "A simple replacement of functools.partial"
49 "A simple replacement of functools.partial"
50 def __init__(self, func, *args, **kw):
50 def __init__(self, func, *args, **kw):
51 self.func = func
51 self.func = func
52 self.args = args
52 self.args = args
53 self.keywords = kw
53 self.keywords = kw
54 def __call__(self, *otherargs, **otherkw):
54 def __call__(self, *otherargs, **otherkw):
55 kw = self.keywords.copy()
55 kw = self.keywords.copy()
56 kw.update(otherkw)
56 kw.update(otherkw)
57 return self.func(*(self.args + otherargs), **kw)
57 return self.func(*(self.args + otherargs), **kw)
58
58
59 if sys.version >= '3':
59 if sys.version >= '3':
60 from inspect import getfullargspec
60 from inspect import getfullargspec
61 else:
61 else:
62 class getfullargspec(object):
62 class getfullargspec(object):
63 "A quick and dirty replacement for getfullargspec for Python 2.X"
63 "A quick and dirty replacement for getfullargspec for Python 2.X"
64 def __init__(self, f):
64 def __init__(self, f):
65 self.args, self.varargs, self.varkw, self.defaults = \
65 self.args, self.varargs, self.varkw, self.defaults = \
66 inspect.getargspec(f)
66 inspect.getargspec(f)
67 self.kwonlyargs = []
67 self.kwonlyargs = []
68 self.kwonlydefaults = None
68 self.kwonlydefaults = None
69 def __iter__(self):
69 def __iter__(self):
70 yield self.args
70 yield self.args
71 yield self.varargs
71 yield self.varargs
72 yield self.varkw
72 yield self.varkw
73 yield self.defaults
73 yield self.defaults
74
74
75 DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(')
75 DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(')
76
76
77 # basic functionality
77 # basic functionality
78 class FunctionMaker(object):
78 class FunctionMaker(object):
79 """
79 """
80 An object with the ability to create functions with a given signature.
80 An object with the ability to create functions with a given signature.
81 It has attributes name, doc, module, signature, defaults, dict and
81 It has attributes name, doc, module, signature, defaults, dict and
82 methods update and make.
82 methods update and make.
83 """
83 """
84 def __init__(self, func=None, name=None, signature=None,
84 def __init__(self, func=None, name=None, signature=None,
85 defaults=None, doc=None, module=None, funcdict=None):
85 defaults=None, doc=None, module=None, funcdict=None):
86 self.shortsignature = signature
86 self.shortsignature = signature
87 if func:
87 if func:
88 # func can be a class or a callable, but not an instance method
88 # func can be a class or a callable, but not an instance method
89 self.name = func.__name__
89 self.name = func.__name__
90 if self.name == '<lambda>': # small hack for lambda functions
90 if self.name == '<lambda>': # small hack for lambda functions
91 self.name = '_lambda_'
91 self.name = '_lambda_'
92 self.doc = func.__doc__
92 self.doc = func.__doc__
93 self.module = func.__module__
93 self.module = func.__module__
94 if inspect.isfunction(func):
94 if inspect.isfunction(func):
95 argspec = getfullargspec(func)
95 argspec = getfullargspec(func)
96 self.annotations = getattr(func, '__annotations__', {})
96 self.annotations = getattr(func, '__annotations__', {})
97 for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs',
97 for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs',
98 'kwonlydefaults'):
98 'kwonlydefaults'):
99 setattr(self, a, getattr(argspec, a))
99 setattr(self, a, getattr(argspec, a))
100 for i, arg in enumerate(self.args):
100 for i, arg in enumerate(self.args):
101 setattr(self, 'arg%d' % i, arg)
101 setattr(self, 'arg%d' % i, arg)
102 if sys.version < '3': # easy way
102 if sys.version < '3': # easy way
103 self.shortsignature = self.signature = \
103 self.shortsignature = self.signature = \
104 inspect.formatargspec(
104 inspect.formatargspec(
105 formatvalue=lambda val: "", *argspec)[1:-1]
105 formatvalue=lambda val: "", *argspec)[1:-1]
106 else: # Python 3 way
106 else: # Python 3 way
107 self.signature = self.shortsignature = ', '.join(self.args)
107 self.signature = self.shortsignature = ', '.join(self.args)
108 if self.varargs:
108 if self.varargs:
109 self.signature += ', *' + self.varargs
109 self.signature += ', *' + self.varargs
110 self.shortsignature += ', *' + self.varargs
110 self.shortsignature += ', *' + self.varargs
111 if self.kwonlyargs:
111 if self.kwonlyargs:
112 for a in self.kwonlyargs:
112 for a in self.kwonlyargs:
113 self.signature += ', %s=None' % a
113 self.signature += ', %s=None' % a
114 self.shortsignature += ', %s=%s' % (a, a)
114 self.shortsignature += ', %s=%s' % (a, a)
115 if self.varkw:
115 if self.varkw:
116 self.signature += ', **' + self.varkw
116 self.signature += ', **' + self.varkw
117 self.shortsignature += ', **' + self.varkw
117 self.shortsignature += ', **' + self.varkw
118 self.dict = func.__dict__.copy()
118 self.dict = func.__dict__.copy()
119 # func=None happens when decorating a caller
119 # func=None happens when decorating a caller
120 if name:
120 if name:
121 self.name = name
121 self.name = name
122 if signature is not None:
122 if signature is not None:
123 self.signature = signature
123 self.signature = signature
124 if defaults:
124 if defaults:
125 self.defaults = defaults
125 self.defaults = defaults
126 if doc:
126 if doc:
127 self.doc = doc
127 self.doc = doc
128 if module:
128 if module:
129 self.module = module
129 self.module = module
130 if funcdict:
130 if funcdict:
131 self.dict = funcdict
131 self.dict = funcdict
132 # check existence required attributes
132 # check existence required attributes
133 assert hasattr(self, 'name')
133 assert hasattr(self, 'name')
134 if not hasattr(self, 'signature'):
134 if not hasattr(self, 'signature'):
135 raise TypeError('You are decorating a non function: %s' % func)
135 raise TypeError('You are decorating a non function: %s' % func)
136
136
137 def update(self, func, **kw):
137 def update(self, func, **kw):
138 "Update the signature of func with the data in self"
138 "Update the signature of func with the data in self"
139 func.__name__ = self.name
139 func.__name__ = self.name
140 func.__doc__ = getattr(self, 'doc', None)
140 func.__doc__ = getattr(self, 'doc', None)
141 func.__dict__ = getattr(self, 'dict', {})
141 func.__dict__ = getattr(self, 'dict', {})
142 func.__defaults__ = getattr(self, 'defaults', ())
142 func.__defaults__ = getattr(self, 'defaults', ())
143 func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None)
143 func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None)
144 func.__annotations__ = getattr(self, 'annotations', None)
144 func.__annotations__ = getattr(self, 'annotations', None)
145 # FIXED: The following is try/execpted in IPython to work
145 # FIXED: The following is try/excepted in IPython to work
146 # with IronPython.
146 # with IronPython.
147 try:
147 try:
148 callermodule = sys._getframe(3).f_globals.get('__name__', '?')
148 callermodule = sys._getframe(3).f_globals.get('__name__', '?')
149 except AttributeError: # IronPython _getframe only exists with FullFrames
149 except AttributeError: # IronPython _getframe only exists with FullFrames
150 callermodule = '?'
150 callermodule = '?'
151 func.__module__ = getattr(self, 'module', callermodule)
151 func.__module__ = getattr(self, 'module', callermodule)
152 func.__dict__.update(kw)
152 func.__dict__.update(kw)
153
153
154 def make(self, src_templ, evaldict=None, addsource=False, **attrs):
154 def make(self, src_templ, evaldict=None, addsource=False, **attrs):
155 "Make a new function from a given template and update the signature"
155 "Make a new function from a given template and update the signature"
156 src = src_templ % vars(self) # expand name and signature
156 src = src_templ % vars(self) # expand name and signature
157 evaldict = evaldict or {}
157 evaldict = evaldict or {}
158 mo = DEF.match(src)
158 mo = DEF.match(src)
159 if mo is None:
159 if mo is None:
160 raise SyntaxError('not a valid function template\n%s' % src)
160 raise SyntaxError('not a valid function template\n%s' % src)
161 name = mo.group(1) # extract the function name
161 name = mo.group(1) # extract the function name
162 names = set([name] + [arg.strip(' *') for arg in
162 names = set([name] + [arg.strip(' *') for arg in
163 self.shortsignature.split(',')])
163 self.shortsignature.split(',')])
164 for n in names:
164 for n in names:
165 if n in ('_func_', '_call_'):
165 if n in ('_func_', '_call_'):
166 raise NameError('%s is overridden in\n%s' % (n, src))
166 raise NameError('%s is overridden in\n%s' % (n, src))
167 if not src.endswith('\n'): # add a newline just for safety
167 if not src.endswith('\n'): # add a newline just for safety
168 src += '\n' # this is needed in old versions of Python
168 src += '\n' # this is needed in old versions of Python
169 try:
169 try:
170 code = compile(src, '<string>', 'single')
170 code = compile(src, '<string>', 'single')
171 # print >> sys.stderr, 'Compiling %s' % src
171 # print >> sys.stderr, 'Compiling %s' % src
172 exec(code, evaldict)
172 exec(code, evaldict)
173 except:
173 except:
174 print('Error in generated code:', file=sys.stderr)
174 print('Error in generated code:', file=sys.stderr)
175 print(src, file=sys.stderr)
175 print(src, file=sys.stderr)
176 raise
176 raise
177 func = evaldict[name]
177 func = evaldict[name]
178 if addsource:
178 if addsource:
179 attrs['__source__'] = src
179 attrs['__source__'] = src
180 self.update(func, **attrs)
180 self.update(func, **attrs)
181 return func
181 return func
182
182
183 @classmethod
183 @classmethod
184 def create(cls, obj, body, evaldict, defaults=None,
184 def create(cls, obj, body, evaldict, defaults=None,
185 doc=None, module=None, addsource=True, **attrs):
185 doc=None, module=None, addsource=True, **attrs):
186 """
186 """
187 Create a function from the strings name, signature and body.
187 Create a function from the strings name, signature and body.
188 evaldict is the evaluation dictionary. If addsource is true an attribute
188 evaldict is the evaluation dictionary. If addsource is true an attribute
189 __source__ is added to the result. The attributes attrs are added,
189 __source__ is added to the result. The attributes attrs are added,
190 if any.
190 if any.
191 """
191 """
192 if isinstance(obj, str): # "name(signature)"
192 if isinstance(obj, str): # "name(signature)"
193 name, rest = obj.strip().split('(', 1)
193 name, rest = obj.strip().split('(', 1)
194 signature = rest[:-1] #strip a right parens
194 signature = rest[:-1] #strip a right parens
195 func = None
195 func = None
196 else: # a function
196 else: # a function
197 name = None
197 name = None
198 signature = None
198 signature = None
199 func = obj
199 func = obj
200 self = cls(func, name, signature, defaults, doc, module)
200 self = cls(func, name, signature, defaults, doc, module)
201 ibody = '\n'.join(' ' + line for line in body.splitlines())
201 ibody = '\n'.join(' ' + line for line in body.splitlines())
202 return self.make('def %(name)s(%(signature)s):\n' + ibody,
202 return self.make('def %(name)s(%(signature)s):\n' + ibody,
203 evaldict, addsource, **attrs)
203 evaldict, addsource, **attrs)
204
204
205 def decorator(caller, func=None):
205 def decorator(caller, func=None):
206 """
206 """
207 decorator(caller) converts a caller function into a decorator;
207 decorator(caller) converts a caller function into a decorator;
208 decorator(caller, func) decorates a function using a caller.
208 decorator(caller, func) decorates a function using a caller.
209 """
209 """
210 if func is not None: # returns a decorated function
210 if func is not None: # returns a decorated function
211 evaldict = func.__globals__.copy()
211 evaldict = func.__globals__.copy()
212 evaldict['_call_'] = caller
212 evaldict['_call_'] = caller
213 evaldict['_func_'] = func
213 evaldict['_func_'] = func
214 return FunctionMaker.create(
214 return FunctionMaker.create(
215 func, "return _call_(_func_, %(shortsignature)s)",
215 func, "return _call_(_func_, %(shortsignature)s)",
216 evaldict, undecorated=func, __wrapped__=func)
216 evaldict, undecorated=func, __wrapped__=func)
217 else: # returns a decorator
217 else: # returns a decorator
218 if isinstance(caller, partial):
218 if isinstance(caller, partial):
219 return partial(decorator, caller)
219 return partial(decorator, caller)
220 # otherwise assume caller is a function
220 # otherwise assume caller is a function
221 first = inspect.getargspec(caller)[0][0] # first arg
221 first = inspect.getargspec(caller)[0][0] # first arg
222 evaldict = caller.__globals__.copy()
222 evaldict = caller.__globals__.copy()
223 evaldict['_call_'] = caller
223 evaldict['_call_'] = caller
224 evaldict['decorator'] = decorator
224 evaldict['decorator'] = decorator
225 return FunctionMaker.create(
225 return FunctionMaker.create(
226 '%s(%s)' % (caller.__name__, first),
226 '%s(%s)' % (caller.__name__, first),
227 'return decorator(_call_, %s)' % first,
227 'return decorator(_call_, %s)' % first,
228 evaldict, undecorated=caller, __wrapped__=caller,
228 evaldict, undecorated=caller, __wrapped__=caller,
229 doc=caller.__doc__, module=caller.__module__)
229 doc=caller.__doc__, module=caller.__module__)
General Comments 0
You need to be logged in to leave comments. Login now