[pygi] Implement nullable argument support, including tests
- From: Zach Goldberg <zgoldberg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygi] Implement nullable argument support, including tests
- Date: Sun, 18 Apr 2010 15:24:29 +0000 (UTC)
commit 79aa416ae8632b123da61d79fb820d9e2704209c
Author: Zach Goldberg <zach zachgoldberg com>
Date: Sat Apr 17 12:00:05 2010 -0400
Implement nullable argument support, including tests
https://bugzilla.gnome.org/show_bug.cgi?id=616035
gi/pygi-argument.c | 43 +++++++++++++++++++++++++++++++++++++------
gi/pygi-argument.h | 3 ++-
gi/pygi-info.c | 19 +++++++++++++------
tests/test_everything.py | 28 ++++++++++++++++++++++++++++
4 files changed, 80 insertions(+), 13 deletions(-)
---
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 0737bb7..df88a6c 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -189,11 +189,16 @@ _pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info,
gint
_pygi_g_type_info_check_object (GITypeInfo *type_info,
- PyObject *object)
+ PyObject *object,
+ gboolean allow_none)
{
GITypeTag type_tag;
gint retval = 1;
+ if (allow_none && object == Py_None) {
+ return retval;
+ }
+
type_tag = g_type_info_get_tag(type_info);
switch (type_tag) {
@@ -351,7 +356,7 @@ check_number_release:
break;
}
- retval = _pygi_g_type_info_check_object(item_type_info, item);
+ retval = _pygi_g_type_info_check_object(item_type_info, item, TRUE);
Py_DECREF(item);
@@ -481,7 +486,7 @@ check_number_release:
break;
}
- retval = _pygi_g_type_info_check_object(item_type_info, item);
+ retval = _pygi_g_type_info_check_object(item_type_info, item, TRUE);
Py_DECREF(item);
@@ -545,7 +550,7 @@ check_number_release:
key = PyList_GET_ITEM(keys, i);
value = PyList_GET_ITEM(values, i);
- retval = _pygi_g_type_info_check_object(key_type_info, key);
+ retval = _pygi_g_type_info_check_object(key_type_info, key, TRUE);
if (retval < 0) {
break;
}
@@ -554,7 +559,7 @@ check_number_release:
break;
}
- retval = _pygi_g_type_info_check_object(value_type_info, value);
+ retval = _pygi_g_type_info_check_object(value_type_info, value, TRUE);
if (retval < 0) {
break;
}
@@ -591,6 +596,10 @@ _pygi_argument_to_array (GArgument *arg,
gssize length;
GArray *g_array;
+ if (arg->v_pointer == NULL) {
+ return NULL;
+ }
+
is_zero_terminated = g_type_info_is_zero_terminated(type_info);
item_type_info = g_type_info_get_param_type(type_info, 0);
@@ -788,6 +797,11 @@ _pygi_argument_from_object (PyObject *object,
{
const gchar *string;
+ if (object == Py_None){
+ arg.v_string = NULL;
+ break;
+ }
+
string = PyString_AsString(object);
/* Don't need to check for errors, since g_strdup is NULL-proof. */
@@ -822,6 +836,11 @@ _pygi_argument_from_object (PyObject *object,
GITransfer item_transfer;
Py_ssize_t i;
+ if (object == Py_None){
+ arg.v_pointer = NULL;
+ break;
+ }
+
length = PySequence_Length(object);
if (length < 0) {
break;
@@ -1005,6 +1024,11 @@ array_item_error:
GITransfer item_transfer;
Py_ssize_t i;
+ if (object == Py_None) {
+ arg.v_pointer = NULL;
+ break;
+ }
+
length = PySequence_Length(object);
if (length < 0) {
break;
@@ -1071,6 +1095,11 @@ list_item_error:
Py_ssize_t i;
+ if (object == Py_None){
+ arg.v_pointer = NULL;
+ break;
+ }
+
length = PyMapping_Length(object);
if (length < 0) {
break;
@@ -1661,7 +1690,9 @@ _pygi_argument_release (GArgument *arg,
break;
case GI_TYPE_TAG_FILENAME:
case GI_TYPE_TAG_UTF8:
- if ((direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
+ /* With allow-none support the string could be NULL */
+ if (arg->v_string != NULL &&
+ (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)
|| (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) {
g_free(arg->v_string);
}
diff --git a/gi/pygi-argument.h b/gi/pygi-argument.h
index c162f2f..821737a 100644
--- a/gi/pygi-argument.h
+++ b/gi/pygi-argument.h
@@ -32,7 +32,8 @@ G_BEGIN_DECLS
/* Private */
gint _pygi_g_type_info_check_object (GITypeInfo *type_info,
- PyObject *object);
+ PyObject *object,
+ gboolean allow_none);
gint _pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info,
gboolean is_instance,
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index dbcf999..824e579 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -692,6 +692,7 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
GITypeTag type_tag;
PyObject *py_arg;
gint retval;
+ gboolean allow_none;
direction = g_arg_info_get_direction(arg_infos[i]);
type_tag = g_type_info_get_tag(arg_type_infos[i]);
@@ -705,7 +706,11 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
g_assert(py_args_pos < n_py_args);
py_arg = PyTuple_GET_ITEM(py_args, py_args_pos);
- retval = _pygi_g_type_info_check_object(arg_type_infos[i], py_arg);
+ allow_none = g_arg_info_may_be_null(arg_infos[i]);
+
+ retval = _pygi_g_type_info_check_object(arg_type_infos[i],
+ py_arg,
+ allow_none);
if (retval < 0) {
goto out;
@@ -945,11 +950,13 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
}
/* Get rid of the GArray. */
- args[i]->v_pointer = array->data;
+ if (array != NULL) {
+ args[i]->v_pointer = array->data;
- if (direction != GI_DIRECTION_INOUT || transfer != GI_TRANSFER_NOTHING) {
- /* The array hasn't been referenced anywhere, so free it to avoid losing memory. */
- g_array_free(array, FALSE);
+ if (direction != GI_DIRECTION_INOUT || transfer != GI_TRANSFER_NOTHING) {
+ /* The array hasn't been referenced anywhere, so free it to avoid losing memory. */
+ g_array_free(array, FALSE);
+ }
}
}
@@ -1990,7 +1997,7 @@ _wrap_g_field_info_set_value (PyGIBaseInfo *self,
{
gboolean retval;
- retval = _pygi_g_type_info_check_object(field_type_info, py_value);
+ retval = _pygi_g_type_info_check_object(field_type_info, py_value, TRUE);
if (retval < 0) {
goto out;
}
diff --git a/tests/test_everything.py b/tests/test_everything.py
index 8347081..148b8af 100644
--- a/tests/test_everything.py
+++ b/tests/test_everything.py
@@ -46,6 +46,34 @@ class TestEverything(unittest.TestCase):
self.assertEquals(surface.get_width(), 10)
self.assertEquals(surface.get_height(), 10)
+
+class TestNullableArgs(unittest.TestCase):
+ def test_in_nullable_hash(self):
+ Everything.test_ghash_null_in(None)
+
+ def test_in_nullable_list(self):
+ Everything.test_gslist_null_in(None)
+ Everything.test_glist_null_in(None)
+
+ def test_in_nullable_array(self):
+ Everything.test_array_int_null_in(None, -1)
+
+ def test_in_nullable_string(self):
+ Everything.test_utf8_null_in(None)
+
+ def test_out_nullable_hash(self):
+ self.assertEqual(None, Everything.test_ghash_null_out())
+
+ def test_out_nullable_list(self):
+ self.assertEqual(None, Everything.test_gslist_null_out())
+ self.assertEqual(None, Everything.test_glist_null_out())
+
+ def test_out_nullable_array(self):
+ self.assertEqual((None, 0), Everything.test_array_int_null_out())
+
+ def test_out_nullable_string(self):
+ self.assertEqual(None, Everything.test_utf8_null_out())
+
class TestCallbacks(unittest.TestCase):
called = False
def testCallback(self):
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]