[TransWarp] PEAK Applications Code and Concepts
Phillip J. Eby
pje at telecommunity.com
Wed Feb 26 17:26:55 EST 2003
At 09:09 PM 2/26/03 +0100, Ulrich Eck wrote:
>thank you very much for your exessive comment on our first steps with peak.
I hope that by "excessive" you mean helpful and plentiful, as opposed to
annoying or overwhelming. :)
>first there is a typo in model/elements.py in line 502:
> def _doGet(ob):
Thanks. I'm checking in a fix now.
>>* The acmgr.connection.imapmodel.MessageHeaderField class has some
>>issues. First, you're breaking persistence
>>notification by modifying a stored mutable, unless the mutable itself is
>>Persistent. Second, the proper place to
>>perform format conversions of this sort is in the DM _load() method,
>>either by performing the computation or
>>inserting a LazyLoader. Third, you're breaking validation/observation
>>capabilities by bypassing _link()/_unlink() -
>>this might be okay if you know that the 'data' attribute is implementing
>>all the validation and observation you need.
>>Fourth, if you *really* need to redefine how an object stores its
>>bindings, you can always override '_setBinding()'
>>in the element class. All in all, the MessageHeaderField class is very
>>bad for separation of implementation issues
>>from the domain model.
>Not Done: I'm not 100% shure how i should handle this situation...
>message-header is basically like a dict
>that has standard + optional keys. if i restrict the Element to
>From/To/Subject/+xxx Features i can easily
>load the data into the state-attributes one for each - but then i loose
>the capability to access optional
>header fields ..
You could always define methods to retrieve or manipulate headers. Or just
declare a simple attribute called "headers" or something, that's the mail
header or email message object, and expose that as part of the model.
>a Dict-Like Feature is basically missing :) but i have no clue how to make
>such a thing real, if it would
>be possible and make sense ...
Since in this case you have a dict-like object to start with, why not just
use a plain 'model.Attribute' whose type is the email message type?
>>* Most of your features don't declare a 'referencedType'. *This will
>>break soon*. I expect to add a validation hook
>>to the StructuralFeature._link() method soon, that will expect to call a
>>'mdl_normalize()' class method on the
>>referenced type, to normalize the value of a supplied input object. This
>>will let you do things like:
>hmm .. what type should e.g. a collection of messages get ???
If the message type is based on a peak.model base class, do this:
referencedType = 'path/to/messagetype'
Otherwise, create a message type of your own:
class Message(model.PrimitiveType): # suppress all peak.model direct
def mdl_normalize(klass, value):
# code to verify that 'value' is a message or convert it to one
Optionally, the type can implement mdl_fromString() and mdl_typeCode, but
those things are only needed for loading from XMI at the moment. The
minimum requirement right now is just to implement an mdl_normalize()
method, and even there I think you might be able to use the
default! Anyway, you would then be able to use
'Message' as your feature type.
>or the message.data (if it'll stay alive) that is an email.Message object ??
See above; just use a model.Attribute whose referencedType is an object
representing the type.
>do i need to define a type for each new feature .. will you accept
You need to define types for anything that's important to your
application. I'll consider contributions based on applicability and
usefulness, but by intention this is an area many apps will want to flesh
out for themselves. For new types, mostly you should use
'model.Immutable', 'model.Struct', or 'model.Element' as a base class, and
actually implement the type. For types reused from elsewhere, you just
need the metadata supplied by a "dummy" class based on
'model.PrimitiveType'. You can see examples of this in
'peak.model.datatypes', where I declare a bunch of string and integer
types. PrimitiveTypes are not themselves ever instantiated; there is never
an instance of 'model.Integer', for example. The PrimitiveType is a
stand-in for the *real* integer type, for purposes of supplying model
metadata and behavior like a standard conversion protocol, typecodes, etc.
>e.g. type that i miss:
>- DateTime (preferable with the new datetime module)
Just make a simple PrimitiveType for it, and you're set.
>- List/Collection Type (does this make sense ??)
Not really. Define the *feature* to be a collection, and set its type to
the type of thing that goes *in* the collection.
>how to handle "References" to e.g. Parents that could be of different type ??
Different from what? See below:
referencedType = 'Folder'
referencedEnd = 'contents'
referencedType = 'File'
referencedEnd = 'parent'
Does that answer your question? In this case, File has a parent of Folder,
because it has no contents. Folders can contain files, so the contents is
of type 'File'. But, a folder *is* a file, so it has a parent, which is
Maybe I don't understand your question. :)
>>* I recommend the idiom 'isChangeable = False' for clarity, in place of
>>using '0' for false. I'm also curious
>>whether the status fields should really be represented as derived
>>attributes or methods instead of as read-only
>>attributes, but I don't know/remember enough about IMAP to give an
>what exactly are derived attributes ( perhaps my (still limited) english
>vocabulary prevents me from understanding ...)
A derived attribute (model.DerivedFeature) is one which is computed rather
than stored. To implement this, you set 'isDerived=True' or subclass
'model.DerivedFeature', and then override the 'get()' method so it computes
and returns the value. 'peak.metamodels.UML13.Foundation.Core' has a
couple of examples, like adding a 'qualifiedName' feature to UML model
>Why doesn't a binding provide an Interface automatically it the instance
>bound defines one ??
Because it would then have to know the instance ahead of time, and the
whole point of a binding is to be lazy. By predeclaring the interface, the
class can keep a registry of what attributes will supply what interfaces,
and when a request for one comes in, it just activates that
attribute. Also, this allows you to declare that an object supports an
interface that is independent of what it claims. For example, the
component might supply an 'ILDAPConnection', but I might declare it to
provide 'IUserDB_LDAPConnection', to say that it fills a particular
application role. As far as the connection knows, it is just a plain LDAP
connection. As far as the application is concerned, it's the *user
database* LDAP connection, though, and not the *mail routing* LDAP
>today we started work on the generic LDAPEntityDM - wouldn't that one
>belong to peak.storage when finished and
>our code quality/implementation is acceptable ??
It would be nice to have one. For my "day job" it may have more stringent
requirements and I'd prefer to maintain only one, but if it can be done by
enhancing yours (if needed) rather than creating one from scratch I'm good
with that too.
Note for example that one particular requirement we have is for
normalization of DN's... we work with different LDAP servers that behave
somewhat quirkily as to their DN syntax, so I want to make sure that any DN
used as an oid has been normalized to a standard format.
>(note on LDAPConnection: the case of keys e.g. objectclass vs. objectClass
>in LDAP is making life hard,
>would it make sense to store ldap-keys in the result allways lower case
>for example ??)
Yes, it would.
>I also started a prototype of a SQLEntityDM that get's a field/index-spec
>and build the needed queries
>(once). it's inspired by PyDO (from skunkweb) .. and i have a question on
>peak tries hard to decouple different ascpects of your app.
>wouldn't it make sense to give the SQLConnections some more methods that
>hide implementation details
>like Sequences, ParameterPlaceholders or StoredProcedure-Calls that are
>not defined in the python dbapi2.
We'll see. One thing I've (almost) learned is that it's better to wait
until closer to when you need something rather than to just go out and
write things like that. The reason I say "almost learned" is that there's
a *lot* in PEAK right now that isn't actually needed yet... like my recent
addition of RLock and ResourceManager to 'peak.util.threads'. I wrote them
to support a vision I had of how to do a generally useful FileDM, but I'm
actually thinking I might not actually use them for the first FileDM I
write, which will be very basic and aimed mainly at getting a primitive
ability to write XMI files.
>again .. thanks and keep going this project and poke on us if you have
>tasks where we could help.
Hmmm... want to work out a way to speed up peak.model attribute
access? :) Currently reading a 'model.Attribute' is from 13 to 39 times
slower than reading regular Python object attributes. I'd be happier with
5 to 10 times, so that's a 3-4x performance increase needed.
More information about the PEAK