root/galaxy-central/eggs/decorator-3.1.2-py2.6.egg/decorator.py

リビジョン 3, 10.0 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1##########################     LICENCE     ###############################
2##
3##   Copyright (c) 2005, Michele Simionato
4##   All rights reserved.
5##
6##   Redistributions of source code must retain the above copyright
7##   notice, this list of conditions and the following disclaimer.
8##   Redistributions in bytecode form must reproduce the above copyright
9##   notice, this list of conditions and the following disclaimer in
10##   the documentation and/or other materials provided with the
11##   distribution.
12
13##   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14##   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15##   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16##   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17##   HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18##   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19##   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
20##   OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21##   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
22##   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23##   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
24##   DAMAGE.
25
26"""
27Decorator module, see http://pypi.python.org/pypi/decorator
28for the documentation.
29"""
30
31__all__ = ["decorator", "FunctionMaker", "partial",
32           "deprecated", "getinfo", "new_wrapper"]
33
34import os, sys, re, inspect, string, warnings
35try:
36    from functools import partial
37except ImportError: # for Python version < 2.5
38    class partial(object):
39        "A simple replacement of functools.partial"
40        def __init__(self, func, *args, **kw):
41            self.func = func
42            self.args = args               
43            self.keywords = kw
44        def __call__(self, *otherargs, **otherkw):
45            kw = self.keywords.copy()
46            kw.update(otherkw)
47            return self.func(*(self.args + otherargs), **kw)
48
49DEF = re.compile('\s*def\s*([_\w][_\w\d]*)\s*\(')
50
51# basic functionality
52class FunctionMaker(object):
53    """
54    An object with the ability to create functions with a given signature.
55    It has attributes name, doc, module, signature, defaults, dict and
56    methods update and make.
57    """
58    def __init__(self, func=None, name=None, signature=None,
59                 defaults=None, doc=None, module=None, funcdict=None):
60        if func:
61            # func can be a class or a callable, but not an instance method
62            self.name = func.__name__
63            if self.name == '<lambda>': # small hack for lambda functions
64                self.name = '_lambda_'
65            self.doc = func.__doc__
66            self.module = func.__module__
67            if inspect.isfunction(func):
68                argspec = inspect.getargspec(func)
69                self.args, self.varargs, self.keywords, self.defaults = argspec
70                for i, arg in enumerate(self.args):
71                    setattr(self, 'arg%d' % i, arg)
72                self.signature = inspect.formatargspec(
73                    formatvalue=lambda val: "", *argspec)[1:-1]
74                self.dict = func.__dict__.copy()
75        if name:
76            self.name = name
77        if signature is not None:
78            self.signature = signature
79        if defaults:
80            self.defaults = defaults
81        if doc:
82            self.doc = doc
83        if module:
84            self.module = module
85        if funcdict:
86            self.dict = funcdict
87        # check existence required attributes
88        assert hasattr(self, 'name')
89        if not hasattr(self, 'signature'):
90            raise TypeError('You are decorating a non function: %s' % func)
91
92    def update(self, func, **kw):
93        "Update the signature of func with the data in self"
94        func.__name__ = self.name
95        func.__doc__ = getattr(self, 'doc', None)
96        func.__dict__ = getattr(self, 'dict', {})
97        func.func_defaults = getattr(self, 'defaults', ())
98        callermodule = sys._getframe(3).f_globals.get('__name__', '?')
99        func.__module__ = getattr(self, 'module', callermodule)
100        func.__dict__.update(kw)
101
102    def make(self, src_templ, evaldict=None, addsource=False, **attrs):
103        "Make a new function from a given template and update the signature"
104        src = src_templ % vars(self) # expand name and signature
105        evaldict = evaldict or {}
106        mo = DEF.match(src)
107        if mo is None:
108            raise SyntaxError('not a valid function template\n%s' % src)
109        name = mo.group(1) # extract the function name
110        reserved_names = set([name] + [
111            arg.strip(' *') for arg in self.signature.split(',')])
112        for n, v in evaldict.iteritems():
113            if n in reserved_names:
114                raise NameError('%s is overridden in\n%s' % (n, src))
115        if not src.endswith('\n'): # add a newline just for safety
116            src += '\n'
117        try:
118            code = compile(src, '<string>', 'single')
119            exec code in evaldict
120        except:
121            print >> sys.stderr, 'Error in generated code:'
122            print >> sys.stderr, src
123            raise
124        func = evaldict[name]
125        if addsource:
126            attrs['__source__'] = src
127        self.update(func, **attrs)
128        return func
129
130    @classmethod
131    def create(cls, obj, body, evaldict, defaults=None,
132               doc=None, module=None, addsource=True,**attrs):
133        """
134        Create a function from the strings name, signature and body.
135        evaldict is the evaluation dictionary. If addsource is true an attribute
136        __source__ is added to the result. The attributes attrs are added,
137        if any.
138        """
139        if isinstance(obj, str): # "name(signature)"
140            name, rest = obj.strip().split('(', 1)
141            signature = rest[:-1] #strip a right parens           
142            func = None
143        else: # a function
144            name = None
145            signature = None
146            func = obj
147        fun = cls(func, name, signature, defaults, doc, module)
148        ibody = '\n'.join('    ' + line for line in body.splitlines())
149        return fun.make('def %(name)s(%(signature)s):\n' + ibody,
150                        evaldict, addsource, **attrs)
151 
152def decorator(caller, func=None):
153    """
154    decorator(caller) converts a caller function into a decorator;
155    decorator(caller, func) decorates a function using a caller.
156    """
157    if func is not None: # returns a decorated function
158        return FunctionMaker.create(
159            func, "return _call_(_func_, %(signature)s)",
160            dict(_call_=caller, _func_=func), undecorated=func)
161    else: # returns a decorator
162        if isinstance(caller, partial):
163            return partial(decorator, caller)
164        # otherwise assume caller is a function
165        f = inspect.getargspec(caller)[0][0] # first arg
166        return FunctionMaker.create(
167            '%s(%s)' % (caller.__name__, f),
168            'return decorator(_call_, %s)' % f,
169            dict(_call_=caller, decorator=decorator), undecorated=caller,
170            doc=caller.__doc__, module=caller.__module__)
171
172###################### deprecated functionality #########################
173
174@decorator
175def deprecated(func, *args, **kw):
176    "A decorator for deprecated functions"
177    warnings.warn(
178        ('Calling the deprecated function %r\n'
179         'Downgrade to decorator 2.3 if you want to use this functionality')
180        % func.__name__, DeprecationWarning, stacklevel=3)
181    return func(*args, **kw)
182
183@deprecated
184def getinfo(func):
185    """
186    Returns an info dictionary containing:
187    - name (the name of the function : str)
188    - argnames (the names of the arguments : list)
189    - defaults (the values of the default arguments : tuple)
190    - signature (the signature : str)
191    - doc (the docstring : str)
192    - module (the module name : str)
193    - dict (the function __dict__ : str)
194   
195    >>> def f(self, x=1, y=2, *args, **kw): pass
196
197    >>> info = getinfo(f)
198
199    >>> info["name"]
200    'f'
201    >>> info["argnames"]
202    ['self', 'x', 'y', 'args', 'kw']
203   
204    >>> info["defaults"]
205    (1, 2)
206
207    >>> info["signature"]
208    'self, x, y, *args, **kw'
209    """
210    assert inspect.ismethod(func) or inspect.isfunction(func)
211    regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
212    argnames = list(regargs)
213    if varargs:
214        argnames.append(varargs)
215    if varkwargs:
216        argnames.append(varkwargs)
217    signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults,
218                                      formatvalue=lambda value: "")[1:-1]
219    return dict(name=func.__name__, argnames=argnames, signature=signature,
220                defaults = func.func_defaults, doc=func.__doc__,
221                module=func.__module__, dict=func.__dict__,
222                globals=func.func_globals, closure=func.func_closure)
223
224@deprecated
225def update_wrapper(wrapper, model, infodict=None):
226    "A replacement for functools.update_wrapper"
227    infodict = infodict or getinfo(model)
228    wrapper.__name__ = infodict['name']
229    wrapper.__doc__ = infodict['doc']
230    wrapper.__module__ = infodict['module']
231    wrapper.__dict__.update(infodict['dict'])
232    wrapper.func_defaults = infodict['defaults']
233    wrapper.undecorated = model
234    return wrapper
235
236@deprecated
237def new_wrapper(wrapper, model):
238    """
239    An improvement over functools.update_wrapper. The wrapper is a generic
240    callable object. It works by generating a copy of the wrapper with the
241    right signature and by updating the copy, not the original.
242    Moreovoer, 'model' can be a dictionary with keys 'name', 'doc', 'module',
243    'dict', 'defaults'.
244    """
245    if isinstance(model, dict):
246        infodict = model
247    else: # assume model is a function
248        infodict = getinfo(model)
249    assert not '_wrapper_' in infodict["argnames"], (
250        '"_wrapper_" is a reserved argument name!')
251    src = "lambda %(signature)s: _wrapper_(%(signature)s)" % infodict
252    funcopy = eval(src, dict(_wrapper_=wrapper))
253    return update_wrapper(funcopy, model, infodict)
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。