Example #1
0
def _generate_signal_callback(backend, info, args, arg_types):
    sig_args = []

    ret_type = info.get_return_type()
    cls = get_cbreturn_class(ret_type)
    return_value = cls(backend, info, ret_type)

    for arg, type_ in zip(args, arg_types):
        cls = get_cbarg_class(type_)
        excaped_name = escape_identifier(arg.name)
        sig_arg = cls(backend, arg, type_, excaped_name)
        sig_args.append(sig_arg)

    for arg in sig_args:
        arg.setup()

    body = CodeBlock()

    outs_vars = []
    for arg in sig_args:
        if arg.is_aux:
            continue
        block, out = arg.process()
        if block:
            block.write_into(body)
        outs_vars.append(out)

    argument_list = ", ".join([a.name for a in sig_args])
    forward_arguments = ", ".join(outs_vars)
    func_name = escape_parameter(info.name)
    cb_name = backend.var()

    return_var = backend.var()
    return_block, out_var = return_value.process(return_var)
    return_block = return_block or CodeBlock()

    block, var = backend.parse("""
def $cb_wrapper($dummy, $args):
    $body
    $ret = $callback($out_args)
    $post
    return $out
""",
                               args=argument_list,
                               out_args=forward_arguments,
                               cb_wrapper=func_name,
                               callback=cb_name,
                               body=body,
                               post=return_block,
                               out=out_var,
                               ret=return_var)

    def create_sig_for_func(real_func):
        f = block.compile(**{cb_name: real_func})[func_name]
        return backend.get_callback(f, sig_args, return_value, is_signal=True)

    return create_sig_for_func
Example #2
0
 def test_escape_identifier(self):
     self.assertEqual(escape_identifier("class"), "class_")
     self.assertEqual(escape_identifier("2BUTTON_PRESS"), "_2BUTTON_PRESS")
     # most things from the gir are partial identifiers, so an empty
     # string can occur
     self.assertEqual(escape_identifier(""), "_")
Example #3
0
def generate_dummy_callable(info, func_name, method=False):
    """Takes a GICallableInfo and generates a dummy callback function which
    just raises but has a correct docstring. They are mainly accessible for
    documentation, so the API reference can reference a real thing.

    func_name can be different than info.name because vfuncs, for example,
    get prefixed with 'do_' when exposed in Python.
    """

    assert isinstance(info, GICallableInfo)

    # FIXME: handle out args and trailing user_data ?

    arg_infos = list(info.get_args())
    arg_types = [a.get_type() for a in arg_infos]
    return_type = info.get_return_type()

    # the null backend is good enough here
    backend = get_backend("null")()

    args = []
    for arg_info, arg_type in zip(arg_infos, arg_types):
        cls = get_argument_class(arg_type)
        name = escape_identifier(arg_info.name)
        name = escape_parameter(name)
        args.append(cls(name, args, backend, arg_info, arg_type))

    cls = get_return_class(return_type)
    return_value = cls(info, return_type, args, backend)

    for arg in args:
        arg.setup()

    return_value.setup()

    func_name = escape_identifier(func_name)
    docstring = build_docstring(func_name, args, return_value, False)

    in_args = [a for a in args if not a.is_aux and a.in_var]
    in_names = [a.in_var for a in in_args]

    var_fac = backend.var
    var_fac.add_blacklist(in_names)
    self_name = ""
    if method:
        self_name = var_fac.request_name("self")
        in_names.insert(0, self_name)

    main, var = backend.parse("""
def $func_name($func_args):
    '''$docstring'''

    raise NotImplementedError("This is just a dummy callback function")
""", func_args=", ".join(in_names), docstring=docstring, func_name=func_name)

    func = main.compile()[func_name]
    func._code = main
    func.__doc__ = docstring
    func.__module__ = info.namespace

    return func
Example #4
0
def generate_callback_wrapper(info):
    backend = get_backend("ctypes")()

    args = list(info.get_args())
    arg_types = [a.get_type() for a in args]

    ret_type = info.get_return_type()
    cls = get_cbreturn_class(ret_type)
    return_value = cls(backend, info, ret_type)

    cb_args = []
    for arg, type_ in zip(args, arg_types):
        cls = get_cbarg_class(type_)
        excaped_name = escape_identifier(arg.name)
        cb_arg = cls(backend, arg, type_, excaped_name)
        cb_args.append(cb_arg)

    for arg in cb_args:
        arg.setup()

    body = CodeBlock()

    outs_vars = []
    for arg in cb_args:
        if arg.is_aux:
            continue
        block, out = arg.process()
        if block:
            block.write_into(body)
        outs_vars.append(out)

    arg_names = [a.name for a in cb_args]
    backend.var.add_blacklist(arg_names)

    argument_list = ", ".join(arg_names)
    forward_arguments = ", ".join(outs_vars)
    func_name = escape_parameter(info.name)
    cb_name = backend.var()

    return_var = backend.var()
    return_block, out_var = return_value.process(return_var)
    return_block = return_block or CodeBlock()

    docstring = build_docstring(func_name, cb_args)

    block, var = backend.parse("""
def $cb_wrapper($args):
    $body
    # $docstring
    $ret = $callback($out_args)
    $post
    return $out
""",
                               args=argument_list,
                               out_args=forward_arguments,
                               cb_wrapper=func_name,
                               callback=cb_name,
                               body=body,
                               docstring=docstring,
                               ret=return_var,
                               out=out_var,
                               post=return_block)

    def create_cb_for_func(real_func):
        if real_func is not None:
            # binds the callback to the block and compiles it
            func = block.compile(**{cb_name: real_func})[func_name]
        else:
            func = None
        return backend.get_callback(func, cb_args, return_value)

    return create_cb_for_func, docstring
Example #5
0
def _generate_function(backend, info, arg_infos, arg_types,
                       return_type, method):

    args = []
    for arg_info, arg_type in zip(arg_infos, arg_types):
        cls = get_argument_class(arg_type)
        name = escape_identifier(arg_info.name)
        args.append(cls(name, args, backend, arg_info, arg_type))

    cls = get_return_class(return_type)
    return_value = cls(info, return_type, args, backend)
    throws = info.flags.value & GIFunctionInfoFlags.THROWS

    if throws:
        args.append(ErrorArgument(args, backend))

    # setup
    for arg in args:
        arg.setup()

    return_value.setup()

    # in args
    in_args = [a for a in args if not a.is_aux and a.in_var]

    # set description used for exceptions
    for i, arg in enumerate(in_args):
        arg.desc = "%s() argument '%s'(%d)" % (info.name, arg.in_var, i + 1)

    # if the last in argument is a user data, make it a positional argument
    if in_args and in_args[-1].is_userdata:
        name = in_args[-1].in_var
        in_args[-1].in_var = "*" + name

    in_names = [a.in_var for a in in_args]

    var_fac = backend.var
    var_fac.add_blacklist([n.strip("*") for n in in_names])
    self_name = ""
    if method:
        self_name = var_fac.request_name("self")
        in_names.insert(0, self_name)
    in_names = ", ".join(in_names)

    # pre call
    body = CodeBlock()
    for arg in args:
        if arg.is_aux or arg.is_userdata:
            continue
        block = arg.pre_call()
        if block:
            block.write_into(body)

    block = return_value.pre_call()
    if block:
        block.write_into(body)

    # generate call
    lib = backend.get_library(info.namespace)
    symbol = info.symbol
    block, func = backend.get_function(lib, symbol, args,
                                       return_value, method,
                                       throws)
    if block:
        block.write_into(body)

    # do the call
    call_vars = [a.call_var for a in args if a.call_var]
    if method:
        # there are not unbound method in Python 3 and also no
        # type checking for the "self" object, but at least raise
        # TypeError if getting the pointer value fails which
        # should cover most cases

        if PY3:
            block, var = backend.parse("""
try:
    $ptr = %s._obj
except AttributeError:
    raise TypeError
""" % self_name)
        else:
            block, var = backend.parse("$ptr = %s._obj" % self_name)
        block.write_into(body)

        call_vars.insert(0, var["ptr"])
    call_block, var = backend.parse("$ret = $func($args)",
                                    func=func, args=", ".join(call_vars))
    call_block.write_into(body)
    ret = var["ret"]

    out = []

    # handle errors first
    if throws:
        error_arg = args.pop()
        block = error_arg.post_call()
        if block:
            block.write_into(body)

    # process return value
    if not return_value.ignore:
        block, return_var = return_value.post_call(ret)
        assert return_var
        if block:
            block.write_into(body)
        out.append((return_var, None))

    # process out args
    for arg in args:
        if arg.is_aux or arg.is_userdata:
            continue
        block = arg.post_call()
        if block:
            block.write_into(body)
        if arg.out_var:
            out.append((arg.out_var, arg.name))

    if len(out) == 1:
        body.write_line("return %s" % out[0][0])
    elif len(out) > 1:
        # for more than one value use a named tuple.
        out_vars, out_names = zip(*out)
        ntuple = create_return_tuple(out_names)
        block, var = backend.parse("""
return $ntuple((%s))
""" % ", ".join(out_vars), ntuple=ntuple)
        block.write_into(body)

    # build final function block

    func_name = escape_identifier(info.name)

    docstring = build_docstring(func_name, args, return_value, throws)

    main, var = backend.parse("""
# backend: $backend_name
def $func_name($func_args):
    '''$docstring'''

    $func_body
""", backend_name=backend.NAME, func_args=in_names, docstring=docstring,
     func_body=body, func_name=func_name)

    func = main.compile()[func_name]
    func._code = main
    func.__doc__ = docstring
    func.__module__ = info.namespace

    return func