decorator.py (5796B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\ccpProfile\decorator.py 2 from __future__ import print_function 3 __version__ = '3.3.2' 4 __all__ = ['decorator', 'FunctionMaker', 'partial'] 5 import sys, re, inspect 6 try: 7 from functools import partial 8 except ImportError: 9 10 class partial(object): 11 12 def __init__(self, func, *args, **kw): 13 self.func = func 14 self.args = args 15 self.keywords = kw 16 17 def __call__(self, *otherargs, **otherkw): 18 kw = self.keywords.copy() 19 kw.update(otherkw) 20 return self.func(*(self.args + otherargs), **kw) 21 22 23 if sys.version >= '3': 24 from inspect import getfullargspec 25 else: 26 27 class getfullargspec(object): 28 29 def __init__(self, f): 30 self.args, self.varargs, self.varkw, self.defaults = inspect.getargspec(f) 31 self.kwonlyargs = [] 32 self.kwonlydefaults = None 33 self.annotations = getattr(f, '__annotations__', {}) 34 35 def __iter__(self): 36 yield self.args 37 yield self.varargs 38 yield self.varkw 39 yield self.defaults 40 41 42 DEF = re.compile('\\s*def\\s*([_\\w][_\\w\\d]*)\\s*\\(') 43 44 class FunctionMaker(object): 45 46 def __init__(self, func = None, name = None, signature = None, defaults = None, doc = None, module = None, funcdict = None): 47 self.shortsignature = signature 48 if func: 49 self.name = func.__name__ 50 if self.name == '<lambda>': 51 self.name = '_lambda_' 52 self.doc = func.__doc__ 53 self.module = func.__module__ 54 if inspect.isfunction(func): 55 argspec = getfullargspec(func) 56 for a in ('args', 'varargs', 'varkw', 'defaults', 'kwonlyargs', 'kwonlydefaults', 'annotations'): 57 setattr(self, a, getattr(argspec, a)) 58 59 for i, arg in enumerate(self.args): 60 setattr(self, 'arg%d' % i, arg) 61 62 self.signature = inspect.formatargspec(formatvalue=(lambda val: ''), *argspec)[1:-1] 63 allargs = list(self.args) 64 if self.varargs: 65 allargs.append('*' + self.varargs) 66 if self.varkw: 67 allargs.append('**' + self.varkw) 68 try: 69 self.shortsignature = ', '.join(allargs) 70 except TypeError: 71 self.shortsignature = self.signature 72 73 self.dict = func.__dict__.copy() 74 if name: 75 self.name = name 76 if signature is not None: 77 self.signature = signature 78 if defaults: 79 self.defaults = defaults 80 if doc: 81 self.doc = doc 82 if module: 83 self.module = module 84 if funcdict: 85 self.dict = funcdict 86 if not hasattr(self, 'signature'): 87 raise TypeError('You are decorating a non function: %s' % func) 88 89 def update(self, func, **kw): 90 func.__name__ = self.name 91 func.__doc__ = getattr(self, 'doc', None) 92 func.__dict__ = getattr(self, 'dict', {}) 93 func.__defaults__ = getattr(self, 'defaults', ()) 94 func.__kwdefaults__ = getattr(self, 'kwonlydefaults', None) 95 callermodule = sys._getframe(3).f_globals.get('__name__', '?') 96 func.__module__ = getattr(self, 'module', callermodule) 97 func.__dict__.update(kw) 98 99 def make(self, src_templ, evaldict = None, addsource = False, **attrs): 100 src = src_templ % vars(self) 101 evaldict = evaldict or {} 102 mo = DEF.match(src) 103 if mo is None: 104 raise SyntaxError('not a valid function template\n%s' % src) 105 name = mo.group(1) 106 names = set([name] + [ arg.strip(' *') for arg in self.shortsignature.split(',') ]) 107 for n in names: 108 if n in ('_func_', '_call_'): 109 raise NameError('%s is overridden in\n%s' % (n, src)) 110 111 if not src.endswith('\n'): 112 src += '\n' 113 try: 114 code = compile(src, '<string>', 'single') 115 exec code in evaldict 116 except: 117 print('Error in generated code:', file=sys.stderr) 118 print(src, file=sys.stderr) 119 raise 120 121 func = evaldict[name] 122 if addsource: 123 attrs['__source__'] = src 124 self.update(func, **attrs) 125 return func 126 127 @classmethod 128 def create(cls, obj, body, evaldict, defaults = None, doc = None, module = None, addsource = True, **attrs): 129 if isinstance(obj, str): 130 name, rest = obj.strip().split('(', 1) 131 signature = rest[:-1] 132 func = None 133 else: 134 name = None 135 signature = None 136 func = obj 137 self = cls(func, name, signature, defaults, doc, module) 138 ibody = '\n'.join((' ' + line for line in body.splitlines())) 139 return self.make(('def %(name)s(%(signature)s):\n' + ibody), evaldict, addsource, **attrs) 140 141 142 def decorator(caller, func = None): 143 if func is not None: 144 evaldict = func.__globals__.copy() 145 evaldict['_call_'] = caller 146 evaldict['_func_'] = func 147 return FunctionMaker.create(func, 'return _call_(_func_, %(shortsignature)s)', evaldict, undecorated=func, __wrapped__=func) 148 elif isinstance(caller, partial): 149 return partial(decorator, caller) 150 else: 151 first = inspect.getargspec(caller)[0][0] 152 evaldict = caller.__globals__.copy() 153 evaldict['_call_'] = caller 154 evaldict['decorator'] = decorator 155 return FunctionMaker.create('%s(%s)' % (caller.__name__, first), 'return decorator(_call_, %s)' % first, evaldict, undecorated=caller, __wrapped__=caller, doc=caller.__doc__, module=caller.__module__)