[PEAK] References between models

Phillip J. Eby pje at telecommunity.com
Thu Nov 13 12:09:38 EST 2003


At 05:14 PM 11/13/03 +0100, Radek Kanovsky wrote:
>Hi all,
>
>I am not sure how to solve this problem. There is following directory
>structure:
>
>    mylib/:           __init__.py
>    mylib/contact/:   __init__.py model.py storage.py ...
>    mylib/invoice/:   __init__.py model.py storage.py ...
>    mylib/service/:   __init__.py model.py storage.py ...
>    ....
>
>`contact', `invoice', `service', etc. are components that contains
>Element definitions (model.py) and corresponding data managers
>(storage.py). Every component implements one aspect or problem
>and application is simply built (often) by assembling components
>together. But it is obvious that invoices must belong to some
>subject so there is reference to mylib.contact.model.Contact from
>mylib.invoice.model.Invoice:
>
>     mylib/invoice/model.py:
>
>             class Invoice (model.Element) :
>                 ...
>                 class contact (model.Attribute) :
>                     referencedType = mylib.contact.model.Contact
>                 ...
>
>And that is exactly what I don't like very much. There are for example
>15 components that have reference to mylib.contact.model.Contact. If
>there is need for replacing default mylib.contact.model.Contact with
>something slightly different, I need to repair 15 Elements in particular
>application only for this simple purpose.
>
>I am not sure where to aim my investigation. Elements don't support
>properties lookup and have restricted component lookup because they
>have no IConfigurationRoot among parents. What I am thinking of now is
>something as ElementTemplate with some substitution capabilities.
>Not finished yet, just idea:

Why not use constants, e.g.:

CONTACT = 'mylib/contact/model/Contact'

class Invoice...
     ...
         class contact...
             referencedType = CONTACT


If the problem is actually that you need to have variations of your 
package(s) that replace certain classes, then using module inheritance (see 
the API docs for peak.config.modules) may be the solution.


>Is this reasonable? Is there some other solution for such situations?

There's an easier way to do what you did.  Note that configuration lookups 
go by way of a '_getConfigData' method on a component.  So, in your 'mylib' 
package module, you could add:

protocols.advise(moduleProvides = [config.IConfigSource])

def _getConfigData(forObj,key):
     # do something based on key, and return a value or NOT_FOUND

And once you've done this, you can use PropertyName() instances to link to 
other elements.

This is sort of a hack, because peak.model.features checks for 
isinstance(referencedType,str) and then does a lookup.  I should change 
this to instead adapt to an 'ITypeReference' interface, so that any 
IConfigKey (such as interfaces, property names, etc.) can potentially be 
used to access a type.  But, that should be backward-compatible with the 
hacky approach.

Note that one way you could implement your _getConfigData method is as follows:

protocols.advise(moduleProvides = [config.IConfigSource])
map = config.PropertyMap()
config.loadConfigFile(map, config.fileNearModule(__name__,'peak.ini'))
_getConfigData = map._getConfigData
del map

Now, you'll have a package-level configuration based on 'peak.ini' in the 
package directory.

To everybody else: DON'T DO THIS UNLESS YOU UNDERSTAND THE 
LIMITATIONS.  This is *not* really configuration, despite what it looks 
like.  There's no real "configuration" because everything is a 
constant.  Obviously, whatever file you load is going to be a 
constant.  You might think, "well I could get something from the 
environment, or...".  Stop right there.  Now you're *bypassing* the 
configuration system, which is based on component context, not on globals.

Modules cannot have meaningful configuration because modules are 
singletons.  There is only one, so how can it be "configured"?  It is what 
it is, so it cannot be configured differently for different uses.  This is 
exactly why modules do not have a configuration root in PEAK, or by default 
have any configuration mechanism.  If you need to do something special like 
what Radek is trying to do, you can use these hacks to have some 
configuration, but it is ultimately a hack.




More information about the PEAK mailing list