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 -~----------~----~----~----~------~----~------~--~---