From: Fredrik Tolf Date: Wed, 5 Jun 2013 10:58:54 +0000 (+0200) Subject: Merge branch 'python3' of git.dolda2000.com:/srv/git/r/wrw into python3 X-Git-Url: http://dolda2000.com/gitweb/?p=wrw.git;a=commitdiff_plain;h=a9a78095b1696f56946abfc7c284f86a21fdcc2d;hp=3b67497cb853ea7dd49f579566e5f0b60a3c97d7 Merge branch 'python3' of git.dolda2000.com:/srv/git/r/wrw into python3 --- diff --git a/wrw/__init__.py b/wrw/__init__.py index acf7f64..eb4a0a0 100644 --- a/wrw/__init__.py +++ b/wrw/__init__.py @@ -1,7 +1,7 @@ __all__ = ["wsgiwrap", "restart", "cookie", "formdata"] from . import proto -from .util import wsgiwrap, stringwrap, formparams, persession, sessiondata, autodirty, manudirty, specdirty +from .util import wsgiwrap, stringwrap, formparams, funplex, persession, sessiondata, autodirty, manudirty, specdirty from .dispatch import restart from . import cookie from .form import formdata diff --git a/wrw/dispatch.py b/wrw/dispatch.py index 768d3f4..5276892 100644 --- a/wrw/dispatch.py +++ b/wrw/dispatch.py @@ -24,6 +24,7 @@ def defaulterror(req, excinfo): def wraphandler(handler, excinfo): def wrapped(req): return handler(req, excinfo) + wrapped.__wrapped__ = handler return wrapped errorhandler = env.var(defaulterror) diff --git a/wrw/resp.py b/wrw/resp.py index bdceb90..ebd98ec 100644 --- a/wrw/resp.py +++ b/wrw/resp.py @@ -72,3 +72,9 @@ class redirect(dispatch.restart): req.ohead["Location"] = proto.appendurl(proto.requrl(req), self.url) req.ohead["Content-Length"] = 0 return [] + +class unmodified(dispatch.restart): + def handle(self, req): + req.status(304, "Not Modified") + req.ohead["Content-Length"] = "0" + return [] diff --git a/wrw/sp/util.py b/wrw/sp/util.py index df3e6ab..ad99e8b 100644 --- a/wrw/sp/util.py +++ b/wrw/sp/util.py @@ -1,3 +1,5 @@ +import io +from .. import dispatch from . import cons def findnsnames(el): @@ -144,6 +146,12 @@ class formatter(object): def fragment(cls, out, el, *args, **kw): cls(out=out, root=el, *args, **kw).node(el) + @classmethod + def format(cls, el, *args, **kw): + buf = io.BytesIO() + cls.output(buf, el, *args, **kw) + return buf.getvalue() + def update(self, **ch): ret = type(self).__new__(type(self)) ret.__dict__.update(self.__dict__) @@ -212,3 +220,20 @@ class indenter(formatter): def start(self): super(indenter, self).start() self.write('\n') + +class response(dispatch.restart): + charset = "utf-8" + doctype = None + formatter = indenter + + def __init__(self, root): + super().__init__() + self.root = root + + @property + def ctype(self): + raise Exception("a subclass of wrw.sp.util.response must override ctype") + + def handle(self, req): + req.ohead["Content-Type"] = self.ctype + return [self.formatter.format(self.root, doctype=self.doctype, charset=self.charset)] diff --git a/wrw/sp/xhtml.py b/wrw/sp/xhtml.py index 52e7f9f..5f1ca45 100644 --- a/wrw/sp/xhtml.py +++ b/wrw/sp/xhtml.py @@ -60,4 +60,5 @@ def forreq(req, tree): def xhtmlresp(callable): def wrapper(req): return forreq(req, callable(req)) + wrapper.__wrapped__ = callable return wrapper diff --git a/wrw/util.py b/wrw/util.py index eaa6a62..ed32cc6 100644 --- a/wrw/util.py +++ b/wrw/util.py @@ -1,9 +1,10 @@ -import inspect -from . import req, dispatch, session, form, resp +import inspect, math +from . import req, dispatch, session, form, resp, proto def wsgiwrap(callable): def wrapper(env, startreq): return dispatch.handleenv(env, startreq, callable) + wrapper.__wrapped__ = callable return wrapper def stringwrap(charset): @@ -29,8 +30,47 @@ def formparams(callable): if spec.args[i] not in args: raise resp.httperror(400, "Missing parameter", ("The query parameter `", resp.h.code(spec.args[i]), "' is required but not supplied.")) return callable(**args) + wrapper.__wrapped__ = callable return wrapper +class funplex(object): + def __init__(self, *funs, **nfuns): + self.dir = {} + self.dir.update(((self.unwrap(fun).__name__, fun) for fun in funs)) + self.dir.update(nfuns) + + @staticmethod + def unwrap(fun): + while hasattr(fun, "__wrapped__"): + fun = fun.__wrapped__ + return fun + + def __call__(self, req): + if req.pathinfo == "": + raise resp.redirect(req.uriname + "/") + if req.pathinfo[:1] != "/": + raise resp.notfound() + p = req.pathinfo[1:] + if p == "": + p = "__index__" + bi = 1 + else: + p = p.partition("/")[0] + bi = len(p) + 1 + if p in self.dir: + return self.dir[p](req.shift(bi)) + raise resp.notfound() + + def add(self, fun): + self.dir[self.unwrap(fun).__name__] = fun + return fun + + def name(self, name): + def dec(fun): + self.dir[name] = fun + return fun + return dec + def persession(data = None): def dec(callable): def wrapper(req): @@ -43,6 +83,7 @@ def persession(data = None): sess[data] = data() sess[callable] = callable(data) return sess[callable].handle(req) + wrapper.__wrapped__ = callable return wrapper return dec @@ -75,6 +116,7 @@ class preiter(object): def pregen(callable): def wrapper(*args, **kwargs): return preiter(callable(*args, **kwargs)) + wrapper.__wrapped__ = callable return wrapper class sessiondata(object): @@ -220,3 +262,10 @@ class specdirty(sessiondata, metaclass=specclass): ss[i] = specslot.unbound else: ss[i] = val + +def datecheck(req, mtime): + if "If-Modified-Since" in req.ihead: + rtime = proto.phttpdate(req.ihead["If-Modified-Since"]) + if rtime >= math.floor(mtime): + raise resp.unmodified() + req.ohead["Last-Modified"] = proto.httpdate(mtime)