Imported Upstream version 3.19.91
[platform/upstream/python-gobject.git] / gi / pygi-error.c
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * vim: tabstop=4 shiftwidth=4 expandtab
3  *
4  * Copyright (C) 1998-2003  James Henstridge
5  *               2004-2008  Johan Dahlin
6  * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>
7  * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include "pyglib.h"
24 #include "pygi-private.h"
25 #include "pygi-error.h"
26 #include "pygtype.h"
27
28
29 PyObject *PyGError = NULL;
30 static PyObject *exception_table = NULL;
31
32 /**
33  * pygi_error_marshal_to_py:
34  * @error: a pointer to the GError.
35  *
36  * Checks to see if @error has been set.  If @error has been set, then a
37  * GLib.GError Python exception object is returned (but not raised).
38  *
39  * Returns: a GLib.GError Python exception object, or NULL.
40  */
41 PyObject *
42 pygi_error_marshal_to_py (GError **error)
43 {
44     PyGILState_STATE state;
45     PyObject *exc_type;
46     PyObject *exc_instance;
47     const char *domain = NULL;
48
49     g_return_val_if_fail(error != NULL, NULL);
50
51     if (*error == NULL)
52         return NULL;
53
54     state = pyglib_gil_state_ensure();
55
56     exc_type = PyGError;
57     if (exception_table != NULL)
58     {
59         PyObject *item;
60         item = PyDict_GetItem(exception_table, PYGLIB_PyLong_FromLong((*error)->domain));
61         if (item != NULL)
62             exc_type = item;
63     }
64
65     if ((*error)->domain) {
66         domain = g_quark_to_string ((*error)->domain);
67     }
68
69     exc_instance = PyObject_CallFunction (exc_type, "ssi",
70                                           (*error)->message,
71                                           domain,
72                                           (*error)->code);
73
74     pyglib_gil_state_release(state);
75
76     return exc_instance;
77 }
78
79 /**
80  * pygi_error_check:
81  * @error: a pointer to the GError.
82  *
83  * Checks to see if the GError has been set.  If the error has been
84  * set, then the glib.GError Python exception will be raised, and
85  * the GError cleared.
86  *
87  * Returns: True if an error was set.
88  */
89 gboolean
90 pygi_error_check (GError **error)
91 {
92     PyGILState_STATE state;
93     PyObject *exc_instance;
94
95     g_return_val_if_fail(error != NULL, FALSE);
96     if (*error == NULL)
97         return FALSE;
98
99     state = pyglib_gil_state_ensure();
100
101     exc_instance = pygi_error_marshal_to_py (error);
102     PyErr_SetObject(PyGError, exc_instance);
103     Py_DECREF(exc_instance);
104     g_clear_error(error);
105
106     pyglib_gil_state_release(state);
107
108     return TRUE;
109 }
110
111 /**
112  * pygi_error_marshal_from_py:
113  * @pyerr: A Python exception instance.
114  * @error: a standard GLib GError ** output parameter
115  *
116  * Converts from a Python implemented GError into a GError.
117  *
118  * Returns: TRUE if the conversion was successful, otherwise a Python exception
119  *          is set and FALSE is returned.
120  */
121 gboolean
122 pygi_error_marshal_from_py (PyObject *pyerr, GError **error)
123 {
124     gboolean res = FALSE;
125     PyObject *py_message = NULL,
126              *py_domain = NULL,
127              *py_code = NULL;
128
129     if (PyObject_IsInstance (pyerr, PyGError) != 1) {
130         PyErr_Format (PyExc_TypeError, "Must be GLib.Error, not %s",
131                       pyerr->ob_type->tp_name);
132         return FALSE;
133     }
134
135     py_message = PyObject_GetAttrString (pyerr, "message");
136     if (!py_message || !PYGLIB_PyUnicode_Check (py_message)) {
137         PyErr_SetString (PyExc_ValueError,
138                          "GLib.Error instances must have a 'message' string attribute");
139         goto cleanup;
140     }
141
142     py_domain = PyObject_GetAttrString (pyerr, "domain");
143     if (!py_domain || !PYGLIB_PyUnicode_Check (py_domain)) {
144         PyErr_SetString (PyExc_ValueError,
145                          "GLib.Error instances must have a 'domain' string attribute");
146         goto cleanup;
147     }
148
149     py_code = PyObject_GetAttrString (pyerr, "code");
150     if (!py_code || !PYGLIB_PyLong_Check (py_code)) {
151         PyErr_SetString (PyExc_ValueError,
152                          "GLib.Error instances must have a 'code' int attribute");
153         goto cleanup;
154     }
155
156     res = TRUE;
157     g_set_error_literal (error,
158                          g_quark_from_string (PYGLIB_PyUnicode_AsString (py_domain)),
159                          PYGLIB_PyLong_AsLong (py_code),
160                          PYGLIB_PyUnicode_AsString (py_message));
161
162 cleanup:
163     Py_XDECREF (py_message);
164     Py_XDECREF (py_code);
165     Py_XDECREF (py_domain);
166     return res;
167 }
168
169 /**
170  * pygi_gerror_exception_check:
171  * @error: a standard GLib GError ** output parameter
172  *
173  * Checks to see if a GError exception has been raised, and if so
174  * translates the python exception to a standard GLib GError.  If the
175  * raised exception is not a GError then PyErr_Print() is called.
176  *
177  * Returns: 0 if no exception has been raised, -1 if it is a
178  * valid glib.GError, -2 otherwise.
179  */
180 gboolean
181 pygi_gerror_exception_check (GError **error)
182 {
183     int res = -1;
184     PyObject *type, *value, *traceback;
185     PyErr_Fetch(&type, &value, &traceback);
186     if (type == NULL)
187         return 0;
188     PyErr_NormalizeException(&type, &value, &traceback);
189     if (value == NULL) {
190         PyErr_Restore(type, value, traceback);
191         PyErr_Print();
192         return -2;
193     }
194     if (!value ||
195         !PyErr_GivenExceptionMatches(type,
196                                      (PyObject *) PyGError)) {
197         PyErr_Restore(type, value, traceback);
198         PyErr_Print();
199         return -2;
200     }
201     Py_DECREF(type);
202     Py_XDECREF(traceback);
203
204     if (!pygi_error_marshal_from_py (value, error)) {
205         PyErr_Print();
206         res = -2;
207     }
208
209     Py_DECREF(value);
210     return res;
211
212 }
213
214 /**
215  * pygi_register_exception_for_domain:
216  * @name: name of the exception
217  * @error_domain: error domain
218  *
219  * Registers a new GLib.Error exception subclass called #name for
220  * a specific #domain. This exception will be raised when a GError
221  * of the same domain is passed in to pygi_error_check().
222  *
223  * Returns: the new exception
224  */
225 PyObject *
226 pygi_register_exception_for_domain (gchar *name,
227                                     gint error_domain)
228 {
229     PyObject *exception;
230
231     exception = PyErr_NewException(name, PyGError, NULL);
232
233     if (exception_table == NULL)
234         exception_table = PyDict_New();
235
236     PyDict_SetItem(exception_table,
237                    PYGLIB_PyLong_FromLong(error_domain),
238                    exception);
239
240     return exception;
241 }
242
243 static gboolean
244 _pygi_marshal_from_py_gerror (PyGIInvokeState   *state,
245                               PyGICallableCache *callable_cache,
246                               PyGIArgCache      *arg_cache,
247                               PyObject          *py_arg,
248                               GIArgument        *arg,
249                               gpointer          *cleanup_data)
250 {
251     GError *error = NULL;
252     if (pygi_error_marshal_from_py (py_arg, &error)) {
253         arg->v_pointer = error;
254         *cleanup_data = error;
255         return TRUE;
256     } else {
257         return FALSE;
258     }
259 }
260
261
262 static void
263 _pygi_marshal_from_py_gerror_cleanup  (PyGIInvokeState *state,
264                                        PyGIArgCache    *arg_cache,
265                                        PyObject        *py_arg,
266                                        gpointer         data,
267                                        gboolean         was_processed)
268 {
269     if (was_processed) {
270         g_error_free ((GError *)data);
271     }
272 }
273
274 static PyObject *
275 _pygi_marshal_to_py_gerror (PyGIInvokeState   *state,
276                             PyGICallableCache *callable_cache,
277                             PyGIArgCache      *arg_cache,
278                             GIArgument        *arg)
279 {
280     GError *error = arg->v_pointer;
281     PyObject *py_obj = NULL;
282
283     py_obj = pygi_error_marshal_to_py (&error);
284
285     if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && error != NULL) {
286         g_error_free (error);
287     }
288
289     if (py_obj != NULL) {
290         return py_obj;
291     } else {
292         Py_RETURN_NONE;
293     }
294 }
295
296 static gboolean
297 pygi_arg_gerror_setup_from_info (PyGIArgCache  *arg_cache,
298                                  GITypeInfo    *type_info,
299                                  GIArgInfo     *arg_info,
300                                  GITransfer     transfer,
301                                  PyGIDirection  direction)
302 {
303     if (!pygi_arg_base_setup (arg_cache, type_info, arg_info, transfer, direction)) {
304         return FALSE;
305     }
306
307     if (direction & PYGI_DIRECTION_FROM_PYTHON) {
308         arg_cache->from_py_marshaller = _pygi_marshal_from_py_gerror;
309
310         /* Assign cleanup function if we manage memory after call completion. */
311         if (arg_cache->transfer == GI_TRANSFER_NOTHING) {
312             arg_cache->from_py_cleanup = _pygi_marshal_from_py_gerror_cleanup;
313         }
314     }
315
316     if (direction & PYGI_DIRECTION_TO_PYTHON) {
317         arg_cache->to_py_marshaller = _pygi_marshal_to_py_gerror;
318         arg_cache->meta_type = PYGI_META_ARG_TYPE_PARENT;
319     }
320
321     return TRUE;
322 }
323
324 PyGIArgCache *
325 pygi_arg_gerror_new_from_info (GITypeInfo   *type_info,
326                                GIArgInfo    *arg_info,
327                                GITransfer    transfer,
328                                PyGIDirection direction)
329 {
330     gboolean res = FALSE;
331     PyGIArgCache *arg_cache = NULL;
332
333     arg_cache = pygi_arg_cache_alloc ();
334     if (arg_cache == NULL)
335         return NULL;
336
337     res = pygi_arg_gerror_setup_from_info (arg_cache,
338                                            type_info,
339                                            arg_info,
340                                            transfer,
341                                            direction);
342     if (res) {
343         return arg_cache;
344     } else {
345         pygi_arg_cache_free (arg_cache);
346         return NULL;
347     }
348 }
349
350 static PyObject *
351 pygerror_from_gvalue (const GValue *value)
352 {
353     GError *gerror = (GError *) g_value_get_boxed (value);
354     PyObject *pyerr = pygi_error_marshal_to_py (&gerror);
355     if (pyerr == NULL) {
356         Py_RETURN_NONE;
357     } else {
358         return pyerr;
359     }
360 }
361
362 static int
363 pygerror_to_gvalue (GValue *value, PyObject *pyerror)
364 {
365     GError *gerror = NULL;
366
367     if (pygi_error_marshal_from_py (pyerror, &gerror)) {
368         g_value_take_boxed (value, gerror);
369         return 0;
370     }
371
372     return -1;
373 }
374
375 void
376 pygi_error_register_types (PyObject *module)
377 {
378     PyObject *error_module = PyImport_ImportModule ("gi._error");
379     if (!error_module) {
380         return;
381     }
382
383     /* Stash a reference to the Python implemented gi._error.GError. */
384     PyGError = PyObject_GetAttrString (error_module, "GError");
385
386     pyg_register_gtype_custom (G_TYPE_ERROR,
387                                pygerror_from_gvalue,
388                                pygerror_to_gvalue);
389 }
390