[TransWarp] peak.naming .. first contact

Phillip J. Eby pje at telecommunity.com
Fri Feb 14 12:42:49 EST 2003

At 04:27 PM 2/14/03 +0100, Ulrich Eck wrote:
>Imap is somewhat special, cause is has basically 3 different types of
>1. Connection: The Connection is the root object that does basically all
>   all the work.
>   it should be accessible through an URL like: 
> "imap://user:auth@host.name:port"

Sounds good.  Note that you can derive the connection from 
storage.ManagedConnection if you want to make use of its "lazy opening" 

>2. Folder: Folders can contain other Folders and Messages. Folders should
>   probably be Contexts that allow retrieval of child-Folders and Messages
>   as well as creating child-Folders and Messages.
>   a FolderURL would look like this: 
> "imap://user:auth@host.name:port/folder.path"
>3. Message: The Message is the "Leaf" of that tree that represent the 
>actual message
>   given an MessageUrl the message should be retrieved from the server.
>   a MessageURL would look like this: 
> "imap://user:auth@host.name:port/folder.path/123"
>What i have now:
>1. an imapURL(naming.ParsedURL) class that does the parsing of that url 
>   the retrieve method currently returns:
>   - a connection-object if no folder/message was given
>   - a connection-object with the selected Folder if folder given but not 
> message
>   - an email.Message-object if folder/messageid is given.
>2. an imapFolderPath(naming.CompoundName) that defines that a folder-path 
>is seperated
>   with a "." and left-to-right.
>what i think i need (but don't know how to implement):
>- ImapFolderContext: a naming.NameContext that represents that actual folder
>   hierarchy and has methods to lookup/bind other contexts and leafs.
>i've had a look at the Property-Context impl, where the URL doesn't 
>implement the
>"retrieve" method but the context has _get/_contextNNS methods implemented.
>Am I on the right path ??

Here's a sketch of what I suggest:

class imapFolderContext(naming.NameContext):

     def imapConn(self,d,a):
         return imapConnection(address=self.namingAuthority)

     imapConn = binding.Once(imapConn, provides=IConnectionToIMAP)

     def _get(self, name, retrieve=True):
         # this is rough; you'll need to flesh it out a bit
         return self.__class__(self, namingAuthority=self.namingAuthority,

     def _contextNNS(self, attrs=None):
         # this needs work too...
         return imapMessageContext(self, folderPath=self.nameInContext, 
...), attrs

class imapMessageContext(naming.NameContext):

     imapConn = binding.bindTo(IConnectionToIMAP)

     # _get method retrieves message from folder using self.imapConn

These two contexts will use different 'compoundParser' definitions; the 
first one wants a '.'-based name parser for the folder path, and the other 
wants a flat syntax for the message number.  Your imapURL will use a 
*composite* name parser for its body, and the folder path syntax for its 
*compound* parser.

The URL class doesn't need a retrieve method.  That's for URLs which are 
pure addresses that don't really have a "name in context" part, just a 
"naming authority" part.

Anyway, you want to use a composite name and two kinds of contexts here, 
because the folder naming system is not the same as the message naming 
system.  The '/' between the folder path and the message identifier 
effectively means "go to the Next Naming System" (NNS).  So by implementing 
a _contextNNS() method that returns another naming context class that 
implements the "next naming system", PEAK will bridge the gap for you.

The PropertyContext, PropertyPath, and PropertyURL classes in 
peak.naming.factories.config_ctx are good examples for all of this, except 
that you need a second context class, and also a way to "pass down" a 
connection object among the contexts so that they can share the same 
connection.  Once you've done this, you can do things like:


fooFolderCtx = aContext['foo'] # get subfolder 'folder.path.foo'
aMessage = aContext['/1234']  # message 1234 from 'folder.path'

barMsgCtx = fooFolderCtx['bar/']  # message context for 'folder.path.foo.bar'
anotherMsg = barMsgCtx['456']   # message 456 from 'folder.path.foo.bar'

See how this works?

As far as the folder (not message) contexts go, you probably want to 
implement 'createSubcontext' and 'destroySubcontext', not bind/unbind.  The 
message context can implement bind/unbind, which means you can do:



fooFolderCtx['/1234'] = aMessage

Note that even though the folder context doesn't implement bind/unbind, the 
composite name will be looked up using the 'resolveToInterface()' method, 
and the message context will be told to "bind('1234',aMessage)".

>I also thought about building datamanagers for imap-access, but i have no
>idea how to setup tree-like dm-structures. Setting up datamangers would
>have the advantage of being able to cache results and more ..

It's certainly possible to do that, but the implementation structure would 
probably be very different than what I've outlined.  Instead of passing 
down a connection between contexts, you'd probably need to pass down the 
data manager.

>or (if more appropriate) how to build dm's for tree-like content?
>(i could imagine using a tuple(<folder>,[None|messageid]) as key for the dm.)

You could do it that way, if by '<folder>' you mean a folder path string.

I'd say that the optimal way to do this depends a lot on your application 
and how it wants to use IMAP.  If you need to acess IMAP in a 
"navigational" way, naming contexts might be better.  If you need to 
address specific objects or transform representation, data managers are 
more suited.  If you need a mixture of both, you can combine the two, 
either as a data manager that returns naming contexts, or as a set of 
naming contexts that use a data manager "behind the scenes".

More information about the PEAK mailing list