[pygobject] Check the type of the instance object



commit 98f54f9d33996baeaa8c8c1240310f5396d03a1d
Author: John (J5) Palmieri <johnp redhat com>
Date:   Tue Sep 14 14:10:49 2010 -0400

    Check the type of the instance object
    
    * in python 2 methods were added to classes as unbound methods and they would
      check the instance type to make sure it was correct
    * in python 3 for perfomance reasons methods are added to classes as simple
      functions which treat the instance as an untyped argument so no checks
      are made.
    * this patch adds a type check so that the correct errors are thrown in
      python 3 (python 2 this just adds another layer of redundancy should
      something change with type checking in the future)
    * since GI handles regular args and the instance arg slightly differently
      we had to split out the interface checks in _pygi_g_type_info_check_object
      in order to not duplicate code
    
    https://bugzilla.gnome.org/show_bug.cgi?id=615872

 gi/pygi-argument.c |  182 +++++++++++++++++++++++++++------------------------
 gi/pygi-argument.h |    2 +
 gi/pygi-invoke.c   |   14 ++++
 3 files changed, 112 insertions(+), 86 deletions(-)
---
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index 301a767..82d5855 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -161,6 +161,101 @@ _pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info,
 }
 
 gint
+_pygi_g_type_interface_check_object (GIBaseInfo *info,
+                                     PyObject   *object)
+{
+    gint retval = 1;
+    GIInfoType info_type;
+
+    info_type = g_base_info_get_type (info);
+    switch (info_type) {
+        case GI_INFO_TYPE_CALLBACK:
+            if (!PyCallable_Check (object)) {
+                PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+                              object->ob_type->tp_name);
+                retval = 0;
+            }
+            break;
+        case GI_INFO_TYPE_ENUM:
+            retval = 0;
+            if (PyNumber_Check (object)) {
+                PyObject *number = PYGLIB_PyNumber_Long (object);
+                if (number == NULL)
+                    PyErr_Clear();
+                else {
+                    glong value = PYGLIB_PyLong_AsLong (number);
+                    int i;
+                    for (i = 0; i < g_enum_info_get_n_values (info); i++) {
+                        GIValueInfo *value_info = g_enum_info_get_value (info, i);
+                        glong enum_value = g_value_info_get_value (value_info);
+                        if (value == enum_value) {
+                            retval = 1;
+                            break;
+                        }
+                    }
+                }
+            }
+            if (retval < 1)
+                retval = _pygi_g_registered_type_info_check_object (
+                             (GIRegisteredTypeInfo *) info, TRUE, object);
+            break;
+        case GI_INFO_TYPE_FLAGS:
+            if (PyNumber_Check (object)) {
+                /* Accept 0 as a valid flag value */
+                PyObject *number = PYGLIB_PyNumber_Long (object);
+                if (number == NULL)
+                    PyErr_Clear();
+                else {
+                    long value = PYGLIB_PyLong_AsLong (number);
+                    if (value == 0)
+                        break;
+                    else if (value == -1)
+                        PyErr_Clear();
+                }
+            }
+            retval = _pygi_g_registered_type_info_check_object (
+                         (GIRegisteredTypeInfo *) info, TRUE, object);
+            break;
+        case GI_INFO_TYPE_STRUCT:
+        {
+            GType type;
+
+            /* Handle special cases. */
+            type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
+            if (g_type_is_a (type, G_TYPE_VALUE)) {
+                GType object_type;
+                object_type = pyg_type_from_object ( (PyObject *) object->ob_type);
+                if (object_type == G_TYPE_INVALID) {
+                    PyErr_Format (PyExc_TypeError, "Must be of a known GType, not %s",
+                                  object->ob_type->tp_name);
+                    retval = 0;
+                }
+                break;
+            } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
+                if (!PyCallable_Check (object)) {
+                    PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
+                                  object->ob_type->tp_name);
+                    retval = 0;
+                }
+                break;
+            }
+
+            /* Fallback. */
+        }
+        case GI_INFO_TYPE_BOXED:
+        case GI_INFO_TYPE_INTERFACE:
+        case GI_INFO_TYPE_OBJECT:
+        case GI_INFO_TYPE_UNION:
+            retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object);
+            break;
+        default:
+            g_assert_not_reached();
+    }
+
+    return retval;
+}
+
+gint
 _pygi_g_type_info_check_object (GITypeInfo *type_info,
                                 PyObject   *object,
                                 gboolean   allow_none)
@@ -346,96 +441,11 @@ check_number_release:
         case GI_TYPE_TAG_INTERFACE:
         {
             GIBaseInfo *info;
-            GIInfoType info_type;
 
             info = g_type_info_get_interface (type_info);
             g_assert (info != NULL);
 
-            info_type = g_base_info_get_type (info);
-
-            switch (info_type) {
-                case GI_INFO_TYPE_CALLBACK:
-                    if (!PyCallable_Check (object)) {
-                        PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
-                                      object->ob_type->tp_name);
-                        retval = 0;
-                    }
-                    break;
-                case GI_INFO_TYPE_ENUM:
-                    retval = 0;
-                    if (PyNumber_Check (object)) {
-                        PyObject *number = PYGLIB_PyNumber_Long (object);
-                        if (number == NULL)
-                            PyErr_Clear();
-                        else {
-                            glong value = PYGLIB_PyLong_AsLong (number);
-                            int i;
-                            for (i = 0; i < g_enum_info_get_n_values (info); i++) {
-                                GIValueInfo *value_info = g_enum_info_get_value (info, i);
-                                glong enum_value = g_value_info_get_value (value_info);
-                                if (value == enum_value) {
-                                    retval = 1;
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                    if (retval < 1)
-                        retval = _pygi_g_registered_type_info_check_object (
-                                     (GIRegisteredTypeInfo *) info, TRUE, object);
-                    break;
-                case GI_INFO_TYPE_FLAGS:
-                    if (PyNumber_Check (object)) {
-                        /* Accept 0 as a valid flag value */
-                        PyObject *number = PYGLIB_PyNumber_Long (object);
-                        if (number == NULL)
-                            PyErr_Clear();
-                        else {
-                            long value = PYGLIB_PyLong_AsLong (number);
-                            if (value == 0)
-                                break;
-                            else if (value == -1)
-                                PyErr_Clear();
-                        }
-                    }
-                    retval = _pygi_g_registered_type_info_check_object (
-                                 (GIRegisteredTypeInfo *) info, TRUE, object);
-                    break;
-                case GI_INFO_TYPE_STRUCT:
-                {
-                    GType type;
-
-                    /* Handle special cases. */
-                    type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
-                    if (g_type_is_a (type, G_TYPE_VALUE)) {
-                        GType object_type;
-                        object_type = pyg_type_from_object ( (PyObject *) object->ob_type);
-                        if (object_type == G_TYPE_INVALID) {
-                            PyErr_Format (PyExc_TypeError, "Must be of a known GType, not %s",
-                                          object->ob_type->tp_name);
-                            retval = 0;
-                        }
-                        break;
-                    } else if (g_type_is_a (type, G_TYPE_CLOSURE)) {
-                        if (!PyCallable_Check (object)) {
-                            PyErr_Format (PyExc_TypeError, "Must be callable, not %s",
-                                          object->ob_type->tp_name);
-                            retval = 0;
-                        }
-                        break;
-                    }
-
-                    /* Fallback. */
-                }
-                case GI_INFO_TYPE_BOXED:
-                case GI_INFO_TYPE_INTERFACE:
-                case GI_INFO_TYPE_OBJECT:
-                case GI_INFO_TYPE_UNION:
-                    retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object);
-                    break;
-                default:
-                    g_assert_not_reached();
-            }
+            retval = _pygi_g_type_interface_check_object(info, object);
 
             g_base_info_unref (info);
             break;
diff --git a/gi/pygi-argument.h b/gi/pygi-argument.h
index ee5d661..d932e8f 100644
--- a/gi/pygi-argument.h
+++ b/gi/pygi-argument.h
@@ -30,6 +30,8 @@ G_BEGIN_DECLS
 
 
 /* Private */
+gint _pygi_g_type_interface_check_object (GIBaseInfo *info,
+                                          PyObject   *object);
 
 gint _pygi_g_type_info_check_object (GITypeInfo *type_info,
                                      PyObject   *object,
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index 52fddcf..014164e 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -379,6 +379,7 @@ _prepare_invocation_state (struct invocation_state *state,
             GIBaseInfo *container_info;
             GIInfoType container_info_type;
             PyObject *py_arg;
+            gint check_val;
 
             container_info = g_base_info_get_container (function_info);
             container_info_type = g_base_info_get_type (container_info);
@@ -386,6 +387,19 @@ _prepare_invocation_state (struct invocation_state *state,
             g_assert (py_args_pos < state->n_py_args);
             py_arg = PyTuple_GET_ITEM (py_args, py_args_pos);
 
+            /* In python 2 python takes care of checking the type
+             * of the self instance.  In python 3 it does not
+             * so we have to check it here
+             */
+            check_val = _pygi_g_type_interface_check_object(container_info,
+                                                            py_arg);
+            if (check_val < 0) {
+                return FALSE;
+            } else if (!check_val) {
+                _PyGI_ERROR_PREFIX ("instance: ");
+                return FALSE;
+            }
+
             switch (container_info_type) {
                 case GI_INFO_TYPE_UNION:
                 case GI_INFO_TYPE_STRUCT:



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