def hax(target: T) -> T: if isinstance(target, CodeType): return cast(T, _hax(target)) if isinstance(target, FunctionType): new = FunctionType( _hax(target.__code__), target.__globals__, target.__name__, target.__defaults__, target.__closure__, ) if target.__annotations__: new.__annotations__ = target.__annotations__.copy() if target.__kwdefaults__ is not None: new.__kwdefaults__ = target.__kwdefaults__.copy() if target.__dict__: new.__dict__ = target.__dict__.copy() return cast(T, new) raise TypeError(f"HAX doesn't support this! Got type {type(target)!r}.")
def loads_function(s): '''Restores a function serialized with :func:`dumps_function`.''' if PY2: name, code, globals_, defaults, closure, func_dict, doc = loads(s) else: name, code, globals_, defaults, closure, func_dict, doc, qualname, kwdefaults, annotations = loads( s) code = marshal.loads(code) for k, v in globals_.items(): if isinstance(v, Module): globals_[k] = v.mod if closure is not None: import ctypes ctypes.pythonapi.PyCell_New.restype = ctypes.py_object ctypes.pythonapi.PyCell_New.argtypes = [ctypes.py_object] closure = tuple(ctypes.pythonapi.PyCell_New(c) for c in closure) globals_['__builtins__'] = __builtins__ r = FunctionType(code, globals_, name, defaults, closure) r.__dict__ = func_dict r.__doc__ = doc if not PY2: r.__qualname__ = qualname r.__kwdefaults__ = kwdefaults r.__annotations__ = annotations return r
def copy_func(func: FunctionType, deep: bool = False) -> FunctionType: """Copy a function as a different object. Args: func: Function object to be copied. deep: If ``True``, mutable attributes of ``func`` are deep-copied. Returns: Function as a different object from the original one. """ copied = FunctionType( func.__code__, func.__globals__, func.__name__, func.__defaults__, func.__closure__, ) # mutable attributes are copied by the given method copier = deepcopy if deep else copy copied.__annotations__ = copier(func.__annotations__) copied.__dict__ = copier(func.__dict__) copied.__kwdefaults__ = copier(func.__kwdefaults__) # immutable attributes are not copied (just assigned) copied.__doc__ = func.__doc__ copied.__module__ = func.__module__ copied.__name__ = func.__name__ copied.__qualname__ = func.__qualname__ return copied
def buildFunction(baseFunc, code=None, glbls=None, name=None, defaults=None, kwdefaults=None, closure=None, annotations=None, doc=None, dct=None): resf = None def _f(): pass if hasattr(_f, 'func_code'): # Python 2.x resf = FunctionType(code or baseFunc.func_code, glbls or baseFunc.func_globals, name or baseFunc.func_name, defaults or baseFunc.func_defaults, closure or baseFunc.func_closure) resf.func_dict = dct or baseFunc.func_dict resf.func_doc = doc or baseFunc.func_doc else: # Python 3.x resf = FunctionType(code or baseFunc.__code__, glbls or baseFunc.__globals__, name or baseFunc.__name__, defaults or baseFunc.__defaults__, closure or baseFunc.__closure__) resf.__kwdefaults__ = kwdefaults or baseFunc.__kwdefaults__ resf.__annotations__ = annotations or baseFunc.__annotations__ resf.__dict__ = dct or baseFunc.__dict__ resf.__doc__ = doc or baseFunc.__doc__ return resf
def handle_deffun(self, func, fdict, fdoc, remote_globals): func = self.unpack(func) g = globals() glbls = {k:g[k] for k in remote_globals if k in g} if remote_globals is not None else g.copy() glbls.update(func[1]) func[1].update(glbls) f = FunctionType(*func) f.__dict__ = self.unpack(fdict) f.__doc__ = self.unpack(fdoc) return self.pack(f)
def _function_constructor(code, fglobals, name, argdefs, closure, kwdefaults, fdict, annotations, qualname, doc, module): func = FunctionType(code, fglobals, name, argdefs, closure) func.__kwdefaults__ = kwdefaults func.__dict__ = fdict func.__annotations__ = annotations func.__qualname__ = qualname func.__doc__ = doc func.__module__ = module return func
def handle_deffun(self, func, fdict, fdoc, remote_globals): func = self.unpack(func) g = globals() glbls = {k: g[k] for k in remote_globals if k in g} if remote_globals is not None else g.copy() glbls.update(func[1]) func[1].update(glbls) f = FunctionType(*func) f.__dict__ = self.unpack(fdict) f.__doc__ = self.unpack(fdoc) return self.pack(f)
def rebindFunction(f, rebindDir=None, **rebinds): '''return *f* with some globals rebound.''' d = {} if rebindDir: d.update(rebindDir) if rebinds: d.update(rebinds) if not d: return f f = getattr(f, 'im_func', f) fd = f.func_globals.copy() fd.update(d) nf = FunctionType(f.func_code, fd, f.func_name, f.func_defaults or ()) nf.__doc__ = f.__doc__ if f.__dict__ is not None: nf.__dict__ = f.__dict__.copy() return nf
def loads_function(s): '''Restores a function serialized with :func:`dumps_function`.''' name, code, globals_, defaults, closure, func_dict, doc, qualname, kwdefaults, annotations = loads(s) code = marshal.loads(code) for k, v in globals_.items(): if isinstance(v, Module): globals_[k] = v.mod if closure is not None: import ctypes ctypes.pythonapi.PyCell_New.restype = ctypes.py_object ctypes.pythonapi.PyCell_New.argtypes = [ctypes.py_object] closure = tuple(ctypes.pythonapi.PyCell_New(c) for c in closure) globals_['__builtins__'] = __builtins__ r = FunctionType(code, globals_, name, defaults, closure) r.__dict__ = func_dict r.__doc__ = doc r.__qualname__ = qualname r.__kwdefaults__ = kwdefaults r.__annotations__ = annotations return r
def func2not_implemented(func): sig_str = func2clean_signature_str(func) if sig_str not in cache__sig_str2code: code = signature_str2not_implemented_func(sig_str).__code__ cache__sig_str2code[sig_str] = code # code really depends on sig_str #cache__not_implemented_codes.add(code) #print('cache__not_implemented_codes', len(cache__not_implemented_codes)) else: code = cache__sig_str2code[sig_str] code_without_freevars = _replace_codestring(func.__code__, code) new = FunctionType(code_without_freevars, globals()) new.__dict__.update(vars(func)) new.__defaults__ = func.__defaults__ new.__kwdefaults__ = func.__kwdefaults__ new.__doc__ = func.__doc__ new.__name__ = func.__name__ new.__qualname__ = func.__qualname__ new.__module__ = func.__module__ new.__annotations__ = func.__annotations__ new.__dict__ = dict(func.__dict__) return new set_func_not_implemented(func) return func
def rebindFunction(f, rebindDir=None, funcName=None, funcDoc=None, argRebindDir=None, propRebindDir=None, **rebinds): '''return a function derived from *f* with rebinds specified by *rebindDir* and/or *rebinds*. Use *funcName* as function name, instead of `f.func_name` as function name, if given. *argRebindDir* is a dictionary mapping function parameter names to defaults. You can use this to turn required parameters into optional ones (by providing a default value for them), to change their default values or to turn optional parameters into required ones. Note that Python requires that required arguments must preceed optional ones. A `ValueError` is raised when *argRebindDir* violates this restriction. Note: we only support simply named parameters (not constructor expressions). *propRebindDir* is a dictionary specifying rebinds for the functions properties. ATT: *f.func_globals* is copied at rebind time. Later modifications may affect *f* but not the rebind function. Note: we would like to rebind closure parts as well but Python currently does not allow to create `cell` instances. Thus, this would be difficult. ''' # unwrap a method f = getattr(f, 'im_func', f) # handle global variable rebinds fg = f.func_globals.copy() if rebindDir: fg.update(rebindDir) if rebinds: fg.update(rebinds) # handle argument (default) rebinds if argRebindDir: args, _, _, defaults = getargspec(f) # ensure all arguments are known unknown = [] for a in argRebindDir: if a not in args: unknown.append(a) if unknown: raise ValueError('unknown arguments in `argRebindDir`: %s' % ', '.join(unknown) ) # determine new defaults defaults = defaults is not None and list(defaults) or [] defaults = [REQUIRED] * (len(args) - len(defaults)) + defaults funcDefaults = [] for (a,d) in zip(args, defaults): if isinstance(a, str) and a in argRebindDir: d = argRebindDir[a] if d is not REQUIRED: funcDefaults.append(d) elif funcDefaults: raise ValueError('required argument after optional one: %s' % a) funcDefaults = tuple(funcDefaults) else: funcDefaults = f.func_defaults or () # construct the new function nf = FunctionType( f.func_code, fg, # func_globals funcName or f.func_name, funcDefaults, f.func_closure, ) # handle the documentation if funcDoc is not None: nf.func_doc = funcDoc else: nf.func_doc = f.func_doc # handle is properties if f.__dict__ is not None: nf.__dict__ = f.__dict__.copy() if propRebindDir: if nf.__dict__ is None: nf.__dict__ = {} nf.__dict__.update(propRebindDir) return nf