-#!/usr/bin/python
+#!/usr/bin/python3
from distutils.core import setup, Extension
__all__ = ["wsgiwrap", "restart", "cookie", "formdata"]
-import proto
-from util import wsgiwrap, formparams, funplex, persession, sessiondata, autodirty, manudirty, specdirty
-from dispatch import restart
-import cookie
-from form import formdata
+from . import proto
+from .util import wsgiwrap, stringwrap, formparams, funplex, persession, sessiondata, autodirty, manudirty, specdirty
+from .dispatch import restart
+from . import cookie
+from .form import formdata
-import Cookie, time
-import proto
+import http.cookies, time
+from . import proto
__all__ = ["cookies", "get", "add"]
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):
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):
import sys, traceback
-import env, req, proto
+from . import env, req, proto
__all__ = ["restart"]
return [str(result)]
def defaulterror(req, excinfo):
- import resp
+ from . import resp
traceback.print_exception(*excinfo)
raise resp.httperror(500)
try:
resp = handler(req)
break
- except restart, i:
+ except restart as i:
handler = i.handle
- except Exception, i:
+ except Exception as i:
if eh is None:
raise
handler = wraphandler(eh, sys.exc_info())
import os
-import resp
+from . import resp
pj = os.path.join
__all__ = ["filehandler"]
elif ext == "html":
ctype = "text/html"
req.ohead["Content-Type"] = ctype
- return open(path, "r")
+ return open(path, "rb")
def resolvefile(self, req, curpath, el):
if os.path.isfile(pj(curpath, el)):
import cgi
-import proto
+from . import proto
__all__ = ["formdata"]
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()]
class formpart(object):
def __init__(self, form):
self.form = form
- self.buf = ""
+ self.buf = b""
self.eof = False
self.head = {}
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:
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
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:
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):
</body>
</html>
""" % (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]
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=""):
if key.lower() in self.dict:
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
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)
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()
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"]
-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"]
class usererror(dispatch.restart):
def __init__(self, message, *detail):
- super(usererror, self).__init__()
+ super().__init__()
self.message = message
self.detail = detail
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):
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):
bases = {"url": proto.requrl,
"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]
import threading, time, pickle, random, os
-import cookie, env
+from . import cookie, env
__all__ = ["db", "get"]
def gennonce(length):
nonce = ""
- for i in xrange(length):
+ for i in range(length):
nonce += chr(random.randint(0, 255))
return nonce
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:
data = self.backdb[sessid]
try:
return pickle.loads(data)
- except Exception, e:
+ except:
raise KeyError()
def freeze(self, sess):
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 = []
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))
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):
def addattr(self, node, k, v):
if v is not None:
- node.attrs[unicode(k)] = unicode(v)
+ node.attrs[str(k)] = str(v)
class constructor(object):
def __init__(self, ns, elcls=element, ctx=None):
-import StringIO
-from wrw import dispatch
-import cons
+import io
+from .. import dispatch
+from . import cons
def findnsnames(el):
names = {}
def proc(el):
if isinstance(el, cons.element):
if el.ns not in names:
- names[el.ns] = u"n" + unicode(nid[0])
+ names[el.ns] = "n" + str(nid[0])
nid[:] = [nid[0] + 1]
for ch in el.children:
proc(ch)
def quotewrite(self, buf):
for ch in buf:
- if ch == u'&':
- self.write(u"&")
- elif ch == u'<':
- self.write(u"<")
- elif ch == u'>':
- self.write(u">")
+ if ch == '&':
+ self.write("&")
+ elif ch == '<':
+ self.write("<")
+ elif ch == '>':
+ self.write(">")
else:
self.write(ch)
self.write(el)
def attrval(self, buf):
- qc, qt = (u"'", u"'") if u'"' in buf else (u'"', u""")
+ qc, qt = ("'", "'") if '"' in buf else ('"', """)
self.write(qc)
for ch in buf:
- if ch == u'&':
- self.write(u"&")
- elif ch == u'<':
- self.write(u"<")
- elif ch == u'>':
- self.write(u">")
+ if ch == '&':
+ self.write("&")
+ elif ch == '<':
+ self.write("<")
+ elif ch == '>':
+ self.write(">")
elif ch == qc:
self.write(qt)
else:
def attr(self, k, v):
self.write(k)
- self.write(u'=')
+ self.write('=')
self.attrval(v)
def shorttag(self, el, **extra):
- self.write(u'<' + self.elname(el))
- for k, v in el.attrs.iteritems():
- self.write(u' ')
+ self.write('<' + self.elname(el))
+ for k, v in el.attrs.items():
+ self.write(' ')
self.attr(k, v)
- for k, v in extra.iteritems():
- self.write(u' ')
+ for k, v in extra.items():
+ self.write(' ')
self.attr(k, v)
- self.write(u" />")
+ self.write(" />")
def elname(self, el):
ns = self.nsnames[el.ns]
if ns is None:
return el.name
else:
- return ns + u':' + el.name
+ return ns + ':' + el.name
def starttag(self, el, **extra):
- self.write(u'<' + self.elname(el))
- for k, v in el.attrs.iteritems():
- self.write(u' ')
+ self.write('<' + self.elname(el))
+ for k, v in el.attrs.items():
+ self.write(' ')
self.attr(k, v)
- for k, v in extra.iteritems():
- self.write(u' ')
+ for k, v in extra.items():
+ self.write(' ')
self.attr(k, v)
- self.write(u'>')
+ self.write('>')
def endtag(self, el):
- self.write(u'</' + self.elname(el) + u'>')
+ self.write('</' + self.elname(el) + '>')
def longtag(self, el, **extra):
self.starttag(el, **extra)
raise Exception("Unknown object in element tree: " + el)
def start(self):
- self.write(u'<?xml version="1.0" encoding="' + self.charset + u'" ?>\n')
+ self.write('<?xml version="1.0" encoding="' + self.charset + '" ?>\n')
if self.doctype:
- self.write(u'<!DOCTYPE %s PUBLIC "%s" "%s">\n' % (self.root.name,
- self.doctype[0],
- self.doctype[1]))
+ self.write('<!DOCTYPE %s PUBLIC "%s" "%s">\n' % (self.root.name,
+ self.doctype[0],
+ self.doctype[1]))
extra = {}
- for uri, nm in self.nsnames.iteritems():
+ for uri, nm in self.nsnames.items():
if uri is None:
continue
if nm is None:
- extra[u"xmlns"] = uri
+ extra["xmlns"] = uri
else:
- extra[u"xmlns:" + nm] = uri
+ extra["xmlns:" + nm] = uri
self.element(self.root, **extra)
@classmethod
@classmethod
def format(cls, el, *args, **kw):
- buf = StringIO.StringIO()
+ buf = io.BytesIO()
cls.output(buf, el, *args, **kw)
return buf.getvalue()
self.col = 0
def write(self, buf):
- for c in buf:
- if c == '\n':
+ for i in range(len(buf)):
+ c = buf[i:i + 1]
+ if c == b'\n':
self.col = 0
else:
self.col += 1
if self.atbol:
return
if self.col != 0:
- self.write('\n')
+ self.write(b'\n')
self.write(indent)
self.atbol = True
class indenter(formatter):
- def __init__(self, indent=u" ", *args, **kw):
+ def __init__(self, indent=" ", *args, **kw):
super(indenter, self).__init__(*args, **kw)
self.out = iwriter(self.out)
self.indent = indent
- self.curind = u""
+ self.curind = ""
def simple(self, el):
for ch in el.children:
formatter = indenter
def __init__(self, root):
- super(response, self).__init__()
+ super().__init__()
self.root = root
@property
-import xml.dom.minidom, StringIO
-import cons as _cons
-import util
+import xml.dom.minidom, io
+from . import cons as _cons
+from . import util
dom = xml.dom.minidom.getDOMImplementation()
-ns = u"http://www.w3.org/1999/xhtml"
-doctype = u"-//W3C//DTD XHTML 1.1//EN"
-dtd = u"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
+ns = "http://www.w3.org/1999/xhtml"
+doctype = "-//W3C//DTD XHTML 1.1//EN"
+dtd = "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
class htmlelement(_cons.element):
def __todoc__(self):
return doc
class xhtmlcontext(_cons.context):
- attrmap = {u"klass": u"class"}
+ attrmap = {"klass": "class"}
def addattr(self, node, k, v):
- k = unicode(k)
- super(xhtmlcontext, self).addattr(node, self.attrmap.get(k, k), v)
+ k = str(k)
+ super().addattr(node, self.attrmap.get(k, k), v)
def cons(ctx=None):
if ctx is None: ctx = xhtmlcontext()
head = h.head
if title:
head(h.title(title))
- if isinstance(css, str) or isinstance(css, unicode):
+ if isinstance(css, str) or isinstance(css, bytes):
head(h.link(rel="stylesheet", type="text/css", href=css))
elif css:
for ss in css:
return head
class htmlformatter(util.formatter):
- allowshort = set([u"br", u"hr", u"img", u"input", u"meta", u"link"])
+ allowshort = set(["br", "hr", "img", "input", "meta", "link"])
def element(self, el, **extra):
if el.name in self.allowshort:
super(htmlformatter, self).element(el, **extra)
def forreq(req, tree):
# XXX: Use proper Content-Type for clients accepting it.
req.ohead["Content-Type"] = "text/html; charset=utf-8"
- buf = StringIO.StringIO()
+ buf = io.BytesIO()
htmlindenter.output(buf, tree, doctype=(doctype, dtd), charset="utf-8")
ret = buf.getvalue()
req.ohead["Content-Length"] = len(ret)
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):
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):
for arg in list(args):
if arg not in spec.args:
del args[arg]
- 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)
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
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
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):
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__:
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):
@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__()
import os, threading
from mako import template, lookup, filters
-import util, form, session, env, resp
+from . import util, form, session, env, resp
# It seems Mako isn't thread-safe.
makolock = threading.Lock()