[py-svn] r21129 - in py/dist/py/rest: . testing
jan at codespeak.net
jan at codespeak.net
Tue Dec 13 14:07:52 CET 2005
Author: jan
Date: Tue Dec 13 14:07:50 2005
New Revision: 21129
Added:
py/dist/py/rest/rst.py
py/dist/py/rest/testing/test_rst.py
Log:
some stuff to generate docutils ReST files
not yet exported
Added: py/dist/py/rest/rst.py
==============================================================================
--- (empty file)
+++ py/dist/py/rest/rst.py Tue Dec 13 14:07:50 2005
@@ -0,0 +1,230 @@
+import py
+from py.xml import Namespace, Tag
+from py.__.xmlobj.visit import SimpleUnicodeVisitor
+from py.__.xmlobj.html import HtmlVisitor
+
+import textwrap
+
+def itertext(text):
+ """ Generator: like string.split, but ''.join(itertext(t)) == t
+
+ >>> list(itertext('word\n second word'))
+ ['word', '\n', ' ', 'second', ' ', 'word']
+ """
+ state_word = 'not isspace()'
+ state_whitespace = '\t\n\x0b\x0c\r'
+ state_space = ' '
+ def compute_state(char):
+ if char in state_whitespace:
+ return state_whitespace
+ if char == ' ':
+ return state_space
+ return state_word
+
+ word = ''
+ state = None
+ for char in text:
+ if state is None:
+ # init
+ state = compute_state(char)
+ word = char
+ continue
+
+ next_state = compute_state(char)
+ if state != state_whitespace and state == next_state:
+ word += char
+ continue
+ yield word
+ word = char
+
+ state = next_state
+ yield word
+
+
+class Out:
+ """ wrap text like textwarp.wrap, but preseves \n
+
+ all lines are left aligned
+ arguments to write must be strings or iterable and
+ return strings of length 1 (chars)
+ """
+
+ def __init__(self, width=70):
+ self.width = width
+ self.lines = ['']
+
+ def copy(self):
+ ' like copy, except self.lines = ['']'
+ return self.__class__(width = self.width)
+
+ def write(self, arg, literal=False):
+ line = self.lines.pop()
+ for w in itertext(arg):
+ if w == '\n':
+ self.lines.append(line)
+ line = ''
+ continue
+ if literal or self.width is None or \
+ line and not line[-1].isspace():
+ line += w
+ continue
+ if len(line) + len(w) > self.width:
+ if line != '':
+ self.lines.append(line)
+ line = w.lstrip()
+ continue
+ line += w
+
+ self.lines.append(line)
+ return self
+
+ def writeln(self, arg='', literal=False):
+ self.write(arg, literal)
+ self.write('\n')
+
+ def write_literal(self, arg):
+ self.write(arg, literal=True)
+
+ def writeln_literal(self, arg):
+ self.writeln(arg, literal=True)
+
+ def append(self, out, indent = '', join=''):
+ keepends = True
+ self.write_literal(join.join(
+ [indent + line
+ for line in out.render().splitlines(keepends)]))
+ #self.write_literal(indent + line)
+
+ def extend(self, out_list, indent = '', infix = ' ',
+ join = '', literal = False):
+ l = list(out_list)
+ for out in l[:-1]:
+ self.append(out, indent, join=join)
+ self.write(infix, literal=literal)
+ self.append(l[-1], indent, join=join)
+
+ def max_length(self):
+ return max([len(l) for l in self.lines])
+
+ def render(self):
+ return '\n'.join(self.lines)
+
+class RestTag(Tag):
+ start_string = ''
+ end_string = ''
+ sep = ''
+
+ def __init__(self, *args, **kwargs):
+ super(RestTag, self).__init__(*args, **kwargs)
+ self.parse_options(self.attr)
+
+ def parse_options(self, attr):
+ pass
+
+ def text(self, width = 70):
+ out = Out(width = width)
+ self.__rest__(out)
+ return out.render()
+
+ def __rest__(self, out):
+ out.write(self.sep)
+ out.write(self.start_string)
+ self.write_children(out, self.render_children(out))
+ out.write(self.end_string)
+ out.write(self.sep)
+
+ def write_children(self, out, child_outs):
+ out.extend(child_outs)
+
+ def render_children(self, out):
+ outs = []
+ for child in self:
+ child_out = out.copy()
+ if isinstance(child, RestTag):
+ child.__rest__(child_out)
+ else:
+ child_out.write(child)
+ outs.append(child_out)
+ return outs
+
+
+class rest(Namespace):
+ __tagclass__ = RestTag
+ __stickname__ = True
+
+ class paragraph(RestTag):
+ sep = '\n\n'
+
+ class emph(RestTag):
+ start_string = '*'
+ end_string = start_string
+
+ class strongemph(RestTag):
+ start_string = '**'
+ end_string = start_string
+
+ class inline_literal(RestTag):
+ start_string = "``"
+ end_string = "``"
+
+ class interpreted_text(RestTag):
+ start_string ='`'
+ end_string = '`'
+ role = ''
+
+ def parse_options(self, attr):
+ self.role = getattr(attr, 'role', self.role)
+ if self.role:
+ self.start_string = ':%s:%s' % (self.role, self.start_string)
+
+ class explicit_markup(RestTag):
+ sep = '\n\n'
+ start_string = '.. '
+
+ def write_children(self, out, child_outs):
+ out.extend(child_outs, join = ' ' * len(self.start_string))
+
+ class title(RestTag):
+ sep = '\n'
+ start_string = '#'
+ end_string = '#'
+ quotes = """! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~""".split()
+
+ def parse_options(self, attr):
+ self.start_string = getattr(attr, 'overline', '#')
+ self.end_string = getattr(attr, 'underline', '#')
+
+ def __rest__(self, out):
+ child_outs = self.render_children(out)
+ max_length = max([o.max_length() for o in child_outs])
+ out.write(self.sep)
+ out.writeln_literal(self.start_string * max_length)
+ out.extend(child_outs)
+ out.writeln()
+ out.writeln_literal(self.end_string * max_length)
+ out.write(self.sep)
+
+ class list_item(RestTag):
+ sep = '\n\n'
+ start_string = '* '
+
+ def parse_options(self, attr):
+ self.start_string = getattr(attr, 'bullet', '*') + ' '
+ if getattr(attr, 'enumerate', False):
+ self.start_string = '#. '
+
+ def write_children(self, out, child_outs):
+ out.extend(child_outs, join = ' ' * len(self.start_string))
+
+ class literal_block(RestTag):
+ sep = '\n\n'
+ start_string = '::\n\n'
+ indent = ' '
+ quote = ' '
+ quotes = """! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~""".split() + [' ']
+
+ def parse_options(self, attr):
+ self.quote = getattr(attr, 'quote', ' ')
+
+ def write_children(self, out, child_outs):
+ out.extend(child_outs, indent = self.quote)
Added: py/dist/py/rest/testing/test_rst.py
==============================================================================
--- (empty file)
+++ py/dist/py/rest/testing/test_rst.py Tue Dec 13 14:07:50 2005
@@ -0,0 +1,288 @@
+import py
+from py.__.rest.rst import rest, Out, itertext, RestTag
+from py.__.misc import rest as pyrest
+
+#temp = py.test.ensuretemp('check_rest')
+temp = py.path.local.mkdtemp()
+
+def check_rest(content, include_dir = None):
+ if isinstance(content, RestTag):
+ content = content.text()
+ content = unicode(content)
+ print content
+ tempdir = py.path.local.make_numbered_dir(rootdir=temp)
+ if include_dir is None:
+ include_dir = tempdir
+ #logging
+ tempdir.ensure('input.txt').write(content)
+ try:
+ output = pyrest.convert_rest_html(content, include_dir)
+ except:
+ fail_msg = '''
+ failed to convert %s to html, probably not valid reStructuredText
+ see recorded stderr for error message'''
+
+ py.test.fail(fail_msg % tempdir.join('input.txt') + '\n\n' + str(py.code.ExceptionInfo()))
+ tempdir.ensure('output.html').write(output)
+ return True
+
+def render_xml(arg):
+ return arg.unicode()
+
+class TestSplit:
+
+ def test_empyt_string(self):
+ assert list(itertext('')) == ['']
+
+ def test_whitespace(self):
+ assert list(itertext(' ')) == [' ']
+
+ def test_single_word(self):
+ assert list(itertext('word')) == ['word']
+
+ def test_word_with_whitespace(self):
+ assert list(itertext('word ')) == ['word', ' ']
+
+ def test_two_words(self):
+ assert list(itertext('first second')) == ['first', ' ', 'second']
+
+ def test_trailing_newline(self):
+ assert list(itertext('\nfirst word')) == ['\n', 'first', ' ', 'word']
+ def test_newline_and_space_are_seperated(self):
+ assert list(itertext('\n third_item')) == ['\n', ' ', 'third_item']
+
+class TestOut:
+
+ def test_write_nothing(self):
+ assert Out().write('').render() == ''
+
+ def test_write_returns_self(self):
+ out = Out()
+ assert out.write('') is out
+ assert out.write('') is not Out().write('')
+
+ def test_write_newline(self):
+ out = Out()
+ out.write('\n')
+ assert len(out.lines) == 2
+ assert out.render() == '\n'
+
+ def test_write_one_line(self):
+ text = "'[B]ut assume that I have some other use case' isn't a valid use case. - Fredrik Lundh"
+ out = Out(width=None)
+ out.write(text)
+ assert out.lines == [text]
+ assert out.render() == text
+
+ def test_write_and_width(self):
+ text = "This sentence is 36 characters wide."
+ out = Out(width = 36)
+ out.write(text)
+ assert len(out.lines) == 1
+ out = Out(width = 35)
+ out.write(text)
+ assert len(out.lines) == 2
+
+ def test_write_and_newline(self):
+ text = "1234567890\n1234567890"
+ out = Out(width=30)
+ out.write(text)
+ assert len(out.lines) == 2
+ assert len(out.lines[0]) == 10
+ assert out.render() == text
+ out.write(text)
+ assert len(out.lines) == 3
+
+ def test_write_with_trailing_newline(self):
+ text = "0123456789\n"
+ out = Out()
+ out.write(text)
+ assert len(out.lines) == 2
+ assert out.render() == text
+
+ def test_write_long_word(self):
+ text = '12345678901234567890'
+ out = Out(width=19)
+ out.write(text)
+ assert len(out.lines) == 1
+ assert text == out.render()
+ out.write('1')
+ assert len(out.lines) == 1
+ out.write(' 2')
+ assert len(out.lines) == 2
+
+ def test_long_literal_and_newline(self):
+ text = '12345678901234567890'
+ out = Out(width=10)
+ out.write_literal(text)
+ assert len(out.lines) == 1
+ text += '\n1234567890'
+ out.write_literal(text)
+ assert len(out.lines) == 2
+
+ def test_append(self):
+ out = Out()
+ out.write('First line\n')
+ out.write('Second line')
+
+ root_out = Out()
+ root_out.write('Root')
+ root_out.append(out)
+
+ assert len(root_out.lines) == 2
+
+ def test_max_length(self):
+ out = Out()
+ out.write('1234567890')
+ out.writeln()
+ out.write('123456789')
+ assert out.max_length() == 10
+
+
+class TestRest:
+ disabled = False
+ def setup_method(self, method):
+ self.text = {}
+
+ self.text['paragraph'] = "Paragraphs consist of blocks of left-aligned text with no markup indicating any other body element. Blank lines separate paragraphs from each other and from other body elements. Paragraphs may contain inline markup."
+
+ def test_paragraph(self):
+ para = rest.paragraph(self.text['paragraph'])
+ print render_xml(para)
+ text = para.text()
+ check_rest(text)
+ assert text[0] == '\n'
+ assert text[-1] == '\n'
+
+ def test_emph(self):
+ emph = rest.emph('strong')
+ assert emph.text() == '*strong*'
+ assert check_rest(emph.text())
+
+ def test_add_whitespace(self):
+ para = rest.paragraph('Starttext', rest.emph('EMPHASIS'), 'endtext')
+ assert para.text() == '\n\nStarttext *EMPHASIS* endtext\n\n'
+
+ def test_nested_emph(self):
+ "Nested Inline Markup not allowed in ReST"
+ emph = rest.emph('start', rest.emph('middle'), 'end')
+ check_rest(emph.text())
+ assert emph.text() == '*start *middle* end*'
+
+
+ def test_strongemph(self):
+ phrase = 'failure is not an option'
+ emph = rest.strongemph(phrase)
+ assert emph.text() == '**' + phrase + '**'
+
+ def test_title(self):
+ phrase = 'Everything should be built top-down, except the first time.'
+ title = rest.title(phrase)
+ expected = title.sep + title.start_string * len(phrase) \
+ +'\n' + phrase + '\n' + title.end_string *len(phrase)\
+ + '\n' + title.sep
+ assert title.text() == expected
+ check_rest(title.text())
+
+## def test_subtitle():
+## phrase = 'If your computer speaks English it was probably made in Japan'
+## subtitle = rest.subtitle(phrase)
+## expected = phrase + '\n' + subtitle.underline * len(phrase) + '\n'
+## assert unicode(subtitle) == expected
+## assert check_rest(subtitle)
+
+
+ def test_paragraph(self):
+ phrase = "Perhaps if we wrote programs from childhood on, as adults we'd be able to read them."
+ para = rest.paragraph(phrase)
+ assert check_rest(para)
+
+ def test_list_item(self):
+ item_text = 'A short item.'
+ item = rest.list_item(item_text)
+ assert item.text() == item.sep + item.start_string + item_text \
+ + item.end_string + item.sep
+ check_rest(item)
+
+ def test_list_item_multiline(self):
+ item_text = '01234567890 1234567890'
+ item = rest.list_item(item_text)
+ assert len(item.text(width=15).splitlines()) == 5
+ check_rest(item.text(width=15))
+
+ def test_list_item_custom_bullet(self):
+ item_text = '12345678901234567890'
+ item = rest.list_item(item_text, bullet='+')
+ assert item.text().strip()[0] == '+'
+ check_rest(item)
+
+ def test_auto_enumerated_list(self):
+ item_text = '12345678901234567890'
+ item = rest.list_item(item_text, enumerate = True)
+ assert item.text().strip()[0:2] == '#.'
+ check_rest(item)
+
+ def test_literal_block(self):
+ block_text = '''\
+ This line is only 45 characters wide.
+ This one is even longer (two spaces).
+ '''
+
+ block = rest.literal_block(block_text)
+ assert block.text()[:6] == '\n\n::\n\n'
+ out = Out()
+ block.__rest__(out)
+ assert out.max_length() == len(block.quote) + max([len(l) for l in block_text.splitlines()])
+ check_rest(block)
+
+ block = rest.literal_block(block_text, quote= rest.literal_block.quotes[3])
+ assert block.text().strip()[4] == rest.literal_block.quotes[3]
+
+
+ def test_interpreted_text(self):
+
+ itext = rest.interpreted_text('just text')
+ assert itext.text() == '`just text`'
+ itext_role = rest.interpreted_text('just text with role', role = 'red')
+ assert itext_role.text().startswith(':red:`just')
+
+ def test_directive(self):
+ pass
+
+
+# create texts with rest objects
+
+ def test_block_quote(self):
+ block ="""\
+This is an ordinary paragraph, introducing a block quote.
+
+ "It is my business to know things. That is my trade."
+
+ -- Sherlock Holmes
+ """
+ assert check_rest(block)
+
+
+
+ def test_quoted_line_block(self):
+ text = """\
+Take it away, Eric the Orchestra Leader!
+
+ | A one, two, a one two three four
+ |
+ | Half a bee, philosophically,
+ | must, *ipso facto*, half not be.
+ | But half the bee has got to be,
+ | *vis a vis* its entity. D'you see?
+ |
+ | But can a bee be said to be
+ | or not to be an entire bee,
+ | when half the bee is not a bee,
+ | due to some ancient injury?
+ |
+ | Singing...
+ """
+ assert check_rest(text)
+
+#def test_temdir_output():
+# py.test.skip('tempdir is %s' % temp)
More information about the pytest-commit
mailing list