Commit 729072e7 authored by John (J5) Palmieri's avatar John (J5) Palmieri

Allow passing None for callbacks which are annotated allow-none

* Many callbacks are optional parameters yet we were asserting on
  Py_None
* We now check to see if allow_none is set when setting up callbacks,
  if it is set and py_function == Py_None, we set the closure to NULL
  and return
* pygi-invoke.c now checks to see if the closure == NULL when setting
  arguments
* if it is NULL there is no reason to set the the destroy notify handler
  so we skip that too

https://bugzilla.gnome.org/show_bug.cgi?id=620906
parent a3eb5c7d
......@@ -161,9 +161,11 @@ _pygi_create_callback (GIBaseInfo *function_info,
PyObject *py_function;
guint8 i, py_argv_pos;
PyObject *py_user_data;
gboolean allow_none;
callback_arg = g_callable_info_get_arg ( (GICallableInfo*) function_info, callback_index);
scope = g_arg_info_get_scope (callback_arg);
allow_none = g_arg_info_may_be_null (callback_arg);
callback_type = g_arg_info_get_type (callback_arg);
g_assert (g_type_info_get_tag (callback_type) == GI_TYPE_TAG_INTERFACE);
......@@ -185,6 +187,11 @@ _pygi_create_callback (GIBaseInfo *function_info,
for (i = 0; i < n_args && i < py_argc; i++) {
if (i == callback_index) {
py_function = PyTuple_GetItem (py_argv, py_argv_pos);
/* if we allow none then set the closure to NULL and return */
if (allow_none && py_function == Py_None) {
*closure_out = NULL;
return TRUE;
}
found_py_function = TRUE;
} else if (i == user_data_index) {
py_user_data = PyTuple_GetItem (py_argv, py_argv_pos);
......
......@@ -113,6 +113,7 @@ _prepare_invocation_state (struct invocation_state *state,
return FALSE;
if (state->callback_index != G_MAXUINT8) {
if (!_pygi_create_callback (function_info,
state->is_method,
state->is_constructor,
......@@ -428,7 +429,11 @@ _prepare_invocation_state (struct invocation_state *state,
GIDirection direction;
if (i == state->callback_index) {
state->args[i]->v_pointer = state->closure->closure;
if (state->closure)
state->args[i]->v_pointer = state->closure->closure;
else
/* Some callbacks params accept NULL */
state->args[i]->v_pointer = NULL;
py_args_pos++;
continue;
} else if (i == state->user_data_index) {
......@@ -436,8 +441,11 @@ _prepare_invocation_state (struct invocation_state *state,
py_args_pos++;
continue;
} else if (i == state->destroy_notify_index) {
PyGICClosure *destroy_notify = _pygi_destroy_notify_create();
state->args[i]->v_pointer = destroy_notify->closure;
if (state->closure) {
/* No need to clean up if the callback is NULL */
PyGICClosure *destroy_notify = _pygi_destroy_notify_create();
state->args[i]->v_pointer = destroy_notify->closure;
}
continue;
}
......
......@@ -264,3 +264,7 @@ class TestCallbacks(unittest.TestCase):
TestCallbacks.called = False
obj_ = Everything.TestObj.new_callback(callbackWithUserData, None)
self.assertTrue(TestCallbacks.called)
def testCallbackNone(self):
# make sure this doesn't assert or crash
Everything.test_simple_callback(None)
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment