After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 123891 - gobject.PARAM_CONSTRUCT problem
gobject.PARAM_CONSTRUCT problem
Status: RESOLVED DUPLICATE of bug 161177
Product: pygobject
Classification: Bindings
Component: gobject
2.9.0
Other Linux
: Normal normal
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
Depends on: 305560
Blocks:
 
 
Reported: 2003-10-05 12:30 UTC by Lorenzo Gil Sanchez
Modified: 2006-01-09 14:11 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
code example (1.00 KB, text/plain)
2003-10-05 12:31 UTC, Lorenzo Gil Sanchez
Details

Description Lorenzo Gil Sanchez 2003-10-05 12:30:15 UTC
When creating a GObject property with the gobject.PARAM_CONSTRUCT flag the
gobject.GObject.__init__(self) calls the do_set_property() method with that
property initial value.

The problem is that the self object used in that do_set_property() call
during the initialization is different that the one returned by the call to
MyObject().

Run the example attached to understand what I mean
Comment 1 Lorenzo Gil Sanchez 2003-10-05 12:31:33 UTC
Created attachment 20475 [details]
code example
Comment 2 James Henstridge 2003-11-12 11:31:23 UTC
Just for reference, this is the sequence of events that happens when
you do instantiate an object that calls
__gobject_init__/GObject.__init__ in its constructor, and has custom
properties that get initialised:

[ foo is the instance, FooBar is the class below, baz is a construct
property ]


Python code constructs instance (w = FooBar())
  * FooBar.__init__ is called
    * FooBar.__init__ calls self.__gobject_init__()
      * __gobject_init__ calls g_object_new(typeid, ...)
        * instance is created
        * set_property called for all construct properties
===>      * do_set_property called on PyObject wrapper corresponding
            to newly created GObject.
      * __gobject_init__ assigns new instance to "obj" member of
        PyGObject struct for self
      * associate "self" with the new GObject instance
w now instantiated.

The problem is that the wrapper isn't associated with the C level
instance until g_object_new() returns.  However, setting of properties
may try to request a wrapper for the new C level instance (which
creates one if none exist).

I am not sure how to fix this.  I can check to see if a wrapper has
been created when g_object_new() returns, but I can't really tell the
do_set_property wrapper about the wrapper that is being constructed.
Comment 3 Christian Reis (not reading bugmail) 2003-11-13 20:55:36 UTC
Can you perhaps delay the call to do_set_wrapper until the 'real'
instance is available?
Comment 4 James Henstridge 2003-11-14 01:57:15 UTC
By do_set_wrapper, do you mean do_set_property()?  If so, then the
answer is no.  The set_property calls get initiated by the code in
libgobject, rather than anything I have control of.

The definition of a construct property is that set_property() will
always get invoked for the property during g_object_new().  If the
programmer doesn't specify a value for the property, set_property()
gets called with the default property.
Comment 5 James Henstridge 2003-12-01 06:29:03 UTC
After thinking about this a bit, I came up with a few ideas on how to
handle this.

It is a bit of a hack, but might work:

1) when calling g_type_register(), add a property
   _pygtk_gobject_wrapper to the new type if it doesn't already exist.
   The property would be a CONSTRUCT_ONLY property.
2) The set_property handler would check if the property being set was
   "_pygtk_gobject_wrapper", and if so, associate the wrapper with
   the new GObject.  It would probably print a warning if a wrapper
   had already been associated with the object.
3) alter __gobject_init__() to implicitly set _pygtk_gobject_wrapper
   (if the property exists for the GType) as the first property.

I think this should cut in before any implicit properties are set (or
any other properties for that matter).
Comment 6 Christian Reis (not reading bugmail) 2004-02-29 00:32:33 UTC
James, do you plan on working on this?
Comment 7 Gustavo Carneiro 2005-05-26 10:51:03 UTC
I have just discovered something interesting.  I was about to make a patch to
propose a g_object_set_constructor_property, but then I discovered in the code
that construct-only properties can be set with g_object_set_property if the
object is in a "in construction" state.  GObjects enter such state before being
returned by g_type_create_instance, and leave it when the constructor() virtual
returns.

Therefore, supporting construc-only properties in pygtk is not so complicated:
  1.  We override GObjectClass->constructor; in it we:
    a) create an instance (g_type_create_instance)
    b) create python wrapper and attach it to the GObject instance
    c) set the construction properties, using g_object_set_property

  Steps a)+c) are normal GObject constructor procedures; we just need to add b).
 To add b), we need to be able to pass arbitrary parameters (data/qdata) into
the constructor.  That last part is more complicated...
Comment 8 James Henstridge 2005-05-27 04:20:37 UTC
Rather than calling g_type_create_instance() directly, you should chain up to
the parent's ->constructor() implementation (g_type_create_instance() is
apparently only meant to be used by code that is implementing new fundamental
types).

You can easily filter the construct properties list before passing it to the
parent constructor though (assuming there is an easy way to tell which
properties have a Python setter implementation behind them).
Comment 9 Gustavo Carneiro 2005-05-27 09:58:29 UTC
  OK, chaining up to parent constructor could be done I guess.  Filtering out
_all_ properties before chaining shouldn't be a problem, as we can set them
afterwards in the outer constructor.

  What really worries me about chaining to parent constructor is this (in
g_object_constructor):

      GObjectNotifyQueue *nqueue = g_object_notify_queue_freeze (object,
&property_notify_context);
         /* ... set properties ... */
      g_object_notify_queue_thaw (object, nqueue);

  I'm not so sure of the side-effecs of these "notify queue" freeze/thaw calls.
 Do you think it's ok to call them one time without changing any properties, and
later on calling them again this time with properties changed?  If so, then I
agree we should chain the constructor, but we need the patch in bug 305560 first. 

PS1:  I have uploaded some additional notes bug #161177.  

PS2: I am tempted to mark this bus as dup of bug #161177, as I think the
problems 1) constructor properties  and 2) creating PyGObject from g_object_new,
should both be solved in an integrated way, at the same time.
Comment 10 James Henstridge 2005-05-30 04:20:29 UTC
I didn't say it explicitly, but one of the other reasons for calling the parent
class's ->constructor is that pygtk is not the only piece of code that overrides
the constructor -- from a quick look, GtkButton, GtkCList, GtkCTree,
GtkFileChooserButton, GtkFileChooserDefault, GtkFileChooserDialog,
GtkFileChooserWidget, GtkInvisible, GtkLayout, GnomeIconList and GnomeAppbar all
provide custom constructors, and will presumably malfunction if those
constructors aren't called.

From what I can tell, g_object_notify_queue_freeze/thaw are just internal
versions of g_object_freeze_notify/thaw_notify (the latter appear to be wrappers
round the former with some additional safety checks).

The effect of the notify freeze/thaw code is to reduce the number of "notify"
signals that get emitted.  If I call g_object_set_property() twice for the
property "foo", then the "notify::foo" signal will be emitted twice.  If I wrap
the _set_property() calls with a _freeze_notify()/_thaw_notify() pair, then
"notify::foo" will only be emitted once (on the _thaw_notify() call).  If no
properties get changed within the freeze/thaw pair, then there will be no effect.
Comment 11 Gustavo Carneiro 2005-07-10 10:33:21 UTC

*** This bug has been marked as a duplicate of 161177 ***