Python component model

G

Guest

Fredrik said:
python already has excellent and ridiculously easy-to-program ways to hook
things up. after all, hooking things up is what python programmers tend to do,
most of their time.

I agree.
if you want better support for more precise hooking, post some examples.

I want a design-time environment to hook up my objects in a visual way.
I think it is easier than doing it manually, even in Python.
handwavy references to what "other may need" is another thing you should
avoid if you want your Python change proposal to be successful.

I did not say what "others may need".
 
F

Fredrik Lundh

Edward Diener No Spam said:
I want a design-time environment to hook up my objects in a visual way.
I think it is easier than doing it manually, even in Python.

what objects? what hooks? visually, in what way?
I did not say what "others may need".

I'm not sure I see the big difference between "perhaps others do [have a need]"
and "others may need", but that's me.

</F>
 
G

Guest

Diez said:
The amazing flexibility stems from the fact that it is _runtime_. This is
_exactly_ the difference between static and dynamic typing.

If a static analysis (_not_ importing the module, which can trigger
arbitrary code being run!!!) is supposed to deliver the component
architecture, you are either introducing static typing, or get into the
danger of lose coupling between declaration and implementation, rendering
the whole thing pretty useless.

Yes, I am suggesting static typing functionality for a subset of Python
attributes. How this can be done I am still investigating on my own.
Of course, with a bit of discipline, you can create such a introspection
facility that offers its properties after a mere import, see ZOPE
interfaces for example.

But in the end, it boils down to declaring stuff for that purpose alone, and
introducing static typing, whereas other languages declare typing for their
own needs, and add the component model upon that.

And then you lose a _lot_ of what python makes powerful, for a very doubtful
benefit IMHO.

Adding a feature, such as static typing functionality for the situation
of doing visual RAD programming, does not "lose a _lot_ of what makes
python powerful".

My idea of adding static typing is not an attempt to change the language
but rather to develop Python classes which encapsulate the idea of a
variable and a type for the purposes of emulating component properties
and component events. If a language addition is needed instead I will
investigate how to propose it.
 
S

Steve Holden

Fredrik said:
:

I want a design-time environment to hook up my objects in a visual way.
I think it is easier than doing it manually, even in Python.


what objects? what hooks? visually, in what way?

I did not say what "others may need".


I'm not sure I see the big difference between "perhaps others do [have a need]"
and "others may need", but that's me.
He's wriggling anyway, as his opening post said (among other things) "I
believe that Python should have a common components model for all RAD
development environments ...". So unless he's the only person who's
going to use these development environments it does indeed sound a
little prescriptive.

regards
Steve
 
G

Guest

Tim said:
There's no doubt that Python's excellent introspection mechanism
allows an outside RAD-like tool to inspect the workings of any Python
object. But that does not make it a component model in my original use
of the term on this thread. A RAD tool needs to know what properties
and events within a class can be manipulated visually, and it needs to
be able to serialize those properties and events so that they are set
at run-time automatically once an object is created.

A little visual inspection of some objects:

tim@oblique:~$ python
Python 2.3.5 (#2, Sep 4 2005, 22:01:42)
[GCC 3.3.5 (Debian 1:3.3.5-13)] on linux2
Type "help", "copyright", "credits" or "license" for more information.... def __init__(self, name, age=None):
... self.name = name
... self.age = age
... def whoami(self):
... if self.age is not None:
... return "%s (%i)" % (
... self.name,
... self.age)
... return self.name
...
p = Person("Sandy")
[s for s in dir(p) if not s.startswith('_') and
callable(eval('p.%s' % s))]
['whoami']
[s for s in dir(p) if not s.startswith('_') and not
callable(eval('p.%s' % s))]
['age', 'name']

Thus, you have the ability to find an object's methods/events (things
that are callable()), and its properties (things that are not
callable()). Any "RAD" tool that wants can pull these properties, just
as my command-line RAD tool can ;)

Not all attributes are component properties in typical Visual RAD tool.
In most visual RAD tools which I have used a component property is a
publicly exposed type/name which may or may not have the backing of an
actual data member and does have a function to get the type's value if
the property is readable and does have a function associated with it to
set the type's value if the property is writable. This is very close to
the class properties in Python. The difference is that normally a type
must be associated with a property whereas in Python, as I understand
it, the type of a class property is unknown.

Furthermore by a component event I do not mean methods on the event
creator's side but rather an event source. This would look something
like a tuple of callable functions of a particular signature to which an
event sink could add an event handler so that when a particular event
occurred on the event source the event handlers added to the event
source would each be called.
As for serializing them,
import shelve
d = shelve.open('tmp/stuff.shlv')
d['person'] = p
p = 'hello'
p 'hello'
p = d['person']
p.whoami() 'Sandy'
p.age = 42
p.whoami() 'Sandy (42)'
d['person'] = p
d.close()
p = 'hello2'
p 'hello2'
d = shelve.open('tmp/stuff.shlv')
p = d['person']
p.whoami()
'Sandy (42)'

which seems to work fine for me. This can be used for creating all
sorts of flavors of objects at design time, storing them, and then
restoring them at runtime.

I realize that Python has excellent abilities in all these areas,
including serialization. But a component model for serialization must
not only have the ability of serializing and deserializing all of the
component's data, as well as any base classes, it must also have a means
of allowing the class itself to specify which data needs to be
serialized and which not, as well as allow for the class to seriliaze
all or part of its own data.
 
G

Guest

Fredrik said:
external serialization was not part of your original definition.

Well, knock me over.
I think you have to be a *lot* more concrete here. repeatedly referring to
"some kind of hypothetical property (that isn't a property)" and "some kind
of hypothetical event (that isn't a public method)" and "some kind of hypo-
thetical RAD tool" won't get you anywhere.

My OP was just to query whether a component model existed for Python,
like JavaBeans for Java or .Net for C#, C++/CLI etc. After that came
suggestions of what I thought such a component model was about, which I
thought I answered generally. Not you want details. No doubt next will
come a demand for code.

OK, here is my idea of what such a component model envisages as a list
of items. After this, unless I get some intelligent comments from people
who might be interested in what I envision, or something very similar, I
will be off to investigate it myself rather than do battle with the
horde of people who will just tell me that Python, being a great
language, does not need what I have suggested.

1) Component property: This is a glorified attribute with a type that
can either be specified in a "static" manner, or always be discovered
dynamically, or have converters back and forth between a string and the
actual value represented by the component property. A component property
has a getter function to retrieve the value if it is readable and a
setter function to set the value if it is writable. It must be either
readable or writable or both. A component property is not any Python
class attribute since a component has the right to specify only certain
values as manipulatable in a design-time RAD environment.

2) Component event: This is an type which encapsulates an array, or a
list of callable objects with the same function signature, along with
the functionality to add and remove elements from the array, as well as
cycle through the array calling the callable objects as a particular
event is triggered. A component event is an event source for a
particular event. Component events have to be dicoverable by the Visual
RAD system so that an object's appropriate event handler, an event sink,
can be hooked to the component event itself, an event source, through a
design time interface which propagates the connection at run-time.

3: Component serialization: A component which has its properties and
events set by a visual design-time RAD environment needs to be
serialized at design time and deserialized at run-time. This can be a
default serialization of all component properties and events, or the
component itself can participate in the serilization effort either
wholly or partly.

4) Custom property and component editors: A component editor can present
a property editor or an editor for an entire component which the visual
design-time RAD environment can use to allow the programmer end-user of
the component to set or get component property values. Normally a design
time environment will present default property editors for each
component property type, but a component can override this.

5) Custom type converters: A component should be able to specify a
custom converter for any property to convert, in both directions or
either direction, between the property's string value as seen by a
property editor and the actual value of the component property's type.

This is the general gist of those things which are needed in a visual
Design-time RAD environment.
 
S

skip

Edward> My OP was just to query whether a component model existed for
Edward> Python, like JavaBeans for Java or .Net for C#, C++/CLI
Edward> etc.

For those of us who've never used Java, .Net or C++/CLI, a more concrete
description of what you were after from the beginning would have been
helpful.

Skip
 
N

Nick Vatamaniuc

Edward said:
A RAD IDE tool to hook up components into an application or library (
module in Python ) has nothing to do with terseness and everything to do
with ease of programming. All you are saying is that you don't have a
need for this, but perhaps others do. I don't mind others saying they
have no need or seeing no benefit. But if you have ever used a visual
design-time environment for creating applications you might feel
differently.

"Thinking in Java or C++" as opposed to Python does not mean anything to
me as a general statement. I am well aware of the difference between
statically and dynamically typed languages but why this should have
anything to do with RAD programming is beyond me. Do you care to
elucidate this distinction ?


Python has great facilities for a component model, much better than the
other languages I use regularly ( C++, C#, Java ). I am not arguing
against that. A component model for RAD tools allows the tool to expose
properties and events to the end-user at design time so that at run-time
the properties and events are automatically setup once an object is
instantiated. The essence of a component model for RAD programming is
how one specifies properties and events for a class to be manipulated by
the RAD tool at design time. Another obvious part of the component model
is how one specifies that the properties and events one sets up at
design-time are serialized so that at run-time they are properly set. A
final element of a component model is the ability of a component to
interact with the environment in which it exists at design time, through
property editors, and at run-time, the latter being obviously more
important for visual controls than non-visual components.

You mention properties (1), events(2) and serialization(3).

1. Python has properties. I had a link in my previous post that pointed
towards some of the features of the new classes, properties are among
them..

2. As for event models -- it seems that Python doesn't have it because
there isn't one best event model. Each application domain will have its
own "best" event model. For example an event model for a network
(distributed) application [think Twisted] will be different than an
event model of a GUI [think wxWidgets]. Implementing an observer
pattern is not that hard in Python. Events could be lists, classes or
strings or anything you desire -- it all depends on your needs. But
there isn't one best-for-all event model out there. If there was one,
everyone would be using it by now.

3. As for serialization -- it exists in Python as well. Look up pickle,
marshaling and shelves.


The reason I said that you don't need a RAD tool in Python is because
Python itself is a RAD tool. Most of the things you mention as
necessary for RAD environment are already in Python! The ones that
aren't can just be specified by you. In other words the developers who
wrote Twisted specified a certain execution and event model and others
can write plugins for it. What you might not have is a common and
popular visual drag-and-drop tool, but you can write it and perhaps
find others who also need it. Who knows, it might turn into a
successful project.

-N.V.
 
F

fumanchu

Edward said:
OK, here is my idea of what such a component model envisages as a list
of items. After this, unless I get some intelligent comments from people
who might be interested in what I envision, or something very similar, I
will be off to investigate it myself rather than do battle with the
horde of people who will just tell me that Python, being a great
language, does not need what I have suggested.

[This quote hacked up by me:]
1) Component property: This is a glorified attribute with a type that
a) can be specified in a "static" manner, or discovered dynamically,
b) has converters between a string and the actual value
c) has a getter function to retrieve the value if it is readable and a
setter function to set the value if it is writable.
d) be either readable or writable or both.
e) not any Python class attribute since a component has the right
to specify only certain values as manipulatable in a design-time
RAD environment.

Whenever you say "glorified attribute", your first thought should be
"Python descriptor" (but not your last--it's not a cure-all). They are
able to do all of (a, b, c, d, e) which I marked in your text above.
For example, here's a descriptor for
attributes-you-want-to-persist-in-a-database from my ORM, Dejavu (see
http://projects.amor.org/dejavu/browser/trunk/units.py#l290):


class UnitProperty(object):
"""Data descriptor for Unit data which will persist in storage."""

def __init__(self, type=unicode, index=False, hints=None, key=None,
default=None):
self.type = type
self.index = index
if hints is None: hints = {}
self.hints = hints
self.key = key
self.default = default

def __get__(self, unit, unitclass=None):
if unit is None:
# When calling on the class instead of an instance...
return self
else:
return unit._properties[self.key]

def __set__(self, unit, value):
if self.coerce:
value = self.coerce(unit, value)
oldvalue = unit._properties[self.key]
if oldvalue != value:
unit._properties[self.key] = value

def coerce(self, unit, value):
if value is not None and not isinstance(value, self.type):
# Try to cast the value to self.type.
try:
value = self.type(value)
except Exception, x:
x.args += (value, type(value))
raise
return value

def __delete__(self, unit):
raise AttributeError("Unit Properties may not be deleted.")
a) can be specified in a "static" manner, or discovered dynamically,

The "component model" can either scan a class for instances of
UnitProperty or keep a registry of them in the class or elsewhere (via
a metaclass + add_property functions).
b) has converters between a string and the actual value

Note the "coerce" function above. Something similar could be done for
serialization (which I can prove in my case because I use UnitProperty
to help produce SQL ;) but you could just as easily pickle
unit._properties and be done with it.
c) has a getter function to retrieve the value if it is readable and a
setter function to set the value if it is writable.
d) be either readable or writable or both.

Descriptors that only have __get__ are read-only; if they have __set__
they are read-write.
e) not any Python class attribute since a component has the right
to specify only certain values as manipulatable in a design-time
RAD environment.

Right. Descriptors allow the creator of a class to use "normal"
attributes (including functions) which don't participate in the
component model.
2) Component event: This is an type which encapsulates an array, or a
list of callable objects with the same function signature, along with
the functionality to add and remove elements from the array, as well as
cycle through the array calling the callable objects as a particular
event is triggered. A component event is an event source for a
particular event. Component events have to be dicoverable by the Visual
RAD system so that an object's appropriate event handler, an event sink,
can be hooked to the component event itself, an event source, through a
design time interface which propagates the connection at run-time.

This can be accomplished by creating a ComponentEvent descriptor whose
__get__ returns an object with a __call__ method. Here's a base class
for something similar (again, from Dejavu):

class UnitAssociation(object):
"""Non-data descriptor method to retrieve related Units via
attributes."""

to_many = None

def __init__(self, nearKey, farClass, farKey):
# Since the keys will be used as kwarg keys, they must be
strings.
self.nearKey = str(nearKey)
self.farKey = str(farKey)

self.nearClass = None
self.farClass = farClass

def __get__(self, unit, unitclass=None):
if unit is None:
# When calling on the class instead of an instance...
return self
else:
m = types.MethodType(self.related, unit, unitclass)
return m

def __delete__(self, unit):
raise AttributeError("Unit Associations may not be deleted.")

def related(self, unit, expr=None, **kwargs):
raise NotImplementedError

Subclasses override the "related" method, but a ComponentEvent class
could just as easily do:

def run(self, *args, **kwargs):
for sink in self.sinks:
sink(*args, **kwargs)
3: Component serialization: A component which has its properties and
events set by a visual design-time RAD environment needs to be
serialized at design time and deserialized at run-time. This can be a
default serialization of all component properties and events, or the
component itself can participate in the serilization effort either
wholly or partly.

In Dejavu, the UnitProperty class is your "component property" and the
Unit class is the component. The Unit class has a copy method:

def __copy__(self):
newUnit = self.__class__()
for key in self.properties:
if key in self.identifiers:
prop = getattr(self.__class__, key)
newUnit._properties[key] = prop.default
else:
newUnit._properties[key] = self._properties[key]
newUnit.sandbox = None
return newUnit

It wouldn't be hard to replace "newUnit._properties[key] =
self._properties[key]" with "dump(self._properties[key])".
4) Custom property and component editors: A component editor can present
a property editor or an editor for an entire component which the visual
design-time RAD environment can use to allow the programmer end-user of
the component to set or get component property values. Normally a design
time environment will present default property editors for each
component property type, but a component can override this.

This is the hard part. I believe Dabo has done some work in this space,
but this is where the tight coupling comes in between code and tool, a
coupling which Python has traditionally resisted.
5) Custom type converters: A component should be able to specify a
custom converter for any property to convert, in both directions or
either direction, between the property's string value as seen by a
property editor and the actual value of the component property's type.

A ComponentProperty descriptor could include a custom pair of methods
to get/set as string. This is often done in web frameworks which need
to coerce incoming string values to the correct type.

All of which is to say: nobody's done this yet because parts 1, 2, 3
and 5 are trivial to do with descriptors, but actually building a
visual RAD environment is too much work. ;)


Robert Brewer
System Architect
Amor Ministries
(e-mail address removed)
 
P

Paul Boddie

Edward> My OP was just to query whether a component model existed for
Edward> Python, like JavaBeans for Java or .Net for C#, C++/CLI
Edward> etc.

For those of us who've never used Java, .Net or C++/CLI, a more concrete
description of what you were after from the beginning would have been
helpful.
From vague recollections of the original Java Beans technology, the
primary "innovation" was to have getProperty and setProperty methods,
along with things like isCapability and hasProperty, if I remember
correctly. None of this was really shocking to anyone using Python,
mostly because Python had __getattr__ and __setattr__ even back then
for customising real property/attribute access, and Python's run-time
introspection capabilities were superior to Java's (and probably still
are).

The other innovation was the introduction of standard interfaces for
listening to and dispatching events, where you implement some listener
interface and respond to events in order to "care about" those events.
I don't recall any particularly good mechanisms for connecting beans to
each other in order to fire off events, although the beanbox (or
whatever the graphical tool originally promoted was called) and/or the
IDE is supposed to help you with that part of the work.

The groovy 1990s API is actually viewable in various places; here, for
example:

http://www.doc.ic.ac.uk/~jpc1/linux/bdk-doc-1.0/apis.html

Despite the supposedly exciting advances heralded by Java Beans, a
large part of the technology was just codifying existing practices and
techniques, but it could be argued that such techniques have been
superseded by signal/slot mechanisms and more advanced event
architectures (pioneered by frameworks like Qt and since adopted by
Gtk, I believe).

Paul
 
K

Kay Schluehr

fumanchu said:
This is the hard part. I believe Dabo has done some work in this space,
but this is where the tight coupling comes in between code and tool, a
coupling which Python has traditionally resisted.

I do think it's just about presenting component properties and their
types / value ranges. I do think this can be easily achieved using
decorators that might also add the right kind of token for
introspection purposes to the function/method attributes. Descriptors
i.e. customized binding semantics might cover one aspect of
componentization but as I understood Edward he asked for uniform
declarative semantics. Components in this sense are just specialized
objects such as TestCase classes in the PyUnit framework. What I still
do not understand is the reference to "many RAD" tools which is
completely hypothetical to me. The portability of components across
different GUI designers for the same underlying toolkit is a quite
speculative future requirement to say the least.
 
F

Fredrik Lundh

fumanchu said:
This is the hard part. I believe Dabo has done some work in this space,
but this is where the tight coupling comes in between code and tool, a
coupling which Python has traditionally resisted.

that's not that hard on a pure technical level; even a "basic" tool
like IDLE can hook itself into an executing Python process. once you're
hooked up, you can inspect and modify most about everything.

for example, doing remote tweaking of live Tkinter widget trees is
pretty straight-forward.

coming up with a good way to capture the modifications, and use them in
your actual application, is a bit harder. do you really want to replace
plain old source code with some kind of more or less obscure resource
files?

and designing a metadata vocabulary that's powerful enough to be useful
for more than just one or a few target domains might be really hard.

</F>
 
P

Peter Maas

Diez said:
The amazing flexibility stems from the fact that it is _runtime_. This is
_exactly_ the difference between static and dynamic typing.

Not _exactly_. You can have static typing in an interpreted language (Java)
and dynamic typing in a machine language (Basic with variants).
 
G

Guest

Paul said:
primary "innovation" was to have getProperty and setProperty methods,
along with things like isCapability and hasProperty, if I remember
correctly. None of this was really shocking to anyone using Python,
mostly because Python had __getattr__ and __setattr__ even back then
for customising real property/attribute access, and Python's run-time
introspection capabilities were superior to Java's (and probably still
are).

There is no argument on my part that Python's introspection and metadata
capabilities are superior to Java, as well as its potential attribute
as component property model. In the theoretical Python model I proposed,
the designer of the component must have the ability to specify which of
the component's attributes are properties and how this is controlled (
via __getattr__ and __setattr__ ? descriptors as someone else suggested
? other ideas ? ). Merely saying that all of an object's attributes are
component properties for the purposes of a visual RAD designer can not
be correct.

I actually think that Java's notion of preoperties in JavaBeans, which
are just getter and setter functions with a particular naming
convention, determined by Java as a default, or through an associated
BeanInfo class, is rather klutzy and much prefer that of .Net or
Borland's VCL where a particular language construct is used for
properties instead. Of course with Python's superior metadata abilities,
a particular new language construct shouldn't be necessary.
The other innovation was the introduction of standard interfaces for
listening to and dispatching events, where you implement some listener
interface and respond to events in order to "care about" those events.
I don't recall any particularly good mechanisms for connecting beans to
each other in order to fire off events, although the beanbox (or
whatever the graphical tool originally promoted was called) and/or the
IDE is supposed to help you with that part of the work.

The beanbox did nothing to help setup events, event sources, or event
listeners. It just presented a graphical example of a visual RAD tool
which could tie event sources to event listeners. It is onerous in
JavaBeans to connect event sources to event listeners, and takes a good
deal of manual coding although doing it is easy to understand.
The groovy 1990s API

1997.

Again Borland's VCL or .Net have much better solutions for events but
again require language constructs which Python ought not need given its
strong metadata possibilities to supply a component event model.
is actually viewable in various places; here, for
example:

http://www.doc.ic.ac.uk/~jpc1/linux/bdk-doc-1.0/apis.html

The BDK is no longer supported in the latest version of Java and
JavaBeans. Instead there is a Bean Builder at
https://bean-builder.dev.java.net/ .
Despite the supposedly exciting advances heralded by Java Beans, a
large part of the technology was just codifying existing practices and
techniques, but it could be argued that such techniques have been
superseded by signal/slot mechanisms and more advanced event
architectures (pioneered by frameworks like Qt and since adopted by
Gtk, I believe).

I agree and I would want to have a component event model for Python that
is much superior to the JavaBeans event model in ease of use. A much
better ideal for component properties and component events is presented
by .Net, where there are actual language keywords which perform the
magic. I would guess that Qt and Gtk also follow a better ease of use
path, perhaps with macros in C++. But Python should be able to do as
good or better than any of these environments.
 
G

Guest

fumanchu said:
Edward said:
OK, here is my idea of what such a component model envisages as a list
of items. After this, unless I get some intelligent comments from people
who might be interested in what I envision, or something very similar, I
will be off to investigate it myself rather than do battle with the
horde of people who will just tell me that Python, being a great
language, does not need what I have suggested.

[This quote hacked up by me:]
1) Component property: This is a glorified attribute with a type that
a) can be specified in a "static" manner, or discovered dynamically,
b) has converters between a string and the actual value
c) has a getter function to retrieve the value if it is readable and a
setter function to set the value if it is writable.
d) be either readable or writable or both.
e) not any Python class attribute since a component has the right
to specify only certain values as manipulatable in a design-time
RAD environment.

Whenever you say "glorified attribute", your first thought should be
"Python descriptor" (but not your last--it's not a cure-all). They are
able to do all of (a, b, c, d, e) which I marked in your text above.
For example, here's a descriptor for
attributes-you-want-to-persist-in-a-database from my ORM, Dejavu (see
http://projects.amor.org/dejavu/browser/trunk/units.py#l290):


class UnitProperty(object):
"""Data descriptor for Unit data which will persist in storage."""

def __init__(self, type=unicode, index=False, hints=None, key=None,
default=None):
self.type = type
self.index = index
if hints is None: hints = {}
self.hints = hints
self.key = key
self.default = default

def __get__(self, unit, unitclass=None):
if unit is None:
# When calling on the class instead of an instance...
return self
else:
return unit._properties[self.key]

def __set__(self, unit, value):
if self.coerce:
value = self.coerce(unit, value)
oldvalue = unit._properties[self.key]
if oldvalue != value:
unit._properties[self.key] = value

def coerce(self, unit, value):
if value is not None and not isinstance(value, self.type):
# Try to cast the value to self.type.
try:
value = self.type(value)
except Exception, x:
x.args += (value, type(value))
raise
return value

def __delete__(self, unit):
raise AttributeError("Unit Properties may not be deleted.")
a) can be specified in a "static" manner, or discovered dynamically,

The "component model" can either scan a class for instances of
UnitProperty or keep a registry of them in the class or elsewhere (via
a metaclass + add_property functions).
b) has converters between a string and the actual value

Note the "coerce" function above. Something similar could be done for
serialization (which I can prove in my case because I use UnitProperty
to help produce SQL ;) but you could just as easily pickle
unit._properties and be done with it.
c) has a getter function to retrieve the value if it is readable and a
setter function to set the value if it is writable.
d) be either readable or writable or both.

Descriptors that only have __get__ are read-only; if they have __set__
they are read-write.
e) not any Python class attribute since a component has the right
to specify only certain values as manipulatable in a design-time
RAD environment.

Right. Descriptors allow the creator of a class to use "normal"
attributes (including functions) which don't participate in the
component model.
2) Component event: This is an type which encapsulates an array, or a
list of callable objects with the same function signature, along with
the functionality to add and remove elements from the array, as well as
cycle through the array calling the callable objects as a particular
event is triggered. A component event is an event source for a
particular event. Component events have to be dicoverable by the Visual
RAD system so that an object's appropriate event handler, an event sink,
can be hooked to the component event itself, an event source, through a
design time interface which propagates the connection at run-time.

This can be accomplished by creating a ComponentEvent descriptor whose
__get__ returns an object with a __call__ method. Here's a base class
for something similar (again, from Dejavu):

class UnitAssociation(object):
"""Non-data descriptor method to retrieve related Units via
attributes."""

to_many = None

def __init__(self, nearKey, farClass, farKey):
# Since the keys will be used as kwarg keys, they must be
strings.
self.nearKey = str(nearKey)
self.farKey = str(farKey)

self.nearClass = None
self.farClass = farClass

def __get__(self, unit, unitclass=None):
if unit is None:
# When calling on the class instead of an instance...
return self
else:
m = types.MethodType(self.related, unit, unitclass)
return m

def __delete__(self, unit):
raise AttributeError("Unit Associations may not be deleted.")

def related(self, unit, expr=None, **kwargs):
raise NotImplementedError

Subclasses override the "related" method, but a ComponentEvent class
could just as easily do:

def run(self, *args, **kwargs):
for sink in self.sinks:
sink(*args, **kwargs)
3: Component serialization: A component which has its properties and
events set by a visual design-time RAD environment needs to be
serialized at design time and deserialized at run-time. This can be a
default serialization of all component properties and events, or the
component itself can participate in the serilization effort either
wholly or partly.

In Dejavu, the UnitProperty class is your "component property" and the
Unit class is the component. The Unit class has a copy method:

def __copy__(self):
newUnit = self.__class__()
for key in self.properties:
if key in self.identifiers:
prop = getattr(self.__class__, key)
newUnit._properties[key] = prop.default
else:
newUnit._properties[key] = self._properties[key]
newUnit.sandbox = None
return newUnit

It wouldn't be hard to replace "newUnit._properties[key] =
self._properties[key]" with "dump(self._properties[key])".
4) Custom property and component editors: A component editor can present
a property editor or an editor for an entire component which the visual
design-time RAD environment can use to allow the programmer end-user of
the component to set or get component property values. Normally a design
time environment will present default property editors for each
component property type, but a component can override this.

This is the hard part. I believe Dabo has done some work in this space,
but this is where the tight coupling comes in between code and tool, a
coupling which Python has traditionally resisted.

It's more of a coupling between a type and a tool. Only user-defined
types as component properties need their own property editor, whereas
all other Python types can be coupled with default property editors. Of
course the class designer must have a right to create their own property
editor for a particular type or a particular property of that type in
order to override the default property editors for a particular type.
A ComponentProperty descriptor could include a custom pair of methods
to get/set as string. This is often done in web frameworks which need
to coerce incoming string values to the correct type.

Thanks for your information abouit using descriptors. I will look into
it further but I really appreciate your example.
All of which is to say: nobody's done this yet because parts 1, 2, 3
and 5 are trivial to do with descriptors, but actually building a
visual RAD environment is too much work. ;)

The idea of course is that with the correct component underpinnings and
perhaps high-level modules which make it easy for a visual RAD
environment to introspect the necessary component properties and
component events, as well as serialize them at design time and create
code to deserialize them at run-time, the work of creating a visual RAD
environment would not be so daunting.
 
F

Fredrik Lundh

Edward said:
I agree and I would want to have a component event model for Python that
is much superior to the JavaBeans event model in ease of use.

isn't that an old Perlis quote? "I want a component event model in
which I need only say what I wish done"?

</F>
 
G

Guest

Kay said:
I do think it's just about presenting component properties and their
types / value ranges. I do think this can be easily achieved using
decorators that might also add the right kind of token for
introspection purposes to the function/method attributes. Descriptors
i.e. customized binding semantics might cover one aspect of
componentization but as I understood Edward he asked for uniform
declarative semantics.

Uniform in the sense that a visual RAD tool introspecting a Python class
would be able to say that s type X is a component property and type Y is
a component event, and everything is is just normal Python code which
the RAD tool can ignore.
Components in this sense are just specialized
objects such as TestCase classes in the PyUnit framework.

Totally agreed. But the common functionality they add is valuable to
visual RAD tools.
What I still
do not understand is the reference to "many RAD" tools which is
completely hypothetical to me.

You are right that I should not have mentioned this without experience
with the many Python tools, notable Python web page development
environments, which are out there.
The portability of components across
different GUI designers for the same underlying toolkit is a quite
speculative future requirement to say the least.

It's been a success in the Java world with JavaBeans and EJBs within
environments like Eclipse, NetBeans, JBuilder, and others; and its been
a success in the .Net world with .Net components within Visual Studio,
Borland Development Studio, and potentially others, so ideally it could
be a success in the Python world.

I believe the only knock against Python, as opposed to Java or .Net, is
that it does not present enough ease of use environments to creating
large scale applications, whether Linux, Windows, or Web applications. I
believe part of that reason is because Python developers who, whether
they wanted to distribute their classes for free or want to sell them
for a profit, are presented with endless technologies built with Python,
each one demanding a slightly different approach to class reusability,
are reticent to develop their ideas for many different environments.

Wanting a common PME component model is a way of saying that Python
class developers can develop their classes as components and at least at
the base level can expect them to work flawlessly in any Python
environment. I am NOT against a particular environment building further
requirements on top of a common Python component model, and in fact
would expect it in many cases. But given inheritance in OOP, and in
Python of course, this might be as easy for me as deriving a new class
from my particular base class component for a particular visual RAD
development environment, adding the extra function needed onto my
derived class, and away we go.
 
G

Guest

Fredrik said:
that's not that hard on a pure technical level; even a "basic" tool
like IDLE can hook itself into an executing Python process. once you're
hooked up, you can inspect and modify most about everything.

for example, doing remote tweaking of live Tkinter widget trees is
pretty straight-forward.

coming up with a good way to capture the modifications, and use them in
your actual application, is a bit harder. do you really want to replace
plain old source code with some kind of more or less obscure resource
files?

The Visual Studio RAD IDE environment actually modifies source code
constructors, via an InitializeComponent() function called from it, in
order to set properties and events in components. It does mark the
function as such with comments in the source code. OTOH Borland's VCL
uses the resource file technique you scorn above, linking in the code
via resources and automatically updating a component's properties and
events from base class components constructors. I believe Java's JVM
automatically deserializes .ser files at run-time saved by a RAD
designer in order to set properties and events on an object of a class.

There are obviously numerous techniques, so one should theoretically
work well with Python.
and designing a metadata vocabulary that's powerful enough to be useful
for more than just one or a few target domains might be really hard.

That's the are I am most interested in.
 
P

Peter Maas

Bruno said:
> Marc 'BlackJack' Rintsch wrote:
> (snip)
> Python itself is a RAD tool.
>
> +1 QOTW

No, please stop self-assuring, self-pleasing QOTWs! This afternoon
I was in the local book warehouse and went to the computer book
department. They had banned 2-3 Python books together with some
Perl- and C/C++ stuff into the last row. At the regular place I found
a huge pile of Java books and - in comparison to Java - a small but
growing number of books about Ruby in general, Ruby on Rails and -
new to me - JRuby.

Now I don't think that Ruby is a bad language. But I think Python is
better and it started earlier. I don't know whether Ruby on Rails was
a fluke or the result of clever analysis. Since a large part of
programming is web programming it is not bad to have a good and visible
tool in place to attract programmers. It is also a good idea to hook on
Java's success but while Jython 2.2 is in alpha state since 3 years I
see an increasing number of books/articles telling how to migrate from
Java to (J)Ruby. Since I started using Python 4 years ago I hear Ruby
people announce with an amazing audacitiy that Ruby is bound to be number
one and will for sure leave Python behind.

To prevent this to happen parts of the Python community should have a
more critical attitude to the language. Too often I hear the same
mantras being repeated over and over again (GIL, self, IDE etc.). I
don't say these mantras are all wrong but perhaps it would be good to
remove the GIL just to stop people talking about Python's lack of
multi-threading or polish Python's class syntax to stop people talking
about Python's OO being bolted on etc. Programmers often choose their
languages by very silly reasoning (silliest being the indentation issue)
and maybe we should take the silliness into account instead of laughing
about those silly folks.

I for my part would be happy to see a Delphi-like RAD tool for Python,
a reference implementation for web programming as part of the standard
library, Jython 2.5, Python for PHP or whatever attracts new programmers.

Peter Maas, Aachen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,201
Latest member
KourtneyBe

Latest Threads

Top