diff options
author | Simon van der Linden <svdlinden@src.gnome.org> | 2009-08-11 17:15:23 +0200 |
---|---|---|
committer | Simon van der Linden <svdlinden@src.gnome.org> | 2009-08-14 23:21:23 +0200 |
commit | 28f26269be4df370eb229a03b43115945cf24972 (patch) | |
tree | b27f57cdc14d1cb36c5f53d16b5be6dab716a8d0 | |
parent | dc0e8bb5a5ab97349bef0ca34335b655124d9556 (diff) | |
download | pygobject-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.am | 2 | ||||
-rw-r--r-- | gi/gimodule.c | 41 | ||||
-rw-r--r-- | gi/module.py | 46 | ||||
-rw-r--r-- | gi/pygi-argument.c | 20 | ||||
-rw-r--r-- | gi/pygi-info.c | 21 | ||||
-rw-r--r-- | gi/pygi-private.h | 5 | ||||
-rw-r--r-- | gi/pygi.h | 15 | ||||
-rw-r--r-- | gi/types.py | 60 | ||||
-rw-r--r-- | gobject/pygboxed.c | 37 | ||||
-rw-r--r-- | tests/test_girepository.py | 93 |
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 { \ @@ -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 |