[Zope-dev] zope.globalrequest?

Chris McDonough chrism at plope.com
Fri Jan 16 06:39:41 EST 2009


Hanno Schlichting wrote:
> Christian Theune wrote:
>> I noticed 'zope.globalrequest' on the PyPI RSS feed today and wonder
>> about it. IMHO this implements an anti-pattern in an official way
>> without a warning that this needs to be handled with care.
> 
> The discussion for this happened on the plone-dev mailing list. The
> reasoning for the functionality is to provide a clean way to get to the
> request, without relying on Acquisition. Storing the request in a thread
> local is similar to the way other web-frameworks handle this.

One thing I'll suggest if this gets used by Plone or Zope 2: in the unlikely
case that you'd want to call one Zope app from within another (impossible for
various other reasons right not, but maybe not forever), the thread local
structure would need to be a stack.  Something like this:

import threading

class ThreadLocalRequestManager(threading.local):
    def __init__(self):
        self.stack = []

    def push(self, request):
        self.stack.append(request)

    def pop(self):
        if self.stack:
            return self.stack.pop()

    def get(self):
        try:
            return self.stack[-1]
        except IndexError:
            return None

    def clear(self):
        self.stack[:] = []

And then it would be used like so...

manager = ThreadLocalRequestManager()
try:
   manager.push(request)
   .... do stuff ....
finally:
   manager.pop()

> 
> The idea is to have this in default Plone and maybe suggest it for
> inclusion into Zope2 core. For Zope3 it is certainly not appropriate in
> general, as Zope3 has a clear abstraction of request dependent code.

It's probably inappropriate in Zope2 as well, but useful.

One of the reasons you can't run more than one Zope (2 or 3) application in the
same process is that the CA uses a global registry for its ZCML and the various
APIs (getUtility, getAdapter, etc) expect to be able to consult that single
registry, when you might need several.  The only practical way out of this that
keeps old code running is to make a CA registry per application and push "the
right" one on to a thread local stack when a request comes in (and pop it off
when the request is finished).  For this reason, it *might* even be more useful
to build a "context manager" that can manage more than just the request, e.g.

class Context(object):
    def __init__(self, request, registry):
        self.request = request
        self.registry = registry

class ThreadLocalContextManager(threading.local):
    def __init__(self):
        self.stack = []

    def push(self, context):
        self.stack.append(context)

    def pop(self):
        if self.stack:
            return self.stack.pop()

    def get(self):
        try:
            return self.stack[-1]
        except IndexError:
            return global_context

    def clear(self):
        self.stack[:] = []

global_registry = getGlobalSiteManager()
global_context = Context(None, global_registry)
context_manager = ThreadLocalContextManager()

- C


More information about the Zope-Dev mailing list