diff options
-rw-r--r-- | gi/pygi-argument.c | 43 | ||||
-rw-r--r-- | gi/pygi-argument.h | 3 | ||||
-rw-r--r-- | gi/pygi-info.c | 19 | ||||
-rw-r--r-- | 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): |