[py-svn] r34597 - in py/dist/py/rst: . testing
guido at codespeak.net
guido at codespeak.net
Tue Nov 14 14:49:06 CET 2006
Author: guido
Date: Tue Nov 14 14:49:04 2006
New Revision: 34597
Added:
py/dist/py/rst/testing/test_transform.py
py/dist/py/rst/transform.py
Modified:
py/dist/py/rst/rst.py
py/dist/py/rst/testing/test_rst.py
Log:
Added first bits of an event based Rest tree transformation thingie (a la SAX
but then for converting an rst.Rest tree to e.g. HTML), fixed support for
nested dlist items.
Modified: py/dist/py/rst/rst.py
==============================================================================
--- py/dist/py/rst/rst.py (original)
+++ py/dist/py/rst/rst.py Tue Nov 14 14:49:04 2006
@@ -268,6 +268,15 @@
def text(self):
idepth = self.get_indent_depth()
indent = self.indent + (idepth + 1) * ' '
+ txt = '\n'.join(self.render_children(indent))
+ ret = []
+ if idepth:
+ ret.append('\n')
+ item_char = self.item_chars[idepth]
+ ret += [indent[len(item_char)+1:], item_char, ' ', txt[len(indent):]]
+ return ''.join(ret)
+
+ def render_children(self, indent):
txt = []
for child in self.children:
if isinstance(child, AbstractText):
@@ -276,13 +285,7 @@
txt.append(p.text())
else:
txt.append(child.text())
- txt = '\n'.join(txt)
- ret = []
- if idepth:
- ret.append('\n')
- item_char = self.item_chars[idepth]
- ret += [indent[2:], item_char, ' ', txt[len(indent):]]
- return ''.join(ret)
+ return txt
def get_indent_depth(self):
depth = 0
@@ -293,14 +296,24 @@
return depth - 1
class OrderedListItem(ListItem):
- item_chars = ("#.",)
+ item_chars = ["#."] * 5
class DListItem(ListItem):
item_chars = None
def __init__(self, term, definition, *args, **kwargs):
- self.item_chars = ('%s\n ' % (term,),)
+ self.term = term
super(DListItem, self).__init__(definition, *args, **kwargs)
+ def text(self):
+ idepth = self.get_indent_depth()
+ indent = self.indent + (idepth + 1) * ' '
+ txt = '\n'.join(self.render_children(indent))
+ ret = []
+ if idepth:
+ ret.append('\n')
+ ret += [indent[2:], self.term, '\n', txt]
+ return ''.join(ret)
+
class Link(AbstractText):
start = '`'
end = '`_'
Modified: py/dist/py/rst/testing/test_rst.py
==============================================================================
--- py/dist/py/rst/testing/test_rst.py (original)
+++ py/dist/py/rst/testing/test_rst.py Tue Nov 14 14:49:04 2006
@@ -284,21 +284,6 @@
assert txt == expected
checkrest(txt)
-def test_title_following_links_empty_line():
- expected = """\
-Foo, bar and `baz`_.
-
-.. _`baz`: http://www.baz.com
-
-Spam
-----
-
-Spam, eggs and spam.
-"""
- txt = Rest(Paragraph("Foo, bar and ", Link("baz", "http://www.baz.com")),
- Title('Spam'), Paragraph('Spam, eggs and spam.'))
- checkrest(txt)
-
def test_definition_list():
expected = """\
foo
@@ -313,6 +298,27 @@
assert txt == expected
checkrest(txt)
+def test_nested_dlists():
+ expected = """\
+foo
+ bar baz
+
+ qux
+ quux
+"""
+ txt = Rest(DListItem('foo', 'bar baz', DListItem('qux', 'quux'))).text()
+ assert txt == expected
+
+def test_nested_list_dlist():
+ expected = """\
+* foo
+
+ foobar
+ baz
+"""
+ txt = Rest(ListItem('foo', DListItem('foobar', 'baz'))).text()
+ assert txt == expected
+
def test_transition():
txt = Rest(Paragraph('foo'), Transition(), Paragraph('bar')).text()
assert txt == 'foo\n\n%s\n\nbar\n' % ('-' * 79,)
@@ -354,3 +360,18 @@
Some paragraph content.
"""
+def test_title_following_links_empty_line():
+ expected = """\
+Foo, bar and `baz`_.
+
+.. _`baz`: http://www.baz.com
+
+Spam
+----
+
+Spam, eggs and spam.
+"""
+ txt = Rest(Paragraph("Foo, bar and ", Link("baz", "http://www.baz.com")),
+ Title('Spam'), Paragraph('Spam, eggs and spam.'))
+ checkrest(txt)
+
Added: py/dist/py/rst/testing/test_transform.py
==============================================================================
--- (empty file)
+++ py/dist/py/rst/testing/test_transform.py Tue Nov 14 14:49:04 2006
@@ -0,0 +1,38 @@
+import py
+from py.__.rst.rst import *
+from py.__.rst.transform import *
+
+def convert_to_html(tree):
+ handler = HTMLHandler()
+ t = RestTransformer(tree)
+ t.parse(handler)
+ return handler.html
+
+class HTMLHandler(py.__.rst.transform.HTMLHandler):
+ def startDocument(self):
+ pass
+ endDocument = startDocument
+
+def test_transform_basic_html():
+ for rest, expected in ((Rest(Title('foo')), '<h1>foo</h1>'),
+ (Rest(Paragraph('foo')), '<p>foo</p>'),
+ (Rest(SubParagraph('foo')),
+ '<p class="sub">foo</p>'),
+ (Rest(LiteralBlock('foo\nbar')),
+ '<pre>foo\nbar</pre>'),
+ (Rest(Paragraph(Link('foo',
+ 'http://www.foo.com/'))),
+ '<p><a href="http://www.foo.com/">foo</a></p>')):
+ html = convert_to_html(rest)
+ assert html == expected
+
+def test_transform_list_simple():
+ rest = Rest(ListItem('foo'), ListItem('bar'))
+ html = convert_to_html(rest)
+ assert html == '<ul><li>foo</li><li>bar</li></ul>'
+
+def test_transform_list_nested():
+ rest = Rest(ListItem('foo'), ListItem('bar', ListItem('baz')))
+ html = convert_to_html(rest)
+ assert html == '<ul><li>foo</li><li>bar<ul><li>baz</li></ul></li></ul>'
+
Added: py/dist/py/rst/transform.py
==============================================================================
--- (empty file)
+++ py/dist/py/rst/transform.py Tue Nov 14 14:49:04 2006
@@ -0,0 +1,163 @@
+from py.__.rst import rst
+
+class RestTransformer(object):
+ def __init__(self, tree):
+ self.tree = tree
+ self._titledepths = {}
+ self._listmarkers = []
+
+ def parse(self, handler):
+ handler.startDocument()
+ self.parse_nodes(self.tree.children, handler)
+ handler.endDocument()
+
+ def parse_nodes(self, nodes, handler):
+ for node in nodes:
+ name = node.__class__.__name__
+ if name == 'Rest':
+ continue
+ try:
+ getattr(self, 'handle_%s' % (name,))(node, handler)
+ except AttributeError:
+ # caused by the handler not implementing something (well, let's
+ # assume that at least ;)
+ py.std.sys.stderr.write('Warning: error handling node %s\n' % (
+ node,))
+ def handle_Title(self, node, handler):
+ depthkey = (node.abovechar, node.belowchar)
+ if depthkey not in self._titledepths:
+ if not self._titledepths:
+ depth = 1
+ else:
+ depth = max(self._titledepths.values()) + 1
+ self._titledepths[depthkey] = depth
+ else:
+ depth = self._titledepths[depthkey]
+ handler.startTitle(depth)
+ self.parse_nodes(node.children, handler)
+ handler.endTitle(depth)
+
+ def handle_ListItem(self, node, handler):
+ # XXX oomph...
+ startlist = False
+ c = node.parent.children
+ nodeindex = c.index(node)
+ if nodeindex == 0:
+ startlist = True
+ else:
+ prev = c[nodeindex - 1]
+ if not isinstance(prev, rst.ListItem):
+ startlist = True
+ elif prev.indent < node.indent:
+ startlist = True
+ endlist = False
+ if nodeindex == len(c) - 1:
+ endlist = True
+ else:
+ next = c[nodeindex + 1]
+ if not isinstance(next, rst.ListItem):
+ endlist = True
+ elif next.indent < node.indent:
+ endlist = True
+ type = isinstance(node, rst.OrderedListItem) and 'o' or 'u'
+ handler.startListItem('u', startlist)
+ self.parse_nodes(node.children, handler)
+ handler.endListItem('u', endlist)
+
+ def handle_Transition(self, node, handler):
+ handler.handleTransition()
+
+ def handle_Paragraph(self, node, handler):
+ handler.startParagraph()
+ self.parse_nodes(node.children, handler)
+ handler.endParagraph()
+
+ def handle_SubParagraph(self, node, handler):
+ handler.startSubParagraph()
+ self.parse_nodes(node.children, handler)
+ handler.endSubParagraph()
+
+ def handle_LiteralBlock(self, node, handler):
+ handler.handleLiteralBlock(node._text)
+
+ def handle_Text(self, node, handler):
+ handler.handleText(node._text)
+
+ def handle_Em(self, node, handler):
+ handler.handleEm(node._text)
+
+ def handle_Strong(self, node, handler):
+ handler.handleStrong(node._text)
+
+ def handle_Quote(self, node, handler):
+ handler.handleQuote(node._text)
+
+ def handle_Link(self, node, handler):
+ handler.handleLink(node._text, node.target)
+
+def entitize(txt):
+ for char, repl in (('&', 'amp'), ('>', 'gt'), ('<', 'lt'), ('"', 'quot'),
+ ("'", 'apos')):
+ txt = txt.replace(char, '&%s;' % (repl,))
+ return txt
+
+class HTMLHandler(object):
+ def __init__(self, title='untitled rest document'):
+ self.title = title
+ self._data = []
+ self._listdepth = 0
+
+ def startDocument(self):
+ self._data += ['<html>', '<head>', '<title>%s</title>' % (self.title,),
+ '</head>', '<body>']
+
+ def endDocument(self):
+ self._data += ['</body>', '</html>']
+
+ def startTitle(self, depth):
+ self._data.append('<h%s>' % (depth,))
+
+ def endTitle(self, depth):
+ self._data.append('</h%s>' % (depth,))
+
+ def startParagraph(self):
+ self._data.append('<p>')
+
+ def endParagraph(self):
+ self._data.append('</p>')
+
+ def startSubParagraph(self):
+ self._data.append('<p class="sub">')
+
+ def endSubParagraph(self):
+ self._data.append('</p>')
+
+ def handleLiteralBlock(self, text):
+ self._data.append('<pre>%s</pre>' % (entitize(text),))
+
+ def handleText(self, text):
+ self._data.append(entitize(text))
+
+ def handleEm(self, text):
+ self._data.append('<em>%s</em>' % (entitize(text),))
+
+ def startListItem(self, type, startlist):
+ if startlist:
+ nodename = type == 'o' and 'ol' or 'ul'
+ self._data.append('<%s>' % (nodename,))
+ self._data.append('<li>')
+
+ def endListItem(self, type, closelist):
+ self._data.append('</li>')
+ if closelist:
+ nodename = type == 'o' and 'ol' or 'ul'
+ self._data.append('</%s>' % (nodename,))
+
+ def handleLink(self, text, target):
+ self._data.append('<a href="%s">%s</a>' % (entitize(target),
+ entitize(text)))
+
+ def _html(self):
+ return ''.join(self._data)
+ html = property(_html)
+
More information about the pytest-commit
mailing list