diff options
-rw-r--r-- | ChangeLog | 44 | ||||
-rw-r--r-- | gio/gfile.override | 404 | ||||
-rw-r--r-- | gio/gfileenumerator.override | 27 | ||||
-rw-r--r-- | gio/gicon.override | 13 | ||||
-rw-r--r-- | gio/ginputstream.override | 25 | ||||
-rw-r--r-- | gio/gio.override | 241 | ||||
-rw-r--r-- | gio/goutputstream.override | 50 | ||||
-rw-r--r-- | gio/gvolume.override | 56 | ||||
-rw-r--r-- | tests/test_gio.py | 9 |
9 files changed, 455 insertions, 414 deletions
@@ -1,3 +1,47 @@ +2009-01-14 Paul Pogonyshev <pogonyshev@gmx.net> + + Bug 566706 – cleanup GIO overrides + + * gio/gio.override (pygio_notify_new) + (pygio_notify_using_optional_callback) + (pygio_notify_callback_is_valid_full) + (pygio_notify_callback_is_valid) + (pygio_notify_reference_callback): New functions. + (pygio_notify_free): Rename from pygio_free_notify() and extend. + (async_result_callback_marshal): Warn if new `referenced' field is + not set (programming error). + (_wrap_g_drive_eject, _wrap_g_drive_poll_for_media) + (_wrap_g_mount_unmount, _wrap_g_mount_eject) + (_wrap_g_mount_remount): Lots of cleanup: use new functions + instead of repeating code, unify and fix error handling. + + * gio/gfile.override (_wrap_g_file_read_async) + (_wrap_g_file_load_contents_async) + (_wrap_g_file_enumerate_children_async) + (_wrap_g_file_mount_mountable, _wrap_g_file_unmount_mountable) + (_wrap_g_file_mount_enclosing_volume, _wrap_g_file_copy) + (_wrap_g_file_copy_async, _wrap_g_file_move) + (_wrap_g_file_append_to_async, _wrap_g_file_create_async) + (_wrap_g_file_replace_async, _wrap_g_file_query_info_async) + (_wrap_g_file_replace_contents_async): Similar cleanup. + + * gio/gfileenumerator.override + (_wrap_g_file_enumerator_next_files_async): Similar cleanup. + + * gio/gicon.override (_wrap_g_loadable_icon_load_async): Similar + cleanup. + + * gio/ginputstream.override (_wrap_g_input_stream_close_async): + Similar cleanup. + + * gio/goutputstream.override (_wrap_g_output_stream_write_async) + (_wrap_g_output_stream_close_async): Similar cleanup. + + * gio/gvolume.override (_wrap_g_volume_mount) + (_wrap_g_volume_eject): Similar cleanup. + + * tests/test_gio.py (TestFile.test_copy_async): Fix the test. + 2009-01-09 Gustavo J. A. M. Carneiro <gjc@gnome.org> * gobject/gobjectmodule.c (pyg_type_register): Add a comment diff --git a/gio/gfile.override b/gio/gfile.override index f484b08..f4dc152 100644 --- a/gio/gfile.override +++ b/gio/gfile.override @@ -130,7 +130,7 @@ _wrap_g_file_read_async(PyGObject *self, GCancellable *cancellable; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iOO:File.read_async", @@ -139,22 +139,15 @@ _wrap_g_file_read_async(PyGObject *self, &io_priority, &pycancellable, ¬ify->data)) - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + goto error; - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_file_read_async(G_FILE(self->obj), io_priority, @@ -164,6 +157,10 @@ _wrap_g_file_read_async(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_load_contents kwargs @@ -214,7 +211,7 @@ _wrap_g_file_load_contents_async(PyGObject *self, PyGObject *pycancellable = NULL; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OO:File.load_contents_async", @@ -222,17 +219,16 @@ _wrap_g_file_load_contents_async(PyGObject *self, ¬ify->callback, &pycancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); g_file_load_contents_async(G_FILE(self->obj), cancellable, (GAsyncReadyCallback)async_result_callback_marshal, @@ -240,6 +236,10 @@ _wrap_g_file_load_contents_async(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_load_contents_finish kwargs @@ -291,7 +291,7 @@ _wrap_g_file_enumerate_children_async(PyGObject *self, PyObject *args, PyObject GCancellable *cancellable = NULL; PyGObject *py_cancellable = NULL; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|OiOO:GFile.enumerate_children_async", @@ -302,26 +302,19 @@ _wrap_g_file_enumerate_children_async(PyGObject *self, PyObject *args, PyObject &io_priority, &py_cancellable, ¬ify->data)) - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + goto error; - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_FILE_QUERY_INFO_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_file_enumerate_children_async(G_FILE(self->obj), attributes, @@ -333,6 +326,10 @@ _wrap_g_file_enumerate_children_async(PyGObject *self, PyObject *args, PyObject Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_mount_mountable kwargs @@ -350,7 +347,7 @@ _wrap_g_file_mount_mountable(PyGObject *self, GMountMountFlags flags = G_MOUNT_MOUNT_NONE; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O|OOO:File.mount_mountable", @@ -361,27 +358,19 @@ _wrap_g_file_mount_mountable(PyGObject *self, &py_flags, &py_cancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } - - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_MOUNT_MOUNT_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_file_mount_mountable(G_FILE(self->obj), flags, @@ -392,6 +381,10 @@ _wrap_g_file_mount_mountable(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_unmount_mountable kwargs @@ -408,7 +401,7 @@ _wrap_g_file_unmount_mountable(PyGObject *self, GMountUnmountFlags flags = G_MOUNT_UNMOUNT_NONE; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOO:File.unmount_mountable", @@ -417,27 +410,19 @@ _wrap_g_file_unmount_mountable(PyGObject *self, &py_flags, &py_cancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } - - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_MOUNT_UNMOUNT_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_file_unmount_mountable(G_FILE(self->obj), flags, @@ -447,6 +432,10 @@ _wrap_g_file_unmount_mountable(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_mount_enclosing_volume kwargs @@ -464,7 +453,7 @@ _wrap_g_file_mount_enclosing_volume(PyGObject *self, GMountMountFlags flags = G_MOUNT_MOUNT_NONE; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O|OOO:File.mount_enclosing_volume", @@ -475,27 +464,19 @@ _wrap_g_file_mount_enclosing_volume(PyGObject *self, &py_flags, &py_cancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } - - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_MOUNT_MOUNT_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_file_mount_enclosing_volume(G_FILE(self->obj), flags, @@ -506,6 +487,10 @@ _wrap_g_file_mount_enclosing_volume(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_copy kwargs @@ -527,7 +512,7 @@ _wrap_g_file_copy(PyGObject *self, GError *error = NULL; GFileProgressCallback callback = NULL; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OOOO:File.copy", @@ -538,31 +523,23 @@ _wrap_g_file_copy(PyGObject *self, &py_flags, &py_cancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } - - if (notify->callback != NULL) - { - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - callback = (GFileProgressCallback)file_progress_callback_marshal; - Py_INCREF(notify->callback); + if (pygio_notify_using_optional_callback(notify)) { + callback = (GFileProgressCallback)file_progress_callback_marshal; + if (!pygio_notify_callback_is_valid(notify)) + goto error; } - Py_XINCREF(notify->data); if (py_flags && pyg_flags_get_value(G_TYPE_FILE_COPY_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + /* No need to reference callback here, because it will be used + * only while this function is in progress. */ ret = g_file_copy(G_FILE(self->obj), G_FILE(destination->obj), @@ -572,11 +549,15 @@ _wrap_g_file_copy(PyGObject *self, notify, &error); - pygio_free_notify(notify); if (pyg_error_check(&error)) - return NULL; + goto error; + pygio_notify_free(notify); return PyBool_FromLong(ret); + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_copy_async kwargs @@ -585,10 +566,11 @@ _wrap_g_file_copy_async(PyGObject *self, PyObject *args, PyObject *kwargs) { + /* FIXME: Double-check argument order. */ static char *kwlist[] = { "destination", "callback", "flags", "io_priority", "user_data", "cancellable", "progress_callback", "progress_callback_data", NULL }; - PyGIONotify *notify, *progress_callback; + PyGIONotify *notify, *progress_notify; PyObject *py_flags = NULL; PyGObject *destination = NULL; PyGObject *py_cancellable = NULL; @@ -598,8 +580,8 @@ _wrap_g_file_copy_async(PyGObject *self, GCancellable *cancellable; GFileProgressCallback callback = NULL; - notify = g_slice_new0(PyGIONotify); - progress_callback = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); + progress_notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O|OiOOOO:File.copy_async", @@ -611,58 +593,46 @@ _wrap_g_file_copy_async(PyGObject *self, &io_priority, ¬ify->data, &pycancellable, - &progress_callback->callback, - &progress_callback->data - )) - { - g_slice_free(PyGIONotify, notify); - g_slice_free(PyGIONotify, progress_callback); - return NULL; - } + &progress_notify->callback, + &progress_notify->data)) + goto error; + + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; - if (progress_callback->callback != NULL) - { - if (!PyCallable_Check(progress_callback->callback)) - { - PyErr_SetString(PyExc_TypeError, "progress_callback argument not callable"); - g_slice_free(PyGIONotify, notify); - g_slice_free(PyGIONotify, progress_callback); - return NULL; - } - callback = (GFileProgressCallback)file_progress_callback_marshal; - Py_INCREF(progress_callback->callback); - Py_XINCREF(progress_callback->data); - } - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - Py_DECREF(progress_callback->callback); - Py_XDECREF(progress_callback->data); - g_slice_free(PyGIONotify, notify); - g_slice_free(PyGIONotify, progress_callback); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + goto error; + if (pygio_notify_using_optional_callback(progress_notify)) { + callback = (GFileProgressCallback)file_progress_callback_marshal; + if (!pygio_notify_callback_is_valid_full(progress_notify, "progress_callback")) + goto error; + } if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; + pygio_notify_reference_callback(notify); + pygio_notify_reference_callback(progress_notify); + + /* FIXME: 'progress_notify' is not properly freed up as far as I see. */ g_file_copy_async(G_FILE(self->obj), G_FILE(destination->obj), flags, io_priority, cancellable, callback, - progress_callback, + progress_notify, (GAsyncReadyCallback)async_result_callback_marshal, notify); Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + pygio_notify_free(progress_notify); + return NULL; } %% override g_file_move kwargs @@ -684,7 +654,7 @@ _wrap_g_file_move(PyGObject *self, GError *error = NULL; GFileProgressCallback callback = NULL; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OOOO:File.move", @@ -695,31 +665,23 @@ _wrap_g_file_move(PyGObject *self, &py_flags, &py_cancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; + if (pygio_notify_using_optional_callback(notify)) { + callback = (GFileProgressCallback)file_progress_callback_marshal; + if (!pygio_notify_callback_is_valid(notify)) + goto error; } - if (notify->callback != NULL) - { - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - callback = (GFileProgressCallback)file_progress_callback_marshal; - Py_INCREF(notify->callback); - } - Py_XINCREF(notify->data); - if (py_flags && pyg_flags_get_value(G_TYPE_FILE_COPY_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + /* No need to reference callback here, because it will be used + * only while this function is in progress. */ ret = g_file_move(G_FILE(self->obj), G_FILE(destination->obj), @@ -729,11 +691,15 @@ _wrap_g_file_move(PyGObject *self, notify, &error); - pygio_free_notify(notify); if (pyg_error_check(&error)) - return NULL; + goto error; + pygio_notify_free(notify); return PyBool_FromLong(ret); + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_set_attribute kwargs @@ -882,7 +848,7 @@ _wrap_g_file_append_to_async(PyGObject *self, PyObject *args, PyObject *kwargs) int io_priority = G_PRIORITY_DEFAULT; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OiOO:File.append_to_async", @@ -891,27 +857,30 @@ _wrap_g_file_append_to_async(PyGObject *self, PyObject *args, PyObject *kwargs) &flags, &io_priority, &pycancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_FILE_CREATE_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); g_file_append_to_async(G_FILE(self->obj), flags, io_priority, cancellable, (GAsyncReadyCallback)async_result_callback_marshal, notify); Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_create_async kwargs @@ -927,7 +896,7 @@ _wrap_g_file_create_async(PyGObject *self, PyObject *args, PyObject *kwargs) int io_priority = G_PRIORITY_DEFAULT; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OiOO:File.create_async", @@ -936,27 +905,30 @@ _wrap_g_file_create_async(PyGObject *self, PyObject *args, PyObject *kwargs) &flags, &io_priority, &pycancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_FILE_CREATE_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); g_file_create_async(G_FILE(self->obj), flags, io_priority, cancellable, (GAsyncReadyCallback)async_result_callback_marshal, notify); Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_replace_async kwargs @@ -975,7 +947,7 @@ _wrap_g_file_replace_async(PyGObject *self, PyObject *args, PyObject *kwargs) PyObject *py_backup = Py_True; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zOOiOO:File.replace_async", @@ -985,23 +957,22 @@ _wrap_g_file_replace_async(PyGObject *self, PyObject *args, PyObject *kwargs) &flags, &io_priority, &pycancellable, ¬ify->data)) - - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + goto error; make_backup = PyObject_IsTrue(py_backup) ? TRUE : FALSE; + if (!pygio_notify_callback_is_valid(notify)) + goto error; + if (py_flags && pyg_flags_get_value(G_TYPE_FILE_CREATE_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); g_file_replace_async(G_FILE(self->obj), etag, make_backup, flags, io_priority, cancellable, (GAsyncReadyCallback)async_result_callback_marshal, @@ -1009,6 +980,10 @@ _wrap_g_file_replace_async(PyGObject *self, PyObject *args, PyObject *kwargs) Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_query_info_async kwargs @@ -1025,7 +1000,7 @@ _wrap_g_file_query_info_async(PyGObject *self, PyObject *args, PyObject *kwargs) char *attributes; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|OiOO:File.query_info_async", @@ -1035,21 +1010,20 @@ _wrap_g_file_query_info_async(PyGObject *self, PyObject *args, PyObject *kwargs) &flags, &io_priority, &pycancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_FILE_CREATE_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); g_file_query_info_async(G_FILE(self->obj), attributes, flags, io_priority, cancellable, (GAsyncReadyCallback)async_result_callback_marshal, @@ -1057,6 +1031,10 @@ _wrap_g_file_query_info_async(PyGObject *self, PyObject *args, PyObject *kwargs) Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_replace_contents kwargs @@ -1169,7 +1147,7 @@ _wrap_g_file_replace_contents_async(PyGObject *self, PyObject *args, PyObject *k char *contents; char *etag = NULL; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#O|zbOOO:File.replace_contents_async", @@ -1182,21 +1160,21 @@ _wrap_g_file_replace_contents_async(PyGObject *self, PyObject *args, PyObject *k &py_flags, &pycancellable, ¬ify->data)) - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + goto error; + + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_FILE_CREATE_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + pygio_notify_reference_callback(notify); pygio_notify_copy_buffer(notify, contents, length); + g_file_replace_contents_async(G_FILE(self->obj), notify->buffer, notify->buffer_size, @@ -1209,6 +1187,10 @@ _wrap_g_file_replace_contents_async(PyGObject *self, PyObject *args, PyObject *k Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override-slot GFile.tp_richcompare diff --git a/gio/gfileenumerator.override b/gio/gfileenumerator.override index b7a668f..2044e44 100644 --- a/gio/gfileenumerator.override +++ b/gio/gfileenumerator.override @@ -67,7 +67,7 @@ _wrap_g_file_enumerator_next_files_async(PyGObject *self, PyObject *args, PyObje GCancellable *cancellable = NULL; PyGObject *py_cancellable = NULL; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO|iOO:GFileEnumerator.enumerate_children_async", @@ -77,22 +77,15 @@ _wrap_g_file_enumerator_next_files_async(PyGObject *self, PyObject *args, PyObje &io_priority, &py_cancellable, ¬ify->data)) - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + goto error; + + if (!pygio_notify_callback_is_valid(notify)) + goto error; - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); - if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_file_enumerator_next_files_async(G_FILE_ENUMERATOR(self->obj), num_files, @@ -103,6 +96,10 @@ _wrap_g_file_enumerator_next_files_async(PyGObject *self, PyObject *args, PyObje Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_file_enumerator_next_files_finish kwargs diff --git a/gio/gicon.override b/gio/gicon.override index 6cbe180..a4ec7eb 100644 --- a/gio/gicon.override +++ b/gio/gicon.override @@ -109,7 +109,7 @@ _wrap_g_loadable_icon_load_async(PyGObject *self, GCancellable *cancellable; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iOO:gio.LoadableIcon.load_async", @@ -117,16 +117,13 @@ _wrap_g_loadable_icon_load_async(PyGObject *self, ¬ify->callback, &size, &pycancellable, ¬ify->data)) goto error; - if (!PyCallable_Check(notify->callback)) { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - goto error; - } + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) goto error; - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + pygio_notify_reference_callback(notify); g_loadable_icon_load_async(G_LOADABLE_ICON(self->obj), size, @@ -137,7 +134,7 @@ _wrap_g_loadable_icon_load_async(PyGObject *self, return Py_None; error: - g_slice_free(PyGIONotify, notify); + pygio_notify_free(notify); return NULL; } %% diff --git a/gio/ginputstream.override b/gio/ginputstream.override index 443d974..43cd22f 100644 --- a/gio/ginputstream.override +++ b/gio/ginputstream.override @@ -318,7 +318,7 @@ _wrap_g_input_stream_close_async(PyGObject *self, GCancellable *cancellable; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iOO:InputStream.close_async", @@ -327,22 +327,15 @@ _wrap_g_input_stream_close_async(PyGObject *self, &io_priority, &pycancellable, ¬ify->data)) - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + goto error; - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_input_stream_close_async(G_INPUT_STREAM(self->obj), io_priority, @@ -352,6 +345,10 @@ _wrap_g_input_stream_close_async(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_data_input_stream_read_line kwargs diff --git a/gio/gio.override b/gio/gio.override index 0f6ae5f..d0a694b 100644 --- a/gio/gio.override +++ b/gio/gio.override @@ -34,6 +34,7 @@ headers #define BUFSIZE 8192 typedef struct { + gboolean referenced; PyObject *callback; PyObject *data; gpointer buffer; @@ -55,15 +56,72 @@ pygio_notify_copy_buffer(PyGIONotify *notify, gpointer buffer, gsize buffer_size } } +static PyGIONotify * +pygio_notify_new(void) +{ + return g_slice_new0(PyGIONotify); +} + +static gboolean +pygio_notify_using_optional_callback(PyGIONotify *notify) +{ + if (notify->callback) + return TRUE; + else { + notify->data = NULL; + return FALSE; + } +} + +static gboolean +pygio_notify_callback_is_valid_full(PyGIONotify *notify, const gchar *name) +{ + if (!notify->callback) { + PyErr_SetString(PyExc_RuntimeError, "internal error: callback is not set"); + return FALSE; + } + + if (!PyCallable_Check(notify->callback)) { + gchar *error_message = g_strdup_printf("%s argument not callable", name); + + PyErr_SetString(PyExc_TypeError, error_message); + g_free(error_message); + return FALSE; + } + + return TRUE; +} + +static gboolean +pygio_notify_callback_is_valid(PyGIONotify *notify) +{ + return pygio_notify_callback_is_valid_full(notify, "callback"); +} + static void -pygio_free_notify(PyGIONotify *notify) +pygio_notify_reference_callback(PyGIONotify *notify) { - Py_XDECREF(notify->callback); - Py_XDECREF(notify->data); - if (notify->buffer) - g_slice_free1(notify->buffer_size, notify->buffer); + if (!notify->referenced) { + notify->referenced = TRUE; + Py_XINCREF(notify->callback); + Py_XINCREF(notify->data); + } +} - g_slice_free(PyGIONotify, notify); +static void +pygio_notify_free(PyGIONotify *notify) +{ + if (notify) { + if (notify->referenced) { + Py_XDECREF(notify->callback); + Py_XDECREF(notify->data); + } + + if (notify->buffer) + g_slice_free1(notify->buffer_size, notify->buffer); + + g_slice_free(PyGIONotify, notify); + } } static void @@ -76,6 +134,9 @@ async_result_callback_marshal(GObject *source_object, state = pyg_gil_state_ensure(); + if (!notify->referenced) + g_warning("pygio_notify_reference_callback() hasn't been called before using the structure"); + if (notify->data) ret = PyEval_CallFunction(notify->callback, "(OOO)", pygobject_new(source_object), @@ -86,14 +147,13 @@ async_result_callback_marshal(GObject *source_object, pygobject_new(source_object), pygobject_new((GObject *)result)); - if (ret == NULL) - { + if (ret == NULL) { PyErr_Print(); PyErr_Clear(); - } + } Py_XDECREF(ret); - pygio_free_notify(notify); + pygio_notify_free(notify); pyg_gil_state_release(state); } @@ -165,7 +225,7 @@ _wrap_g_drive_eject(PyGObject *self, PyObject *args, PyObject *kwargs) PyGObject *py_cancellable = NULL; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOO:gio.Drive.eject", @@ -173,30 +233,20 @@ _wrap_g_drive_eject(PyGObject *self, PyObject *args, PyObject *kwargs) ¬ify->callback, &py_flags, &py_cancellable, - ¬ify->data)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + ¬ify->data)) + goto error; - if (!PyCallable_Check(notify->callback)) { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_MOUNT_UNMOUNT_FLAGS, - py_flags, (gpointer) &flags)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + py_flags, (gpointer) &flags)) + goto error; - if (!pygio_check_cancellable(py_cancellable, &cancellable)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_check_cancellable(py_cancellable, &cancellable)) + goto error; - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + pygio_notify_reference_callback(notify); g_drive_eject(G_DRIVE(self->obj), flags, @@ -206,6 +256,10 @@ _wrap_g_drive_eject(PyGObject *self, PyObject *args, PyObject *kwargs) Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_drive_poll_for_media kwargs @@ -217,31 +271,23 @@ _wrap_g_drive_poll_for_media(PyGObject *self, PyObject *args, PyObject *kwargs) PyGObject *py_cancellable = NULL; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OO:gio.Drive.eject", kwlist, ¬ify->callback, &py_cancellable, - ¬ify->data)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + ¬ify->data)) + goto error; - if (!PyCallable_Check(notify->callback)) { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_notify_callback_is_valid(notify)) + goto error; - if (!pygio_check_cancellable(py_cancellable, &cancellable)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_check_cancellable(py_cancellable, &cancellable)) + goto error; - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + pygio_notify_reference_callback(notify); g_drive_poll_for_media(G_DRIVE(self->obj), cancellable, @@ -250,6 +296,10 @@ _wrap_g_drive_poll_for_media(PyGObject *self, PyObject *args, PyObject *kwargs) Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override-slot GDrive.tp_repr @@ -362,7 +412,7 @@ _wrap_g_mount_unmount(PyGObject *self, GMountUnmountFlags flags = G_MOUNT_UNMOUNT_NONE; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOO:GMount.unmount", @@ -371,27 +421,19 @@ _wrap_g_mount_unmount(PyGObject *self, &py_flags, &py_cancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } - - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_MOUNT_UNMOUNT_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_mount_unmount(G_MOUNT(self->obj), flags, @@ -401,6 +443,10 @@ _wrap_g_mount_unmount(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_mount_eject kwargs @@ -414,7 +460,7 @@ _wrap_g_mount_eject(PyGObject *self, PyObject *args, PyObject *kwargs) PyGObject *py_cancellable = NULL; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOO:gio.Mount.eject", @@ -422,30 +468,20 @@ _wrap_g_mount_eject(PyGObject *self, PyObject *args, PyObject *kwargs) ¬ify->callback, &py_flags, &py_cancellable, - ¬ify->data)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + ¬ify->data)) + goto error; - if (!PyCallable_Check(notify->callback)) { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_MOUNT_UNMOUNT_FLAGS, - py_flags, (gpointer) &flags)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + py_flags, (gpointer) &flags)) + goto error; - if (!pygio_check_cancellable(py_cancellable, &cancellable)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_check_cancellable(py_cancellable, &cancellable)) + goto error; - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + pygio_notify_reference_callback(notify); g_mount_eject(G_MOUNT(self->obj), flags, @@ -455,6 +491,10 @@ _wrap_g_mount_eject(PyGObject *self, PyObject *args, PyObject *kwargs) Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_mount_remount kwargs @@ -471,7 +511,7 @@ _wrap_g_mount_remount(PyGObject *self, PyObject *args, PyObject *kwargs) PyGObject *py_cancellable = NULL; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOOO:gio.Mount.remount", @@ -480,41 +520,30 @@ _wrap_g_mount_remount(PyGObject *self, PyObject *args, PyObject *kwargs) &py_flags, &py_mount_operation, &py_cancellable, - ¬ify->data)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + ¬ify->data)) + goto error; - if (!PyCallable_Check(notify->callback)) { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_mount_operation != Py_None) { if (!pygobject_check(py_mount_operation, &PyGMountOperation_Type)) { PyErr_SetString(PyExc_TypeError, "mount_operation must be a gio.MountOperation or None"); - g_slice_free(PyGIONotify, notify); - return NULL; + goto error; } mount_operation = G_MOUNT_OPERATION(pygobject_get(py_mount_operation)); } if (py_flags && pyg_flags_get_value(G_TYPE_MOUNT_UNMOUNT_FLAGS, - py_flags, (gpointer) &flags)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + py_flags, (gpointer) &flags)) + goto error; - if (!pygio_check_cancellable(py_cancellable, &cancellable)) { - g_slice_free(PyGIONotify, notify); - return NULL; - } + if (!pygio_check_cancellable(py_cancellable, &cancellable)) + goto error; - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + pygio_notify_reference_callback(notify); g_mount_remount(G_MOUNT(self->obj), flags, @@ -525,6 +554,10 @@ _wrap_g_mount_remount(PyGObject *self, PyObject *args, PyObject *kwargs) Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override-slot GMount.tp_repr diff --git a/gio/goutputstream.override b/gio/goutputstream.override index df9ea94..62a1db2 100644 --- a/gio/goutputstream.override +++ b/gio/goutputstream.override @@ -103,7 +103,7 @@ _wrap_g_output_stream_write_async(PyGObject *self, GCancellable *cancellable; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#O|iOO:OutputStream.write_async", @@ -113,24 +113,17 @@ _wrap_g_output_stream_write_async(PyGObject *self, &io_priority, &pycancellable, ¬ify->data)) - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + goto error; - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; + pygio_notify_reference_callback(notify); pygio_notify_copy_buffer(notify, buffer, count); + g_output_stream_write_async(G_OUTPUT_STREAM(self->obj), notify->buffer, notify->buffer_size, @@ -141,6 +134,10 @@ _wrap_g_output_stream_write_async(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_output_stream_close_async kwargs @@ -156,7 +153,7 @@ _wrap_g_output_stream_close_async(PyGObject *self, GCancellable *cancellable; PyGIONotify *notify; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iOO:OutputStream.close_async", @@ -165,22 +162,15 @@ _wrap_g_output_stream_close_async(PyGObject *self, &io_priority, &pycancellable, ¬ify->data)) - { - g_slice_free(PyGIONotify, notify); - return NULL; - } + goto error; + + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + pygio_notify_reference_callback(notify); g_output_stream_close_async(G_OUTPUT_STREAM(self->obj), io_priority, @@ -190,6 +180,10 @@ _wrap_g_output_stream_close_async(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_memory_output_stream_new noargs diff --git a/gio/gvolume.override b/gio/gvolume.override index 013408f..fcdbb9f 100644 --- a/gio/gvolume.override +++ b/gio/gvolume.override @@ -35,7 +35,7 @@ _wrap_g_volume_mount(PyGObject *self, GMountMountFlags flags = G_MOUNT_MOUNT_NONE; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O|OOO:Volume.mount", @@ -46,27 +46,19 @@ _wrap_g_volume_mount(PyGObject *self, &py_flags, &py_cancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } - - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_MOUNT_MOUNT_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_volume_mount(G_VOLUME(self->obj), flags, @@ -77,6 +69,10 @@ _wrap_g_volume_mount(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_volume_eject kwargs @@ -93,7 +89,7 @@ _wrap_g_volume_eject(PyGObject *self, GMountUnmountFlags flags = G_MOUNT_UNMOUNT_NONE; GCancellable *cancellable; - notify = g_slice_new0(PyGIONotify); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOO:Volume.eject", @@ -102,27 +98,19 @@ _wrap_g_volume_eject(PyGObject *self, &py_flags, &py_cancellable, ¬ify->data)) + goto error; - { - g_slice_free(PyGIONotify, notify); - return NULL; - } - - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotify, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (py_flags && pyg_flags_get_value(G_TYPE_MOUNT_UNMOUNT_FLAGS, py_flags, (gpointer)&flags)) - return NULL; + goto error; if (!pygio_check_cancellable(py_cancellable, &cancellable)) - return NULL; + goto error; + + pygio_notify_reference_callback(notify); g_volume_eject(G_VOLUME(self->obj), flags, @@ -132,6 +120,10 @@ _wrap_g_volume_eject(PyGObject *self, Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override-slot GVolume.tp_repr diff --git a/tests/test_gio.py b/tests/test_gio.py index 10ef6ac..ba05f83 100644 --- a/tests/test_gio.py +++ b/tests/test_gio.py @@ -303,8 +303,11 @@ class TestFile(unittest.TestCase): destination = gio.File('copy.txt') def copied(source_, result): - self.assert_(source_ is source) - self.failUnless(source_.copy_finish(result)) + try: + self.assert_(source_ is source) + self.failUnless(source_.copy_finish(result)) + finally: + loop.quit() def progress(current, total): self.assert_(isinstance(current, long)) @@ -312,7 +315,9 @@ class TestFile(unittest.TestCase): self.assert_(0 <= current <= total) try: + loop = glib.MainLoop() source.copy_async(destination, copied, progress_callback = progress) + loop.run() self.failUnless(os.path.exists('copy.txt')) self.assertEqual(open('file.txt').read(), |