summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon van der Linden <svdlinden@src.gnome.org>2009-08-11 17:15:23 +0200
committerSimon van der Linden <svdlinden@src.gnome.org>2009-08-14 23:21:23 +0200
commit28f26269be4df370eb229a03b43115945cf24972 (patch)
treeb27f57cdc14d1cb36c5f53d16b5be6dab716a8d0
parentdc0e8bb5a5ab97349bef0ca34335b655124d9556 (diff)
downloadpygobject-28f26269be4df370eb229a03b43115945cf24972.tar.gz
Get rid of GIStruct
Make structures inherit from GBoxed. Add a new constructor to GBoxed, which is able to create a structure instance when it is simple (without pointers).
-rw-r--r--gi/Makefile.am2
-rw-r--r--gi/gimodule.c41
-rw-r--r--gi/module.py46
-rw-r--r--gi/pygi-argument.c20
-rw-r--r--gi/pygi-info.c21
-rw-r--r--gi/pygi-private.h5
-rw-r--r--gi/pygi.h15
-rw-r--r--gi/types.py60
-rw-r--r--gobject/pygboxed.c37
-rw-r--r--tests/test_girepository.py93
10 files changed, 158 insertions, 182 deletions
diff --git a/gi/Makefile.am b/gi/Makefile.am
index e0404a72..c7505ce7 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -42,6 +42,8 @@ _gi_la_SOURCES = \
pygi-info.h \
pygi-argument.c \
pygi-argument.h \
+ pygi-boxed.c \
+ pygi-boxed.h \
pygi.h \
pygi-private.h \
gimodule.c
diff --git a/gi/gimodule.c b/gi/gimodule.c
index bccc62a3..d9a33727 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -75,35 +75,29 @@ pygi_type_find_by_gi_info (GIBaseInfo *info)
return pygi_type_find_by_name(namespace_, name);
}
-gpointer
-_pygi_object_get_buffer (PyObject *object,
- gsize *size)
+GIBaseInfo *
+_pygi_object_get_gi_info (PyObject *object,
+ PyTypeObject *type)
{
- PyBufferProcs *py_buffer_procs;
- PyObject *py_buffer;
- gpointer buffer;
+ PyObject *py_info;
+ GIBaseInfo *info = NULL;
- py_buffer = PyObject_GetAttrString(object, "__buffer__");
- if (py_buffer == NULL) {
- return NULL;
+ py_info = PyObject_GetAttrString(object, "__info__");
+ if (py_info == NULL) {
+ goto out;
}
-
- if(!PyBuffer_Check(py_buffer)) {
- PyErr_Format(PyExc_TypeError, "Must be buffer, not %s",
- object->ob_type->tp_name);
+ if (!PyObject_TypeCheck(py_info, type)) {
+ PyErr_Format(PyExc_TypeError, "attribute '__info__' must be %s, not %s",
+ type->tp_name, py_info->ob_type->tp_name);
+ goto out;
}
- /* We don't need to keep a reference. */
- Py_DECREF(py_buffer);
-
- py_buffer_procs = py_buffer->ob_type->tp_as_buffer;
+ info = PyGIBaseInfo_GET_GI_INFO(py_info);
- *size = (*py_buffer_procs->bf_getreadbuffer)(py_buffer, 0, &buffer);
- if (*size < 0) {
- return NULL;
- }
+out:
+ Py_XDECREF(py_info);
- return buffer;
+ return info;
}
static PyObject *
@@ -129,7 +123,8 @@ static PyMethodDef _pygi_functions[] = {
};
struct PyGI_API PyGI_API = {
- pygi_type_find_by_gi_info
+ pygi_type_find_by_gi_info,
+ pygi_boxed_new
};
PyMODINIT_FUNC
diff --git a/gi/module.py b/gi/module.py
index 7311dbd2..a06db4e8 100644
--- a/gi/module.py
+++ b/gi/module.py
@@ -26,7 +26,7 @@ import gobject
from gobject import \
GObject, \
GInterface, \
- GEnum
+ GBoxed
from ._gi import \
Repository, \
@@ -38,8 +38,8 @@ from ._gi import \
InterfaceInfo, \
StructInfo
from .types import \
- GObjectIntrospectionMeta, \
- GIStruct, \
+ GObjectMeta, \
+ GBoxedMeta, \
Function
repository = Repository.get_default()
@@ -74,16 +74,7 @@ class DynamicModule(object):
raise AttributeError("%r object has no attribute %r" % (
self.__class__.__name__, name))
- if isinstance(info, StructInfo):
- # FIXME: This could be wrong for structures that are registered (like GValue or GClosure).
- bases = (GIStruct,)
- name = info.get_name()
- dict_ = {
- '__info__': info,
- '__module__': info.get_namespace()
- }
- value = GObjectIntrospectionMeta(name, bases, dict_)
- elif isinstance(info, EnumInfo):
+ if isinstance(info, EnumInfo):
type_ = info.get_g_type()
if type_.is_a(gobject.TYPE_ENUM):
value = gobject.enum_from_g_type(type_)
@@ -99,29 +90,38 @@ class DynamicModule(object):
setattr(value, name, value(value_info.get_value()))
elif isinstance(info, RegisteredTypeInfo):
+ g_type = info.get_g_type()
+
# Check if there is already a Python wrapper.
- gtype = info.get_g_type()
- if gtype.pytype is not None:
- self.__dict__[name] = gtype.pytype
- return
+ if g_type != gobject.TYPE_NONE and g_type.pytype is not None:
+ self.__dict__[name] = g_type.pytype
+ return gtype.pytype
# Create a wrapper.
if isinstance(info, ObjectInfo):
- parent = get_parent_for_object(info)
- bases = (parent,)
+ bases = (get_parent_for_object(info),)
+ metaclass = GObjectMeta
elif isinstance(info, InterfaceInfo):
+ # FIXME
bases = (GInterface,)
+ metaclass = GObjectMeta
+ elif isinstance(info, StructInfo):
+ bases = (GBoxed,)
+ metaclass = GBoxedMeta
else:
raise NotImplementedError(info)
name = info.get_name()
dict_ = {
'__info__': info,
- '__module__': info.get_namespace(),
- '__gtype__': gtype
+ '__module__': self.__namespace__,
+ '__gtype__': g_type
}
- value = GObjectIntrospectionMeta(name, bases, dict_)
- gtype.pytype = value
+ value = metaclass(name, bases, dict_)
+
+ if g_type != gobject.TYPE_NONE:
+ g_type.pytype = value
+
elif isinstance(info, FunctionInfo):
value = Function(info)
else:
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 868b4ae7..e4f12a82 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -906,8 +906,6 @@ array_item_error:
case GI_INFO_TYPE_STRUCT:
{
GType type;
- gsize size;
- gpointer buffer;
type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info);
@@ -953,9 +951,7 @@ array_item_error:
break;
}
- buffer = _pygi_object_get_buffer(object, &size);
-
- arg.v_pointer = buffer;
+ arg.v_pointer = pyg_boxed_get(object, void);
break;
}
case GI_INFO_TYPE_OBJECT:
@@ -1332,8 +1328,6 @@ _pygi_argument_to_object (GArgument *arg,
{
GType type;
PyObject *py_type = NULL;
- gsize size;
- PyObject *buffer = NULL;
/* Handle special cases first. */
type = g_registered_type_info_get_g_type((GIRegisteredTypeInfo *)info);
@@ -1343,23 +1337,13 @@ _pygi_argument_to_object (GArgument *arg,
break;
}
- /* Create a Python buffer. */
- size = g_struct_info_get_size((GIStructInfo *)info);
- buffer = PyBuffer_FromReadWriteMemory(arg->v_pointer, size);
- if (buffer == NULL) {
- break;
- }
-
- /* Wrap the structure. */
py_type = pygi_type_find_by_gi_info(info);
if (py_type == NULL) {
- Py_DECREF(buffer);
break;
}
- object = PyObject_CallFunction(py_type, "O", buffer);
+ object = pygi_boxed_new((PyTypeObject *)py_type, arg->v_pointer, TRUE /* FIXME */);
- Py_DECREF(buffer);
Py_DECREF(py_type);
break;
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index eb14e425..a165376b 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -583,11 +583,8 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
g_assert_not_reached();
break;
case GI_INFO_TYPE_STRUCT:
- {
- gsize size;
- in_args[0].v_pointer = _pygi_object_get_buffer(py_arg, &size);
+ in_args[0].v_pointer = pyg_boxed_get(py_arg, void);
break;
- }
case GI_INFO_TYPE_OBJECT:
in_args[0].v_pointer = pygobject_get(py_arg);
break;
@@ -1053,19 +1050,9 @@ _wrap_g_struct_info_get_methods (PyGIBaseInfo *self)
return infos;
}
-static PyObject *
-_wrap_g_struct_info_new_buffer (PyGIBaseInfo *self)
-{
- gsize size = g_struct_info_get_size ((GIStructInfo*)self->info);
- PyObject *buffer = PyBuffer_New (size);
- Py_INCREF(buffer);
- return buffer;
-}
-
static PyMethodDef _PyGIStructInfo_methods[] = {
{ "get_fields", (PyCFunction)_wrap_g_struct_info_get_fields, METH_NOARGS },
{ "get_methods", (PyCFunction)_wrap_g_struct_info_get_methods, METH_NOARGS },
- { "new_buffer", (PyCFunction)_wrap_g_struct_info_new_buffer, METH_NOARGS },
{ NULL, NULL, 0 }
};
@@ -1405,8 +1392,7 @@ _wrap_g_field_info_get_value (PyGIBaseInfo *self,
if (container_info_type == GI_INFO_TYPE_STRUCT
|| container_info_type == GI_INFO_TYPE_BOXED) {
- gsize size;
- buffer = _pygi_object_get_buffer(object, &size);
+ buffer = pyg_boxed_get(object, void);
if (buffer == NULL) {
goto return_;
}
@@ -1505,8 +1491,7 @@ _wrap_g_field_info_set_value (PyGIBaseInfo *self,
if (container_info_type == GI_INFO_TYPE_STRUCT
|| container_info_type == GI_INFO_TYPE_BOXED) {
- gsize size;
- buffer = _pygi_object_get_buffer(object, &size);
+ buffer = pyg_boxed_get(object, void);
if (buffer == NULL) {
goto return_;
}
diff --git a/gi/pygi-private.h b/gi/pygi-private.h
index eabaef0e..a76cffca 100644
--- a/gi/pygi-private.h
+++ b/gi/pygi-private.h
@@ -19,6 +19,7 @@
#include "pygi-repository.h"
#include "pygi-info.h"
#include "pygi-argument.h"
+#include "pygi-boxed.h"
G_BEGIN_DECLS
@@ -54,8 +55,8 @@ PyObject* pygi_type_find_by_gi_info (GIBaseInfo *info);
/* Private */
-gpointer _pygi_object_get_buffer (PyObject *object,
- gsize *size);
+GIBaseInfo* _pygi_object_get_gi_info (PyObject *object,
+ PyTypeObject *type);
#define _PyGI_ERROR_PREFIX(format, ...) G_STMT_START { \
diff --git a/gi/pygi.h b/gi/pygi.h
index 8cf4a4e2..0187ebce 100644
--- a/gi/pygi.h
+++ b/gi/pygi.h
@@ -39,18 +39,31 @@ typedef struct {
PyObject *inst_weakreflist;
} PyGIBaseInfo;
+#define PyGIBaseInfo_GET_GI_INFO(object) g_base_info_ref(((PyGIBaseInfo *)object)->info)
+
struct PyGI_API {
+ /* Misc */
PyObject* (*type_find_by_gi_info) (GIBaseInfo *info);
+
+ /* Boxed */
+ PyObject* (*boxed_new) (PyTypeObject *type,
+ gpointer pointer,
+ gboolean own_pointer);
};
#ifndef __PYGI_PRIVATE_H__
-struct PyGI_API *PyGI_API = NULL;
+static struct PyGI_API *PyGI_API = NULL;
+/* Misc */
#define pygi_type_find_by_gi_info (PyGI_API->type_find_by_gi_info)
+/* Boxed */
+#define pygi_boxed_new (PyGI_API->boxed_new)
+
+
static int
pygi_import (void)
{
diff --git a/gi/types.py b/gi/types.py
index 0dbadb29..7dfda04d 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -54,26 +54,7 @@ class Field(object):
return self.info.set_value(instance, value)
-class GObjectIntrospectionMeta(gobject.GObjectMeta):
-
- def __init__(cls, name, bases, dict_):
- super(GObjectIntrospectionMeta, cls).__init__(name, bases, dict_)
-
- if hasattr(cls, '__gtype__'):
- setObjectHasNewConstructor(cls.__gtype__)
-
- # Only set up the wrapper methods and fields in their base classes.
- if cls.__name__ == cls.__info__.get_name():
- if isinstance(cls.__info__, InterfaceInfo):
- cls._setup_methods()
-
- if isinstance(cls.__info__, ObjectInfo):
- cls._setup_fields()
- cls._setup_methods()
-
- if isinstance(cls.__info__, StructInfo):
- cls._setup_fields()
- cls._setup_methods()
+class MetaClassHelper(object):
def _setup_methods(cls):
constructor_infos = []
@@ -116,20 +97,33 @@ class GObjectIntrospectionMeta(gobject.GObjectMeta):
setattr(cls, name, Field(field_info))
-class GIStruct(object):
+class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
+
+ def __init__(cls, name, bases, dict_):
+ super(GObjectMeta, cls).__init__(name, bases, dict_)
- def __init__(self, buffer=None):
- if buffer is None:
- buffer = self.__info__.new_buffer()
- self.__buffer__ = buffer
+ # Avoid touching anything else than the base class.
+ if cls.__name__ != cls.__info__.get_name():
+ return;
+
+ if hasattr(cls, '__gtype__'):
+ setObjectHasNewConstructor(cls.__gtype__)
+
+ cls._setup_methods()
+
+ if isinstance(cls.__info__, ObjectInfo):
+ cls._setup_fields()
+
+
+class GBoxedMeta(type, MetaClassHelper):
+
+ def __init__(cls, name, bases, dict_):
+ super(GBoxedMeta, cls).__init__(name, bases, dict_)
- def __eq__(self, other):
- for field_info in self.__info__.get_fields():
- name = field_info.get_name()
- if getattr(self, name) != getattr(other, name):
- return False
- return True
+ # Avoid touching anything else than the base class.
+ if cls.__name__ != cls.__info__.get_name():
+ return;
- def __ne__(self, other):
- return not self.__eq__(other)
+ cls._setup_fields()
+ cls._setup_methods()
diff --git a/gobject/pygboxed.c b/gobject/pygboxed.c
index 5d08a517..2b8e6de9 100644
--- a/gobject/pygboxed.c
+++ b/gobject/pygboxed.c
@@ -25,6 +25,9 @@
#endif
#include <pyglib.h>
+#if HAVE_PYGI_H
+# include <pygi.h>
+#endif
#include "pygobject-private.h"
#include "pygboxed.h"
@@ -38,7 +41,12 @@ pyg_boxed_dealloc(PyGBoxed *self)
{
if (self->free_on_dealloc && self->boxed) {
PyGILState_STATE state = pyglib_gil_state_ensure();
- g_boxed_free(self->gtype, self->boxed);
+ if (!g_type_is_a(self->gtype, G_TYPE_BOXED)) {
+ /* Void pointers are also allowed. */
+ g_free(self->boxed);
+ } else {
+ g_boxed_free(self->gtype, self->boxed);
+ }
pyglib_gil_state_release(state);
}
@@ -181,6 +189,26 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed,
return (PyObject *)self;
}
+#if HAVE_PYGI_H
+static PyObject *
+pyg_boxed_new_ (PyTypeObject *type,
+ PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = { NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) {
+ return NULL;
+ }
+
+ if (pygi_import() < 0) {
+ return NULL;
+ }
+
+ return pygi_boxed_new(type, NULL, TRUE);
+}
+#endif /* HAVE_PYGI_H */
+
void
pygobject_boxed_register_types(PyObject *d)
{
@@ -194,11 +222,16 @@ pygobject_boxed_register_types(PyObject *d)
PyGBoxed_Type.tp_methods = pygboxed_methods;
PyGBoxed_Type.tp_free = (freefunc)pyg_boxed_free;
PyGBoxed_Type.tp_hash = (hashfunc)pyg_boxed_hash;
-
+#if HAVE_PYGI_H
+ PyGBoxed_Type.tp_new = (newfunc)pyg_boxed_new_;
+#endif
+
PYGOBJECT_REGISTER_GTYPE(d, PyGBoxed_Type, "GBoxed", G_TYPE_BOXED);
+#if !HAVE_PYGI_H
/* We don't want instances to be created in Python, but
* PYGOBJECT_REGISTER_GTYPE assigned PyObject_GenericNew as instance
* constructor. It's not too late to revert it to NULL, though. */
PyGBoxed_Type.tp_new = (newfunc)NULL;
+#endif
}
diff --git a/tests/test_girepository.py b/tests/test_girepository.py
index 81748819..3b59f0ca 100644
--- a/tests/test_girepository.py
+++ b/tests/test_girepository.py
@@ -30,13 +30,6 @@ utf8_nonconst = 'nonconst \xe2\x99\xa5 utf8'
test_sequence = ('1', '2', '3')
test_dict = {'foo': 'bar', 'baz': 'bat', 'qux': 'quux'}
-def createStructA():
- a = Everything.TestStructA()
- a.some_int = 3
- a.some_int8 = 1
- a.some_double = 4.15
- a.some_enum= Everything.TestEnum.VALUE3
- return a
class SignalHandler:
def __init__(self):
@@ -545,7 +538,19 @@ class TestGIEverything(unittest.TestCase):
# Structures
def testStructA(self):
- a = createStructA()
+ # Test inheritance.
+ self.assertTrue(issubclass(Everything.TestStructA, gobject.GBoxed))
+
+ # Test instanciation.
+ a = Everything.TestStructA()
+ self.assertTrue(isinstance(a, Everything.TestStructA))
+
+ # Test fields.
+ a.some_int = 3
+ a.some_int8 = 1
+ a.some_double = 4.15
+ a.some_enum= Everything.TestEnum.VALUE3
+
self.assertEquals(a.some_int, 3)
self.assertEquals(a.some_int8, 1)
self.assertEquals(a.some_double, 4.15)
@@ -555,74 +560,38 @@ class TestGIEverything(unittest.TestCase):
self.assertRaises(ValueError, setattr, a, 'some_int8', INT8_MIN-1)
self.assertRaises(ValueError, setattr, a, 'some_int8', INT8_MAX+1)
+ # Test method call and marshalling.
a_out = Everything.TestStructA()
a.clone(a_out)
- self.assertEquals(a, a_out)
+
+ self.assertEquals(a.some_int, a_out.some_int)
+ self.assertEquals(a.some_int8, a_out.some_int8)
+ self.assertEquals(a.some_double, a_out.some_double)
+ self.assertEquals(a.some_enum, a_out.some_enum)
# Test instance checking by passing a wrong instance.
self.assertRaises(TypeError, Everything.TestStructA.clone, 'a', a_out)
def testStructB(self):
b = Everything.TestStructB()
- b.some_int8 = 3
- a = createStructA()
+ a = Everything.TestStructA()
+
+ # Test nested structures.
b.nested_a = a
- self.assertEquals(a, b.nested_a)
+ a_out = b.nested_a
+
+ self.assertTrue(isinstance(b.nested_a, Everything.TestStructA))
+ self.assertEquals(a.some_int, a_out.some_int)
+ self.assertEquals(a.some_int8, a_out.some_int8)
+ self.assertEquals(a.some_double, a_out.some_double)
+ self.assertEquals(a.some_enum, a_out.some_enum)
# Test assignment checking.
self.assertRaises(TypeError, setattr, b, 'nested_a', 'a')
self.assertRaises(TypeError, setattr, b, 'nested_a', Everything.TestStructB())
- b_out = Everything.TestStructB()
- b.clone(b_out)
- self.assertEquals(b, b_out)
-
-
-# Plain-old-data boxed types
-
- def testSimpleBoxedA(self):
- a = Everything.TestSimpleBoxedA()
- a.some_int = 42
- a.some_int8 = 7
- a.some_double = 3.14
- a.some_enum = Everything.TestEnum.VALUE3
-
- self.assertEquals(42, a.some_int)
- self.assertEquals(7, a.some_int8)
- self.assertAlmostEquals(3.14, a.some_double)
- self.assertEquals(Everything.TestEnum.VALUE3, a.some_enum)
-
- self.assertRaises(TypeError, setattr, a, 'some_int', 'a')
- self.assertRaises(ValueError, setattr, a, 'some_int8', INT8_MIN-1)
- self.assertRaises(ValueError, setattr, a, 'some_int8', INT8_MAX+1)
-
- a_out = a.copy()
- self.assertTrue(a.equals(a_out))
- self.assertEquals(a, a_out)
-
- # Test instance checking by passing a wrong instance.
- self.assertRaises(TypeError, Everything.TestSimpleBoxedA.copy, 'a')
- self.assertRaises(TypeError, Everything.TestSimpleBoxedA.copy, gobject.GObject())
-
- # Test boxed as return value.
- a_const = Everything.test_simple_boxed_a_const_return()
- self.assertEquals(5, a_const.some_int)
- self.assertEquals(6, a_const.some_int8)
- self.assertAlmostEquals(7.0, a_const.some_double)
-
- def testSimpleBoxedB(self):
- a_const = Everything.test_simple_boxed_a_const_return()
-
- b = Everything.TestSimpleBoxedB()
- b.some_int = 42
- b.nested_a = a_const.copy()
-
- self.assertEquals(a_const, b.nested_a)
-
- self.assertRaises(TypeError, setattr, b, 'nested_a', 'a')
-
- b_out = b.copy()
- self.assertEquals(b, b_out)
+ def testStructC(self):
+ self.assertRaises(TypeError, Everything.TestStructC)
# GObject