[pygi] Allow passing None for callbacks which are annotated allow-none



commit 729072e73d65e7fd5b5197ebe5a8c53a449d0ec0
Author: John (J5) Palmieri <johnp redhat com>
Date:   Mon Jun 7 17:12:09 2010 -0400

    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

 gi/pygi-callbacks.c      |    7 +++++++
 gi/pygi-invoke.c         |   14 +++++++++++---
 tests/test_everything.py |    4 ++++
 3 files changed, 22 insertions(+), 3 deletions(-)
---
diff --git a/gi/pygi-callbacks.c b/gi/pygi-callbacks.c
index ac9ca6a..a12eaed 100644
--- a/gi/pygi-callbacks.c
+++ b/gi/pygi-callbacks.c
@@ -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);
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index 63e57e7..16b4037 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -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;
             }
 
diff --git a/tests/test_everything.py b/tests/test_everything.py
index 06a8d8c..36de1e3 100644
--- a/tests/test_everything.py
+++ b/tests/test_everything.py
@@ -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



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]