Calling an Handler from another one

2,991 views
Skip to first unread message

Meir Kriheli

unread,
Mar 21, 2012, 7:30:19 AM3/21/12
to python-tornado
Hi,

I'd like to instantiate and call another handler from the current handler using the same method,  using it to add  to (or optionally replace) the current response. The original handlers should and can be called as usual (via url spec)

This is needed for the implementation of "route" handler, which will serve the responses from the appropriate handlers based on  GET params - so  URL specs won't help.

Is instantiating the handler (passing to it the application and request) enough ? How is the response handled in that case ?

Thanks
--
Meir

Aleksandar Radulovic

unread,
Mar 21, 2012, 8:34:25 AM3/21/12
to python-...@googlegroups.com
It seems to me that you're doing something out of the ordinary.. First
of all, why are you implementing a "route" handler, when the routing
is very capable?

Maybe one way of solving this is by using helper methods (instead of
actuall handlers) which would be called from your "route" handler and
the original handlers.

-alex

--
a lex 13 x
http://a13x.net | @a13xnet

Meir Kriheli

unread,
Mar 21, 2012, 8:42:09 AM3/21/12
to python-...@googlegroups.com
HI,

On Wed, Mar 21, 2012 at 2:34 PM, Aleksandar Radulovic <al...@a13x.net> wrote:
It seems to me that you're doing something out of the ordinary.. First
of all, why are you implementing a "route" handler, when the routing
is very capable?


That's the demand of the api designers, not my call. I prefer URL specs, and those are already implemented, now the need I've described above.

 
Maybe one way of solving this is by using helper methods (instead of
actuall handlers) which would be called from your "route" handler and
the original handlers.


That's one way, But there are lots of them, and I prefer not rewrite/refactor all of them.
 
-alex

On Wed, Mar 21, 2012 at 12:30 PM, Meir Kriheli <mkri...@gmail.com> wrote:
> Hi,
>
> I'd like to instantiate and call another handler from the current handler
> using the same method,  using it to add  to (or optionally replace) the
> current response. The original handlers should and can be called as usual
> (via url spec)
>
> This is needed for the implementation of "route" handler, which will serve
> the responses from the appropriate handlers based on  GET params - so  URL
> specs won't help.
>
> Is instantiating the handler (passing to it the application and request)
> enough ? How is the response handled in that case ?
>
> Thanks
> --
> Meir



--
a lex 13 x
http://a13x.net | @a13xnet



--

Didip Kerabat

unread,
Mar 21, 2012, 12:53:15 PM3/21/12
to python-...@googlegroups.com
Using mixin is the typical way to share common method between different handlers.

You can take a look at tornado.auth mixins for ideas.

- Didip -

Alek Storm

unread,
Mar 21, 2012, 4:48:27 PM3/21/12
to python-...@googlegroups.com
This sounds like a typical RPC pattern, where all requests are sent to the same URL endpoint, and the server dispatches the request to the correct handler based on the `method` URI parameter. I'd make all the RPC method handlers methods of your RequestHandler class, and dispatch inside your `get()` method:

class RPCHandler(RequestHandler):
    HANDLERS = ('add', 'delete', 'query', 'etc')
    def get(self):
        method = self.get_argument('method')
        if method in self.HANDLERS:
            getattr(self, method)()

    def add(self):
        # handle

Alek

Meir Kriheli

unread,
Mar 22, 2012, 3:25:09 AM3/22/12
to python-...@googlegroups.com
Hi,

Thanks for all this, we're already using Mixins and helper functions a lot, but trust me that this scenario is not same. The are other scenarios as well, e.g:

/get/movies/ which should be mapped/routed to something like /get_section/<movies_section_id>/, but the actual movies_section_id is dynamic settings/database dependant, and will vary between installations.

Please, back to the original question, can it be done ?

Alek Storm

unread,
Mar 22, 2012, 3:48:35 AM3/22/12
to python-...@googlegroups.com
Assuming your routing looks like this:

Application([
    (r"/get/movies", MoviesHandler),
    (r"/get_section/([^/]+)", SectionHandler),
])

You can do this in MoviesHandler:

class MoviesHandler(RequestHandler):
    def get(self):
        SectionHandler(self.application, self.request).get(movies_section_id)

Your use case is interesting. I wrote a web framework on top of the Tornado HTTPServer that would handle exposing the same resource through multiple URIs quite gracefully - I should get around to releasing it.

Alek

Meir Kriheli

unread,
Mar 29, 2012, 9:27:00 AM3/29/12
to python-...@googlegroups.com
Hi,

On Thu, Mar 22, 2012 at 9:48 AM, Alek Storm <alek....@gmail.com> wrote:
Assuming your routing looks like this:

Application([
    (r"/get/movies", MoviesHandler),
    (r"/get_section/([^/]+)", SectionHandler),
])

You can do this in MoviesHandler:

class MoviesHandler(RequestHandler):
    def get(self):
        SectionHandler(self.application, self.request).get(movies_section_id)

Your use case is interesting. I wrote a web framework on top of the Tornado HTTPServer that would handle exposing the same resource through multiple URIs quite gracefully - I should get around to releasing it.

Alek


Thanks. Looks like it isn't enough, had to copy some values, and also call finish(), to make sure close callbacks are cleared:

            e.get()

            self._write_buffer = e._write_buffer
            self._headers = e._headers
            self._status_code = e._status_code
            self.finish()

Anything else missing ?

Thanks
 

Alek Storm

unread,
Mar 29, 2012, 3:23:25 PM3/29/12
to python-...@googlegroups.com
You have three options. The first is to call:

SectionHandler(self.application, self.request)._execute(
    [t(self.request) for t in self.application.transforms], movies_section_id)

The second is to construct a new HTTPRequest object, with the same connection object as the original, and send that through routing:

self.application(new httpserver.HTTPRequest(
    method=self.request.method,
    uri=self.request.uri,
    version=self.request.version,
    headers=self.request.headers,
    connection=self.request.connection)

The third is to refactor your code. I still recommend this, and fail to see why it's impossible.

Alek
Reply all
Reply to author
Forward
0 new messages