[py-svn] r34595 - in py/dist/py/rst: . testing

guido at codespeak.net guido at codespeak.net
Tue Nov 14 13:54:05 CET 2006


Author: guido
Date: Tue Nov 14 13:54:03 2006
New Revision: 34595

Modified:
   py/dist/py/rst/rst.py
   py/dist/py/rst/testing/test_rst.py
Log:
Added support for ReST directives (code I wrote on the sprint and during the
train ride back), changed LiteralBlock so it subclasses from AbstractText
(no need to allow anything but plain text in there, only makes it harder),
added support for nested lists.


Modified: py/dist/py/rst/rst.py
==============================================================================
--- py/dist/py/rst/rst.py	(original)
+++ py/dist/py/rst/rst.py	Tue Nov 14 13:54:03 2006
@@ -34,6 +34,8 @@
             class_list = [parent_cls]
         else:
             class_list = parent_cls
+        if obj.allow_nesting:
+            class_list.append(obj)
         
         for _class in class_list:
             if not _class.allowed_child:
@@ -49,6 +51,7 @@
     __metaclass__ = AbstractMetaclass
     parentclass = None # this exists to allow parent to know what
         # children can exist
+    allow_nesting = False
     allowed_child = {}
     defaults = {}
     
@@ -185,16 +188,6 @@
 class SubParagraph(Paragraph):
     indent = " "
     
-class LiteralBlock(Paragraph):
-    indent = " "
-    sep = ""
-    
-    def text(self):
-        all_txt = AbstractNode.text(self)
-        all_txts = all_txt.split('\n')
-        return '::\n\n%s' % ("\n".join([self.indent + i for i in
-                                        all_txts]),)
-
 class Title(Paragraph):
     parentclass = Rest
     belowchar = ""
@@ -233,6 +226,18 @@
         text = escape(self._text)
         return self._reg_whitespace.split(text)
 
+class LiteralBlock(AbstractText):
+    parentclass = Rest
+    start = '::\n\n'
+
+    def text(self):
+        text = self.escape(self._text).split('\n')
+        print text
+        for i, line in enumerate(text):
+            if line.strip():
+                text[i] = '  %s' % (line,)
+        return self.start + '\n'.join(text)
+
 class Em(AbstractText):
     start = "*"
     end = "*"
@@ -258,25 +263,43 @@
         raise NotImplemented('XXX')
 
 class ListItem(Paragraph):
-    item_char = "*"
+    allow_nesting = True
+    item_chars = '*+-'
     
     def text(self):
-        oldindent = self.indent
-        self.indent = oldindent + '  '
-        try:
-            txt = Paragraph.text(self)
-        finally:
-            self.indent = oldindent
-        txt = self.item_char + txt[1:]
-        return txt
+        idepth = self.get_indent_depth()
+        indent = self.indent + (idepth + 1) * '  '
+        txt = []
+        for child in self.children:
+            if isinstance(child, AbstractText):
+                p = Paragraph(child, indent=indent)
+                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):]]
+        print repr(ret)
+        return ''.join(ret)
+
+    def get_indent_depth(self):
+        depth = 0
+        current = self
+        while current.parent is not None:
+            depth += 1
+            current = current.parent
+        return depth - 1
 
 class OrderedListItem(ListItem):
-    item_char = "#."
+    item_chars = ("#.",)
 
 class DListItem(ListItem):
-    item_char = None
+    item_chars = None
     def __init__(self, term, definition, *args, **kwargs):
-        self.item_char = '%s\n ' % (term,)
+        self.item_chars = ('%s\n ' % (term,),)
         super(DListItem, self).__init__(definition, *args, **kwargs)
 
 class Link(AbstractText):
@@ -307,3 +330,33 @@
     def __init__(self, text, **kwargs):
         raise NotImplemented('XXX')
 
+class Directive(Paragraph):
+    indent = '   '
+    def __init__(self, name, *args, **options):
+        self.name = name
+        self.content = options.pop('content', [])
+        children = list(args)
+        super(Directive, self).__init__(*children)
+        self.options = options
+        
+    def text(self):
+        # XXX not very pretty...
+        namechunksize = len(self.name) + 2
+        self.children.insert(0, Text('X' * namechunksize))
+        txt = super(Directive, self).text()
+        txt = '.. %s::%s' % (self.name, txt[namechunksize + 3:],)
+        options = '\n'.join(['   :%s: %s' % (k, v) for (k, v) in
+                             self.options.iteritems()])
+        if options:
+            txt += '\n%s' % (options,)
+
+        if self.content:
+            txt += '\n'
+            for item in self.content:
+                assert item.parentclass == Rest, 'only top-level items allowed'
+                assert not item.indent
+                item.indent = '   '
+                txt += '\n' + item.text()
+        
+        return txt
+

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 13:54:03 2006
@@ -49,7 +49,7 @@
 
 def test_escape_literal():
     txt = LiteralBlock('*escape* ``test``').text()
-    assert txt == '::\n\n *escape* ``test``'
+    assert txt == '::\n\n  *escape* ``test``'
     html = checkrest(txt)
     assert '>\n*escape* ``test``\n</pre>' in html
 
@@ -153,8 +153,8 @@
 
 ::
 
- def fun():
-  some
+  def fun():
+   some
 
 Paragraph
 """
@@ -272,6 +272,18 @@
     assert txt == expected
     checkrest(txt)
 
+def test_nested_lists():
+    expected = """\
+* foo
+
+* bar
+
+  + baz
+"""
+    txt = Rest(ListItem('foo'), ListItem('bar', ListItem('baz'))).text()
+    assert txt == expected
+    checkrest(txt)
+
 def test_title_following_links_empty_line():
     expected = """\
 Foo, bar and `baz`_.
@@ -312,3 +324,33 @@
     py.test.raises(ValueError, 'Rest(Transition(), Paragraph("foo")).text()')
     py.test.raises(ValueError, 'Rest(Paragraph("foo"), Transition()).text()')
 
+def test_directive_simple():
+    txt = Rest(Directive('image', 'images/foo.png')).text()
+    assert txt == '.. image:: images/foo.png\n'
+
+def test_directive_metadata():
+    txt = Rest(Directive('image', 'images/foo.png',
+                         width=200, height=150)).text()
+    assert txt == ('.. image:: images/foo.png\n   :width: 200\n'
+                   '   :height: 150\n')
+
+def test_directive_multiline():
+    txt = Rest(Directive('note', ('This is some string that is too long to '
+                                  'fit on a single line, so it should be '
+                                  'broken up.'))).text()
+    assert txt == """\
+.. note:: This is some string that is too long to fit on a single line, so it
+   should be broken up.
+"""
+
+def test_directive_content():
+    txt = Rest(Directive('image', 'foo.png', width=200, height=100,
+                         content=[Paragraph('Some paragraph content.')])).text()
+    assert txt == """\
+.. image:: foo.png
+   :width: 200
+   :height: 100
+
+   Some paragraph content.
+"""
+



More information about the pytest-commit mailing list