description = "Simple WSGI request wrapper library",
author = "Fredrik Tolf",
author_email = "fredrik@dolda2000.com",
- packages = ["wrw"],
+ packages = ["wrw", "wrw.sp"],
package_data = {"wrw": ["makolib/*.mako"]},
license = "GPL-3")
--- /dev/null
+import xml.dom.minidom
+
+class node(object):
+ def __str__(self):
+ doc = xml.dom.minidom.Document()
+ return self.__todom__(doc).toxml()
+
+class text(node, unicode):
+ def __todom__(self, doc):
+ return doc.createTextNode(self)
+
+class element(node):
+ def __init__(self, ns, name, ctx):
+ self.ns = ns
+ self.name = unicode(name)
+ self.ctx = ctx
+ self.attrs = {}
+ self.children = []
+
+ def __call__(self, *children, **attrs):
+ for child in children:
+ self.children.append(self.ctx.nodefrom(child))
+ for k, v in attrs.iteritems():
+ self.attrs[unicode(k)] = unicode(v)
+ return self
+
+ def __todom__(self, doc):
+ el = doc.createElementNS(self.ns, self.name)
+ for k, v in self.attrs.iteritems():
+ el.setAttribute(k, v)
+ for child in self.children:
+ el.appendChild(child.__todom__(doc))
+ return el
+
+class context(object):
+ def __init__(self):
+ self.nodeconv = {}
+ self.nodeconv[str] = lambda ob: text(ob, "utf-8")
+ self.nodeconv[unicode] = text
+ self.nodeconv[int] = text
+ self.nodeconv[long] = text
+ self.nodeconv[float] = text
+
+ def nodefrom(self, ob):
+ if isinstance(ob, node):
+ return ob
+ if hasattr(ob, "__tonode__"):
+ return ob.__tonode__()
+ if type(ob) in self.nodeconv:
+ return self.nodeconv[type(ob)](ob)
+ raise Exception("No node conversion known for %s objects" % str(type(ob)))
+
+class constructor(object):
+ def __init__(self, ns, elcls = element, ctx=None):
+ self._ns = ns
+ self._elcls = elcls
+ if ctx is None: ctx = context()
+ self._ctx = ctx
+
+ def __getattr__(self, name):
+ return self._elcls(self._ns, name, self._ctx)
--- /dev/null
+import cons
+
+def findnsnames(el):
+ names = {}
+ nid = [1]
+ def proc(el):
+ if isinstance(el, cons.element):
+ if el.ns not in names:
+ names[el.ns] = u"n" + unicode(nid[0])
+ nid[:] = [nid[0] + 1]
+ for ch in el.children:
+ proc(ch)
+ proc(el)
+ if None in names:
+ names[None] = None
+ else:
+ names[el.ns] = None
+ return names
+
+class formatter(object):
+ def __init__(self, out, root, nsnames=None, charset="utf-8", doctype=None):
+ self.root = root
+ if nsnames is None:
+ nsnames = findnsnames(root)
+ self.nsnames = nsnames
+ self.out = out
+ self.charset = charset
+ self.doctype = doctype
+
+ def write(self, text):
+ self.out.write(text.encode(self.charset))
+
+ 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">")
+ else:
+ self.write(ch)
+
+ def text(self, el):
+ self.quotewrite(el)
+
+ def attrval(self, buf):
+ qc, qt = (u"'", u"'") if u'"' in buf else (u'"', u""")
+ 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">")
+ elif ch == qc:
+ self.write(qt)
+ else:
+ self.write(ch)
+ self.write(qc)
+
+ def attr(self, k, v):
+ self.write(k)
+ self.write(u'=')
+ 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.attr(k, v)
+ for k, v in extra.iteritems():
+ self.write(u' ')
+ self.attr(k, v)
+ self.write(u" />")
+
+ def elname(self, el):
+ ns = self.nsnames[el.ns]
+ if ns is None:
+ return el.name
+ else:
+ return ns + u':' + el.name
+
+ def starttag(self, el, **extra):
+ self.write(u'<' + self.elname(el))
+ for k, v in el.attrs.iteritems():
+ self.write(u' ')
+ self.attr(k, v)
+ for k, v in extra.iteritems():
+ self.write(u' ')
+ self.attr(k, v)
+ self.write(u'>')
+
+ def endtag(self, el):
+ self.write(u'</' + self.elname(el) + u'>')
+
+ def longtag(self, el):
+ self.starttag(el, **extra)
+ for ch in el.children:
+ self.node(ch)
+ self.endtag(el)
+
+ def element(self, el, **extra):
+ if len(el.children) == 0:
+ self.shorttag(el, **extra)
+ else:
+ self.longtag(el, **extra)
+
+ def node(self, el):
+ if isinstance(el, cons.element):
+ self.element(el)
+ elif isinstance(el, cons.text):
+ self.text(el)
+ else:
+ raise Exception("Unknown object in element tree: " + el)
+
+ def start(self):
+ self.write(u'<?xml version="1.0" encoding="' + self.charset + u'" ?>\n')
+ if self.doctype:
+ self.write(u'<!DOCTYPE %s PUBLIC "%s" "%s">\n' % (self.root.name,
+ self.doctype[0],
+ self.doctype[1]))
+ extra = {}
+ for uri, nm in self.nsnames.iteritems():
+ if uri is None:
+ continue
+ if nm is None:
+ extra[u"xmlns"] = uri
+ else:
+ extra[u"xmlns:" + nm] = uri
+ self.element(self.root, **extra)
+
+ @classmethod
+ def output(cls, out, el, *args, **kw):
+ cls(out=out, root=el, *args, **kw).start()
+
+ def update(self, **ch):
+ ret = type(self).__new__(type(self))
+ ret.__dict__.update(self.__dict__)
+ ret.__dict__.update(ch)
+ return ret
+
+class iwriter(object):
+ def __init__(self, out):
+ self.out = out
+ self.atbol = True
+ self.col = 0
+
+ def write(self, buf):
+ for c in buf:
+ if c == '\n':
+ self.col = 0
+ else:
+ self.col += 1
+ self.out.write(c)
+ self.atbol = False
+
+ def indent(self, indent):
+ if self.atbol:
+ return
+ if self.col != 0:
+ self.write('\n')
+ self.write(indent)
+ self.atbol = True
+
+class indenter(formatter):
+ def __init__(self, indent=u" ", *args, **kw):
+ super(indenter, self).__init__(*args, **kw)
+ self.out = iwriter(self.out)
+ self.indent = indent
+ self.curind = u""
+
+ def simple(self, el):
+ for ch in el.children:
+ if not isinstance(ch, cons.text):
+ return False
+ return True
+
+ def longtag(self, el, **extra):
+ self.starttag(el, **extra)
+ sub = self
+ reind = False
+ if not self.simple(el):
+ sub = self.update(curind=self.curind + self.indent)
+ sub.out.indent(sub.curind)
+ reind = True
+ for ch in el.children:
+ sub.node(ch)
+ if reind:
+ self.out.indent(self.curind)
+ self.endtag(el)
+
+ def element(self, el, **extra):
+ super(indenter, self).element(el, **extra)
+ if self.out.col > 80 and self.simple(el):
+ self.out.indent(self.curind)
+
+ def start(self):
+ super(indenter, self).start()
+ self.write('\n')
--- /dev/null
+import xml.dom.minidom, StringIO
+import cons as _cons
+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"
+
+class htmlelement(_cons.element):
+ def __todoc__(self):
+ doc = dom.createDocument(None, None, None)
+ doc.appendChild(dom.createDocumentType("html", doctype, dtd))
+ doc.appendChild(self.__todom__(doc))
+ return doc
+
+def cons(ctx=None):
+ return _cons.constructor(ns, htmlelement, ctx)
+
+def head(title=None, css=None):
+ h = cons()
+ head = h.head
+ if title:
+ head(h.title(title))
+ if isinstance(css, str) or isinstance(css, unicode):
+ head(h.link(rel="stylesheet", type="text/css", href=css))
+ elif css:
+ for ss in css:
+ head(h.link(rel="stylesheet", type="text/css", href=ss))
+ return head
+
+class htmlformatter(util.formatter):
+ allowshort = set([u"br", u"hr", u"img", u"input"])
+ def element(self, el, **extra):
+ if el.name in self.allowshort:
+ super(htmlformatter, self).element(el, **extra)
+ else:
+ self.longtag(el, **extra)
+
+class htmlindenter(util.indenter, htmlformatter):
+ pass
+
+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()
+ htmlindenter.output(buf, tree, doctype=(doctype, dtd), charset="utf-8")
+ return [buf.getvalue()]
+
+def xhtmlresp(callable):
+ def wrapper(req):
+ return forreq(req, callable(req))
+ return wrapper