AW: AW: [Zope3-dev] Re: AW: Re: edit view of a object unknown?

Jim Fulton jim at zope.com
Mon Mar 8 10:18:50 EST 2004


Roger ineichen wrote:
> Jim Fulton wrote:
> 

...


>>In your example, would this be a factory for filling in the 
>>question priority field? Or would it be a factory just for 
>>creating priorities, to be used whenevery an IPriority is 
>>expected?  What would you do if more than one factory could 
>>be used to create IPriorities? Would you disallow that? Pick 
>>the first one you find?
> 
> 
> This is the point:
> Right, it's possible to have more then one IPriotity implementation
> on a server. And I don't whant to pick just the first one.

...

> A example of exactly this problem (declare on Interface) you can 
> find in the workflow package in zope.app.workflow,
> they use a import/export handler (ImportExportUtility) and create 
> ProcessDefinitions. It's not possible to have more then one 
> ProcessDefinitions on one server, except you don't know
> which ProssessDefinition is used in the import/export utility
> the wrote in zope.app.workflow.ImportExportUtility.
> ---
> <utility
>     component=".globalimportexport.globalImportExport" 
>     provides="zope.app.interfaces.workflow.IProcessDefinitionImportExport"
>     permission="zope.workflow.ManageProcessDefinitions" 
>     />
> ---
> In the ImportExprotUtility class you see the lines 46-52:
> ---
> for iface, factory in self._importers.getRegisteredMatching():
>     if iface.extends(IProcessDefinition):
>         imp = factory()
>         data.seek(0)
>         if imp.canImport(context, data):
>             data.seek(0)
>             return imp.doImport(context, data)
> ---
> This starts a for: and if the found the first implementation of
> IProcessDefinition they return the first one.
> 
> Exactly here should we call a factory how gets the right implementation
> of the IProcessDefinition.
> 
> It whould be nice to have a directive like.
> ---
> <customObjects
>     for="zope.app.interfaces.workflow.IGlobalProcessDefinitionImportExport"
>     object="zope.app.interfaces.workflow.IProcessDefinition" 
>     uses="zope.app.interfaces.workflow.ProcessDefinition"
>     />
> ---
> And I whould be happy if I can register:
> ---
> <customObjects
>     for="zope.app.interfaces.workflow.IGlobalProcessDefinitionImportExport"
>     interface="zope.app.interfaces.workflow.IProcessDefinition" 
>     object="mypackage.workflow.MyProcessDefinition"
>     />
> ---

I assume that "uses" above should be "factory".

These look a bit like adapter directives.

> These means that we can call in the ImportExportUtility somthing like
> for iface, factory in
> zapi.getRegistredObjectsFor(IGlobalProcessDefinitionImportExport):
>     if iface.extends(IProcessDefinition):
>         imp = factory()
>         data.seek(0)
>         if imp.canImport(context, data):
>             data.seek(0)
>             return imp.doImport(context, data)
> ---
> zapi.getRegistredObjectsFor(AInterface) whould give back all registred 
> Objects for (AInterface). In the example above we get back just one Object 
> (ProcessDefinition or MyProcessDefinition). In other classes we could
> have:
> ---
> <customObjects
>     for="basic.IPerson">
>     <customObject
>        interface="basics.IAddress" 
>        object="basics.Address"
>        />
>     <customObject
>        interface="basics.IDeliveryAdress" 
>        object="custom.MyDeliveryAddress"
>        />
> </customObjects>
> --- 

So, the Interface mentioned in the "for" provides a context for determining
what factory (or what object) to use.



> Generaly I can say, if you declare a class or a factory on a Interface
> it's sometimes not enough. We need additional information
> which Implementation should be used. (If we have more then one
> on a server)

I think you mean to also say that the implemenation to be used should
depend on the place you are using the new thing.

 > At least we run in this problem if scripters
> setup servers and download different products. They don't
> know how many classes implement a Interface. And we will
> get a lot of troubles with this setups.

 > The example above with the workflow works very well until
> a product is installed with a class which is implementing
> (IProcessDefinition), exactly at this time you can't say which 
> class is used. (it's the first class we get form the method
> getRegisteredMatching()).
> 
> Declaring on Interfaces means for me, great flexibility.
> But we loose this felxibility in the implementation.
> And run into problems if the scripters setup servers 
> and not exactly know what they do. In my option if we have 
> to declare the (customObjects) we can anybody tell
> which calss will be added if they run a method like
> the (importProcessDefinition) method in the (ImportExportUtility)
> because they have to declare it  in ZCML.
> 
> I don't hoppe that's a YAGNI. Otherwise sorry about the long mail
> and my crazy wishes. But my wish is; if we use such a complex
> mechanism like ZCML we should be able to support this (layer)
> very well, otherwise we jump all the time between python class
> coding and ZCML arround.

I want to be very careful about creating new kinds of registrations.
We got ourselves into a bad spot by havingg many kinds of registrations.
Fortunately, we realized that most of them could be recast as utilities.

So let me see if I understand you.

When using a particular sort of object, you want to be able to control
what factory is used to compute an implementation for an interface.
To put this more generally, given an object that you are already using,
you want to be able to control how to perform some other function, in
this case, creating an object that provides an interface.

This is what adapters are for. So, for the process-definition example,
we would have:

   <adapter
       for="zope.app.interfaces.workflow.IProcessDefinitionImportExport"
       provides="zope.app.interfaces.workflow.IProcessDefinition"
       factory="mypackage.workflow.MyProcessDefinition"
       />


Then the import/export utility would create a process definition like
this:

    process_definition = IProcessDefinition(self)

Note that before last weekend, this would have been spelled:

    process_definition = zapi.getAdapter(self, IProcessDefinition)

Also note that your factory would take the import/export object
as an argument.


Thanks for providing a concrete example.

Jim

-- 
Jim Fulton           mailto:jim at zope.com       Python Powered!
CTO                  (540) 361-1714            http://www.python.org
Zope Corporation     http://www.zope.com       http://www.zope.org




More information about the Zope3-dev mailing list