There has been an ongoing debate about whether StackedObjectProxies
(SOPs) are necessary in Pylons, vs going back to threadlocals.

The general wisdom is that SOPs are necessary only when running
multiple instances of Pylons applications in the same process; e.g.,
in composite scenarios.  This is a rare situation, but Pylons uses
SOPs anyway to avoid failures when the situation does come up.

The problem is that this concurrent-applications issue takes an
inordinate amount of developer time to address.  It has come up with
SQLAlchemy's Session, Routes, and WebHelpers.  Threadlocals are a
well-understood Python-wide issue, and relatively easy to implement
because you create a threadlocal.threadlocal() object and it magically
does the right thing. But SOPs are a Pylons peculiarity and require
explicit registration (pushing/popping values), which makes one
hesitate before using them in say Routes.  At minimum it's an
additional dependency.

Compounding the problem, Pylons, Routes, and WebHelpers are
interdependent in a way that's not shown by their formal dependencies,
which I'm now trying to unravel.  Routes url_for() depends on
request_config(), which uses a threadlocal set by the Routes
middleware (for the current request info). The Rails helpers import
url_for and several functions use it, including its redirect_to().
The new helpers improve on this by explicitily importing
routes.url_for in the functions that use it, and documenting this
dependency.  pylons.controllers.util also imports url_for and defines
another redirect_to().  All this is a circle of interdependencies.

WebHelpers 0.6 encourages the new helpers but many programmers put
"from webhelpers.rails import *" into their apps because they're using
the old helpers throughout.  This is necessary as a transition stage,
but it makes it harder to clean up the interdependencies because
people are still using rails.url_for and rails.redirect_to, even in
new applications.

As I said, request_config is a threadlocal.  That's apparently
incorrect under Pylons; it should be a SOP.  But no users have
complained about wrong URLs due to this.  Perhaps that's because few
sites do compositing.  Or perhaps we're being overly paranoid.  Or
perhaps because the data is request local and initialized for every
request, which is not the case for pylons.app_globals.

So could SOPs be removed by making sure Pylons refreshes the pylons.*
globals at the beginning of every request, perhaps using a hidden SOP
to manage app_globals?  Or could we leave app_globals a SOP and
convert the others to threadlocals?  app_globals is highly
Pylons-specific and is not used for very many things.  Most
importantly, it's not something Routes or WebHelpers care about,
whereas they do have an interest in the current request info and
session.

With SQLAlchemy's Session, we've never resolved what happens if you
share it between instances of the same Pylons app mounted at different
points in the same site.  Does it matter?  Again, each request in a
thread proceeds from beginning to end, going through exactly one app
instance.  And if they're mounted as app-subapp, the subapp should
have full_stack=False.  The difference affects whether the Session can
be a module variable in a composite scenario, or whether it has to be
under app_globals.

As for Routes, matching is done in the middleware so it has direct
access to the request info.  But url_for doesn't have direct access.
Pylons could inject into Routes and WebHelpers a url factory function
like this:

    def environ_factory():
        from pylons import request
        return request.environ

If request is already a SOP (or threadlocal?), this would let url_for
and WebHelpers access the current data on demand.  Then the question
becomes, where to inject it.  Routes already has a middleware but
WebHelpers does not. But this can't be built into the middleware
because it's Pylons specific.  So Pylons would have to provide the
functions, and the user would have to pass them to the middlewares'
constructors.

This is similar to an idea I've been bandying about for a while,
whether to define a generic "framework services" API for WebHelpers,
so that it can access the request info and session and generate URLs
without being tied to a framework.  This was too complicated for
Routes 0.6, so it just imports url_for and pylons.session directly.
And the code is actually simpler that way.  And it wouldn't be that
difficult for another framework user to copy the class and reimplement
the Pylons-specific parts.  But in order to eliminate that
request_config, I'd need to do something like this  environ_factory or
a framework services API.

-- 
Mike Orr <[EMAIL PROTECTED]>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"pylons-devel" group.
To post to this group, send email to pylons-devel@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/pylons-devel?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to