On Sat, May 24, 2008 at 09:30:18PM +0100, Laurence Rowe wrote:
> Brian Sutherland wrote:
>> On Fri, May 23, 2008 at 11:39:39PM +0100, Laurence Rowe wrote:
>>> We need to differentiate between the interface for session configuration
>>> and session usage from an application.
>>> For session usage I think it is fairly simple. We should define an
>>> ISessionContext interface such that:
>>> class ISessionContext(Interface):
>>> def __call__():
>>> "return a session in this context"
>> (I was thinking about proposing an interface called ISessionMaker doing
>> much the same thing)
>> I'm not sure what "in this context" means?
> The context of this application instance. Say you have two instances of an
> application, one pointed at database A, another at database B. It is
> possible to involve both applications in a single request / transaction.
> You must be sure that you are working with the correct session.
Are the instances you are talking about persistent objects in the ZODB?
>>> A future version of collective.lead could implement an ISessionContext.
>>> Client code however should have a cleaner interface, a plain ISession.
>>> This is accessed through a lookup on the context, translated into a
>>> simple adapter:
>>> def session_adapter(context):
>>> session_context = queryUtility(ISessionContext, context=context,
>> Why call queryUtility with the context keyword?
>>> if session_context is not None:
>>> return session_context()
>>> This will allow application code to do something like:
>>> session = ISession(context)
>>> ob = session.query(MyClass)
>> This really confuses me. What is the context? Does it have any meaning?
>> Or is it just a shorter way to write:
>> session = getUtility(ISessionContext)()
>> Does the value of context have an effect on what you get from the
>> ISession adaptation?
> Yes, as it translates directly to the getUtility lookup. It ensures that
> lookups in /appA go to a local utility defined in /appA and lookups in
> /appB go to a local utility defined in /appB.
I've been burned by using context as a keyword to getUtility before.
When your context doesn't have a proper __parent__ pointer, the default
IComponentLookup adapter falls back to the global site manager and
ignores the local one. That causes no end of confusion and hard to debug
bugs as people will call ISession on objects with and without __parent__
pointers and then wonder why it fails.
Perhaps a more robust way is to rely on the site stored while traversing
* appA implements ISite and has a local ISessionContext utility
* The path appA is traversed over (i.e. the url path is /appA/foo)
* queryUtility(ISessionContext) then returns the local utility from
appA without the need to specify a "context"
(thanks to the magic in zope.app.component.hooks)
I think the only situation where you really want to specify a "context"
for queryUtility is when you want to access a local utility registered
in /appB from a URL path like /appA/foo. That seems pretty rare and
You could implement a function like:
return queryUtility(ISessionContext, name=name)()
That does the right thing in almost all cases (i.e. uses the closest
local site), and is much more robust.
>>> Of course it would be possible to register a ScopedSession globally as
>>> such a utility, but more usually a local utility should be registered.
>> Depends what you're doing. If you are running without a ZODB, you have
>> mostly just global utilities.
>> It would be a pity if zope.sqlalchemy started to depend on the ZODB.
> Wihout ZODB and zope.app.component it seems unlikely that you would be able
> to register a local utility, the idea of ISessionContext is so that you
> might be able to register a ScopedSession as a global utility too.
I very much like the idea of ISessionContext!
I'm just not sure about how you suggest using it in client code.
Zope-Dev maillist - Zope-Dev@zope.org
** No cross posts or HTML encoding! **
(Related lists -