示例#1
0
文件: __init__.py 项目: alarmcom/gwpy
def reader(name=None, doc=None, mp_flattener=False):
    """Construct a new unified input/output reader.

    This method is required to create a new copy of the
    :func:`astropy.io.registry.read` with a dynamic docstring.

    Returns
    -------
    read : `function`
        a copy of the :func:`astropy.io.registry.read` function

    doc : `str`
        custom docstring for this reader

    mp_flattener : `function`
        the function to flatten multiple instances of the parent object,
        enabling multiprocessed reading via the `nproc` argument
    """
    func = FunctionType(read.func_code, read.func_globals,
                        name or read.func_name, read.func_defaults,
                        read.func_closure)
    if doc is not None:
        func.__doc__ = doc.strip('\n ')
    if mp_flattener:
        return with_nproc(func, mp_flattener)
    else:
        return func
示例#2
0
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
示例#3
0
 def chained_function(meta, func, mod):
     d = ModuleChainedDict(mod.__dict__, func.__globals__)
     newfunc = FunctionType(func.__code, d)
     newfunc.__doc__ = func.__doc__
     newfunc.__defaults__ = newfunc.__defaults__
     newfunc.__kwdefaults__ = func.__kwdefaults__
     return newfunc
示例#4
0
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
示例#5
0
文件: pickle.py 项目: simon-ca/pymor
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
示例#6
0
 def chained_function(meta, func, mod):
     d = _NSChainedDict(mod.__dict__, func.__globals__)
     newfunc = FunctionType(func.__code__, d)
     newfunc.__doc__ = func.__doc__
     newfunc.__defaults__ = func.__defaults__
     newfunc.__kwdefaults__ = func.__kwdefaults__
     return newfunc
示例#7
0
    def __new__(cls,
                mplayer=MPLAYER_PATH,
                pipe=PIPE_PATH,
                stdout=STDOUT_PATH,
                pid=PID_PATH,
                debug=False):
        def _doc_creator(item):
            ## Doc creator for the command
            doc_info = item['comment']
            py_command = item['pycommand']
            doc = '%s\n%s' % (py_command, doc_info)
            return doc

        ## Creating new class methods from mplayer cmdlist_dict
        cmdlist_dict = CmdDictGenerator(mplayer).get_cmdlist()

        for item in cmdlist_dict.keys():
            if item == 'get_property': continue
            if item == 'set_property': continue
            #if item == 'set_property_osd': continue
            doc = _doc_creator(cmdlist_dict[item])
            # Creating a dictionary that would include variables from
            # item and globals() (excluding locals()).
            # This is necessary for passing it to a new method.
            method_dict = {'item': cmdlist_dict[item]}
            for i in globals().keys():
                if i in locals().keys(): continue
                method_dict[i] = globals()[i]
            # Creating a function
            if 'get' not in item:
                if len(cmdlist_dict[item]['types']) != 0:
                    # If list of types contains some types
                    new_method = FunctionType(cls._new_args_method.func_code,
                                              method_dict, item)
                else:
                    # If list of types is empty
                    new_method = FunctionType(cls._new_simple_method.func_code,
                                              method_dict, item)
            else:
                new_method = FunctionType(cls._new_get_method.func_code,
                                          method_dict, item)
            # Adding doc, editing name
            new_method.__doc__ = doc
            new_method.__name__ = item
            # Adding function to this class as a method

            setattr(cls, item, new_method)
        # Create 'properties' property and
        # making it use the doc from Properties class
        properties_class = Properties()

        def get_properties(self):
            return properties_class

        properties = property(fget=get_properties, doc=Properties.__doc__)

        setattr(cls, 'properties', properties)

        return super(Player, cls).__new__(cls)
示例#8
0
def _update_function(oldfunc: FunctionType, newfunc: FunctionType):
    """Update a function object."""
    logger.info(f"Patch function {oldfunc.__qualname__}")
    oldfunc.__doc__ = newfunc.__doc__
    oldfunc.__dict__.update(newfunc.__dict__)
    oldfunc.__annotations__ = newfunc.__annotations__
    oldfunc.__code__ = newfunc.__code__
    oldfunc.__defaults__ = newfunc.__defaults__
示例#9
0
 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)
示例#10
0
def _make_typedarg_rule(f, name):
    """Copy a rule and allow for annotations.

    """
    rule = FunctionType(f.__code__, f.__globals__, name, f.__defaults__,
                        f.__closure__)

    new_doc = f.__doc__.replace('fpdef', 'tfpdef')
    rule.__doc__ = new_doc.replace('varargslist', 'typedargslist')
    return rule
示例#11
0
    def __new__(cls, mplayer=MPLAYER_PATH, pipe=PIPE_PATH, 
                     stdout=STDOUT_PATH, pid=PID_PATH, debug=False):

        def _doc_creator(item):
            ## Doc creator for the command
            doc_info  = item['comment']
            py_command = item['pycommand']
            doc = '%s\n%s' % (py_command, doc_info)
            return doc

        ## Creating new class methods from mplayer cmdlist_dict
        cmdlist_dict = CmdDictGenerator(mplayer).get_cmdlist()
        for item in cmdlist_dict.keys():
            if item == 'get_property': continue
            if item == 'set_property': continue
            #if item == 'set_property_osd': continue
            doc = _doc_creator(cmdlist_dict[item])
            # Creating a dictionary that would include variables from 
            # item and globals() (excluding locals()).
            # This is necessary for passing it to a new method.
            method_dict = {'item': cmdlist_dict[item]}
            for i in globals().keys():
                if i in locals().keys(): continue
                method_dict[i] = globals()[i]
            # Creating a function
            if 'get' not in item:
                if len(cmdlist_dict[item]['types']) != 0:
                    # If list of types contains some types
                    new_method = FunctionType(cls._new_args_method.func_code,
                                              method_dict,
                                              item)
                else:
                    # If list of types is empty
                    new_method = FunctionType(cls._new_simple_method.func_code,
                                              method_dict,
                                              item)
            else:
                new_method = FunctionType(cls._new_get_method.func_code,
                                          method_dict,
                                          item)
            # Adding doc, editing name
            new_method.__doc__ = doc
            new_method.__name__ = item
            # Adding function to this class as a method
            setattr(cls, item, new_method)
        # Create 'properties' property and 
        # making it use the doc from Properties class
        properties_class = Properties()
        def get_properties(self):
            return properties_class
        properties = property(fget=get_properties, 
                              doc=Properties.__doc__)
        setattr(cls, 'properties', properties)
        return super(Player, cls).__new__(cls)
示例#12
0
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
示例#13
0
文件: _misc.py 项目: RNAer/scikit-bio
    def interpolate(self, obj, name):
        """Inject the formatted listing in the second blank line of `name`."""
        f = getattr(obj, name)
        f2 = FunctionType(f.__code__, f.__globals__, name=f.__name__, argdefs=f.__defaults__, closure=f.__closure__)

        # Conveniently the original docstring is on f2, not the new ones if
        # inheritence is happening. I have no idea why.
        t = f2.__doc__.split("\n\n")
        t.insert(2, self.formatted_listing())
        f2.__doc__ = "\n\n".join(t)

        setattr(obj, name, f2)
示例#14
0
def alias(name: str, doc: str, fun: Callable[..., Any]) -> Callable[..., Any]:
    # Adapted from https://stackoverflow.com/questions/13503079/how-to-create-a-copy-of-a-python-function#
    # See also help(type(lambda: 0))
    alias = FunctionType(fun.__code__,
                         fun.__globals__,
                         name=name,
                         argdefs=fun.__defaults__,
                         closure=fun.__closure__)
    alias = update_wrapper(alias, fun)
    alias.__kwdefaults__ = fun.__kwdefaults__
    alias.__doc__ = doc
    return alias
示例#15
0
 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)
示例#16
0
    def interpolate(self, obj, name):
        """Inject the formatted listing in the second blank line of `name`."""
        f = getattr(obj, name)
        f2 = FunctionType(f.__code__, f.__globals__, name=f.__name__,
                          argdefs=f.__defaults__, closure=f.__closure__)

        # Conveniently the original docstring is on f2, not the new ones if
        # inheritence is happening. I have no idea why.
        t = f2.__doc__.split("\n\n")
        t.insert(2, self.formatted_listing())
        f2.__doc__ = "\n\n".join(t)

        setattr(obj, name, f2)
示例#17
0
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
示例#18
0
def alias(name: str, doc: str, fun: Callable[..., Any]) -> Callable[..., Any]:
    # Adapted from https://stackoverflow.com/questions/13503079/how-to-create-a-copy-of-a-python-function#
    # See also help(type(lambda: 0))
    _fun = cast(FunctionType, fun)
    args = (_fun.__code__, _fun.__globals__)
    kwargs = {
        'name': name,
        'argdefs': _fun.__defaults__,
        'closure': _fun.__closure__
    }
    alias = FunctionType(*args, **kwargs)  # type: ignore
    alias = cast(FunctionType, update_wrapper(alias, _fun))
    alias.__kwdefaults__ = _fun.__kwdefaults__
    alias.__doc__ = doc
    return alias
示例#19
0
文件: __init__.py 项目: alarmcom/gwpy
def writer(doc=None):
    """Construct a new unified input/output writeer.

    This method is required to create a new copy of the
    :func:`astropy.io.registry.write` with a dynamic docstring.

    Returns
    -------
    write : `function`
        A copy of the :func:`astropy.io.registry.write` function
    """
    func = FunctionType(write.func_code, write.func_globals,
                        write.func_name, write.func_defaults,
                        write.func_closure)
    if doc is not None:
        func.__doc__ = doc.strip('\n ')
    return func
示例#20
0
文件: __init__.py 项目: bfarr/gwpy
def writer(doc=None):
    """Construct a new unified input/output writeer.

    This method is required to create a new copy of the
    :func:`astropy.io.registry.write` with a dynamic docstring.

    Returns
    -------
    write : `function`
        A copy of the :func:`astropy.io.registry.write` function
    """
    func = FunctionType(write.func_code, write.func_globals,
                        write.func_name, write.func_defaults,
                        write.func_closure)
    if doc is not None:
        func.__doc__ = doc.strip('\n ')
    return func
示例#21
0
def reader(name=None, doc=None):
    """Construct a new unified input/output reader.

    This method is required to create a new copy of the
    :func:`astropy.io.registry.read` with a dynamic docstring.

    Returns
    -------
    read : `function`
        A copy of the :func:`astropy.io.registry.read` function
    """
    func = FunctionType(read.func_code, read.func_globals,
                        name or read.func_name, read.func_defaults,
                        read.func_closure)
    if doc is not None:
        func.__doc__ = doc.strip('\n ')
    return func
示例#22
0
文件: utils.py 项目: lizh06/RxPY
def alias(name: str, doc: str, fun: Callable[_P, _T]) -> Callable[_P, _T]:
    # Adapted from
    # https://stackoverflow.com/questions/13503079/how-to-create-a-copy-of-a-python-function#
    # See also help(type(lambda: 0))
    _fun = cast(FunctionType, fun)
    args = (_fun.__code__, _fun.__globals__)
    kwargs = {
        "name": name,
        "argdefs": _fun.__defaults__,
        "closure": _fun.__closure__
    }
    alias_ = FunctionType(*args, **kwargs)  # type: ignore
    alias_ = update_wrapper(alias_, _fun)
    alias_.__kwdefaults__ = _fun.__kwdefaults__
    alias_.__doc__ = doc
    alias_.__annotations__ = _fun.__annotations__
    return alias_
示例#23
0
文件: __init__.py 项目: yangnk42/gwpy
def reader(name=None, doc=None):
    """Construct a new unified input/output reader.

    This method is required to create a new copy of the
    :func:`astropy.io.registry.read` with a dynamic docstring.

    Returns
    -------
    read : `function`
        A copy of the :func:`astropy.io.registry.read` function
    """
    func = FunctionType(read.func_code, read.func_globals, name
                        or read.func_name, read.func_defaults,
                        read.func_closure)
    if doc is not None:
        func.__doc__ = doc.strip('\n ')
    return func
示例#24
0
    def interpolate(self, obj, name):
        """Inject the formatted listing in the second blank line of `name`."""
        # Py2/3 compatible way of calling getattr(obj, name).__func__
        f = getattr(obj, name).__get__(None, type(None))

        if hasattr(f, 'func_code'):
            f2 = FunctionType(f.func_code, f.func_globals, name=f.func_name,
                              argdefs=f.func_defaults, closure=f.func_closure)
        else:
            f2 = FunctionType(f.__code__, f.__globals__, name=f.__name__,
                              argdefs=f.__defaults__, closure=f.__closure__)
        # Conveniently the original docstring is on f2, not the new ones if
        # inheritence is happening. I have no idea why.
        t = f2.__doc__.split("\n\n")
        t.insert(2, self.formatted_listing())
        f2.__doc__ = "\n\n".join(t)

        setattr(obj, name, f2)
示例#25
0
    def interpolate(self, obj, name):
        """Inject the formatted listing in the second blank line of `name`."""
        # Py2/3 compatible way of calling getattr(obj, name).__func__
        f = getattr(obj, name).__get__(None, type(None))

        if hasattr(f, 'func_code'):
            f2 = FunctionType(f.func_code, f.func_globals, name=f.func_name,
                              argdefs=f.func_defaults, closure=f.func_closure)
        else:
            f2 = FunctionType(f.__code__, f.__globals__, name=f.__name__,
                              argdefs=f.__defaults__, closure=f.__closure__)
        # Conveniently the original docstring is on f2, not the new ones if
        # inheritence is happening. I have no idea why.
        t = f2.__doc__.split("\n\n")
        t.insert(2, self.formatted_listing())
        f2.__doc__ = "\n\n".join(t)

        setattr(obj, name, f2)
示例#26
0
def modfuncglobals(func, *ds, **kw):
    '''Add globals to a function.'''
    dp = dictproxy()
    newfunc = FunctionType(func.__code__, dictproxy(dp, func.__globals__))
    newfunc.__name__ = func.__name__
    newfunc.__doc__ = func.__doc__
    newfunc.__defaults__ = func.__defaults__
    newfunc.__kwdefaults__ = func.__kwdefaults__
    newfunc.__scopes__ = dp.maps

    def add(*ds, **kw):
        for d in ds[::-1]:
            newfunc.__scopes__.insert(0, d)
        if kw:
            newfunc.add(kw)
        return newfunc

    newfunc.add = add
    newfunc.add(*ds, **kw)
    return newfunc
示例#27
0
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
示例#28
0
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
示例#29
0
def compile_func(func_str: str) -> FunctionType:
    """Compile **func_str** into a :class:`code<types.CodeType>` instance."""
    global_dict = {'np': np}
    x = np.array([[0.0, np.nan], [np.inf, 5.0]])

    func_str = func_str.replace('numpy', 'np')

    # Load all module specified in **func_str**
    while True:
        try:
            x.copy()
            exec(func_str)
        except NameError as ex:
            module = str(ex).split("'")[1]
            exec(f'import {module}')
            global_dict[module] = eval(module)
        else:
            break

    # Exchange all ';' characters for '\n'
    str_list = func_str.split(';')
    func_str2 = ''.join(f'    {i.strip().rstrip()}\n' for i in str_list[:-1])
    func_str2 += f'    return {str_list[-1].strip().rstrip()}'

    # Compile the code of the to-be returned function
    code_compile = compile(f'def weight(x):\n{func_str2}', '<string>', 'exec')
    for code in code_compile.co_consts:
        if isinstance(code, CodeType):
            break
    else:
        raise ValueError(
            "Failed to find 'code' instance in 'code_compile.co_consts'")

    # Construct and return the new function
    func = FunctionType(code, globals=global_dict, name='weight')
    func.__doc__ = f"Dynamically generated function; returns ``{func_str}``."
    func.__annotations__ = {'x': np.ndarray, 'return': np.ndarray}
    return func
示例#30
0
def _clone(origin_fun, new_fun_name, name, extra=None):
    # update the checkers/accessors dico
    original_checkers = origin_fun.checker.arg_type_list
    new_dict = dict(original_checkers)

    if extra is not None:
        new_dict.update(extra)

    # clone the function
    new_fun = FunctionType(code=origin_fun.__code__,
                           globals=origin_fun.__globals__,
                           name=new_fun_name,
                           argdefs=origin_fun.__defaults__,
                           closure=origin_fun.__closure__)

    # apply decorator
    fun_decorator = shellMethod(**new_dict)
    fun_decorator(new_fun)

    # updat the docstring
    new_fun.__doc__ = new_fun.__doc__.replace("environment", name)

    return new_fun
示例#31
0
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
示例#32
0
def rebuild_func(
    func,
    cls=None,
    *wrappers,
    defaults_copy=None,
    kwdefaults_copy=None,
    dict_copy=None,
    closure_copy=None,
    global_ns=None,
    name=None,
    qualname=None,
    module=False,
    doc=False,
    annotations=False,
):
    """Create a copy of `func` that can be used as a method by any `cls`

    The main perk is giving a `cls` the ability to use *any* Python
    `function` as a bound method, regardless of where it was defined.
    In other words, it doesn't matter if a function was defined in the
    global scope, another module, or in the body of another class.
    Most importantly, functions that use zero-argument super will behave
    exactly the same as if they had been defined in `cls`.

    Unfortunately, there is one limitation.
    Wrapped functions not defined in the scope of a class body will not
    be able to use zero argument super. If they are wrapped *after*
    being bound with this function, they should have no problem working

    For convenience, any *wrappers provided will be applied after binding
    in the same order as decorator syntax, top to bottom or right to left
    ie. wrappers *(a, b ,c) will be equivalent to a(b(c(func)))

    There are nearly limitless uses for this black magic, but some
    good examples are the ability to make true deepcopies of functions,
    changing default/kwonly defaults, and tricking functions into using
    global references to objects not in the module it was defined in.

    To simplify the application of making true deepcopies of functions,
    which requires deepcopying of the original function's mutable
    attributes: __defaults__, __kwdefaults__, __dict__, and __closure__,
    the arguments `defaults_copy`, `kwdefaults_copy, `dict_copy`, and
    `closure_copy`, respectively, accept a callable that takes a single
    argument (the object to be copied) and returns an object of the
    same type (and length if applicable) to the original.
    If `defaults_copy` and `kwdefaults_copy` return None, the new
    function will no longer have default values.

    Otherwise, shallow copies of __defaults__, __kwdefaults__, and
    __dict__ are used, along with a deepcopy of __closure__.
    
    Parameters:

    :: `defaults_copy`
        called as defaults_copy(func.__defaults__) to replace
        `func.__defaults__`, the attribute that stores a tuple
        containing the default values of positional arguments.
        
        Removes default positional arguments entirely if it returns None

    :: `kwdefaults_copy`
        called as kwdefaults_copy(func.__kwdefaults__) to replace
        `func.__kwdefaults__`, the attribute that stores a mapping
        containing the default values of keyword only arguments.

        Removes default kwonly arguments entirely if it returns None
        
    :: `dict_copy`
        called as dict_copy(func.__dict__) to replace `func.__dict__`

    :: `closure_copy`
        called as closure_copy(func.__closure__) to replace
        `func.__closure__`, the attribute that stores references
        to any nonlocal names used by `func`

    :: `global_ns`
        used to replace func.__globals__
        
        Will raise NameError if it doesn't contain all global references
        used by `func`.
        
    :: `name`
        a string that replaces func.__name__

    :: `qualname`
        if None, will generate a new __qualname__ automatically,
        which depends on the values in `name`, `func`, and `cls`

        Otherwise, a string

    :: `module`
        can be any type and is used to replace `func.__module__`

    :: `doc`
        can be any type and is used to replace `func.__doc__`
        
    :: `annotations`
        None to clear or mapping to replace `func.__annotations__`

        By default is a shallow copy of `func.__annotations__`
    """

    # validate func
    if not is_func(func):
        raise TypeError('func must be function object')
    else:
        f = func

    # validate cls
    if cls is None:
        class_was_not_none = False
    elif not is_heap_type(cls):
        raise TypeError('cls must be None or a Python class')
    else:
        class_was_not_none = True

    # validate defaults_copy
    defaults = f.__defaults__
    if defaults_copy is None:
        defaults = None if defaults is None else tuple_copy(defaults)
    elif not callable(defaults_copy):
        raise TypeError('defaults_copy must be a callable')
    else:
        defaults = defaults_copy(defaults)

    # validate kwdefaults_copy
    kwdefaults = f.__kwdefaults__
    if kwdefaults_copy is None:
        kwdefaults = None if kwdefaults is None else {**kwdefaults}
    elif not callable(kwdefaults_copy):
        raise TypeError('kwdefaults_copy must be a callable')
    else:
        kwdefaults = kwdefaults_copy(kwdefaults)

    # validate dict_copy
    new_dict = descriptor_getattr(f, '__dict__')
    if dict_copy is None:
        new_dict = {**new_dict}
    elif not callable(dict_copy):
        raise TypeError('dict_copy must be a callable')
    else:
        new_dict = dict_copy(new_dict)

    # validate closure_copy
    closure = f.__closure__
    if closure_copy is None:
        if is_tuple(closure):
            closure = deepcopy_closure(closure)
    elif not callable(closure_copy):
        raise TypeError('closure_copy must be a callable')
    else:
        closure = closure_copy(closure)

    # validate name
    if name is None:
        name = f.__name__
    elif not is_str(name):
        raise TypeError('function __name__ must be a string')

    # validate qualname
    if qualname is None:
        qualname = f'{cls.__name__}.{name}' if class_was_not_none else name
    elif not is_str(qualname):
        raise TypeError('function __qualname__ must be a string')

    # validate annotations
    f_annotations = f.__annotations__
    if annotations is False:
        annotations = None if f_annotations is None else {**f_annotations}
    elif not is_mapping(annotations):
        raise TypeError('annotations must be None or a mapping')

    # validate global_ns
    sentinel = object()
    if global_ns is None:
        global_ns = f.__globals__
    elif not is_dict(global_ns):
        raise TypeError('function __globals__ must be a dict')
    builtins = global_ns.get('__builtins__', sentinel)
    if builtins is sentinel:
        builtin_ns = {}
    elif is_dict(builtins):
        builtin_ns = builtins
    # the only time __builtins__ can be a module is if it IS builtins
    elif builtins is _builtins:
        builtin_ns = builtins.__dict__
    else:
        raise TypeError('f.__globals__["__builtins__"] must be a dict'
                        f'or the "builtins" module, not {builtins!r}')
    missing = set()
    code = f.__code__
    co_freevars = code.co_freevars
    co_flags = code.co_flags
    co_names = code.co_names
    co_code = code.co_code

    for co_name in co_names:
        if iskeyword(co_name):
            continue
        ob = global_ns.get(co_name, sentinel)
        if ob is sentinel:
            ob = builtin_ns.get(co_name, sentinel)
            if ob is sentinel:
                if class_was_not_none and co_name == '__class__':
                    continue
                missing.add(co_name)
    module = f.__module__ if module is False else module
    doc = f.__doc__ if doc is False else module
    if class_was_not_none:
        has_classcell = 'super' in co_names
        # replace LOAD_GLOBAL('__class__') opcodes with LOAD_DEREF('__class__')
        if '__class__' in co_names:
            j = co_names.index('__class__')
            #co_names = co_names[:j] + co_names[j+1:]
            bytecode = bytearray(co_code)
            for instr in dis.Bytecode(code):
                if instr.opname == 'LOAD_GLOBAL' and instr.argval == '__class__':
                    has_classcell = True
                    closure = closure or ()
                    i = len(closure)
                    # if len(closure) >= 256,
                    # the LOAD_DEREF opcode will use EXTENDED_ARG
                    if i > 255:
                        repl = b'\x90\x01\x88' + i.to_bytes(3, 'little')
                    else:
                        repl = b'\x88' + i.to_bytes(1, 'little')
                    x = instr.offset
                    bytecode[x:x + 2] = repl
            co_code = bytes(bytecode)
        # only add a class cell if necessary
        if has_classcell:
            cell = build_class_cell(cls)
            closure = closure or ()
            # insert/replace the __class__ cell if it is already in freevars
            if '__class__' in co_freevars:
                i = co_freevars.index('__class__')
                j = len(closure) == len(co_freevars)
                closure = (*closure[:i], cell, *closure[i + j:])
            # add if it doesn't
            else:
                co_freevars += ('__class__', )
                closure += (cell, )
    # ensure NOFREE flag is set if there are no frevars
    if not co_freevars:
        co_flags = (co_flags | NOFREE)
        if f.__closure__ is not None:
            raise TypeError('function closure was a tuple when its'
                            'code.co_freevars was empty')
    # since python 3.6, the NOFREE flag actually does what it's
    # supposed to do, so it must be unset to enable access of __closure__
    else:
        co_flags = (co_flags | NOFREE) ^ NOFREE
    code = update_code(code,
                       freevars=co_freevars,
                       flags=co_flags,
                       names=co_names,
                       code=co_code)
    method = FunctionType(code, global_ns, closure=closure)
    method.__defaults__ = defaults
    method.__kwdefaults__ = kwdefaults
    method.__name__ = name
    method.__qualname__ = qualname
    method.__annotations__ = annotations
    method.__module__ = module
    method.__doc__ = doc
    FunctionType.__dict__['__dict__'].__set__(method, new_dict)
    for wrapper in reversed(wrappers):
        method = wrapper(method)
    return method
示例#33
0
                            one of {std_imgs}".format(
            img_name=img_name,
            std_imgs=STANDARD_IMAGES.keys()))


# uses the pkg_resources provider to load in data in the .egg file
from . import STANDARD_IMAGE_DIRECTORY
# ND 9/7/18 - dynamically populate paths to the standard test images
# assumes the only thing in the STANDARD_IMAGE_DIRECTORY are images
STANDARD_IMAGE_PATHS = list(
    glob.glob(os.path.join(STANDARD_IMAGE_DIRECTORY, '*')))
STANDARD_IMAGES = {os.path.basename(impath).split(
    '.')[0]: impath for impath in STANDARD_IMAGE_PATHS}

# ND 9/7/18 - create convenience functions to load each of the standard test
# images as attributes of func
funcs = SimpleNamespace()
for img_name in STANDARD_IMAGES.keys():
    # JM: modifies function creation to also include docstrings
    partial_func = partial(get_standard_image, img_name)
    # ND changed partial funcs to FunctionType
    std_img_func = FunctionType(
        partial_func.func.__code__, globals(), img_name, partial_func.args)

    std_img_func.__doc__ = "standard image retrieval for {}".format(img_name)
    globals()[img_name] = std_img_func
    setattr(funcs, img_name, std_img_func)

# JM: deletes last remaining partial function from scope to remove Sphinx warning
del partial_func, img_name
示例#34
0
 def decorator(overriden: _Func) -> _Func:
     overriden.__doc__ = original.__doc__
     overriden.__signature__ = _signature(original)  # type: ignore
     return overriden
示例#35
0
def make_function(
    code: CodeType,
    globals_: T.Any,
    name: str,
    signature: _FullerSig,
    docstring: str = None,
    closure: T.Any = None,
    qualname: str = None,
    # options
    _add_signature: bool = False,
):
    r"""Make a function with a specified signature and docstring.

    This is pure python and may not make the fastest functions

    Parameters
    ----------
    code : code
        the .__code__ method of a function
    globals_ : Any
    name : str
    signature : Signature
        inspect.Signature converted to utilipy.Signature
    docstring : str
    closure : Any
    qualname : str

    Returns
    -------
    function: Callable
        the created function

    Other Parameters
    ----------------
    \_add_signature : bool
        Whether to add `signature` as ``__signature__``.

    .. todo::

        check how signature and closure relate
        __qualname__

    """
    if not isinstance(signature, _FullerSig):  # not my custom signature
        signature = _FullerSig(
            parameters=signature.parameters.values(),
            return_annotation=signature.return_annotation,
            # docstring=docstring  # not yet implemented
        )
    # else:
    #     pass

    # make function
    function = FunctionType(
        code, globals_, name=name, argdefs=signature.defaults, closure=closure
    )

    # assign properties not (properly) handled by FunctionType
    function.__kwdefaults__ = signature.__kwdefaults__
    function.__annotations__ = signature.__annotations__
    function.__doc__ = docstring

    if qualname is not None:
        function.__qualname__ = qualname

    if _add_signature:
        function.__signature__ = signature.__signature__  # classical signature

    return function
    def _register_query(
        cls,
        method_name: str,
        device_command: str,
        response_parser=str,
        response_validator=None,
        args=[],
        coroutine=False,
        docstring=None,
    ):
        """Make a function for this class which will access the device.

        Args:
            method_name (str): Name of the method to create
            device_command (str): Command to send to the device. Arguments can follow
            response_parser (callable, optional): Function to pass the response to. Must return a string. If not provided, the device's response will returned as a string. If set to None, the device's response will not be read.
            response_validator (callable, optional): Function to pass the response to before the parser. Can raise an error. Returns are ignored. Defaults to None.
            args (list, optional): List of arguments for the command, as ``GenericDriver.Arg`` objects. Defaults to [].
            coroutine (bool, optional): If true, create an async coroutine instead of a normal method, wrapping serial calls in a threaded executor. Defaults to False.
            docstring (str, optional): Docstring for the created method.
        """
        registered_args = [GenericDriver.Arg(*a) for a in args]

        # Define a function that will be called with the arguments provided.
        # This is guaranteed to get the right number of arguments with defaults
        # already present because we will call it from a wrapper
        @with_lock
        @with_handler
        def func(self, *args):
            arg_strings = []
            for arg, registered_arg in zip(args, registered_args):
                arg_strings.append(registered_arg.validator(arg))

            cmd_string = self.command_separator.join([device_command] +
                                                     arg_strings)

            logger.debug("Sending command '%s'", cmd_string)

            self._flush_all_buffers()

            if response_parser:
                r = self.instr.query(cmd_string)

                # Validate the response if available
                if response_validator:
                    response_validator(r)

                # Return the parsed result
                return response_parser(r)
            else:
                self.instr.write(cmd_string)

        async def func_async(self, *args):
            loop = asyncio.get_event_loop()
            return await loop.run_in_executor(None, partial(func, self, *args))

        logger.debug("Registering method %s with coroutine = %s", method_name,
                     coroutine)

        # Build a python function which takes the arguments as named. This is useful because now our bound methods
        # are real python methods, and so can respond to e.g.
        #     obj.set_mode(1)
        # or
        #     obj.set_mode(mode=1)
        # Also, python does the validation of number of args and setting of defaults for us
        list_of_arg_names = ["self"]
        for arg in registered_args:
            if not re.match(r"^[\w_]+$", arg.name):
                raise ValueError("'{}' is an invalid argument name".format(
                    arg.name))
            list_of_arg_names.append(arg.name)
        all_arg_names = ", ".join(list_of_arg_names)

        defaults = []
        for arg in registered_args:
            if arg.default:
                defaults.append(arg.default)
            else:
                if defaults:
                    raise ValueError(
                        "You can't have arguments without defaults after arguments with defaults"
                    )

        # Compile the wrapping function to call the one we already defined
        if coroutine:
            func_code_str = """async def wrapping_func({args}): return await func_async({args})""".format(
                args=all_arg_names)
        else:
            func_code_str = """def wrapping_func({args}): return func({args})""".format(
                args=all_arg_names)

        wrapping_func_code = compile(func_code_str, "<string>", "exec")

        # Bind this wrapping code to create a function. Pass it the current
        # context so that it can refer to func(). Also pass it the default
        # values required.
        wrapping_func = FunctionType(
            wrapping_func_code.co_consts[0],
            {
                **globals(),
                **locals()
            },
            method_name,
            tuple(defaults),
        )

        # Add a doc string
        if not docstring:
            docstring = """
Query "{}"

This function is automatically generated. It will call the command "{}"
and expects you to pass it {} arguments named {}.
        """.format(
                method_name,
                device_command,
                len(args),
                [arg.name for arg in registered_args],
            ).strip()

        wrapping_func.__doc__ = docstring

        setattr(cls, method_name, wrapping_func)