From: Fredrik Tolf Date: Mon, 2 Sep 2013 01:26:39 +0000 (+0200) Subject: Merge branch 'master' into python3 X-Git-Url: http://dolda2000.com/gitweb/?p=wrw.git;a=commitdiff_plain;h=babf3e21cb06bf867e3ec98003d4a077090b8839;hp=-c Merge branch 'master' into python3 Conflicts: wrw/resp.py wrw/util.py --- babf3e21cb06bf867e3ec98003d4a077090b8839 diff --combined wrw/cookie.py index b66e293,140ba8f..c6e848f --- a/wrw/cookie.py +++ b/wrw/cookie.py @@@ -1,5 -1,5 +1,5 @@@ -import Cookie, time -import proto +import http.cookies, time +from . import proto __all__ = ["cookies", "get", "add"] @@@ -11,10 -11,10 +11,10 @@@ def addcookies(req) class cookiedict(object): def __init__(self, req): try: - self.bk = Cookie.SimpleCookie(req.ihead.get("Cookie")) - except Cookie.CookieError: - self.bk = Cookie.SimpleCookie() - self.codec = Cookie.SimpleCookie() + self.bk = http.cookies.SimpleCookie(req.ihead.get("Cookie")) + except http.cookies.CookieError: + self.bk = http.cookies.SimpleCookie() + self.codec = http.cookies.SimpleCookie() req.oncommit(addcookies) def __getitem__(self, name): @@@ -23,14 -23,14 +23,14 @@@ def __contains__(self, name): return name in self.bk - def get(self, name, default = None): + def get(self, name, default=None): if name not in self.bk: return default return self.bk[name].value def add(self, name, value, **kw): self.codec[name] = value - for key, value in kw.iteritems(): + for key, value in kw.items(): self.codec[name][key] = value def __setitem__(self, name, value): @@@ -39,7 -39,7 +39,7 @@@ def cookies(req): return req.item(cookiedict) - def get(req, name, default = None): + def get(req, name, default=None): return cookies(req).get(name, default) def add(req, name, value, **kw): diff --combined wrw/form.py index 98d2ed9,0363b0b..c97b0f9 --- a/wrw/form.py +++ b/wrw/form.py @@@ -1,5 -1,5 +1,5 @@@ import cgi -import proto +from . import proto __all__ = ["formdata"] @@@ -13,7 -13,7 +13,7 @@@ class formwrap(object) def __getitem__(self, key): return self.cf[key][0] - def get(self, key, default = ""): + def get(self, key, default=""): if key in self: return self.cf[key][0] return default @@@ -32,7 -32,7 +32,7 @@@ return list(iter()) def keys(self): - return self.cf.keys() + return list(self.cf.keys()) def values(self): return [val for key, val in self.items()] @@@ -43,7 -43,7 +43,7 @@@ class badmultipart(Exception) class formpart(object): def __init__(self, form): self.form = form - self.buf = "" + self.buf = b"" self.eof = False self.head = {} @@@ -52,8 -52,8 +52,8 @@@ def fillbuf(self, sz): req = self.form.req - mboundary = "\r\n--" + self.form.boundary + "\r\n" - lboundary = "\r\n--" + self.form.boundary + "--\r\n" + mboundary = b"\r\n--" + self.form.boundary + b"\r\n" + lboundary = b"\r\n--" + self.form.boundary + b"--\r\n" while not self.eof: p = self.form.buf.find(mboundary) if p >= 0: @@@ -78,7 -78,7 +78,7 @@@ raise badmultipart("Missing last multipart boundary") self.form.buf += ret - def read(self, limit = -1): + def read(self, limit=-1): self.fillbuf(limit) if limit >= 0: ret = self.buf[:limit] @@@ -88,10 -88,10 +88,10 @@@ self.buf = "" return ret - def readline(self, limit = -1): + def readline(self, limit=-1): last = 0 while True: - p = self.buf.find('\n', last) + p = self.buf.find(b'\n', last) if p < 0: if self.eof: ret = self.buf @@@ -114,15 -114,12 +114,15 @@@ self.close() return False - def parsehead(self): + def parsehead(self, charset): def headline(): ln = self.readline(256) - if ln[-1] != '\n': + if ln[-1] != ord(b'\n'): raise badmultipart("Too long header line in part") - return ln.rstrip() + try: + return ln.decode(charset).rstrip() + except UnicodeError: + raise badmultipart("Form part header is not in assumed charset") ln = headline() while True: @@@ -154,33 -151,29 +154,33 @@@ raise badmultipart("Form part uses unexpected transfer encoding: %r" % encoding) class multipart(object): - def __init__(self, req): + def __init__(self, req, charset): val, par = proto.pmimehead(req.ihead.get("Content-Type", "")) if req.method != "POST" or val != "multipart/form-data": raise badmultipart("Request is not a multipart form") if "boundary" not in par: raise badmultipart("Multipart form lacks boundary") - self.boundary = par["boundary"] + try: + self.boundary = par["boundary"].encode("us-ascii") + except UnicodeError: + raise badmultipart("Multipart boundary must be ASCII string") self.req = req - self.buf = "\r\n" + self.buf = b"\r\n" self.eof = False + self.headcs = charset self.lastpart = formpart(self) self.lastpart.close() def __iter__(self): return self - def next(self): + def __next__(self): if not self.lastpart.eof: raise RuntimeError("All form parts must be read entirely") if self.eof: raise StopIteration() self.lastpart = formpart(self) - self.lastpart.parsehead() + self.lastpart.parsehead(self.headcs) return self.lastpart def formdata(req): diff --combined wrw/proto.py index 0a6a430,8c8dcee..96a8878 --- a/wrw/proto.py +++ b/wrw/proto.py @@@ -98,14 -98,14 +98,15 @@@ def simpleerror(env, startreq, code, ti """ % (title, title, htmlq(msg)) + buf = buf.encode("us-ascii") startreq("%i %s" % (code, title), [("Content-Type", "text/html"), ("Content-Length", str(len(buf)))]) return [buf] def urlq(url): ret = "" + invalid = "&=#?/\"'" for c in url: - if c == "&" or c == "=" or c == "#" or c == "?" or c == "/" or (ord(c) <= 32): + if c in invalid or (ord(c) <= 32): ret += "%%%02X" % ord(c) else: ret += c diff --combined wrw/req.py index 11f856c,41fd330..016d2d8 --- a/wrw/req.py +++ b/wrw/req.py @@@ -19,9 -19,9 +19,9 @@@ class headdict(object) del self.dict[key.lower()] def __iter__(self): - return iter((list[0] for list in self.dict.itervalues())) + return iter((list[0] for list in self.dict.values())) - def get(self, key, default = ""): + def get(self, key, default=""): if key.lower() in self.dict: return self.dict[key.lower()][1] return default @@@ -67,29 -67,29 +67,29 @@@ class limitreader(object) ra = min(ra, size) while len(self.buf) < ra: ret = self.bk.read(ra - len(self.buf)) - if ret == "": + if ret == b"": raise IOError("Unexpected EOF") self.buf.extend(ret) self.rb += len(ret) - ret = str(self.buf[:ra]) + ret = bytes(self.buf[:ra]) self.buf = self.buf[ra:] return ret def readline(self, size=-1): off = 0 while True: - p = self.buf.find('\n', off) + p = self.buf.find(b'\n', off) if p >= 0: - ret = str(self.buf[:p + 1]) + ret = bytes(self.buf[:p + 1]) self.buf = self.buf[p + 1:] return ret off = len(self.buf) if size >= 0 and len(self.buf) >= size: - ret = str(self.buf[:size]) + ret = bytes(self.buf[:size]) self.buf = self.buf[size:] return ret if self.rb == self.limit: - ret = str(self.buf) + ret = bytes(self.buf) self.buf = bytearray() return ret ra = self.limit - self.rb @@@ -97,7 -97,7 +97,7 @@@ ra = min(ra, size) ra = min(ra, 1024) ret = self.bk.read(ra) - if ret == "": + if ret == b"": raise IOError("Unpexpected EOF") self.buf.extend(ret) self.rb += len(ret) @@@ -109,9 -109,9 +109,9 @@@ class lineiter(object): def __iter__(self): return self - def next(self): + def __next__(self): ret = rd.readline() - if ret == "": + if ret == b"": raise StopIteration() return ret return lineiter() @@@ -148,7 -148,7 +148,7 @@@ class origrequest(request) self.input = limitreader(env["wsgi.input"], int(clen)) else: # XXX: What to do? - self.input = io.BytesIO("") + self.input = io.BytesIO(b"") else: # Assume input is chunked and read until ordinary EOF. self.input = env["wsgi.input"] diff --combined wrw/resp.py index ebd98ec,7fae787..965df6c --- a/wrw/resp.py +++ b/wrw/resp.py @@@ -1,5 -1,5 +1,5 @@@ -import dispatch, proto, env -from sp import xhtml +from . import dispatch, proto, env +from .sp import xhtml h = xhtml.cons() __all__ = ["skeleton", "skelfor", "setskel", "usererror"] @@@ -28,7 -28,7 +28,7 @@@ def setskel(req, skel) class usererror(dispatch.restart): def __init__(self, message, *detail): - super(usererror, self).__init__() + super().__init__() self.message = message self.detail = detail @@@ -36,40 -36,46 +36,46 @@@ return skelfor(req).error(req, self.message, *self.detail) class message(dispatch.restart): - def __init__(self, msg, *detail): - super(message, self).__init__() - self.message = msg + def __init__(self, message, *detail): + super().__init__() + self.message = message self.detail = detail def handle(self, req): - return skelfor(req).error(req, self.message, *self.detail) + return skelfor(req).message(req, self.message, *self.detail) class httperror(usererror): - def __init__(self, status, message = None, detail = None): + def __init__(self, status, message=None, detail=None): if message is None: message = proto.statusinfo[status][0] if detail is None: detail = (proto.statusinfo[status][1],) - super(httperror, self).__init__(message, *detail) + super().__init__(message, *detail) self.status = status def handle(self, req): req.status(self.status, self.message) - return super(httperror, self).handle(req) + return super().handle(req) class notfound(httperror): def __init__(self): - return super(notfound, self).__init__(404) + return super().__init__(404) class redirect(dispatch.restart): - def __init__(self, url, status = 303): + bases = {"url": proto.requrl, + "script": proto.scripturl, + "site": proto.siteurl} + + def __init__(self, url, status=303, base="url"): - super(redirect, self).__init__() + super().__init__() self.url = url self.status = status + self.bases[base] + self.base = base def handle(self, req): req.status(self.status, "Redirect") - req.ohead["Location"] = proto.appendurl(proto.requrl(req), self.url) + req.ohead["Location"] = proto.appendurl(self.bases[self.base](req), self.url) req.ohead["Content-Length"] = 0 return [] diff --combined wrw/session.py index 0a17c6d,1e615e3..e7d8581 --- a/wrw/session.py +++ b/wrw/session.py @@@ -1,5 -1,5 +1,5 @@@ import threading, time, pickle, random, os -import cookie, env +from . import cookie, env __all__ = ["db", "get"] @@@ -11,12 -11,12 +11,12 @@@ def hexencode(str) def gennonce(length): nonce = "" - for i in xrange(length): + for i in range(length): nonce += chr(random.randint(0, 255)) return nonce class session(object): - def __init__(self, lock, expire = 86400 * 7): + def __init__(self, lock, expire=86400 * 7): self.id = hexencode(gennonce(16)) self.dict = {} self.lock = lock @@@ -39,7 -39,7 +39,7 @@@ def __getitem__(self, key): return self.dict[key] - def get(self, key, default = None): + def get(self, key, default=None): return self.dict.get(key, default) def __setitem__(self, key, value): @@@ -74,7 -74,7 +74,7 @@@ return "" % self.id class db(object): - def __init__(self, backdb = None, cookiename = "wrwsess", path = "/"): + def __init__(self, backdb=None, cookiename="wrwsess", path="/"): self.live = {} self.cookiename = cookiename self.path = path @@@ -86,7 -86,7 +86,7 @@@ def clean(self): now = int(time.time()) with self.lock: - clist = self.live.keys() + clist = list(self.live.keys()) for sessid in clist: with self.lock: try: @@@ -204,7 -204,7 +204,7 @@@ data = self.backdb[sessid] try: return pickle.loads(data) - except Exception, e: + except: raise KeyError() def freeze(self, sess): @@@ -235,7 -235,7 +235,7 @@@ class dirback(object) with open(os.path.join(self.path, key), "w") as out: out.write(value) - default = env.var(db(backdb = dirback(os.path.join("/tmp", "wrwsess-" + str(os.getuid()))))) + default = env.var(db(backdb=dirback(os.path.join("/tmp", "wrwsess-" + str(os.getuid()))))) def get(req): return default.val.get(req) diff --combined wrw/sp/cons.py index 74a6ea6,ce258c6..c4d9999 --- a/wrw/sp/cons.py +++ b/wrw/sp/cons.py @@@ -3,18 -3,18 +3,18 @@@ import xml.dom.minido class node(object): pass -class text(node, unicode): +class text(node, str): def __todom__(self, doc): return doc.createTextNode(self) -class raw(node, unicode): +class raw(node, str): def __todom__(self, doc): raise Exception("Cannot convert raw code to DOM objects") class element(node): def __init__(self, ns, name, ctx): self.ns = ns - self.name = unicode(name) + self.name = str(name) self.ctx = ctx self.attrs = {} self.children = [] @@@ -22,13 -22,13 +22,13 @@@ def __call__(self, *children, **attrs): for child in children: self.ctx.addchild(self, child) - for k, v in attrs.iteritems(): + for k, v in attrs.items(): self.ctx.addattr(self, k, v) return self def __todom__(self, doc): el = doc.createElementNS(self.ns, self.name) - for k, v in self.attrs.iteritems(): + for k, v in self.attrs.items(): el.setAttribute(k, v) for child in self.children: el.appendChild(child.__todom__(doc)) @@@ -41,9 -41,10 +41,9 @@@ class context(object): def __init__(self): self.nodeconv = {} - self.nodeconv[str] = lambda ob: text(ob, "utf-8") - self.nodeconv[unicode] = text + self.nodeconv[bytes] = lambda ob: text(ob, "utf-8") + self.nodeconv[str] = text self.nodeconv[int] = text - self.nodeconv[long] = text self.nodeconv[float] = text def nodefrom(self, ob): @@@ -59,10 -60,10 +59,10 @@@ node.children.append(self.nodefrom(child)) def addattr(self, node, k, v): - node.attrs[unicode(k)] = unicode(v) + node.attrs[str(k)] = str(v) class constructor(object): - def __init__(self, ns, elcls = element, ctx=None): + def __init__(self, ns, elcls=element, ctx=None): self._ns = ns self._elcls = elcls if ctx is None: ctx = context() diff --combined wrw/util.py index ed32cc6,7459b6d..79a8240 --- a/wrw/util.py +++ b/wrw/util.py @@@ -1,5 -1,5 +1,5 @@@ import inspect, math -import req, dispatch, session, form, resp, proto +from . import req, dispatch, session, form, resp, proto def wsgiwrap(callable): def wrapper(env, startreq): @@@ -7,26 -7,17 +7,26 @@@ wrapper.__wrapped__ = callable return wrapper +def stringwrap(charset): + def dec(callable): + def wrapper(*args, **kwargs): + bk = callable(*args, **kwargs) + for string in bk: + yield string.encode(charset) + return wrapper + return dec + def formparams(callable): + spec = inspect.getargspec(callable) def wrapper(req): data = form.formdata(req) - spec = inspect.getargspec(callable) args = dict(data.items()) args["req"] = req if not spec.keywords: for arg in list(args): if arg not in spec.args: del args[arg] - for i in range(len(spec.args) - len(spec.defaults)): - for i in xrange(len(spec.args) - (len(spec.defaults) if spec.defaults else 0)): ++ for i in range(len(spec.args) - (len(spec.defaults) if spec.defaults else 0)): 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) @@@ -71,7 -62,7 +71,7 @@@ class funplex(object) return fun return dec - def persession(data = None): + def persession(data=None): def dec(callable): def wrapper(req): sess = session.get(req) @@@ -94,12 -85,12 +94,12 @@@ class preiter(object) self.bk = real self.bki = iter(real) self._next = None - self.next() + self.__next__() def __iter__(self): return self - def next(self): + def __next__(self): if self._next is self.end: raise StopIteration() ret = self._next @@@ -121,7 -112,7 +121,7 @@@ def pregen(callable) class sessiondata(object): @classmethod - def get(cls, req, create = True): + def get(cls, req, create=True): sess = cls.sessdb().get(req) with sess.lock: try: @@@ -140,7 -131,7 +140,7 @@@ class autodirty(sessiondata): @classmethod def get(cls, req): - ret = super(autodirty, cls).get(req) + ret = super().get(req) if "_is_dirty" not in ret.__dict__: ret.__dict__["_is_dirty"] = False return ret @@@ -152,18 -143,18 +152,18 @@@ return self._is_dirty def __setattr__(self, name, value): - super(autodirty, self).__setattr__(name, value) + super().__setattr__(name, value) if "_is_dirty" in self.__dict__: self.__dict__["_is_dirty"] = True def __delattr__(self, name): - super(autodirty, self).__delattr__(name, value) + super().__delattr__(name, value) if "_is_dirty" in self.__dict__: self.__dict__["_is_dirty"] = True class manudirty(object): def __init__(self, *args, **kwargs): - super(manudirty, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.__dirty = False def sessfrozen(self): @@@ -206,7 -197,7 +206,7 @@@ class specslot(object) class specclass(type): def __init__(self, name, bases, tdict): - super(specclass, self).__init__(name, bases, tdict) + super().__init__(name, bases, tdict) sslots = set() dslots = set() for cls in self.__mro__: @@@ -218,7 -209,8 +218,7 @@@ for i, slot in enumerate(self.__sslots_a__): setattr(self, slot, specslot(slot, i, slot in dslots)) -class specdirty(sessiondata): - __metaclass__ = specclass +class specdirty(sessiondata, metaclass=specclass): __slots__ = ["session", "__sslots__", "_is_dirty"] def __specinit__(self): @@@ -226,7 -218,7 +226,7 @@@ @staticmethod def __new__(cls, req, sess): - self = super(specdirty, cls).__new__(cls) + self = super().__new__(cls) self.session = sess self.__sslots__ = [specslot.unbound] * len(cls.__sslots_a__) self.__specinit__()