Re: [pygtk] Gobject properties to PyObject attributes mapping
Jan Weil schrieb: I don't like this idea either. Especially because it's quite easy to emulate this behaviour in Python (see example attached). That's obviously not an option if you had to wrap every gtk widget by hand. This one wouldn't let me sleep. But it's really fun (see example attached). Good night, Jan import gobject import gtk import new import types class MyObject: def __init__(self): if issubclass(self.__class__, gobject.GObject): self.properties = [] for param in gobject.list_properties(self): self.properties.append(param.name) def __setattr__(self, key, value): self.__dict__[key] = value if hasattr(self, "properties") and key in self.properties: self.set_property(key, value) def __getattr__(self, key): if hasattr(self, "properties") and key in self.properties: return self.get_property(key) else: return self.__dict__.get(key, None) __dict__ = globals() for _o in gtk.__dict__.values(): if type(_o) is types.TypeType and issubclass(_o, gtk.Widget): def __init__(self, *args, **keys): self.__gtk_class.__init__(self, *args, **keys) MyObject.__init__(self) __dict__[_o.__name__] = new.classobj(_o.__name__, (MyObject, _o), {"__init__": __init__, "__gtk_class": _o}) #!/usr/bin/env python import gtk import mygtk b = mygtk.Button(label = "Hello, world!") def on_clicked(*args): b.label = b.label + "\nHello, world!" print b.get_property("label") b.connect("clicked", on_clicked) w = mygtk.Window() w.add(b) w.show_all() gtk.main() ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
Iñaki García Etxebarria schrieb: But IMO the main question is whether it is really advantageously to map the properties to attributes. I think so, it produces readable code, and many times is very natural. And, to me at least, the design of the properties api in gobject is thought with this kind of purposes in mind. I totally agree that the code becomes more readable and even more beautiful. I am by no means an expert of OOP but what I read is that public data members in the long run tend to be unflexible. Thus you typically provide a pair of accessors like set_value, get_value (set_property/get_property). But probably my view is not pythonesque (?) enough. Eventually, these attributes only look like public data members and what happens internally if they are accessed is still under control. Jan ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
This may not be a democracy, but I would vote against this change. Merging namespaces like this is asking for trouble. If it is done at all, it should only be at the explicit request of the programmer (e.g., import gtk.__propertyHack__ as gtk). On Fri, 2003-08-08 at 15:20, Iñaki García Etxebarria wrote: > IMHO, there are more advantages than disadvantages [just put a big fat > warning in the next few releases or something], but that is left to the > maintainers to decide. ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
Christian Reis kiko at async.com.br wrote: Ah; Note that this is wrong here. You should not return None from getattr, or all lookups on the object for non-existent attributes will return None. This should be: try: return self.__dict__[key] except KeyError: raise AttributeError, key See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52238 Thanks, I wasn't aware of that one! You could skip the if self.__properties there, but since setattr can potentially be called a lot and the list of properties is long, it might save some (potentially infinitesimal ) time. (PS: I'm not sharp on how the 'in' operator is implemented; if it's a constant-time operation then this is silly and you can skip the self.__properties check). Well this code was by no means optimized. It was more something like a proof of concept (for myself). But IMO the main question is whether it is really advantageously to map the properties to attributes. What about read-only properties? Can you control the access to certain properties? Jan ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
On Mon, Aug 11, 2003 at 01:11:01AM +0200, Jan Weil wrote: > I am by no means an expert of OOP but what I read is that public data > members in the long run tend to be unflexible. > Thus you typically provide a pair of accessors like set_value, get_value > (set_property/get_property). Well, it could be argued that providing accessors is only a more elegant way of making private data public . The line is hard to draw, but I would say in the general case of a *widget*, having properties as attributes makes a lot of sense and simplifies code significantly. Yes, you get an increased change of a namespace conflict with user code, but I find it sanitizes things if the properties are well-named: dorothy_label.label = "This doesn't look like Kansas anymore" dorothy_label.justify = JUSTIFY_LEFT -- should really do the obvious (and not set vaporous "label" and "justify" attributes that have nothing to do with the label's behaviour). > Eventually, these attributes only look like public data members and what > happens internally if they are accessed is still under control. Yes, you can always use Python properties to control access to instance attributes. Take care, -- Christian Reis, Senior Engineer, Async Open Source, Brazil. http://async.com.br/~kiko/ | [+55 16] 261 2331 | NMFL ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
On Sun, Aug 10, 2003 at 11:36:05AM +0200, Jan Weil wrote: > Did you try this code? Are you suggesting I don't test my code submissions? :o) No; I don't have PyGTK2 available on my network. > The problem is that if you assign to __properties in __init__, > __setattr__ is called which calls __getattr__ in the if clause but > __properties isn't set yet --> recursion > Therefor you have to treat the internal properties list attribute in a > special manner and that's why I couldn't hide it (__*). Yeah, my bad. Just do it a tiny bit differently: > Christian Reis kiko at async.com.br wrote: > > You could get away with something a bit simpler even: > > > > class MyObject: > > def __init__(self): > > if issubclass(self.__class__, gobject.GObject): > > self.__properties = list(gobject.list_properties(self) > > else: > > self.__properties = [] if isinstance(self, gobject.GObject): props = list(gobject.list_properties(self) else: props = [] self.__dict__['_MyObject__properties'] = props The name mangling needs to be done or else the lookup below will fail. > > def __setattr__(self, key, value): > > if self.__properties and key in self.__properties: > > self.set_property(key, value) > > else: > > self.__dict__[key] = value > > > > def __getattr__(self, key): > > if self.__properties and key in self.__properties: > > return self.get_property(key) > > else: > > return self.__dict__.get(key, None) Ah; Note that this is wrong here. You should not return None from getattr, or all lookups on the object for non-existent attributes will return None. This should be: try: return self.__dict__[key] except KeyError: raise AttributeError, key See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52238 You could skip the if self.__properties there, but since setattr can potentially be called a lot and the list of properties is long, it might save some (potentially infinitesimal ) time. (PS: I'm not sharp on how the 'in' operator is implemented; if it's a constant-time operation then this is silly and you can skip the self.__properties check). Take care, -- Christian Reis, Senior Engineer, Async Open Source, Brazil. http://async.com.br/~kiko/ | [+55 16] 261 2331 | NMFL ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
El vie, 08-08-2003 a las 15:07, Gustavo J. A. M. Carneiro escribió: > > label = gtk.Label() > > label.label = 'Hello World' # Changes the label in the gui > > print label.label # prints 'Hello World' > > Perhaps it is wiser to add a small prefix to the python attribute, to > avoid possible conflicts with user code? Example: I agree there could be a conflict, honestly I don't know how can we avoid this without adding the prefix (which sort of defeats the purpose of the patch, which is transparent, elegant access to properties). There's certainly code that will break, see for example examples/gobject/properties.py in the pygtk distribution. On the other hand, that's the only thing pygtk code I have seen that breaks, and it is trivial to fix (prefix the internal class variable foo with prop_ to avoid the recursion, for example). IMHO, there are more advantages than disadvantages [just put a big fat warning in the next few releases or something], but that is left to the maintainers to decide. Kind regards, Iñaki ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
> But IMO the main question is whether it is really advantageously to map > the properties to attributes. I think so, it produces readable code, and many times is very natural. And, to me at least, the design of the properties api in gobject is thought with this kind of purposes in mind. > What about read-only properties? It's easy to check this when __set__ is called. If the property is readonly emit a Type Error and put an informative error description, as done in other parts of Python. It wasn't in my patch, but it's three-four lines if you want it. > Can you control the access to certain properties? What for? Sorry, I don't see the point in this, cannot you always use the normal "function" api anyway? Iñaki ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
On Sun, Aug 10, 2003 at 03:55:56AM +0200, Jan Weil wrote: > Good night, > > class MyObject: > def __init__(self): > if issubclass(self.__class__, gobject.GObject): > self.properties = [] > for param in gobject.list_properties(self): > self.properties.append(param.name) > > def __setattr__(self, key, value): > self.__dict__[key] = value > if hasattr(self, "properties") and key in self.properties: > self.set_property(key, value) > > def __getattr__(self, key): > if hasattr(self, "properties") and key in self.properties: > return self.get_property(key) > else: > return self.__dict__.get(key, None) You could get away with something a bit simpler even: class MyObject: def __init__(self): if issubclass(self.__class__, gobject.GObject): self.__properties = list(gobject.list_properties(self)) else: self.__properties = [] def __setattr__(self, key, value): if self.__properties and key in self.__properties: self.set_property(key, value) else: self.__dict__[key] = value def __getattr__(self, key): if self.__properties and key in self.__properties: return self.get_property(key) else: return self.__dict__.get(key, None) Take care, -- Christian Reis, Senior Engineer, Async Open Source, Brazil. http://async.com.br/~kiko/ | [+55 16] 261 2331 | NMFL ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
I don't like this idea either. Especially because it's quite easy to emulate this behaviour in Python (see example attached). Jan Jon Willeke schrieb: This may not be a democracy, but I would vote against this change. Merging namespaces like this is asking for trouble. If it is done at all, it should only be at the explicit request of the programmer (e.g., import gtk.__propertyHack__ as gtk). On Fri, 2003-08-08 at 15:20, Iñaki García Etxebarria wrote: IMHO, there are more advantages than disadvantages [just put a big fat warning in the next few releases or something], but that is left to the maintainers to decide. #!/usr/bin/env python import gobject import gtk class MyObject: def __init__(self): if issubclass(self.__class__, gobject.GObject): self.properties = [] for param in gobject.list_properties(self): self.properties.append(param.name) def __setattr__(self, key, value): self.__dict__[key] = value if hasattr(self, "properties") and key in self.properties: self.set_property(key, value) class MyLabel(MyObject, gtk.Label): def __init__(self, str=None): gtk.Label.__init__(self, str) MyObject.__init__(self) if __name__ == "__main__": w = gtk.Window() l = MyLabel() l.label = "Hello, world!" print l.label w.add(l) w.show_all() gtk.main() ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
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; iowner_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_pro
Re: [pygtk] Gobject properties to PyObject attributes mapping
A Qui, 2003-08-07 às 19:22, Iñaki García Etxebarria escreveu: > Howdy everyone, > > Attached goes a patch against pygtk 1.99.17 that lets you do things like > --- > label = gtk.Label() > label.label = 'Hello World' # Changes the label in the gui > print label.label # prints 'Hello World' Perhaps it is wiser to add a small prefix to the python attribute, to avoid possible conflicts with user code? Example: label = gtk.Label() label.prop_label = 'Hello World' # Changes the label in the gui print label.prop_label # prints 'Hello World' Or maybe not... Either way is fine by me, I think this is a great idea. > --- > for any gobject. I.e., setting gobject properties as if they were > regular attributes. I hope this hasn't been decided against before, imho > it is nice sugar. > > I'm a novice with Python and not an expert with gtk2, so I don't expect > it to be accepted (the method is certainly not optimal and probably not > Pythonesque in style), but hopefully it will inspire someone to > implement the feature properly. > > Kind regards, > Iñaki > > __ > ___ > pygtk mailing list [EMAIL PROTECTED] > http://www.daa.com.au/mailman/listinfo/pygtk > Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/ -- Gustavo João Alves Marques Carneiro <[EMAIL PROTECTED]> <[EMAIL PROTECTED]> ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
Re: [pygtk] Gobject properties to PyObject attributes mapping
On Thu, Aug 07, 2003 at 08:22:06PM +0200, Iñaki García Etxebarria wrote: > Howdy everyone, > > Attached goes a patch against pygtk 1.99.17 that lets you do things like > --- > label = gtk.Label() > label.label = 'Hello World' # Changes the label in the gui > print label.label # prints 'Hello World' > --- > for any gobject. I.e., setting gobject properties as if they were > regular attributes. I hope this hasn't been decided against before, imho > it is nice sugar. > > I'm a novice with Python and not an expert with gtk2, so I don't expect > it to be accepted (the method is certainly not optimal and probably not > Pythonesque in style), but hopefully it will inspire someone to > implement the feature properly. +1 by me. I'm for this change, and I've discussed it with other people on #pygtk before (Joe Shaw, IIRC, and Johan). Take care, -- Christian Reis, Senior Engineer, Async Open Source, Brazil. http://async.com.br/~kiko/ | [+55 16] 261 2331 | NMFL ___ pygtk mailing list [EMAIL PROTECTED] http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/