[pybank] Add support for structs
- From: Johan Dahlin <johan src gnome org>
- To: svn-commits-list gnome org
- Subject: [pybank] Add support for structs
- Date: Thu, 28 May 2009 11:13:06 -0400 (EDT)
commit 0dbfcea29919e7fd22bb2f2e642a63ec08f59077
Author: Tomeu Vizoso <tomeu sugarlabs org>
Date: Thu May 7 17:18:13 2009 +0200
Add support for structs
---
bank/bank-argument.c | 21 +++-
bank/bank-info.c | 361 +++++++++++++++++++++++++++++++++---------------
bank/bank.c | 1 +
bank/btypes.py | 44 ++++++
bank/module.py | 37 +++++-
everything_unittest.py | 5 +-
6 files changed, 353 insertions(+), 116 deletions(-)
diff --git a/bank/bank-argument.c b/bank/bank-argument.c
index 0920484..a4265d4 100644
--- a/bank/bank-argument.c
+++ b/bank/bank-argument.c
@@ -109,11 +109,30 @@ pyg_argument_to_pyobject(GArgument *arg, GITypeInfo *type_info)
{
GITypeTag type_tag;
PyObject *obj;
+ GIBaseInfo* interface_info;
+ GIInfoType interface_type;
g_return_val_if_fail(type_info != NULL, NULL);
type_tag = g_type_info_get_tag(type_info);
if ( type_tag == GI_TYPE_TAG_INTERFACE ) {
- if ( arg->v_pointer == NULL ) {
+ interface_info = g_type_info_get_interface(type_info);
+ interface_type = g_base_info_get_type(interface_info);
+
+ if (interface_type == GI_INFO_TYPE_STRUCT || interface_type == GI_INFO_TYPE_BOXED) {
+ // Create new struct based on arg->v_pointer
+ const gchar *module_name = g_base_info_get_namespace(interface_info);
+ const gchar *type_name = g_base_info_get_name(interface_info);
+ PyObject *module = PyImport_ImportModule(module_name);
+ PyTypeObject *tp = (PyTypeObject *)PyObject_GetAttrString(module, type_name);
+
+ // TODO: Pass a reference to the arg->v_pointer
+ obj = PyObject_GC_New(PyObject, tp);
+ if (obj == NULL)
+ return NULL;
+ PyObject_GC_Track(obj);
+ Py_INCREF(obj);
+ return obj;
+ } else if ( arg->v_pointer == NULL ) {
obj = Py_None;
Py_INCREF(obj);
return obj;
diff --git a/bank/bank-info.c b/bank/bank-info.c
index 77f6be4..62f3b5b 100644
--- a/bank/bank-info.c
+++ b/bank/bank-info.c
@@ -327,134 +327,250 @@ _wrap_g_function_info_invoke(PyGIBaseInfo *self, PyObject *args)
{
GArgument *in_args;
GArgument *out_args;
+ GArgument *out_values;
GArgument return_arg;
- gboolean is_method;
- int n_in_args;
- int n_out_args;
+ int n_args;
+ int expected_in_argc;
+ int expected_out_argc;
int i;
- PyObject *py_arg;
- GIDirection direction;
- GError *error = NULL;
- GIArgInfo *arg_info;
+ int argv_pos;
+ int in_args_pos;
+ int out_args_pos;
+ GError *error;
+ gboolean failed;
+ GIFunctionInfoFlags flags;
+ gboolean is_method;
+ gboolean invoke_ok;
+ GITypeInfo *return_info;
+ GITypeTag return_tag;
+ PyObject **return_values;
+ int n_return_values;
+ int next_rval;
PyObject *retval;
- int flags;
+ PyObject *py_arg;
flags = g_function_info_get_flags((GIFunctionInfo*)self->info);
- is_method = (flags & GI_FUNCTION_IS_METHOD) != 0 &&
- (flags & GI_FUNCTION_IS_CONSTRUCTOR) == 0;
-
- n_in_args = is_method ? 1 : 0;
- n_out_args = 0;
- for (i = 0; i < g_callable_info_get_n_args((GICallableInfo*)self->info); i++) {
- arg_info = g_callable_info_get_arg((GICallableInfo*)self->info, i);
- direction = g_arg_info_get_direction(arg_info);
- if (direction == GI_DIRECTION_IN) {
- n_in_args++;
- } else if (direction == GI_DIRECTION_OUT) {
- n_out_args++;
- } else if (direction == GI_DIRECTION_INOUT) {
- /* FIXME - just map these as in args temporarily, we need to
- * get gtk_init_check etc. working */
- n_in_args++;
- n_out_args++;
- }
- g_base_info_unref((GIBaseInfo*)arg_info);
+ is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
+
+ expected_in_argc = 0;
+ expected_out_argc = 0;
+
+ n_args = g_callable_info_get_n_args( (GICallableInfo*) self->info);
+ for (i = 0; i < n_args; i++) {
+ GIDirection direction;
+ GIArgInfo *arg_info;
+
+ arg_info = g_callable_info_get_arg( (GICallableInfo*) self->info, i);
+ direction = g_arg_info_get_direction(arg_info);
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT)
+ expected_in_argc += 1;
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ expected_out_argc += 1;
+ g_base_info_unref( (GIBaseInfo*) arg_info);
}
- in_args = g_new0(GArgument, n_in_args);
- out_args = g_new0(GArgument, n_out_args);
+ g_debug("Call is to %s %s.%s with expected: %d in args, %d out args, %d total args",
+ is_method ? "method" : "function",
+ g_base_info_get_namespace( (GIBaseInfo*) self->info),
+ g_base_info_get_name( (GIBaseInfo*) self->info),
+ expected_in_argc,
+ expected_out_argc,
+ n_args);
+
+ if (is_method)
+ expected_in_argc += 1;
+
+ in_args = g_newa(GArgument, expected_in_argc);
+ out_args = g_newa(GArgument, expected_out_argc);
+ /* each out arg is a pointer, they point to these values */
+ out_values = g_newa(GArgument, expected_out_argc);
+
+ failed = FALSE;
+ in_args_pos = 0; /* index into in_args */
+ out_args_pos = 0; /* into out_args */
+ argv_pos = 0; /* index into argv */
+
if (is_method) {
- py_arg = PyTuple_GetItem(args, 0);
- if (!py_arg)
- return NULL;
- if (py_arg == Py_None)
- in_args[0].v_pointer = NULL;
- else
+ GIBaseInfo *container = g_base_info_get_container((GIBaseInfo *) self->info);
+ GIInfoType type = g_base_info_get_type(container);
+
+ py_arg = PyTuple_GetItem(args, 0);
+ if (!py_arg)
+ return NULL;
+ if (py_arg == Py_None)
+ in_args[0].v_pointer = NULL;
+ else if (type == GI_INFO_TYPE_STRUCT || type == GI_INFO_TYPE_BOXED) {
+ PyObject *buffer = PyObject_GetAttrString((PyObject *)py_arg,
+ "__buffer__");
+ in_args[0].v_pointer = PyString_AsString(buffer);
+ } else { /* by fallback is always object */
in_args[0].v_pointer = pygobject_get(py_arg);
+ }
+ ++in_args_pos;
}
- for (i = 0; i < g_callable_info_get_n_args((GICallableInfo*)self->info); i++) {
- arg_info = g_callable_info_get_arg((GICallableInfo*)self->info, i);
- direction = g_arg_info_get_direction(arg_info);
- int offset = i + (is_method ? 1 : 0);
- if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
- py_arg = PyTuple_GetItem(args, offset);
- if (!py_arg)
- return NULL;
- in_args[offset] = pyg_argument_from_pyobject(py_arg, arg_info);
- }
-
- g_base_info_unref((GIBaseInfo*)arg_info);
+
+ for (i = 0; i < n_args; i++) {
+ GIDirection direction;
+ GIArgInfo *arg_info;
+ GArgument *out_value;
+
+ arg_info = g_callable_info_get_arg( (GICallableInfo*) self->info, i);
+ direction = g_arg_info_get_direction(arg_info);
+
+ out_value = NULL;
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
+ g_assert(out_args_pos < expected_out_argc);
+
+ out_value = &out_values[out_args_pos];
+ out_args[out_args_pos].v_pointer = out_value;
+ ++out_args_pos;
+ }
+
+ if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
+ py_arg = PyTuple_GetItem(args, i);
+ GArgument in_value = pyg_argument_from_pyobject(py_arg, arg_info);
+
+ ++argv_pos;
+
+ if (direction == GI_DIRECTION_IN) {
+ in_args[in_args_pos] = in_value;
+ } else {
+ /* INOUT means we pass a pointer */
+ g_assert(out_value != NULL);
+ *out_value = in_value;
+ in_args[in_args_pos].v_pointer = out_value;
+ }
+
+ ++in_args_pos;
+ }
+
+ g_base_info_unref( (GIBaseInfo*) arg_info);
+
+ if (failed)
+ break;
+ }
+
+ if (failed) {
+ g_error("Failed to convert all args.");
+ return NULL;
+ }
+
+ g_assert(in_args_pos == expected_in_argc);
+ g_assert(out_args_pos == expected_out_argc);
+
+ error = NULL;
+ invoke_ok = g_function_info_invoke( (GIFunctionInfo*) self->info,
+ in_args, expected_in_argc,
+ out_args, expected_out_argc,
+ &return_arg,
+ &error);
+
+ /* Return value and out arguments are valid only if invocation doesn't
+ * return error. In arguments need to be released always.
+ */
+ failed = FALSE;
+
+ return_info = g_callable_info_get_return_type( (GICallableInfo*) self->info);
+ g_assert(return_info != NULL);
+
+ return_tag = g_type_info_get_tag(return_info);
+
+ retval = NULL;
+
+ next_rval = 0; /* index into return_values */
+
+ n_return_values = expected_out_argc;
+ if (return_tag != GI_TYPE_TAG_VOID)
+ n_return_values += 1;
+
+ return_values = NULL; /* Quiet gcc warning about initialization */
+ if (n_return_values > 0) {
+ if (invoke_ok) {
+ return_values = g_newa(PyObject*, n_return_values);
+ }
+
+ if (return_tag != GI_TYPE_TAG_VOID) {
+ return_values[next_rval] = pyg_argument_to_pyobject(&return_arg, return_info);
+
+ ++next_rval;
+ }
+ }
+
+ /* We walk over all args, release in args (if allocated) and convert
+ * all out args
+ */
+ in_args_pos = is_method ? 1 : 0; /* index into in_args */
+ out_args_pos = 0; /* into out_args */
+
+ for (i = 0; i < n_args; i++) {
+ GIDirection direction;
+ GIArgInfo *arg_info;
+ GITypeInfo *arg_type_info;
+
+ arg_info = g_callable_info_get_arg( (GICallableInfo*) self->info, i);
+ direction = g_arg_info_get_direction(arg_info);
+
+ arg_type_info = g_arg_info_get_type(arg_info);
+
+ if (direction == GI_DIRECTION_IN) {
+ g_assert(in_args_pos < expected_in_argc);
+
+ ++in_args_pos;
+ } else {
+ /* INOUT or OUT */
+ if (direction == GI_DIRECTION_INOUT)
+ g_assert(in_args_pos < expected_in_argc);
+ g_assert(next_rval < n_return_values);
+ g_assert(out_args_pos < expected_out_argc);
+
+ return_values[next_rval] = pyg_argument_to_pyobject(&out_args[out_args_pos], arg_type_info);
+
+ if (direction == GI_DIRECTION_INOUT)
+ ++in_args_pos;
+
+ ++out_args_pos;
+
+ ++next_rval;
+ }
+
+ g_base_info_unref( (GIBaseInfo*) arg_type_info);
+ g_base_info_unref( (GIBaseInfo*) arg_info);
}
- if (g_function_info_invoke((GIFunctionInfo*)self->info,
- in_args, n_in_args,
- out_args, n_out_args,
- &return_arg,
- &error)) {
- GITypeInfo *return_info;
- GITypeTag type_tag;
-
- return_info = g_callable_info_get_return_type
- ((GICallableInfo*)self->info);
-
- type_tag = g_type_info_get_tag((GITypeInfo*)return_info);
-
- if (n_out_args == 1) {
- retval = pyg_argument_to_pyobject(&return_arg, return_info);
- } else {
- PyObject *tuple;
- PyObject *item;
- int j = 0;
- int last = 0;
- int n_args;
- int start;
-
-
- if (n_out_args > 0) {
- if (g_type_info_get_tag((GITypeInfo*)return_info) != GI_TYPE_TAG_VOID) {
- item = pyg_argument_to_pyobject(&return_arg, return_info);
- tuple = PyTuple_New(n_out_args+1);
- PyTuple_SetItem(tuple, 0, item);
- start = 1;
- } else {
- tuple = PyTuple_New(n_out_args);
- start = 0;
- }
-
- n_args = g_callable_info_get_n_args((GICallableInfo*)self->info);
- for (i = 0; i < n_out_args; i++) {
-
- if (last >= n_args)
- break;
-
- for (j = last; j < n_args; j++) {
- arg_info = g_callable_info_get_arg((GICallableInfo*)self->info, j);
- direction = g_arg_info_get_direction(arg_info);
- if (direction != GI_DIRECTION_IN) {
- GITypeInfo *type_info;
- type_info = g_arg_info_get_type(arg_info);
- item = pyg_argument_to_pyobject(&out_args[i], type_info);
- PyTuple_SetItem(tuple, i+start, item);
- last = j;
- g_base_info_unref((GIBaseInfo*)type_info);
- }
- g_base_info_unref((GIBaseInfo*)arg_info);
- }
- }
- retval = tuple;
- } else {
- retval = pyg_argument_to_pyobject(&return_arg, return_info);
+ g_assert(next_rval == n_return_values);
+ g_assert(out_args_pos == expected_out_argc);
+ g_assert(in_args_pos == expected_in_argc);
+
+ if (invoke_ok && n_return_values > 0) {
+ if (n_return_values == 0) {
+ retval = Py_None;
+ Py_INCREF(retval);
+ } else if (n_return_values == 1) {
+ retval = return_values[0];
+ } else {
+ retval = PyTuple_New(n_return_values);
+ for (i = 0; i < n_return_values; i++) {
+ PyTuple_SetItem(retval, i, return_values[i]);
}
- }
- g_base_info_unref((GIBaseInfo*)return_info);
+ }
+ }
+
+ g_base_info_unref( (GIBaseInfo*) return_info);
+
+ if (invoke_ok) {
+ return failed ? NULL : retval;
} else {
- g_print("Error: %s\n", error->message);
-
+ g_assert(error != NULL);
+ g_error("Error invoking %s.%s: %s",
+ g_base_info_get_namespace( (GIBaseInfo*) self->info),
+ g_base_info_get_name( (GIBaseInfo*) self->info),
+ error->message);
+ g_error_free(error);
+
retval = Py_None;
Py_INCREF(retval);
+ return retval;
}
-
- return retval;
}
static PyMethodDef _PyGIFunctionInfo_methods[] = {
@@ -490,7 +606,30 @@ static PyMethodDef _PyGIRegisteredTypeInfo_methods[] = {
/* GIStructInfo */
NEW_CLASS("StructInfo", GIStructInfo);
+
+static PyObject *
+_wrap_g_struct_info_get_methods(PyGIBaseInfo *self)
+{
+ int i, length;
+ PyObject *retval;
+
+ g_base_info_ref(self->info);
+ length = g_struct_info_get_n_methods((GIStructInfo*)self->info);
+ retval = PyTuple_New(length);
+
+ for (i = 0; i < length; i++) {
+ GIFunctionInfo *function;
+ function = g_struct_info_get_method((GIStructInfo*)self->info, i);
+ PyTuple_SetItem(retval, i, pyg_info_new(function));
+ g_base_info_unref((GIBaseInfo*)function);
+ }
+ g_base_info_unref(self->info);
+
+ return retval;
+}
+
static PyMethodDef _PyGIStructInfo_methods[] = {
+ { "getMethods", (PyCFunction)_wrap_g_struct_info_get_methods, METH_NOARGS },
{ NULL, NULL, 0 }
};
diff --git a/bank/bank.c b/bank/bank.c
index 7a25f63..202eb7b 100644
--- a/bank/bank.c
+++ b/bank/bank.c
@@ -35,6 +35,7 @@
REGISTER_TYPE(d, type, name)
static PyMethodDef pybank_functions[] = {
+ //{ "getParamType", (PyCFunction)_wrap_g_type_info_get_param_type, METH_VARARGS },
{ NULL, NULL, 0 }
};
diff --git a/bank/btypes.py b/bank/btypes.py
index 8a8b35b..593bd0a 100644
--- a/bank/btypes.py
+++ b/bank/btypes.py
@@ -120,6 +120,7 @@ class Callable(object):
inArgs.append(value)
+ print "invoke with args %r" % inArgs
retval = self.info.invoke(*inArgs)
if self.info.isConstructor():
@@ -282,3 +283,46 @@ def buildInterface(info):
return newType
+def buildBoxed(info):
+ className = info.getName()
+ namespaceName = info.getNamespace()
+ fullName = namespaceName + '.' + className
+
+ if _classDict.has_key(fullName):
+ return _classDict[fullName]
+
+ namespace = {}
+ namespace['__info__'] = info
+ namespace['__module__'] = namespaceName
+ newType = type(className, (object,), namespace)
+
+ constructors = []
+ for method in info.getMethods():
+ if method.isConstructor():
+ constructors.append(method)
+ elif method.isMethod():
+ methodName = method.getName()
+ setattr(newType, methodName, new.instancemethod(Method(method, className),
+ None, newType))
+ else: # probably a static method
+ func = Method(method, className, call_type=Method.STATIC_METHOD)
+ setattr(newType, method.getName(), staticmethod(func))
+
+ setupConstructors(className, newType, constructors)
+
+ def __getattr__(self, name):
+ pass
+ newType.__getattr__ = new.instancemethod(__getattr__, None, newType)
+
+ def __setattr__(self, name, value):
+ pass
+ newType.__setattr__ = new.instancemethod(__setattr__, None, newType)
+
+ def __init__(self, buf):
+ self.__dict__['__buffer__'] = buf
+ newType.__init__ = new.instancemethod(__init__, None, newType)
+
+ _classDict[fullName] = newType
+
+ return newType
+
diff --git a/bank/module.py b/bank/module.py
index 523504c..32d1986 100644
--- a/bank/module.py
+++ b/bank/module.py
@@ -22,8 +22,9 @@ import os
import gobject
from gobject import GEnum
-from .btypes import Function, buildClass, buildInterface
-from .repo import EnumInfo, FunctionInfo, ObjectInfo, UnresolvedInfo, InterfaceInfo
+from .btypes import Function, buildClass, buildInterface, buildBoxed
+from .repo import EnumInfo, FunctionInfo, ObjectInfo, UnresolvedInfo, \
+ InterfaceInfo, StructInfo
from .repository import repository
class DynamicModule(object):
@@ -85,6 +86,9 @@ class DynamicModule(object):
return self._create_function(type_info)
elif isinstance(type_info, InterfaceInfo):
return self._create_interface(type_info)
+ elif isinstance(type_info, StructInfo) or \
+ isinstance(type_info, BoxedInfo):
+ return self._create_boxed(type_info)
else:
raise NotImplementedError(type_info)
@@ -181,3 +185,32 @@ class DynamicModule(object):
self.__dict__[name] = klass
return klass
+
+ def _create_boxed(self, boxed_info):
+ name = boxed_info.getName()
+
+ namespace = repository.get_c_prefix(boxed_info.getNamespace())
+ full_name = namespace + name
+ boxed_info.getGType()
+ gtype = None
+ try:
+ gtype = gobject.GType.from_name(full_name)
+ except RuntimeError:
+ pass
+ else:
+ if gtype.pytype is not None:
+ return gtype.pytype
+ # Check if the klass is already created, eg
+ # present in our namespace, this is necessary since we're
+ # not always entering here through the __getattr__ hook.
+ klass = self.__dict__.get(name)
+ if klass:
+ return klass
+
+ klass = buildBoxed(boxed_info)
+ if gtype is not None:
+ gtype.pytype = klass
+ self.__dict__[name] = klass
+
+ return klass
+
diff --git a/everything_unittest.py b/everything_unittest.py
index 384e590..7be9b55 100644
--- a/everything_unittest.py
+++ b/everything_unittest.py
@@ -242,15 +242,16 @@ class TestGIEverything(unittest.TestCase):
def testStructA(self):
a = self.createStructA()
- Everything.test_struct_a_clone(a, a_out)
+ a_out = a.clone()
self.assertEquals(a, a_out)
def testStructB(self):
b = Everything.TestStructB()
b.some_int8 = 3
b.nested_a = self.createStructA()
- Everything.test_struct_b_clone(b, b_out)
+ b_out = b.clone()
self.assertEquals(b, b_out)
+ self.assertEquals(b.nested_a, b_out.nested_a)
def testInterface(self):
self.assertTrue(issubclass(Everything.TestInterface, gobject.GInterface))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]