Hi, El dom, 10-08-2003 a las 01:04, Jan Weil escribió: > I don't like this idea either. > Especially because it's quite easy to emulate this behaviour in Python > (see example attached). Well, as long as I can write the Python code as I want, I don't care much about the underlying implementation :-) So I'm OK if I can do what you suggest (or if I have to do 'from gtk import iñaki_is_on_crack', as another message suggested).
That said, and inspired by bug 81879 in gnome-python bugzilla, attached goes a descriptor implementation of the same behavior (hey, we can all have some fun coding weird stuff ;-)). This should make the binding of the properties rather elegant, now you can do help(gtk.Label) and you get a list with the attributes with their corresponding documentation (in case gtk provides any), gtk.Label.label.__doc__ works too, of course. This means less confusion if things don't behave as expected. dir(gtk.Label) lists the attributes as regular attributes, which it didn't do in my previous patch. In three words, completely transparent access. I would do the 'from gtk import crack' thingie but I have no clue on how to do that. Enjoy, Iñaki
--- ../pygobject.c Thu Jul 31 15:10:16 2003 +++ pygobject.c Sun Aug 10 20:28:51 2003 @@ -80,6 +80,87 @@ g_array_append_val(sink_funcs, sf); } +static PyObject * +pygobject_get_prop_descr(PyGObject *self, char *param_name) +{ + GParamSpec *pspec; + GValue value = { 0, }; + PyObject *ret; + + pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj), + param_name); + if (!pspec) { + PyErr_SetString(PyExc_TypeError, + "the object does not support the given parameter"); + return NULL; + } + g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); + g_object_get_property(self->obj, param_name, &value); + ret = pyg_value_as_pyobject(&value, TRUE); + g_value_unset(&value); + return ret; +} + +static int +pygobject_set_prop_descr(PyGObject *self, PyObject *pvalue, char *param_name) +{ + GParamSpec *pspec; + GValue value = { 0, }; + + pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj), + param_name); + if (!pspec) { + PyErr_SetString(PyExc_TypeError, + "the object does not support the given parameter"); + return -1; + } + g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); + if (pyg_value_from_pyobject(&value, pvalue) < 0) { + PyErr_SetString(PyExc_TypeError, + "could not convert argument to correct param type"); + return -1; + } + g_object_set_property(self->obj, param_name, &value); + g_value_unset(&value); + return 0; +} + +static void +pygobject_add_class_properties_as_descriptors (GType gtype, + PyTypeObject *type) +{ + GObjectClass *class; + GParamSpec **props; + guint n_props = 0, i; + PyObject *descr; + char *name, *prop_name; + PyGetSetDef *def; + + class = g_type_class_ref(gtype); + props = g_object_class_list_properties(class, &n_props); + for (i=0; i<n_props; i++) { + if (props[i]->owner_type != gtype) + continue; + + /* Python won't make a copy so we need the strdup */ + prop_name = g_strdup(g_param_spec_get_name(props[i])); + name = g_strdup(prop_name); + /* Convert '-' to '_' */ + g_strdelimit(name, "-", '_'); + def = g_new(struct PyGetSetDef, 1); + def->name = name; + def->doc = g_strdup(g_param_spec_get_blurb(props[i])); + def->closure = prop_name; + def->get = (getter)pygobject_get_prop_descr; + def->set = (setter)pygobject_set_prop_descr; + descr = PyDescr_NewGetSet(type, def); + PyDict_SetItemString(type->tp_dict, name, descr); + Py_DECREF(descr); + } + g_free (props); + g_type_class_unref (class); +} + /** * pygobject_register_class: * @dict: the module dictionary. A reference to the type will be stored here. @@ -122,6 +203,7 @@ type->tp_weaklistoffset = offsetof(PyGObject, weakreflist); type->tp_dictoffset = offsetof(PyGObject, inst_dict); + if (PyType_Ready(type) < 0) { g_warning ("couldn't make the type `%s' ready", type->tp_name); return; @@ -135,6 +217,9 @@ /* stash a pointer to the python class with the GType */ Py_INCREF(type); g_type_set_qdata(gtype, pygobject_class_key, type); + + /* add the class properties as member descriptors */ + pygobject_add_class_properties_as_descriptors(gtype, type); } /* set up __doc__ descriptor on type */ @@ -508,52 +593,26 @@ pygobject_get_property(PyGObject *self, PyObject *args) { gchar *param_name; - GParamSpec *pspec; - GValue value = { 0, }; - PyObject *ret; if (!PyArg_ParseTuple(args, "s:GObject.get_property", ¶m_name)) return NULL; - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj), - param_name); - if (!pspec) { - PyErr_SetString(PyExc_TypeError, - "the object does not support the given parameter"); - return NULL; - } - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - g_object_get_property(self->obj, param_name, &value); - ret = pyg_value_as_pyobject(&value, TRUE); - g_value_unset(&value); - return ret; + + return pygobject_get_prop_descr(self, param_name); } static PyObject * pygobject_set_property(PyGObject *self, PyObject *args) { gchar *param_name; - GParamSpec *pspec; - GValue value = { 0, }; PyObject *pvalue; if (!PyArg_ParseTuple(args, "sO:GObject.set_property", ¶m_name, &pvalue)) return NULL; - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj), - param_name); - if (!pspec) { - PyErr_SetString(PyExc_TypeError, - "the object does not support the given parameter"); - return NULL; - } - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - if (pyg_value_from_pyobject(&value, pvalue) < 0) { - PyErr_SetString(PyExc_TypeError, - "could not convert argument to correct param type"); + + if (pygobject_set_prop_descr(self, pvalue, param_name)) return NULL; - } - g_object_set_property(self->obj, param_name, &value); - g_value_unset(&value); + Py_INCREF(Py_None); return Py_None; }
_______________________________________________ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/