2010-11-20

(第3回)Python mini Hack-a-thon

Python mini Hack-a-thon に初めて行きました。もともと Plone/Zope の hack-a-thon だったらしいのですが、最近は Plone/Zope に特化していないのということなので、こっそり参加です。何かを作り上げるっていうよりも、Python 3.2 を使うことが目的でした。が、しかし、最初の自己紹介で「Python 3 で何かつくる」って言ってしまった手前、まあなにかやろう、と。

標準ライブラリだけを使って、BaseHTTPRequestHandler を継承してフレームワークを作るというのが、どんなもんか、というのが興味あったのですよね。WSGI とかは無視で。

実は一番困ったのは、BaseHTTPRequestHandler.wfile.write() には文字列ではなくて、bytes や bytearray を渡す必要があったんですね。このへん、Python 3 の話をするときにいつも言ってるのですが、自分がやってしまうとは。

久しぶりに、どうでもいいコードを書いた。たのしぃ。やべぇ。

     
import sys
import http.server
import re

PORT = 8001

# --------------------------------------------------------------
# Request handler
# --------------------------------------------------------------

class Handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        return self.show()

    def show(self):
        view = self._find_view(self.path)
        response = view(Request(self.path, self.command))
        response.render(self)

    def _find_view(self, path):
        for pattern, view in urls:
            if re.match("^"+pattern+"$", path):
                break
        else:
            view = error_404
        return view

class Request(object):
    def __init__(self, path, method):
        self.path = path
        self.method = method

class Response(object):
    def __init__(self, data,
                 headers={"Content-type":"text/html"}):
        self.status = 200
        self.headers = headers
        self.data = data

    def render(self, handler):
        self._render_status(handler)
        self._render_headers(handler)
        self._render_content(handler)

    def _render_status(self, handler):
        handler.send_response(self.status)
   
    def _render_headers(self, handler):
        for k,v in self.headers.items():
            handler.send_header(k, v)
        handler.end_headers()

    def _render_content(self, handler):
        data = self.data
        if data is not None:
            handler.wfile.write(data.encode("utf8"))
   
# --------------------------------------------------------------
# View(s)
# --------------------------------------------------------------

def index(request):
    t = "<html><head><title>Hello</title></head><body><p>Hello</p></body></html>"
    return Response(t)

def error_404(request):
    response = Response("404 Not Found", {})
    response.status = 404
    return response

# --------------------------------------------------------------
# main
# --------------------------------------------------------------
   
urls = [('/hoge.*', index)]

def main():
    print("serving at port", PORT)
    httpd = http.server.HTTPServer(("", PORT), Handler)
    httpd.serve_forever()

if __name__ == "__main__":
    main()