# HG changeset patch # User Tero Marttila # Date 1244227665 -10800 # Node ID fad360dd01da4b9b917e1456fafa9c2616f541c0 # Parent 406da27a4be216b240e513316755d688d4b2d843 rework html a bit to move the render_* funcs to IRenderable, add XHTMLDocument (ugh), missing flatten diff -r 406da27a4be2 -r fad360dd01da degal/html.py --- a/degal/html.py Fri Jun 05 21:46:43 2009 +0300 +++ b/degal/html.py Fri Jun 05 21:47:45 2009 +0300 @@ -1,5 +1,7 @@ """ - Generating HTML tags + Generating XHTML output + + XXX: use a 'real' XML builder? """ from cgi import escape @@ -17,6 +19,55 @@ abstract + def render_lines (self, indent=u'\t', newline=u'\n') : + """ + Render full output lines with given newlines + + >>> list(Tag('xx', 'yy').render_lines()) + [u'\\n', u'\\tyy\\n', u'\\n'] + """ + + for line in self.render_raw_lines(indent) : + yield line + newline + + def render_unicode (self, **render_opts) : + """ + Render full tag as a single unicode string + + >>> Tag('xx', 'yy').render_unicode() + u'\\n\\tyy\\n\\n' + """ + + return "".join(self.render_lines(**render_opts)) + + def render_str (self, encoding='ascii', **render_opts) : + """ + Render full tag as an encoded string + + >>> Tag('xx', 'yy').render_str() + '\\n\\tyy\\n\\n' + """ + + return self.render_unicode(**render_opts).encode(encoding) + + def render_out (self, stream, encoding, **render_opts) : + """ + Render output into the given stream, encoding using the given encoding + + >>> from StringIO import StringIO; buf = StringIO(); Tag('xx', 'yy').render_out(buf, 'ascii'); buf.getvalue() + '\\n\\tyy\\n\\n' + """ + + for line in self.render_lines(**render_opts) : + stream.write(line.encode(encoding)) + + # default output + __str__ = render_str + __unicode__ = render_unicode + + # default .render method + render = render_unicode + class Tag (IRenderable) : """ A HTML tag, with attributes and contents, which can a mixture of data and other renderables(tags). @@ -31,6 +82,8 @@ Items that are None will be omitted from the return value. + XXX: flatten + >>> Tag.process_contents([]) [] >>> Tag.process_contents([None]) @@ -179,54 +232,6 @@ # singleton tag yield u"<%s%s />" % (self.name, attrs_stuff) - def render_lines (self, indent=u'\t', newline=u'\n') : - """ - Render full output lines with given newlines - - >>> list(Tag('xx', 'yy').render_lines()) - [u'\\n', u'\\tyy\\n', u'\\n'] - """ - - for line in self.render_raw_lines(indent) : - yield line + newline - - def render_unicode (self, **render_opts) : - """ - Render full tag as a single unicode string - - >>> Tag('xx', 'yy').render_unicode() - u'\\n\\tyy\\n\\n' - """ - - return "".join(self.render_lines(**render_opts)) - - def render_str (self, charset='ascii', **render_opts) : - """ - Render full tag as an encoded string - - >>> Tag('xx', 'yy').render_str() - '\\n\\tyy\\n\\n' - """ - - return self.render_unicode(**render_opts).encode(charset) - - def render_out (self, stream, charset, **render_opts) : - """ - Render output into the given stream, encoding using the given charset - - >>> from StringIO import StringIO; buf = StringIO(); Tag('xx', 'yy').render_out(buf, 'ascii'); buf.getvalue() - '\\n\\tyy\\n\\n' - """ - - for line in self.render_lines(**render_opts) : - stream.write(line.encode(charset)) - - # default output - __str__ = render_str - __unicode__ = render_unicode - - # default .render method - render = render_unicode def __repr__ (self) : return 'Tag(%s)' % ', '.join( @@ -254,6 +259,71 @@ def render_raw_lines (self, indent=u'\t') : return self.lines +class XHTMLDocument (IRenderable) : + """ + + + + + + ... + + + ... + + + """ + + def __init__ (self, + head, body, + xml_version='1.0', xml_encoding='utf-8', + doctype='html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"', + html_xmlns='http://www.w3.org/1999/xhtml', html_lang='en' + ) : + # store + self.xml_version = xml_version + self.xml_encoding = xml_encoding + self.doctype = doctype + + # build the document + self.document = Tag('html', **{'xmlns': html_xmlns, 'xml:lang': html_lang})( + Tag('head', head), + Tag('body', body), + ) + + def render_raw_lines (self, **render_opts) : + """ + Render the two header lines, and then the document + """ + + yield '' % (self.xml_version, self.xml_encoding) + yield '' % (self.doctype) + + for line in self.document.render_raw_lines(**render_opts) : + yield line + + def _check_encoding (self, encoding) : + if encoding and encoding != self.xml_encoding : + raise ValueError("encoding mismatch: %r should be %r" % (encoding, self.xml_encoding) + + def render_str (self, encoding=None, **render_opts) : + """ + Wrap render_str to verify that the right encoding is used + """ + + self._check_encoding(encoding) + + return super(XHTMLDocument, self).render_str(self.xml_encoding, **render_opts) + + def render_out (self, stream, encoding=None, **render_opts) : + """ + Wrap render_out to verify that the right encoding is used + """ + + self._check_encoding(encoding) + + return super(XHTMLDocument, self).render_out(stream, self.xml_encoding, **render_opts) + class TagFactory (object) : """ Build Tags with names give as attribute names