Re: Models...

Magnus Lie Hetland <[email protected]>
Newsgroups gmane.comp.python.anygui.devel
Message-ID <[email protected]>
Dallas Johnston <[email protected]>:
>
> Hello all,
> 
> I have spent some time today on the Models, implementing a slightly
> modified version of my delegate idea. Instead of having an actual
> class do the delegation, which would break encapsulation =), I have
> delegated (irony intended) all the model management code to the
> Proxy class.
> 
> In fact, due to Proxy handling all the lower level push/pull
> functionality, there really was no other clean way to deal with it.
> Also, by thus having Proxy marshal values into the Models, Attribs
> becomes *far* less complicated, and the Wrappers pushing values up
> into the Proxy causes Proxy to update all related models =).

This sounds good (without having done any detailed thinking on the
subject ;)

> As of now, BooleanModel works like a charm,

Great!

> but there are still very
> menial bugs to iron out, and I need to get some sleep.
> 
> Only one question though... from the test_modv3.py it seems that the
> use of the model is inconsistent. For example, the calls to
> link(newbtn.on, printit2) and log('printit2:',newbtn.on) seem to
> represent the presence of slight confusion in the mind of the author
> with regard to what newbtn.on is supposed to represent in each call.
> In the first case, newbtn.on is assumed to return the actual model
> object, whereas the second case is expecting the value that the
> model represents.

Well, the __repr__ of a model should mimic the value it represents (or
so, I think, was the idea). So for a BooleanModel, __str__ should
either be '1' or '0'... Or perhaps 'True' of 'False', even...

Also, int(BooleanModel()) should return 0 etc. The models should
behave much like the values they represent/contain.

> And discerning wich of these expectations is in fact based in a more
> credible comprehension of the matter is a little more than subtle.

Hm. The point is that button.on can contain any Boolean value, whether
it be an int, a bool, a BooleanModel, or whatever. Basically, the
button shouldn't worry (except for some special-case code for in-place
editing geared towards models).

> In reality, if you are wanting to retrieve the value that he model
> represents, then 'val = widget.property', where 'property' is a
> model, proves the more appealing idiom.

I don't think so... Assuming that by "widget" you mean a proxy, I
think that proxy.property should always return the value of the given
property. If that value happens to be of a Model class, the instance
should be returned anyway. If you choose to treat it as a Boolean
value, it the BooleanModel instance should behave accordingly.

> However, when one wants to
> call a user-provided method on the model, which is the real purpose
> of user-provided models, then a call like
> 'widget.property.calculate()' will fail miserably, as
> 'widget.__getattr__' will have returned the value that 'property'
> represents.

I *absolutely* don't want this sort of behaviour. The following should
hold (for objects that can be modified in-place):

>>> proxy.attr = value
>>> proxy.attr is value
1

If value is a model, that shouldn't make a bit of difference. The only
special-casing of models is handled by the in-place modification
(which uses the value attribute when available) and the assignee
protocol. Nothing else should be needed.

... except for one thing... ;)

In proxy.pull(), all attributes should be modified in-place (if
possible) by the value returned from the wrapper. This ensures that
models aren't replaced etc. (Not sure if this is correctly implemented
at the moment -- I seem to recall Samuele pointing out some errors
there). So, the following should work:

>>> proxy.width = model = NumberModel()
>>> # User modifies proxy graphically
>>> proxy.pull('width') # proxy.width is modified in-place
>>> # model will now trigger an update in its views

But what about proxy.push()? Samuele brought this up: We might end up
with Models in the Wrapper's setters. We might accept this, assuming
that the setters will do any necessary coercing (such as using
list(model) or int(model) etc.) -- I think this is a reasonable
approach -- or we might try to do the coercion before passing the
value to the wrapper. The only reasonable thing we can do there (as I
see it) is to try to use foobar.value (for an object foobar) if it
exists...

But, as I said, I think it is better to require the Wrapper to make
fewer assumptions about the values it receives; e.g. a coordinate will
be number-like, but not necessarily an int. If the back-end needs an
int, then the setter should be implemented something like:

  def setX(self, x):
      if self.widget is not None:
          self.widget.x = int(x)

(assuming that we keep the "wrapper is not None"-checking in the
Wrapper).

The more I think about it, the more I'm convinced that this is the way
to do it.

> And I cannot refer to the old version of Attribs.py without mucking
> about with cvs, so I'll have to look into it tomorrow.
> 
> cheers all,
> --Dallas 

-- 
Magnus Lie Hetland        Practical Python          The Anygui Project
http://hetland.org        http://ppython.com        http://anygui.org


-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.