Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request helper functions #108

Closed
notoriousno opened this issue May 30, 2016 · 1 comment
Closed

Request helper functions #108

notoriousno opened this issue May 30, 2016 · 1 comment

Comments

@notoriousno
Copy link
Contributor

notoriousno commented May 30, 2016

Right now, I have a module that contain helper functions I use to minimize the number lines of code I'm forced to write. Most of the functions are similar to those that Tornado uses to get arguments or form values from a request. I use the following functions frequently (they're similar to Tornado's get_arguments, get_argument, decode_argument functions):

def getter(args, key, default=None):
    try:
        key = key.encode('UTF-8')
    except:
        raise Exception('ERROR: Cannot encode key (%s) using UTF-8' % (str(key)))

    return args.get(key, default)

def getOne(args, key, default=None):
    return getter(args, key, [default])[0]

def getOneCast(args, key, default=None, cast=None, decode=None):
    result = getOne(args, key, default)
    if decode:
        try:
            result = result.decode(decode)
        except Exception as e:
            raise Exception(ERROR: Unable to decode {0} using {1}.\nTRACEBACK: {2}'.format(result, decode, e))
    try:
        return cast(result)
    except Exception as e:
        raise Exception('ERROR: Unable to cast {0}.\nTRACEBACK: {1}'.format(result, e))

I wanted to take a "cleaner" and "simpler" approach and integrate the Request object with these functions, so that I can make a quick call like request.getOne('key'). But I cannot seem to find how to do that. I tried adding the functions to IKleinRequest and KleinRequest for a quick test, but that didn't work. The Request obj that gets passed into the route function is a twisted.web.server.Request obj, so I'm guessing the is getting passed somewhere in the the Twisted code. Is it possible to overload the Request object that gets passed into the route functions using Klein, or will I have to do more diving into Twisted?

Ideally I'd like to be able to only modify Request.args to be able to use a dict like object, but that's a pipe dream at the moment :)

Links

@notoriousno
Copy link
Contributor Author

I figured out how to do this with a bit of Twisted basics. I started by subclassing the Site and Request classes (twisted.web.server). In the Request subclass, I added the helper functions. Then I overloaded the buildProto() function in the Site subclass so the Site.requestFactory is set to my subclassed Request. Then I slightly modified what klein.app.Klein.run does and start a TCP server using my subclasses. Works like a charm!

from klein import Klein
from twisted.web import http, server
from twisted.internet import reactor


#----- Subclasses -----#
class KleinHTTPRequest(server.Request):
    """ Request subclass """

    def getter(self, key, default=None):
        # ...

    def getOne(self, key, default=None):
        # ...

    def getOneCast(self, key, cast, default=None, decoding=None):
       # ...

class KleinSite(server.Site):
    """ Site subclass """

    def buildProtocol(self, addr):
        channel = http.HTTPFactory.buildProtocol(self, addr)
        channel.requestFactory = KleinHTTPRequest            # produce subclassed Request
        channel.site = self
        return channel


#----- Routes -----#
app = Klein()

@app.route('/hello', methods=['POST'])
def home(request):
    return b'hello ' + request.getOne('name', 'world')


#----- Start server -----#
reactor.listenTCP(8000, KleinSite(app.resource()), interface='localhost')
reactor.run()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant