示例#1
0
 def getter(self):
     ret = godot_variant_alloc()
     lib.godot_variant_new_nil(ret)
     args = ffi.new("void*[]", [self._gd_ptr, gd_propname])
     lib.godot_method_bind_ptrcall(cls._meth_get_property,
                                   cls._instance, args, ret)
     return variant_to_pyobj(ret)
示例#2
0
def pybind_script_init(handle, path, source, r_error):
    path = godot_string_to_pyobj(path)
    if verbose:
        print("Loading python script from %s" % path)
    if not path.startswith("res://") or not path.rsplit(
            ".", 1)[-1] in ("py", "pyc", "pyo", "pyd"):
        print(
            "Bad python script path `%s`, must starts by `res://` and ends with `.py/pyc/pyo/pyd`"
            % path)
        r_error[0] = lib.GODOT_ERR_FILE_BAD_PATH
        return ffi.NULL

    # TODO: possible bug if res:// is not part of PYTHONPATH
    # Remove `res://`, `.py` and replace / by .
    modname = path[6:].rsplit(".", 1)[0].replace("/", ".")
    try:
        __import__(modname)  # Force lazy loading of the module
        # TODO: make sure script reloading works
        cls = get_exposed_class_per_module(modname)
    except Exception:
        # If we are here it could be because the file doesn't exists
        # or (more possibly) the file content is not a valid python (or
        # miss an exposed class)
        print("Got exception loading %s (%s): %s" %
              (path, modname, traceback.format_exc()))
        r_error[0] = lib.GODOT_ERR_PARSE_ERROR
        # Obliged to return the structure, but no need in init it
        return ffi.new("godot_pluginscript_script_manifest*")[0]

    r_error[0] = lib.GODOT_OK
    return _build_script_manifest(cls)[0]
示例#3
0
 def setter(self, value):
     gd_value = pyobj_to_variant(value)
     args = ffi.new("void*[]", [self._gd_ptr, gd_propname, gd_value])
     ret = godot_variant_alloc()
     lib.godot_variant_new_nil(ret)
     lib.godot_method_bind_ptrcall(cls._meth_set_property,
                                   cls._instance, args, ret)
     return variant_to_pyobj(ret)
示例#4
0
 def get_integer_constant(cls, classname, constname):
     ret = godot_int_alloc()
     gd_classname = godot_string_from_pyobj(classname)
     gd_constname = godot_string_from_pyobj(constname)
     args = ffi.new("void*[2]", [gd_classname, gd_constname])
     # 2nd arg should be false, which what we get by not initializing it
     lib.godot_method_bind_ptrcall(cls._meth_get_integer_constant,
                                   cls._instance, args, ret)
     return int(ret[0])
示例#5
0
        def bind(self, *args):
            # TODO: allow **kwargs
            # check number of args
            n_args, nm_args, nmd_args = (
                len(args),
                len(meth["args"]),
                len(meth["default_args"]),
            )
            nr_args = nm_args - nmd_args  # number of required arguments
            if n_args < nr_args:  # not enough args, raise error
                if nr_args - n_args == 1:
                    raise TypeError(
                        "%s() missing 1 required positional argument: '%s'"
                        % (methname, meth["args"][nr_args - 1]["name"])
                    )

                else:
                    raise TypeError(
                        "%s() missing %i required positional arguments: "
                        % (methname, nr_args - n_args)
                        + ", ".join(
                            "'%s'" % (arg["name"])
                            for arg in meth["args"][n_args : nr_args - 1]
                        )
                        + " and '%s'" % (meth["args"][nr_args - 1]["name"])
                    )

            if n_args > nm_args:  # too many args, raise error
                if nmd_args == 0:
                    raise TypeError(
                        "%s() takes %i positional argument%s but %i were given"
                        % (methname, nm_args, "s" if nm_args > 1 else "", n_args)
                    )

                else:
                    raise TypeError(
                        "%s() takes from %i to %i positional arguments but %i were given"
                        % (methname, nr_args, nm_args, n_args)
                    )

            # complete missing optional args with default values
            diff = len(args) - len(meth["args"])
            args = args + tuple(meth["default_args"][diff:])

            # TODO: check args type here (ptrcall means segfault on bad args...)
            # print('[PY->GD] Ptrcall %s.%s (%s) on %s with %s' % (classname, methname, meth, self, args))
            raw_args = [
                convert_arg(meth_arg["type"], meth_arg["name"], arg)
                for arg, meth_arg in zip(args, meth["args"])
            ]
            gdargs = ffi.new("void*[]", raw_args) if raw_args else ffi.NULL
            ret = new_uninitialized_gdobj(rettype)
            lib.godot_method_bind_ptrcall(methbind, self._gd_ptr, gdargs, ret)
            ret = gdobj_to_pyobj(rettype, ret)
            # print('[PY->GD] returned:', ret)
            return ret
示例#6
0
 def get_parent_class(cls, classname):
     ret = godot_string_alloc()
     lib.godot_string_new(ret)
     gd_classname = godot_string_from_pyobj(classname)
     args = ffi.new("godot_string**", gd_classname)
     lib.godot_method_bind_ptrcall(cls._meth_get_parent_class,
                                   cls._instance, ffi.cast("void**",
                                                           args), ret)
     raw_str = lib.godot_string_wide_str(ret)
     return ffi.string(raw_str)
示例#7
0
 def constructor(self):
     gd_classname = godot_string_from_pyobj(classname)
     # TODO: alloc this on the stack (using _malloca ?)
     args = ffi.new("void*[]", [gd_classname])
     ret = godot_variant_alloc()
     lib.godot_method_bind_ptrcall(cls._meth_instance, cls._instance, args, ret)
     objret = lib.godot_variant_as_object(ret)
     # Quick'n dirty fix to prevent Ressource objects from beeing automatically
     # freed when the variant is destroyed given it holds the only ref on it
     self._gd_var = ret
     return objret
示例#8
0
def godot_string_from_pyobj_for_ffi_return(pystr):
    """
    /!\ Don't use me unless you have good reason /!\
    Resulting godot_string object will not call godot_string_destroy
    when garbage collected. This is useful when a copy of this object is
    passed as a return value to Godot (which will be then responsible to
    actually call the destructor).
    """
    gdstr = ffi.new("godot_string*")
    lib.godot_string_new_with_wide_string(gdstr, pystr, len(pystr))
    return gdstr
示例#9
0
 def get_class_consts(cls, classname):
     consts = []
     ret = godot_pool_string_array_alloc()
     lib.godot_pool_string_array_new(ret)
     gd_classname = godot_string_from_pyobj(classname)
     gd_true = godot_bool_alloc(True)
     args = ffi.new("void*[2]", [gd_classname, gd_true])
     # 2nd arg should be false, which what we get by not initializing it
     lib.godot_method_bind_ptrcall(cls._meth_get_integer_constant_list,
                                   cls._instance, args, ret)
     for i in range(lib.godot_pool_string_array_size(ret)):
         godot_str = lib.godot_pool_string_array_get(ret, i)
         raw_str = lib.godot_string_wide_str(ffi.addressof(godot_str))
         consts.append(ffi.string(raw_str))
     return consts
示例#10
0
 def get_class_properties(cls, classname):
     properties = []
     ret = godot_array_alloc()
     lib.godot_array_new(ret)
     gd_classname = godot_string_from_pyobj(classname)
     gd_true = godot_bool_alloc(True)
     args = ffi.new("void*[2]", [gd_classname, gd_true])
     # 2nd arg should be false, which what we get by not initializing it
     lib.godot_method_bind_ptrcall(cls._meth_get_property_list,
                                   cls._instance, args, ret)
     for i in range(lib.godot_array_size(ret)):
         var = lib.godot_array_get(ret, i)
         gddict = lib.godot_variant_as_dictionary(ffi.addressof(var))
         propdict = Dictionary.build_from_gdobj(gddict)
         properties.append(propdict)
     return properties
示例#11
0
 def bind(self, *args):
     # print('[PY->GD] Varargs call %s.%s (%s) on %s with %s' % (classname, methname, meth, self, args))
     vaargs = [
         convert_arg(meth_arg["type"], meth_arg["name"], arg, to_variant=True)
         for arg, meth_arg in zip(args, meth["args"])
     ]
     vaargs += [pyobj_to_variant(arg) for arg in args[fixargs_count:]]
     vavaargs = ffi.new("godot_variant*[]", vaargs) if vaargs else ffi.NULL
     # TODO: use `godot_variant_call_error` to raise exceptions
     varret = lib.godot_method_bind_call(
         methbind, self._gd_ptr, vavaargs, len(args), ffi.NULL
     )
     ret = variant_to_pyobj(ffi.addressof(varret))
     lib.godot_variant_destroy(ffi.addressof(varret))
     # print('[PY->GD] returned:', ret)
     return ret
示例#12
0
 def bind(self, *args):
     if len(args) != len(meth['args']):
         raise TypeError(
             '%s() takes %s positional argument but %s were given' %
             (methname, len(meth['args']), len(args)))
     # TODO: check args number and type here (ptrcall means segfault on bad args...)
     # print('[PY->GD] Ptrcall %s.%s (%s) on %s with %s' % (classname, methname, meth, self, args))
     raw_args = [
         convert_arg(meth_arg['type'], meth_arg['name'], arg)
         for arg, meth_arg in zip(args, meth['args'])
     ]
     gdargs = ffi.new("void*[]", raw_args) if raw_args else ffi.NULL
     ret = new_uninitialized_gdobj(rettype)
     lib.godot_method_bind_ptrcall(methbind, self._gd_ptr, gdargs, ret)
     ret = gdobj_to_pyobj(rettype, ret)
     # print('[PY->GD] returned:', ret)
     return ret
示例#13
0
def pybind_get_signal_list(handle):
    # Lazily generate the list of exported properties' names
    cls_or_instance = ffi.from_handle(handle)
    cls = cls_or_instance if isinstance(cls_or_instance,
                                        type) else type(cls_or_instance)
    # Need to store the cached list with a per-class name to avoid shadowing
    # from a parent class
    field = '_%s__signal_raw_list' % cls.__name__
    raw_list = getattr(cls, field, None)
    if not raw_list:
        # Build the list of signals, ready to be access by godot
        raw_list = ffi.new('godot_string[]', len(cls.__signals) + 1)
        for i, name in enumerate(cls.__signals.keys()):
            lib.godot_string_new_unicode_data(ffi.addressof(raw_list[i]), name,
                                              -1)
        # Last entry is an empty string
        lib.godot_string_new(ffi.addressof(raw_list[len(cls.__signals)]))
        setattr(cls, field, raw_list)
    return raw_list
示例#14
0
def pybind_get_meth_list(handle):
    # Lazily generate the list of methods' names
    cls_or_instance = ffi.from_handle(handle)
    cls = cls_or_instance if isinstance(cls_or_instance,
                                        type) else type(cls_or_instance)
    # Need to store the cached list with a per-class name to avoid shadowing
    # from a parent class
    field = '_%s__meth_raw_list' % cls.__name__
    raw_list = getattr(cls, field, None)
    if not raw_list:
        meths = [
            k for k in dir(cls)
            if not k.startswith('__') and callable(getattr(cls, k))
        ]
        raw_list = ffi.new('godot_string[]', len(meths) + 1)
        for i, name in enumerate(meths):
            lib.godot_string_new_unicode_data(ffi.addressof(raw_list[i]), name,
                                              -1)
        # Last entry is an empty string
        lib.godot_string_new(ffi.addressof(raw_list[len(meths)]))
        setattr(cls, field, raw_list)
    return raw_list
def _build_script_manifest(cls):
    from godot.bindings import Dictionary, Array

    def _build_signal_info(signal):
        methinfo = Dictionary()
        methinfo['name'] = signal.name
        # Dummy data, only name is important here
        methinfo['args'] = Array()
        methinfo['default_args'] = Array()
        methinfo['return'] = None
        methinfo['flags'] = lib.METHOD_FLAG_FROM_SCRIPT
        return methinfo

    def _build_method_info(meth, methname):
        spec = inspect.getfullargspec(meth)
        methinfo = Dictionary()
        methinfo['name'] = methname
        # TODO: Handle classmethod/staticmethod
        methinfo['args'] = Array(spec.args)
        methinfo['default_args'] = Array()  # TODO
        # TODO: use annotation to determine return type ?
        methinfo['return'] = None
        methinfo['flags'] = lib.METHOD_FLAG_FROM_SCRIPT
        methinfo['rpc_mode'] = getattr(meth, '__rpc',
                                       lib.GODOT_METHOD_RPC_MODE_DISABLED)
        return methinfo

    def _build_property_info(prop):
        propinfo = Dictionary()
        propinfo['name'] = prop.name
        propinfo['type'] = py_to_gd_type(prop.type)
        propinfo['hint'] = prop.hint
        propinfo['hint_string'] = prop.hint_string
        propinfo['usage'] = prop.usage
        propinfo['default_value'] = prop.default
        propinfo['rset_mode'] = prop.rpc
        return propinfo

    manifest = ffi.new('godot_pluginscript_script_manifest*')
    manifest.data = connect_handle(cls)
    gdname = godot_string_from_pyobj(cls.__name__)
    lib.godot_string_name_new(ffi.addressof(manifest.name), gdname)
    if cls.__bases__ and issubclass(cls.__bases__[0], BaseObject):
        gdbase = godot_string_from_pyobj(cls.__bases__[0].__name__)
        lib.godot_string_name_new(ffi.addressof(manifest.base), gdbase)
    manifest.is_tool = cls.__tool
    lib.godot_dictionary_new(ffi.addressof(manifest.member_lines))
    lib.godot_array_new(ffi.addressof(manifest.methods))
    methods = Array()
    # TODO: include inherited in exposed methods ? Expose Godot base class' ones ?
    # for methname in vars(cls):
    for methname in dir(cls):
        meth = getattr(cls, methname)
        if not inspect.isfunction(meth) or meth.__name__.startswith('__'):
            continue
        methinfo = _build_method_info(meth, methname)
        methods.append(methinfo)

    signals = Array()
    for signal in cls.__signals.values():
        signalinfo = _build_signal_info(signal)
        signals.append(signalinfo)

    properties = Array()
    for prop in cls.__exported.values():
        property_info = _build_property_info(prop)
        properties.append(property_info)

    lib.godot_array_new_copy(ffi.addressof(manifest.methods), methods._gd_ptr)
    lib.godot_array_new_copy(ffi.addressof(manifest.signals), signals._gd_ptr)
    lib.godot_array_new_copy(ffi.addressof(manifest.properties),
                             properties._gd_ptr)
    return manifest
示例#16
0
def _build_script_manifest(cls):
    def _build_signal_info(signal):
        methinfo = Dictionary()
        methinfo["name"] = signal.name
        # Dummy data, only name is important here
        methinfo["args"] = Array()
        methinfo["default_args"] = Array()
        methinfo["return"] = None
        methinfo["flags"] = lib.METHOD_FLAG_FROM_SCRIPT
        return methinfo

    def _build_method_info(meth, methname):
        spec = inspect.getfullargspec(meth)
        methinfo = Dictionary()
        methinfo["name"] = methname
        # TODO: Handle classmethod/staticmethod
        methinfo["args"] = Array(spec.args)
        methinfo["default_args"] = Array()  # TODO
        # TODO: use annotation to determine return type ?
        methinfo["return"] = None
        methinfo["flags"] = lib.METHOD_FLAG_FROM_SCRIPT
        methinfo["rpc_mode"] = getattr(meth, "__rpc",
                                       lib.GODOT_METHOD_RPC_MODE_DISABLED)
        return methinfo

    def _build_property_info(prop):
        propinfo = Dictionary()
        propinfo["name"] = prop.name
        propinfo["type"] = py_to_gd_type(prop.type)
        propinfo["hint"] = prop.hint
        propinfo["hint_string"] = prop.hint_string
        propinfo["usage"] = prop.usage
        propinfo["default_value"] = prop.default
        propinfo["rset_mode"] = prop.rpc
        return propinfo

    manifest = ffi.new("godot_pluginscript_script_manifest*")
    manifest.data = connect_handle(cls)
    # TODO: should be able to use lib.godot_string_new_with_wide_string directly
    gdname = godot_string_from_pyobj(cls.__name__)
    lib.godot_string_name_new(ffi.addressof(manifest.name), gdname)
    if cls.__bases__:
        # Only one Godot parent class (checked at class definition time)
        godot_parent_class = next(
            (b for b in cls.__bases__ if issubclass(b, BaseObject)))
        if godot_parent_class.__dict__.get("__is_godot_native_class"):
            path = godot_parent_class.__name__
        else:
            # Pluginscript wants us to return the parent as a path
            path = "res://%s.py" % "/".join(
                cls.__bases__[0].__module__.split("."))
        gdbase = godot_string_from_pyobj(path)
        lib.godot_string_name_new(ffi.addressof(manifest.base), gdbase)
    manifest.is_tool = cls.__tool
    lib.godot_dictionary_new(ffi.addressof(manifest.member_lines))
    lib.godot_array_new(ffi.addressof(manifest.methods))
    methods = Array()
    # TODO: include inherited in exposed methods ? Expose Godot base class' ones ?
    # for methname in vars(cls):
    for methname in dir(cls):
        meth = getattr(cls, methname)
        if not inspect.isfunction(meth) or meth.__name__.startswith("__"):
            continue

        methinfo = _build_method_info(meth, methname)
        methods.append(methinfo)

    signals = Array()
    for signal in cls.__signals.values():
        signalinfo = _build_signal_info(signal)
        signals.append(signalinfo)

    properties = Array()
    for prop in cls.__exported.values():
        property_info = _build_property_info(prop)
        properties.append(property_info)

    lib.godot_array_new_copy(ffi.addressof(manifest.methods), methods._gd_ptr)
    lib.godot_array_new_copy(ffi.addressof(manifest.signals), signals._gd_ptr)
    lib.godot_array_new_copy(ffi.addressof(manifest.properties),
                             properties._gd_ptr)
    return manifest
示例#17
0
def pyobj_to_variant(pyobj, p_gdvar=None, for_ffi_return=False):
    """
    `initialized=False` means we MUST manually init this by hand no matter what

    `for_ffi_return=True` means the returned variant won't have it destructor called
    once it is garbage collected by python.
    This is typically what we want when we pass the variant object by copy as a
    return value to Godot (which is then in charge of calling the destructor itself).
    """
    if not p_gdvar:
        if for_ffi_return:
            p_gdvar = ffi.new("godot_variant*")
        else:
            p_gdvar = godot_variant_alloc(initialized=False)
    try:
        if pyobj is None:
            lib.godot_variant_new_nil(p_gdvar)
        elif (isinstance(pyobj, bool)):
            lib.godot_variant_new_bool(p_gdvar, pyobj)
        elif (isinstance(pyobj, int)):
            lib.godot_variant_new_int(p_gdvar, pyobj)
        elif (isinstance(pyobj, float)):
            lib.godot_variant_new_real(p_gdvar, pyobj)
        elif (isinstance(pyobj, str)):
            gdstr = godot_string_alloc(initialized=False)
            lib.godot_string_new_with_wide_string(gdstr, pyobj, len(pyobj))
            lib.godot_variant_new_string(p_gdvar, gdstr)
        elif isinstance(pyobj, BaseBuiltin):
            if pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_VECTOR2:
                lib.godot_variant_new_vector2(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_RECT2:
                lib.godot_variant_new_rect2(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_VECTOR3:
                lib.godot_variant_new_vector3(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_TRANSFORM2D:
                lib.godot_variant_new_transform2d(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_PLANE:
                lib.godot_variant_new_plane(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_QUAT:
                lib.godot_variant_new_quat(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_AABB:
                lib.godot_variant_new_aabb(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_BASIS:
                lib.godot_variant_new_basis(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_TRANSFORM:
                lib.godot_variant_new_transform(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_COLOR:
                lib.godot_variant_new_color(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_NODE_PATH:
                lib.godot_variant_new_node_path(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_RID:
                lib.godot_variant_new_rid(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_OBJECT:
                lib.godot_variant_new_object(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_DICTIONARY:
                lib.godot_variant_new_dictionary(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_ARRAY:
                lib.godot_variant_new_array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOL_BYTE_ARRAY:
                lib.godot_variant_new_pool_byte_array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOL_INT_ARRAY:
                lib.godot_variant_new_pool_int_array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOL_REAL_ARRAY:
                lib.godot_variant_new_pool_real_array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOL_STRING_ARRAY:
                lib.godot_variant_new_pool_string_array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOL_VECTOR2_ARRAY:
                lib.godot_variant_new_pool_vector2_array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOL_VECTOR3_ARRAY:
                lib.godot_variant_new_pool_vector3_array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOL_COLOR_ARRAY:
                lib.godot_variant_new_pool_color_array(p_gdvar, pyobj._gd_ptr)
        elif isinstance(pyobj, BaseObject):
            lib.godot_variant_new_object(p_gdvar, pyobj._gd_ptr)
        else:
            raise TypeError("Cannot convert `%s` to Godot's Variant" % pyobj)

    except BaseException:
        # Must init the variant anyway to avoid segfault in it destructor
        lib.godot_variant_new_nil(p_gdvar)
        raise

    return p_gdvar
示例#18
0
def pyobj_to_variant(pyobj, p_gdvar=None):
    # `initialized=False` means we MUST manually init this by hand no matter what
    p_gdvar = p_gdvar if p_gdvar else godot_variant_alloc(initialized=False)
    try:
        if pyobj is None:
            lib.godot_variant_new_nil(p_gdvar)
        elif (isinstance(pyobj, bool)):
            lib.godot_variant_new_bool(p_gdvar, pyobj)
        elif (isinstance(pyobj, int)):
            lib.godot_variant_new_int(p_gdvar, pyobj)
        elif (isinstance(pyobj, float)):
            lib.godot_variant_new_real(p_gdvar, pyobj)
        elif (isinstance(pyobj, str)):
            gdstr = ffi.new("godot_string*")
            pyobj_as_bytes = pyobj.encode()
            lib.godot_string_new_data(gdstr, pyobj_as_bytes,
                                      len(pyobj_as_bytes))
            lib.godot_variant_new_string(p_gdvar, gdstr)
        elif (isinstance(pyobj, bytes)):
            gdstr = ffi.new("godot_string*")
            lib.godot_string_new_data(gdstr, pyobj, len(pyobj))
            lib.godot_variant_new_string(p_gdvar, gdstr)
        elif isinstance(pyobj, BaseBuiltin):
            if pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_VECTOR2:
                lib.godot_variant_new_vector2(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_RECT2:
                lib.godot_variant_new_rect2(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_VECTOR3:
                lib.godot_variant_new_vector3(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_TRANSFORM2D:
                lib.godot_variant_new_transform2d(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_PLANE:
                lib.godot_variant_new_plane(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_QUAT:
                lib.godot_variant_new_quat(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_AABB:
                lib.godot_variant_new_aabb(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_BASIS:
                lib.godot_variant_new_basis(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_TRANSFORM:
                lib.godot_variant_new_transform(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_COLOR:
                lib.godot_variant_new_color(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_NODE_PATH:
                lib.godot_variant_new_nodepath(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_RID:
                lib.godot_variant_new_rid(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_OBJECT:
                lib.godot_variant_new_object(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_DICTIONARY:
                lib.godot_variant_new_dictionary(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_ARRAY:
                lib.godot_variant_new_array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOLBYTEARRAY:
                lib.godot_variant_new_poolbytearray(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOLINTARRAY:
                lib.godot_variant_new_poolintarray(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOLREALARRAY:
                lib.godot_variant_new_poolrealarray(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOLSTRINGARRAY:
                lib.godot_variant_new_poolstringarray(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOLVECTOR2ARRAY:
                lib.godot_variant_new_poolvector2array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOLVECTOR3ARRAY:
                lib.godot_variant_new_poolvector3array(p_gdvar, pyobj._gd_ptr)
            elif pyobj.GD_TYPE == lib.GODOT_VARIANT_TYPE_POOLCOLORARRAY:
                lib.godot_variant_new_poolcolorarray(p_gdvar, pyobj._gd_ptr)
        elif isinstance(pyobj, BaseObject):
            lib.godot_variant_new_object(p_gdvar, pyobj._gd_ptr)
        else:
            raise TypeError("Cannot convert `%s` to Godot's Variant" % pyobj)
    except:
        # Must init the variant anyway to avoid segfault in it destructor
        lib.godot_variant_new_nil(p_gdvar)
        raise
    return p_gdvar