[pygobject] Add namespace and container name to callable cache and include them in all warnings/error messages.



commit a10df7d28c01d70ee33d8e4e9ddaa23f1990ca60
Author: Christoph Reiter <reiter christoph gmail com>
Date:   Tue Jan 27 19:13:54 2015 +0100

    Add namespace and container name to callable cache and include them in all warnings/error messages.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=743468

 gi/pygi-cache.c          |   39 ++++++++++++++++++++++++++++++++++-----
 gi/pygi-cache.h          |    5 +++++
 gi/pygi-closure.c        |    4 +++-
 gi/pygi-invoke.c         |   41 +++++++++++++++++++++++++++++------------
 tests/test_everything.py |    2 +-
 tests/test_gi.py         |   28 ++++++++++++++++++----------
 6 files changed, 90 insertions(+), 29 deletions(-)
---
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
index a572929..ca24517 100644
--- a/gi/pygi-cache.c
+++ b/gi/pygi-cache.c
@@ -657,6 +657,7 @@ _callable_cache_init (PyGICallableCache *cache,
                       GICallableInfo *callable_info)
 {
     gint n_args;
+    GIBaseInfo *container;
 
     if (cache->deinit == NULL)
         cache->deinit = _callable_cache_deinit_real;
@@ -665,18 +666,27 @@ _callable_cache_init (PyGICallableCache *cache,
         cache->generate_args_cache = _callable_cache_generate_args_cache_real;
 
     cache->name = g_base_info_get_name ((GIBaseInfo *) callable_info);
+    cache->namespace = g_base_info_get_namespace ((GIBaseInfo *) callable_info);
+    container = g_base_info_get_container ((GIBaseInfo *) callable_info);
+    cache->container_name = NULL;
+    /* https://bugzilla.gnome.org/show_bug.cgi?id=709456 */
+    if (container != NULL && g_base_info_get_type (container) != GI_INFO_TYPE_TYPE) {
+        cache->container_name = g_base_info_get_name (container);
+    }
     cache->throws = g_callable_info_can_throw_gerror ((GIBaseInfo *) callable_info);
 
     if (g_base_info_is_deprecated (callable_info)) {
         const gchar *deprecated = g_base_info_get_attribute (callable_info, "deprecated");
         gchar *warning;
+        gchar *full_name = pygi_callable_cache_get_full_name (cache);
         if (deprecated != NULL)
-            warning = g_strdup_printf ("%s.%s is deprecated: %s",
-                                       g_base_info_get_namespace (callable_info), cache->name,
+            warning = g_strdup_printf ("%s is deprecated: %s",
+                                       full_name,
                                        deprecated);
         else
-            warning = g_strdup_printf ("%s.%s is deprecated",
-                                       g_base_info_get_namespace (callable_info), cache->name);
+            warning = g_strdup_printf ("%s is deprecated",
+                                       full_name);
+        g_free (full_name);
         PyErr_WarnEx (PyExc_DeprecationWarning, warning, 0);
         g_free (warning);
     }
@@ -696,6 +706,23 @@ _callable_cache_init (PyGICallableCache *cache,
     return TRUE;
 }
 
+gchar *
+pygi_callable_cache_get_full_name (PyGICallableCache *cache)
+{
+    if (cache->container_name != NULL) {
+        return g_strjoin (".",
+                          cache->namespace,
+                          cache->container_name,
+                          cache->name,
+                          NULL);
+    } else {
+        return g_strjoin (".",
+                          cache->namespace,
+                          cache->name,
+                          NULL);
+    }
+}
+
 void
 pygi_callable_cache_free (PyGICallableCache *cache)
 {
@@ -845,11 +872,13 @@ _constructor_cache_invoke_real (PyGIFunctionCache *function_cache,
 
     constructor_class = PyTuple_GetItem (py_args, 0);
     if (constructor_class == NULL) {
+        gchar *full_name = pygi_callable_cache_get_full_name (cache);
         PyErr_Clear ();
         PyErr_Format (PyExc_TypeError,
                       "Constructors require the class to be passed in as an argument, "
                       "No arguments passed to the %s constructor.",
-                      ((PyGICallableCache *) function_cache)->name);
+                      full_name);
+        g_free (full_name);
 
         return FALSE;
     }
diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h
index 0361f00..098f3f1 100644
--- a/gi/pygi-cache.h
+++ b/gi/pygi-cache.h
@@ -158,6 +158,8 @@ typedef struct _PyGIInterfaceCache
 struct _PyGICallableCache
 {
     const gchar *name;
+    const gchar *container_name;
+    const gchar *namespace;
 
     PyGICallingContext calling_context;
 
@@ -265,6 +267,9 @@ pygi_arg_cache_free      (PyGIArgCache *cache);
 void
 pygi_callable_cache_free    (PyGICallableCache *cache);
 
+gchar *
+pygi_callable_cache_get_full_name (PyGICallableCache *cache);
+
 PyGIFunctionCache *
 pygi_function_cache_new     (GICallableInfo *info);
 
diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c
index 2a5a120..65f7e55 100644
--- a/gi/pygi-closure.c
+++ b/gi/pygi-closure.c
@@ -777,10 +777,12 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
         if (user_data_cache != NULL) {
             state->arg_values[destroy_cache->c_arg_index].v_pointer = _pygi_invoke_closure_free;
         } else {
+            char *full_name = pygi_callable_cache_get_full_name (callable_cache);
             gchar *msg = g_strdup_printf("Callables passed to %s will leak references because "
                                          "the method does not support a user_data argument. "
                                          "See: https://bugzilla.gnome.org/show_bug.cgi?id=685598";,
-                                         callable_cache->name);
+                                         full_name);
+            g_free (full_name);
             if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 2)) {
                 g_free(msg);
                 _pygi_invoke_closure_free(closure);
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index a65274a..0151650 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -26,7 +26,7 @@
 #include "pygi-error.h"
 
 static gboolean
-_check_for_unexpected_kwargs (const gchar *function_name,
+_check_for_unexpected_kwargs (PyGICallableCache *cache,
                               GHashTable  *arg_name_hash,
                               PyObject    *py_kwargs)
 {
@@ -54,11 +54,13 @@ _check_for_unexpected_kwargs (const gchar *function_name,
          * found which maps to index 0 for our hash lookup.
          */
         if (!g_hash_table_lookup_extended (arg_name_hash, PyBytes_AsString(key), NULL, NULL)) {
+            char *full_name = pygi_callable_cache_get_full_name (cache);
             PyErr_Format (PyExc_TypeError,
                           "%.200s() got an unexpected keyword argument '%.400s'",
-                          function_name,
+                          full_name,
                           PyBytes_AsString (key));
             Py_DECREF (key);
+            g_free (full_name);
             return FALSE;
         }
 
@@ -84,7 +86,6 @@ _py_args_combine_and_check_length (PyGICallableCache *cache,
     Py_ssize_t n_py_args, n_py_kwargs, i;
     guint n_expected_args;
     GSList *l;
-    const gchar *function_name = cache->name;
 
     n_py_args = PyTuple_GET_SIZE (py_args);
     if (py_kwargs == NULL)
@@ -100,24 +101,28 @@ _py_args_combine_and_check_length (PyGICallableCache *cache,
     }
 
     if (cache->user_data_varargs_index < 0 && n_expected_args < n_py_args) {
+        char *full_name = pygi_callable_cache_get_full_name (cache);
         PyErr_Format (PyExc_TypeError,
                       "%.200s() takes exactly %d %sargument%s (%zd given)",
-                      function_name,
+                      full_name,
                       n_expected_args,
                       n_py_kwargs > 0 ? "non-keyword " : "",
                       n_expected_args == 1 ? "" : "s",
                       n_py_args);
+        g_free (full_name);
         return NULL;
     }
 
     if (cache->user_data_varargs_index >= 0 && n_py_kwargs > 0 && n_expected_args < n_py_args) {
+        char *full_name = pygi_callable_cache_get_full_name (cache);
         PyErr_Format (PyExc_TypeError,
                       "%.200s() cannot use variable user data arguments with keyword arguments",
-                      function_name);
+                      full_name);
+        g_free (full_name);
         return NULL;
     }
 
-    if (n_py_kwargs > 0 && !_check_for_unexpected_kwargs (function_name,
+    if (n_py_kwargs > 0 && !_check_for_unexpected_kwargs (cache,
                                                           cache->arg_name_hash,
                                                           py_kwargs)) {
         return NULL;
@@ -183,24 +188,28 @@ _py_args_combine_and_check_length (PyGICallableCache *cache,
                 Py_INCREF (_PyGIDefaultArgPlaceholder);
                 PyTuple_SET_ITEM (combined_py_args, i, _PyGIDefaultArgPlaceholder);
             } else {
+                char *full_name = pygi_callable_cache_get_full_name (cache);
                 PyErr_Format (PyExc_TypeError,
                               "%.200s() takes exactly %d %sargument%s (%zd given)",
-                              function_name,
+                              full_name,
                               n_expected_args,
                               n_py_kwargs > 0 ? "non-keyword " : "",
                               n_expected_args == 1 ? "" : "s",
                               n_py_args);
+                g_free (full_name);
 
                 Py_DECREF (combined_py_args);
                 return NULL;
             }
         } else if (kw_arg_item != NULL && py_arg_item != NULL) {
+            char *full_name = pygi_callable_cache_get_full_name (cache);
             PyErr_Format (PyExc_TypeError,
                           "%.200s() got multiple values for keyword argument '%.200s'",
-                          function_name,
+                          full_name,
                           arg_name);
 
             Py_DECREF (combined_py_args);
+            g_free (full_name);
             return NULL;
         }
     }
@@ -362,11 +371,13 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac
     gssize i;
 
     if (state->n_py_in_args > cache->n_py_args) {
+        char *full_name = pygi_callable_cache_get_full_name (cache);
         PyErr_Format (PyExc_TypeError,
                       "%s() takes exactly %zd argument(s) (%zd given)",
-                      cache->name,
+                      full_name,
                       cache->n_py_args,
                       state->n_py_in_args);
+        g_free (full_name);
         return FALSE;
     }
 
@@ -387,11 +398,13 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac
                     continue;
 
                 if (arg_cache->py_arg_index >= state->n_py_in_args) {
+                    char *full_name = pygi_callable_cache_get_full_name (cache);
                     PyErr_Format (PyExc_TypeError,
                                   "%s() takes exactly %zd argument(s) (%zd given)",
-                                   cache->name,
+                                   full_name,
                                    cache->n_py_args,
                                    state->n_py_in_args);
+                    g_free (full_name);
 
                     /* clean up all of the args we have already marshalled,
                      * since invoke will not be called
@@ -410,11 +423,13 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac
             case PYGI_DIRECTION_BIDIRECTIONAL:
                 if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) {
                     if (arg_cache->py_arg_index >= state->n_py_in_args) {
+                        char *full_name = pygi_callable_cache_get_full_name (cache);
                         PyErr_Format (PyExc_TypeError,
                                       "%s() takes exactly %zd argument(s) (%zd given)",
-                                       cache->name,
+                                       full_name,
                                        cache->n_py_args,
                                        state->n_py_in_args);
+                        g_free (full_name);
                         pygi_marshal_cleanup_args_from_py_parameter_fail (state,
                                                                           cache,
                                                                           i);
@@ -446,9 +461,11 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac
                     state->args[i] = c_arg;
 
                     if (!_caller_alloc (arg_cache, c_arg)) {
+                        char *full_name = pygi_callable_cache_get_full_name (cache);
                         PyErr_Format (PyExc_TypeError,
                                       "Could not caller allocate argument %zd of callable %s",
-                                      i, cache->name);
+                                      i, full_name);
+                        g_free (full_name);
                         pygi_marshal_cleanup_args_from_py_parameter_fail (state,
                                                                           cache,
                                                                           i);
diff --git a/tests/test_everything.py b/tests/test_everything.py
index 88b6da1..b8a37f1 100644
--- a/tests/test_everything.py
+++ b/tests/test_everything.py
@@ -322,7 +322,7 @@ class TestEverything(unittest.TestCase):
             Everything.test_int8()
         except TypeError:
             (e_type, e) = sys.exc_info()[:2]
-            self.assertEqual(e.args, ("test_int8() takes exactly 1 argument (0 given)",))
+            self.assertEqual(e.args, ("Regress.test_int8() takes exactly 1 argument (0 given)",))
 
     def test_gtypes(self):
         gchararray_gtype = GObject.type_from_name('gchararray')
diff --git a/tests/test_gi.py b/tests/test_gi.py
index 9633f57..dc40f3c 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -2636,29 +2636,29 @@ class TestKeywordArgs(unittest.TestCase):
 
     def test_type_errors(self):
         # test too few args
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (0 given)",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 
arguments (0 given)",
                                  GIMarshallingTests.int_three_in_three_out)
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (1 given)",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 
arguments (1 given)",
                                  GIMarshallingTests.int_three_in_three_out, 1)
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (0 given)",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 
arguments (0 given)",
                                  GIMarshallingTests.int_three_in_three_out, *())
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (0 given)",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 
arguments (0 given)",
                                  GIMarshallingTests.int_three_in_three_out, *(), **{})
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 non-keyword arguments 
(0 given)",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 
non-keyword arguments (0 given)",
                                  GIMarshallingTests.int_three_in_three_out, *(), **{'c': 4})
 
         # test too many args
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 arguments (4 given)",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 
arguments (4 given)",
                                  GIMarshallingTests.int_three_in_three_out, *(1, 2, 3, 4))
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() takes exactly 3 non-keyword arguments 
(4 given)",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 
non-keyword arguments (4 given)",
                                  GIMarshallingTests.int_three_in_three_out, *(1, 2, 3, 4), c=6)
 
         # test too many keyword args
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() got multiple values for keyword 
argument 'a'",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() got multiple values 
for keyword argument 'a'",
                                  GIMarshallingTests.int_three_in_three_out, 1, 2, 3, **{'a': 4, 'b': 5})
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() got an unexpected keyword argument 
'd'",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() got an unexpected 
keyword argument 'd'",
                                  GIMarshallingTests.int_three_in_three_out, d=4)
-        self.assertRaisesMessage(TypeError, "int_three_in_three_out() got an unexpected keyword argument 
'e'",
+        self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() got an unexpected 
keyword argument 'e'",
                                  GIMarshallingTests.int_three_in_three_out, **{'e': 2})
 
     def test_kwargs_are_not_modified(self):
@@ -2780,6 +2780,14 @@ class TestDeprecation(unittest.TestCase):
             warnings.simplefilter('always')
             d.set_time(1)
             self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
+            self.assertEqual(str(warn[0].message), "GLib.Date.set_time is deprecated")
+
+    def test_function(self):
+        with warnings.catch_warnings(record=True) as warn:
+            warnings.simplefilter('always')
+            GLib.strcasecmp("foo", "bar")
+            self.assertTrue(issubclass(warn[0].category, DeprecationWarning))
+            self.assertEqual(str(warn[0].message), "GLib.strcasecmp is deprecated")
 
     def test_deprecated_init_no_keywords(self):
         def init(self, **kwargs):


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