Commit 66c34805 authored by Tomeu Vizoso's avatar Tomeu Vizoso
Browse files

Set a default constructor for boxed structs that don't have one

https://bugzilla.gnome.org/show_bug.cgi?id=602735
parent e7e2fcca
......@@ -34,6 +34,8 @@ _gi_la_SOURCES = \
pygi-argument.h \
pygi-type.c \
pygi-type.h \
pygi-boxed.c \
pygi-boxed.h \
pygi.h \
pygi-private.h \
pygobject-external.h \
......
......@@ -166,6 +166,7 @@ init_gi(void)
_pygi_repository_register_types(m);
_pygi_info_register_types(m);
_pygi_struct_register_types(m);
_pygi_boxed_register_types(m);
_pygi_argument_init();
api = PyCObject_FromVoidPtr((void *)&PyGI_API, NULL);
......
......@@ -35,12 +35,12 @@ from ._gi import \
ConstantInfo, \
StructInfo, \
Struct, \
Boxed, \
enum_add, \
flags_add
from .types import \
GObjectMeta, \
StructMeta, \
Boxed, \
Function
repository = Repository.get_default()
......
......@@ -1557,8 +1557,20 @@ _pygi_argument_to_object (GArgument *arg,
g_assert(is_pointer);
object = pyg_value_as_pyobject(arg->v_pointer, FALSE);
} else if (g_type_is_a(type, G_TYPE_BOXED)) {
PyObject *py_type;
g_assert(is_pointer);
object = pyg_boxed_new(type, arg->v_pointer, FALSE, transfer == GI_TRANSFER_EVERYTHING);
py_type = _pygi_type_get_from_g_type(type);
if (py_type == NULL) {
PyErr_Format(PyExc_ValueError, "couldn't find a wrapper for type '%s'",
g_type_name(type));
break;
}
object = _pygi_boxed_new((PyTypeObject *)py_type, arg->v_pointer, transfer == GI_TRANSFER_EVERYTHING);
Py_DECREF(py_type);
} else if (g_type_is_a(type, G_TYPE_POINTER)) {
PyObject *py_type;
......
/* -*- Mode: C; c-basic-offset: 4 -*-
* vim: tabstop=4 shiftwidth=4 expandtab
*
* Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
*
* pygi-boxed.c: wrapper to handle registered structures.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "pygi-private.h"
#include <pygobject.h>
#include <girepository.h>
static void
_boxed_dealloc (PyGIBoxed *self)
{
GType g_type;
PyObject_GC_UnTrack((PyObject *)self);
PyObject_ClearWeakRefs((PyObject *)self);
if (((PyGBoxed *)self)->free_on_dealloc) {
if (self->slice_allocated) {
g_slice_free1(self->size, ((PyGBoxed *)self)->boxed);
} else {
g_type = pyg_type_from_object((PyObject *)self);
g_boxed_free (g_type, ((PyGBoxed *)self)->boxed);
}
}
((PyGObject *)self)->ob_type->tp_free((PyObject *)self);
}
static PyObject *
_boxed_new (PyTypeObject *type,
PyObject *args,
PyObject *kwargs)
{
static char *kwlist[] = { NULL };
GIBaseInfo *info;
gboolean is_simple;
gsize size;
gpointer boxed;
PyGIBoxed *self = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist)) {
return NULL;
}
info = _pygi_object_get_gi_info((PyObject *)type, &PyGIStructInfo_Type);
if (info == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Format(PyExc_TypeError, "missing introspection information");
}
return NULL;
}
size = g_struct_info_get_size((GIStructInfo *)info);
boxed = g_slice_alloc0(size);
if (boxed == NULL) {
PyErr_NoMemory();
goto out;
}
self = (PyGIBoxed *)_pygi_boxed_new(type, boxed, TRUE);
if (self == NULL) {
g_slice_free1(size, boxed);
goto out;
}
self->size = size;
self->slice_allocated = TRUE;
out:
g_base_info_unref(info);
return (PyObject *)self;
}
static int
_boxed_init (PyObject *self,
PyObject *args,
PyObject *kwargs)
{
/* Don't call PyGBoxed's init, which raises an exception. */
return 0;
}
PyTypeObject PyGIBoxed_Type = {
PyObject_HEAD_INIT(NULL)
0,
"gi.Boxed", /* tp_name */
sizeof(PyGIBoxed), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)_boxed_dealloc, /* tp_dealloc */
(printfunc)NULL, /* tp_print */
(getattrfunc)NULL, /* tp_getattr */
(setattrfunc)NULL, /* tp_setattr */
(cmpfunc)NULL, /* tp_compare */
(reprfunc)NULL, /* tp_repr */
NULL, /* tp_as_number */
NULL, /* tp_as_sequence */
NULL, /* tp_as_mapping */
(hashfunc)NULL, /* tp_hash */
(ternaryfunc)NULL, /* tp_call */
(reprfunc)NULL, /* tp_str */
(getattrofunc)NULL, /* tp_getattro */
(setattrofunc)NULL, /* tp_setattro */
NULL, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
NULL, /* tp_doc */
(traverseproc)NULL, /* tp_traverse */
(inquiry)NULL, /* tp_clear */
(richcmpfunc)NULL, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)NULL, /* tp_iter */
(iternextfunc)NULL, /* tp_iternext */
NULL, /* tp_methods */
NULL, /* tp_members */
NULL, /* tp_getset */
(PyTypeObject *)NULL, /* tp_base */
};
PyObject *
_pygi_boxed_new (PyTypeObject *type,
gpointer boxed,
gboolean free_on_dealloc)
{
PyGIBoxed *self;
GType g_type;
if (!boxed) {
Py_RETURN_NONE;
}
if (!PyType_IsSubtype(type, &PyGIBoxed_Type)) {
PyErr_SetString(PyExc_TypeError, "must be a subtype of gi.Boxed");
return NULL;
}
self = (PyGIBoxed *)type->tp_alloc(type, 0);
if (self == NULL) {
return NULL;
}
((PyGBoxed *)self)->gtype = pyg_type_from_object((PyObject *)type);
((PyGBoxed *)self)->boxed = boxed;
((PyGBoxed *)self)->free_on_dealloc = free_on_dealloc;
self->size = 0;
self->slice_allocated = FALSE;
return (PyObject *)self;
}
void
_pygi_boxed_register_types (PyObject *m)
{
PyGIBoxed_Type.ob_type = &PyType_Type;
PyGIBoxed_Type.tp_base = &PyGBoxed_Type;
PyGIBoxed_Type.tp_new = (newfunc)_boxed_new;
PyGIBoxed_Type.tp_init = (initproc)_boxed_init;
if (PyType_Ready(&PyGIBoxed_Type))
return;
if (PyModule_AddObject(m, "Boxed", (PyObject *)&PyGIBoxed_Type))
return;
}
/* -*- Mode: C; c-basic-offset: 4 -*-
* vim: tabstop=4 shiftwidth=4 expandtab
*
* Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef __PYGI_BOXED_H__
#define __PYGI_BOXED_H__
#include <Python.h>
G_BEGIN_DECLS
extern PyTypeObject PyGIBoxed_Type;
PyObject *
_pygi_boxed_new (PyTypeObject *type,
gpointer boxed,
gboolean free_on_dealloc);
void _pygi_boxed_register_types (PyObject *m);
G_END_DECLS
#endif /* __PYGI_BOXED_H__ */
......@@ -981,7 +981,7 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
break;
}
g_warn_if_fail(transfer == GI_TRANSFER_EVERYTHING);
return_value = pyg_boxed_new(type, return_arg.v_pointer, FALSE, transfer == GI_TRANSFER_EVERYTHING);
return_value = _pygi_boxed_new(py_type, return_arg.v_pointer, transfer == GI_TRANSFER_EVERYTHING);
} else if (g_type_is_a(type, G_TYPE_POINTER) || type == G_TYPE_NONE) {
if (return_arg.v_pointer == NULL) {
PyErr_SetString(PyExc_TypeError, "constructor returned NULL");
......
......@@ -21,6 +21,7 @@
#include "pygi-repository.h"
#include "pygi-info.h"
#include "pygi-struct.h"
#include "pygi-boxed.h"
#include "pygi-argument.h"
#include "pygi-type.h"
......
......@@ -44,6 +44,12 @@ typedef struct {
gboolean free_on_dealloc;
} PyGIStruct;
typedef struct {
PyGBoxed base;
gboolean slice_allocated;
gsize size;
} PyGIBoxed;
struct PyGI_API {
PyObject* (*type_import_by_g_type) (GType g_type);
......
......@@ -33,24 +33,6 @@ from ._gi import \
register_interface_info
class Boxed(gobject.GBoxed):
# Instances of boxed structures cannot be constructed unless they have a
# specific constructor.
#
# To achieve this behavior, PyGBoxed_Type's constructor creates an
# instance, and the initializer eventually raises an exception. If things
# had been implemented correctly, PyGBoxed_Type.tp_new would have been set to
# NULL, and neither a creator nor an initializer wouldn't have been needed.
#
# In order to keep the code generic, we need to revert the right behavior.
def __new__(cls):
raise TypeError, "instances of '%s' cannot be created" % cls.__name__
def __init__(self, *args, **kwargs):
pass
def Function(info):
def function(*args):
......
......@@ -3023,12 +3023,12 @@ test_gi__pointer_struct_inout (TestGIPointerStruct **struct_)
}
TestGIBoxedStruct *
test_gi_boxed_struct_copy (TestGIBoxedStruct *struct_)
TestGIBoxedWithoutConstructorStruct *
test_gi_boxed_without_constructor_struct_copy (TestGIBoxedWithoutConstructorStruct *struct_)
{
TestGIBoxedStruct *new_struct;
TestGIBoxedWithoutConstructorStruct *new_struct;
new_struct = g_slice_new (TestGIBoxedStruct);
new_struct = g_slice_new (TestGIBoxedWithoutConstructorStruct);
*new_struct = *struct_;
......@@ -3036,32 +3036,32 @@ test_gi_boxed_struct_copy (TestGIBoxedStruct *struct_)
}
static void
test_gi_boxed_struct_free (TestGIBoxedStruct *struct_)
test_gi_boxed_without_constructor_struct_free (TestGIBoxedWithoutConstructorStruct *struct_)
{
g_slice_free (TestGIBoxedStruct, struct_);
g_slice_free (TestGIBoxedWithoutConstructorStruct, struct_);
}
GType
test_gi_boxed_struct_get_type (void)
test_gi_boxed_without_constructor_struct_get_type (void)
{
static GType type = 0;
if (type == 0) {
type = g_boxed_type_register_static ("TestGIBoxedStruct",
(GBoxedCopyFunc) test_gi_boxed_struct_copy,
(GBoxedFreeFunc) test_gi_boxed_struct_free);
type = g_boxed_type_register_static ("TestGIBoxedWithoutConstructorStruct",
(GBoxedCopyFunc) test_gi_boxed_without_constructor_struct_copy,
(GBoxedFreeFunc) test_gi_boxed_without_constructor_struct_free);
}
return type;
}
TestGIBoxedInstantiableStruct *
test_gi_boxed_instantiable_struct_copy (TestGIBoxedInstantiableStruct *struct_)
TestGIBoxedStruct *
test_gi_boxed_struct_copy (TestGIBoxedStruct *struct_)
{
TestGIBoxedInstantiableStruct *new_struct;
TestGIBoxedStruct *new_struct;
new_struct = g_slice_new (TestGIBoxedInstantiableStruct);
new_struct = g_slice_new (TestGIBoxedStruct);
*new_struct = *struct_;
......@@ -3069,42 +3069,42 @@ test_gi_boxed_instantiable_struct_copy (TestGIBoxedInstantiableStruct *struct_)
}
static void
test_gi_boxed_instantiable_struct_free (TestGIBoxedInstantiableStruct *struct_)
test_gi_boxed_struct_free (TestGIBoxedStruct *struct_)
{
g_slice_free (TestGIBoxedInstantiableStruct, struct_);
g_slice_free (TestGIBoxedStruct, struct_);
}
GType
test_gi_boxed_instantiable_struct_get_type (void)
test_gi_boxed_struct_get_type (void)
{
static GType type = 0;
if (type == 0) {
type = g_boxed_type_register_static ("TestGIBoxedInstantiableStruct",
(GBoxedCopyFunc) test_gi_boxed_instantiable_struct_copy,
(GBoxedFreeFunc) test_gi_boxed_instantiable_struct_free);
type = g_boxed_type_register_static ("TestGIBoxedStruct",
(GBoxedCopyFunc) test_gi_boxed_struct_copy,
(GBoxedFreeFunc) test_gi_boxed_struct_free);
}
return type;
}
TestGIBoxedInstantiableStruct *
test_gi_boxed_instantiable_struct_new (void)
TestGIBoxedStruct *
test_gi_boxed_struct_new (void)
{
return g_slice_new (TestGIBoxedInstantiableStruct);
return g_slice_new (TestGIBoxedStruct);
}
/**
* test_gi__boxed_instantiable_struct_return:
* test_gi__boxed_struct_return:
* Returns: (transfer none):
*/
TestGIBoxedInstantiableStruct *
test_gi__boxed_instantiable_struct_return (void)
TestGIBoxedStruct *
test_gi__boxed_struct_return (void)
{
static TestGIBoxedInstantiableStruct *struct_ = NULL;
static TestGIBoxedStruct *struct_ = NULL;
if (struct_ == NULL) {
struct_ = g_new(TestGIBoxedInstantiableStruct, 1);
struct_ = g_new(TestGIBoxedStruct, 1);
struct_->long_ = 42;
}
......@@ -3113,26 +3113,26 @@ test_gi__boxed_instantiable_struct_return (void)
}
/**
* test_gi__boxed_instantiable_struct_in:
* test_gi__boxed_struct_in:
* @struct_: (transfer none):
*/
void
test_gi__boxed_instantiable_struct_in (TestGIBoxedInstantiableStruct *struct_)
test_gi__boxed_struct_in (TestGIBoxedStruct *struct_)
{
g_assert(struct_->long_ == 42);
}
/**
* test_gi__boxed_instantiable_struct_out:
* test_gi__boxed_struct_out:
* @struct_: (out) (transfer none):
*/
void
test_gi__boxed_instantiable_struct_out (TestGIBoxedInstantiableStruct **struct_)
test_gi__boxed_struct_out (TestGIBoxedStruct **struct_)
{
static TestGIBoxedInstantiableStruct *new_struct = NULL;
static TestGIBoxedStruct *new_struct = NULL;
if (new_struct == NULL) {
new_struct = g_new(TestGIBoxedInstantiableStruct, 1);
new_struct = g_new(TestGIBoxedStruct, 1);
new_struct->long_ = 42;
}
......@@ -3141,11 +3141,11 @@ test_gi__boxed_instantiable_struct_out (TestGIBoxedInstantiableStruct **struct_)
}
/**
* test_gi__boxed_instantiable_struct_inout:
* test_gi__boxed_struct_inout:
* @struct_: (inout) (transfer none):
*/
void
test_gi__boxed_instantiable_struct_inout (TestGIBoxedInstantiableStruct **struct_)
test_gi__boxed_struct_inout (TestGIBoxedStruct **struct_)
{
g_assert((*struct_)->long_ == 42);
......
......@@ -544,26 +544,26 @@ void test_gi__pointer_struct_inout (TestGIPointerStruct **struct_);
typedef struct {
glong long_;
} TestGIBoxedStruct;
} TestGIBoxedWithoutConstructorStruct;
GType test_gi_boxed_struct_get_type (void) G_GNUC_CONST;
GType test_gi_boxed_without_constructor_struct_get_type (void) G_GNUC_CONST;
typedef struct {
glong long_;
} TestGIBoxedInstantiableStruct;
} TestGIBoxedStruct;
GType test_gi_boxed_instantiable_struct_get_type (void) G_GNUC_CONST;
GType test_gi_boxed_struct_get_type (void) G_GNUC_CONST;
TestGIBoxedInstantiableStruct *test_gi_boxed_instantiable_struct_new (void);
TestGIBoxedStruct *test_gi_boxed_struct_new (void);
TestGIBoxedInstantiableStruct *test_gi__boxed_instantiable_struct_return (void);
TestGIBoxedStruct *test_gi__boxed_struct_return (void);
void test_gi__boxed_instantiable_struct_in (TestGIBoxedInstantiableStruct *struct_);
void test_gi__boxed_struct_in (TestGIBoxedStruct *struct_);
void test_gi__boxed_instantiable_struct_out (TestGIBoxedInstantiableStruct **struct_);
void test_gi__boxed_struct_out (TestGIBoxedStruct **struct_);
void test_gi__boxed_instantiable_struct_inout (TestGIBoxedInstantiableStruct **struct_);
void test_gi__boxed_struct_inout (TestGIBoxedStruct **struct_);
/* Object */
......
......@@ -1228,54 +1228,61 @@ class TestStructure(unittest.TestCase):
del in_struct
del out_struct
def test_boxed_without_constructor_struct(self):
self.assertTrue(issubclass(TestGI.BoxedWithoutConstructorStruct, gobject.GBoxed))
def test_boxed_struct(self):
self.assertTrue(issubclass(TestGI.BoxedStruct, gobject.GBoxed))
struct = TestGI.BoxedWithoutConstructorStruct()
self.assertTrue(isinstance(struct, TestGI.BoxedWithoutConstructorStruct))
self.assertRaises(TypeError, TestGI.BoxedStruct)
new_struct = struct.copy()
self.assertTrue(isinstance(new_struct, TestGI.BoxedWithoutConstructorStruct))
def test_boxed_instantiable_struct(self):
struct = TestGI.BoxedInstantiableStruct()
del struct
del new_struct
def test_boxed_struct(self):
struct = TestGI.BoxedStruct()
self.assertTrue(isinstance(struct, TestGI.BoxedInstantiableStruct))
self.assertTrue(isinstance(struct, TestGI.BoxedStruct))
new_struct = struct.copy()
self.assertTrue(isinstance(new_struct, TestGI.BoxedInstantiableStruct))
self.assertTrue(isinstance(new_struct, TestGI.BoxedStruct))
del struct
del new_struct
def test_boxed_instantiable_struct_return(self):
struct = TestGI.boxed_instantiable_struct_return()
def test_boxed_struct_return(self):
struct = TestGI.boxed_struct_return()
self.assertTrue(isinstance(struct, TestGI.BoxedInstantiableStruct))
self.assertTrue(isinstance(struct, TestGI.BoxedStruct))
self.assertEquals(42, struct.long_)
del struct
def test_boxed_instantiable_struct_in(self):
struct = TestGI.BoxedInstantiableStruct()
def test_boxed_struct_in(self):
struct = TestGI.BoxedStruct()
struct.long_ = 42
TestGI.boxed_instantiable_struct_in(struct)
TestGI.boxed_struct_in(struct)
del struct
def test_boxed_instantiable_struct_out(self):
struct = TestGI.boxed_instantiable_struct_out()
def test_boxed_struct_out(self):
struct = TestGI.boxed_struct_out()
self.assertTrue(isinstance(struct, TestGI.BoxedInstantiableStruct))
self.assertTrue(isinstance(struct, TestGI.BoxedStruct))
self.assertEquals(42, struct.long_)
del struct
def test_boxed_instantiable_struct_inout(self):
in_struct = TestGI.BoxedInstantiableStruct()
def test_boxed_struct_inout(self):
in_struct = TestGI.BoxedStruct()
in_struct.long_ = 42
out_struct = TestGI.boxed_instantiable_struct_inout(in_struct)
out_struct = TestGI.boxed_struct_inout(in_struct)
self.assertTrue(isinstance(out_struct, TestGI.BoxedInstantiableStruct))