[TG2] custom middleware access to tg cache

104 views
Skip to first unread message

Rob

unread,
Jul 31, 2013, 4:20:27 AM7/31/13
to turbo...@googlegroups.com
Using TG v2.2.2 I am trying to access the beaker cache from a custom middleware object but I'm getting an error:
 "TypeError: No object (name: cache) has been registered for this thread."

As per the docs, I am using `wrap_app` in the  construction of `make_base_app`
Stripped down to its bare essentials, I have:

from tg import cache
from proj.config.app_cfg import base_config
from proj.config.environment import load_environment

class MyMiddleware(object):
    base_path = "/my_route"

    def __init__(self, app):        
        self.app = app

    def __call__(self, environment, start_response):
        path = environment.get('PATH_INFO')
        if not path.startswith(self.basepath):
            return self.app(environment, start_response)

        # access cache here.
        # c = environment.get('beaker.cache')   
        # rg = c.regions             # this works
        
        # rg = cache.regions         # should be available from the import but throws:
                                     # TypeError: No object (name: cache) registered in the thread

        status = '200 OK'
        response_headers = [('Content-type','text/plain')]
        start_response(status, response_headers)
        return ['Hello world!\n']


def make_app(global_conf, full_stack=True, **app_conf):
    app = make_base_app(global_conf,
                        full_stack=True, 
                        wrap_app=MyMiddleware,
                        **app_conf
                        )
    
In the __call__() of the custom middleware I am able to access the cache, using:
    c = environment.get('beaker.cache')

But my understanding from the docs is that I should be able to access this via the `from tg import cache` -- and I need to be able to access the cache from a separate function, called by the __call__().  In other words, the cache (in the stack) should be available to any controllers/methods post setup of the custom middleware.  

My understanding of the docs is that, having used `wrap_app` I should have access to the full stack (including the cache) --- but I am unable to access it... 

How am I able to access the cache?  (Is my method above close?!)

Many thanks,
Rob

Moritz Schlarb

unread,
Jul 31, 2013, 4:59:20 AM7/31/13
to turbo...@googlegroups.com
I'd suspect it's simply a matter of importing scope! I had that a while back, too...

Try placing from tg import cache inside the __call__ method and see if it works then!

Rob

unread,
Jul 31, 2013, 5:13:33 AM7/31/13
to turbo...@googlegroups.com
Thank you for the suggestion Moritz, but with the import placed inside the __call__ methode, I still get the same error....

Alessandro Molina

unread,
Aug 1, 2013, 3:04:15 PM8/1/13
to TurboGears .
On Wed, Jul 31, 2013 at 10:20 AM, Rob <robert....@gmail.com> wrote:
Using TG v2.2.2 I am trying to access the beaker cache from a custom middleware object but I'm getting an error:
 "TypeError: No object (name: cache) has been registered for this thread."

As per the docs, I am using `wrap_app` in the  construction of `make_base_app`
Stripped down to its bare essentials, I have:



Hi,
when using WSGI Middlewares you are constrained to the WSGI environment.
WSGI middlewares wrap around the TG application and so everything which is available inside TG itself like the TurboGears Context (tg.request/response/cache), Request and Response objects and so on are not available.

To cope with this issue, TG2.3 introduced application wrappers. They are much like WSGI middlewares but receive a TurboGears Context as parameter and are expected to return a Response object. Inside application wrappers the context is available and so tg.* objects are accessible.

Application wrappers also permit to specify their ordering, so it is possible to say "run this wrapper around this other wrapper" even though they are registered at different times.
You can see a simple example of application wrappers at https://github.com/TurboGears/tg2/blob/master/tests/test_configuration.py#L636


 

Rob

unread,
Aug 2, 2013, 4:44:06 AM8/2/13
to turbo...@googlegroups.com
Hi Alessandro,

Thanks for your response and apologies for taking such a long time getting back to you.

In this particular case, I'm aware that I'm restricted to WSGI... the methods/controllers I'm trying to construct would have to use their own webob response/request.  (Which is absolutely fine!)

I'm having trouble understanding how I can get access to the tg cache and I'm getting a `TypeError No object (name: cache)` -- I'm tied to TG v2.2 for the time being...

Is what I'm trying to do (shown in my first post) possible??

Regards,
Rob. 



PS.  Interestingly, I found a package on github called tgext.less https://bitbucket.org/clsdaniel/tgext.less
which, in and example in the readme section, gives the following:

 
from tgext.less import LESSMiddleware
from tg import cache

make_base_app = base_config.setup_tg_wsgi_app(load_environment)

def make_app(global_conf, full_stack=True, **app_conf):
    app = make_base_app(global_conf, full_stack=True, **app_conf)

    # LESS with beaker cache backend
    app = LESSMiddleware(app, cache=cache)

    return app


But I have absolutely no idea how this example is supposed to work...!

Alessandro Molina

unread,
Aug 2, 2013, 5:48:12 AM8/2/13
to TurboGears .
On Fri, Aug 2, 2013 at 10:44 AM, Rob <robert....@gmail.com> wrote:

I'm having trouble understanding how I can get access to the tg cache and I'm getting a `TypeError No object (name: cache)` -- I'm tied to TG v2.2 for the time being...


As stated in my previous email the TurboGears context is not available outside of the turbogears application.
As your middleware is wrapping around the application is called before the application, and so the context is not available.
The context includes the cache, so tg.cache is not available inside a middleware. WSGI middleware should not make the assumption that they are running inside TG as they are actually running before TG. 

If you really need to use tg.* objects you are limited to using controller_wrappers which are available also in 2.2. Look at http://turbogears.readthedocs.org/en/development/reference/reference.html#tg.configuration.AppConfig.register_hook if you want to see an example.

Otherwise you are bound to environ['beaker.cache'] which is plain WSGI and doesn't require any TG feature.


Rob

unread,
Aug 2, 2013, 7:13:22 AM8/2/13
to turbo...@googlegroups.com

(should anyone else read this post...)
I think my confusion may have stemmed directly from the (v2.2) documentation....  http://turbogears.readthedocs.org/en/rtfd2.2.2/main/RequestFlow.html

"to use a middleware before the TurboGears stack is processed you can wrap the application returned by make_base_app function:

    app = make_base_app(global_conf, full_stack=True, **app_conf)
    app = MyMiddleware(app)
    return app

To use a middleware that is TurboGears specific and wants to have the full TurboGears stack available (session, authentication, database, etc...) you can pass the middleware class to the make_base_app and it will be created wrapping the application:

    app = make_base_app(global_conf, full_stack=True, wrap_app=MyMiddleware, **app_conf)
    return app


From the docs, I assumed that using the latter (ie by using wrap_app) my custom middleware would be wrapped inside of the stack -- and hence have the access.

Thank you very much for the clarification, Alessandro.  I'll have a look to see if `register_hook` can do the job.


Many thanks,
Rob 
Reply all
Reply to author
Forward
0 new messages