Creating decorator that modifies _cp_dispatch

33 views
Skip to first unread message

Adam Baxter

unread,
Jun 23, 2019, 10:08:32 AM6/23/19
to cherrypy-users
Hi,
Perhaps I'm thinking about this the wrong way, but I can't seem to work out how I'd make a decorator like cherrypy.expose, except for modifying the way dispatch works.

What I'd like to do is implement an explicit decorator that /maps/path/segments to variables

@from_path("some","variable","here")
def my_function(*args,**kwargs):
   #if I GET /my_function/one/two/three
   #kwargs would be: {'some': 'one', 'variable': 'two', 'here': 'three'}

but I can't figure out what I need to pass back to the "pipeline" for cherrypy to keep working correctly.

Thanks,
Adam

Sviatoslav Sydorenko

unread,
Jun 23, 2019, 3:40:03 PM6/23/19
to cherryp...@googlegroups.com
It's a classic case for decorators with args. You need to write a function which would return decorator, which would return the substitution for a decorated object.

def from_path(*keys):
    def decorator(http_handler):
        def handler_wrapper(*args, **kwargs):
            return http_handler(*args, **kwargs)  # <-- change kwargs here
        return handler_wrapper
    return decorator

нд, 23 черв. 2019 о 16:08 Adam Baxter <volt...@voltagex.org> пише:
--
You received this message because you are subscribed to the Google Groups "cherrypy-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cherrypy-user...@googlegroups.com.
To post to this group, send email to cherryp...@googlegroups.com.
Visit this group at https://groups.google.com/group/cherrypy-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/cherrypy-users/69b04f8b-99ae-4846-8489-77e0a37b2ce9%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Cheers,
Sviatoslav.

Adam Baxter

unread,
Jul 28, 2019, 5:19:00 AM7/28/19
to cherrypy-users


On Monday, 24 June 2019 05:40:03 UTC+10, Sviatoslav Sydorenko (@webknjaz) wrote:
It's a classic case for decorators with args. You need to write a function which would return decorator, which would return the substitution for a decorated object.

def from_path(*keys):
    def decorator(http_handler):
        def handler_wrapper(*args, **kwargs):
            return http_handler(*args, **kwargs)  # <-- change kwargs here
        return handler_wrapper
    return decorator


Apologies for the super delayed response.

This looks like what I need, but where does http_handler come from in this case?

--Adam
нд, 23 черв. 2019 о 16:08 Adam Baxter <volt...@voltagex.org> пише:
Hi,
Perhaps I'm thinking about this the wrong way, but I can't seem to work out how I'd make a decorator like cherrypy.expose, except for modifying the way dispatch works.

What I'd like to do is implement an explicit decorator that /maps/path/segments to variables

@from_path("some","variable","here")
def my_function(*args,**kwargs):
   #if I GET /my_function/one/two/three
   #kwargs would be: {'some': 'one', 'variable': 'two', 'here': 'three'}

but I can't figure out what I need to pass back to the "pipeline" for cherrypy to keep working correctly.

Thanks,
Adam

--
You received this message because you are subscribed to the Google Groups "cherrypy-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cherryp...@googlegroups.com.


--
Cheers,
Sviatoslav.

Adam Baxter

unread,
Jul 28, 2019, 5:50:51 AM7/28/19
to cherrypy-users
Getting closer:

def from_path(*keys):
    def decorator(http_handler):
        def handler_wrapper(*args, **kwargs):
            kwargs = dict(zip(keys,args))
            return http_handler(args[0], **kwargs)
        return handler_wrapper
    return decorator

class HelloWorld(object):
    def _cp_dispatch(self, vpath):
        print("dispatching " + repr(vpath))
        return self.index
   
    @cherrypy.expose('/')
    @from_path('one','two','three')
    def index(self, **kwargs):
        return f"My kwargs were {kwargs}"
   
cherrypy.quickstart(HelloWorld())


If I GET /a/b/c, the server responds with:
My kwargs were {'one': <__main__.HelloWorld object at 0x7f45622dd860>, 'two': 'b', 'three': 'c'}

I am unsure what's eating the first path segment there.

I would like to implement something similar to the way ASP.NET does attribute-based routing but I'm not sure how much further I'll get. It's been an interesting dive into CherryPy at the least.

Sviatoslav Sydorenko

unread,
Jul 28, 2019, 4:36:30 PM7/28/19
to cherryp...@googlegroups.com
Try logging args/kwargs in your wrapper:

+ print(args)
+ print(kwargs)
  kwargs = dict(zip(keys,args))

But I have another question now: why do you need _cp_dispatch there? What's your end-goal? It seems like you're just looking to reimplement the default method with a regular URI traversal based dispatcher.

I've made a small demo for you. Is this what you're looking for?

$ cat cp_default_handler_demo.py
#! /usr/bin/env python
"""Demo of how to use the ``default`` handler method."""

import cherrypy


class HelloWorld:
    """Collection of traversed URL handlers."""

    @cherrypy.expose
    def index(self, **params):  # pylint: disable=no-self-use
        """Root URI HTTP handler."""
        return f'Hello from index, see params: {params}'

    @cherrypy.expose
    def foo(self, **params):  # pylint: disable=no-self-use
        """Foo URI HTTP handler."""
        return f"""
            Hello from foo, see params: {params};<br>
            cp params: {cherrypy.request.params}
        """

    @cherrypy.expose
    # pylint: disable=no-self-use
    def default(self, one, two=None, three=None, **params):
        """Default URI HTTP handler."""
        return f"""
            Hello from default, see params: {params};<br>
            cp params: {cherrypy.request.params}<br>
            one={one}; two={two}; three={three}
        """


cherrypy.config.update({
    'server.socket_port': 33333,
})
# pylint: disable=expression-not-assigned
__name__ == '__main__' and cherrypy.quickstart(HelloWorld(), '/', {})

$ ./cp_default_handler_demo.py
[28/Jul/2019:22:30:05] ENGINE Listening for SIGTERM.
[28/Jul/2019:22:30:05] ENGINE Listening for SIGHUP.
[28/Jul/2019:22:30:05] ENGINE Listening for SIGUSR1.
[28/Jul/2019:22:30:05] ENGINE Bus STARTING
CherryPy Checker:
The Application mounted at '' has an empty config.

[28/Jul/2019:22:30:05] ENGINE Started monitor thread 'Autoreloader'.
[28/Jul/2019:22:30:05] ENGINE Serving on http://127.0.0.1:33333
[28/Jul/2019:22:30:05] ENGINE Bus STARTED
127.0.0.1 - - [28/Jul/2019:22:30:13] "GET / HTTP/1.1" 200 32 "" "curl/7.65.1"
127.0.0.1 - - [28/Jul/2019:22:30:20] "GET / HTTP/1.1" 200 32 "" "curl/7.65.1"
127.0.0.1 - - [28/Jul/2019:22:30:29] "GET /?x=y HTTP/1.1" 200 40 "" "curl/7.65.1"
127.0.0.1 - - [28/Jul/2019:22:30:40] "GET /foo HTTP/1.1" 200 83 "" "curl/7.65.1"
127.0.0.1 - - [28/Jul/2019:22:30:44] "GET /foo?x=y HTTP/1.1" 200 99 "" "curl/7.65.1"
127.0.0.1 - - [28/Jul/2019:22:31:20] "GET /o/t/tt?hoho=wow HTTP/1.1" 200 152 "" "curl/7.65.1"
^C[28/Jul/2019:22:31:32] ENGINE Keyboard Interrupt: shutting down bus
[28/Jul/2019:22:31:32] ENGINE Bus STOPPING
[28/Jul/2019:22:31:32] ENGINE HTTP Server cherrypy._cpwsgi_server.CPWSGIServer(('127.0.0.1', 33333)) shut down
[28/Jul/2019:22:31:32] ENGINE Stopped thread 'Autoreloader'.
[28/Jul/2019:22:31:32] ENGINE Bus STOPPED
[28/Jul/2019:22:31:32] ENGINE Bus EXITING
[28/Jul/2019:22:31:32] ENGINE Bus EXITED
[28/Jul/2019:22:31:32] ENGINE Waiting for child threads to terminate...

$ curl http://127.0.0.1:33333
Hello from index, see params: {}
$ curl http://127.0.0.1:33333/\?x\=y
Hello from index, see params: {'x': 'y'}
$ curl http://127.0.0.1:33333/foo

            Hello from foo, see params: {};<br>
            cp params: {}
        
$ curl http://127.0.0.1:33333/foo\?x\=y


нд, 28 лип. 2019 о 11:50 Adam Baxter <volt...@voltagex.org> пише:
--
You received this message because you are subscribed to the Google Groups "cherrypy-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cherrypy-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cherrypy-users/40055517-97e3-482b-abe0-ea329ea55f45%40googlegroups.com.


--
Cheers,
Sviatoslav.
Reply all
Reply to author
Forward
0 new messages