various 3k related fixes and cleanups
removal of virtually unused py/rest/rst.py helpers --HG-- branch : trunk
This commit is contained in:
parent
5851471009
commit
6823fa634b
|
@ -147,7 +147,6 @@ initpkg(__name__,
|
||||||
'builtin.print_' : ('./builtin/builtin31.py', 'print_'),
|
'builtin.print_' : ('./builtin/builtin31.py', 'print_'),
|
||||||
'builtin._reraise' : ('./builtin/builtin31.py', '_reraise'),
|
'builtin._reraise' : ('./builtin/builtin31.py', '_reraise'),
|
||||||
'builtin.exec_' : ('./builtin/builtin31.py', 'exec_'),
|
'builtin.exec_' : ('./builtin/builtin31.py', 'exec_'),
|
||||||
'builtin.intern' : ('./builtin/builtin31.py', 'intern'),
|
|
||||||
'builtin._basestring' : ('./builtin/builtin31.py', '_basestring'),
|
'builtin._basestring' : ('./builtin/builtin31.py', '_basestring'),
|
||||||
'builtin._totext' : ('./builtin/builtin31.py', '_totext'),
|
'builtin._totext' : ('./builtin/builtin31.py', '_totext'),
|
||||||
'builtin._isbytes' : ('./builtin/builtin31.py', '_isbytes'),
|
'builtin._isbytes' : ('./builtin/builtin31.py', '_isbytes'),
|
||||||
|
|
|
@ -10,7 +10,6 @@ def test_varnames():
|
||||||
def f(self, y):
|
def f(self, y):
|
||||||
pass
|
pass
|
||||||
assert varnames(f) == ("x",)
|
assert varnames(f) == ("x",)
|
||||||
assert varnames(A.f) == ('y',)
|
|
||||||
assert varnames(A().f) == ('y',)
|
assert varnames(A().f) == ('y',)
|
||||||
|
|
||||||
class TestMultiCall:
|
class TestMultiCall:
|
||||||
|
@ -121,7 +120,7 @@ class TestRegistry:
|
||||||
class api4:
|
class api4:
|
||||||
x = 44
|
x = 44
|
||||||
l = list(plugins.listattr('x', extra=(api4,)))
|
l = list(plugins.listattr('x', extra=(api4,)))
|
||||||
assert l == range(41, 45)
|
assert l == [41,42,43,44]
|
||||||
assert len(list(plugins)) == 3 # otherwise extra added
|
assert len(list(plugins)) == 3 # otherwise extra added
|
||||||
|
|
||||||
def test_api_and_defaults():
|
def test_api_and_defaults():
|
||||||
|
|
|
@ -50,21 +50,14 @@ def test_importall():
|
||||||
base = py.path.local(py.__file__).dirpath()
|
base = py.path.local(py.__file__).dirpath()
|
||||||
nodirs = (
|
nodirs = (
|
||||||
base.join('test', 'testing', 'data'),
|
base.join('test', 'testing', 'data'),
|
||||||
base.join('apigen', 'tracer', 'testing', 'package'),
|
base.join('test', 'web'),
|
||||||
base.join('test', 'testing', 'test'),
|
|
||||||
base.join('test', 'rsession', 'webjs.py'),
|
|
||||||
base.join('apigen', 'source', 'server.py'),
|
|
||||||
base.join('magic', 'greenlet.py'),
|
|
||||||
base.join('path', 'gateway',),
|
base.join('path', 'gateway',),
|
||||||
base.join('doc',),
|
base.join('doc',),
|
||||||
base.join('rest', 'directive.py'),
|
base.join('rest', 'directive.py'),
|
||||||
base.join('test', 'testing', 'import_test'),
|
base.join('test', 'testing', 'import_test'),
|
||||||
base.join('c-extension',),
|
|
||||||
base.join('test', 'report', 'web.py'),
|
|
||||||
base.join('test', 'report', 'webjs.py'),
|
|
||||||
base.join('test', 'report', 'rest.py'),
|
|
||||||
base.join('magic', 'greenlet.py'),
|
|
||||||
base.join('bin'),
|
base.join('bin'),
|
||||||
|
base.join('code', 'oldmagic.py'),
|
||||||
|
base.join('code', '_assertionold.py'),
|
||||||
base.join('execnet', 'script'),
|
base.join('execnet', 'script'),
|
||||||
base.join('compat', 'testing'),
|
base.join('compat', 'testing'),
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,7 +8,7 @@ def check_assertion():
|
||||||
raise ValueError("assertion not enabled: got %s" % s)
|
raise ValueError("assertion not enabled: got %s" % s)
|
||||||
|
|
||||||
def test_invoke_assertion(recwarn, monkeypatch):
|
def test_invoke_assertion(recwarn, monkeypatch):
|
||||||
monkeypatch.setattr(py.std.__builtin__, 'AssertionError', None)
|
monkeypatch.setattr(py.builtin.builtins, 'AssertionError', None)
|
||||||
py.magic.invoke(assertion=True)
|
py.magic.invoke(assertion=True)
|
||||||
try:
|
try:
|
||||||
check_assertion()
|
check_assertion()
|
||||||
|
@ -17,7 +17,7 @@ def test_invoke_assertion(recwarn, monkeypatch):
|
||||||
recwarn.pop(DeprecationWarning)
|
recwarn.pop(DeprecationWarning)
|
||||||
|
|
||||||
def test_invoke_compile(recwarn, monkeypatch):
|
def test_invoke_compile(recwarn, monkeypatch):
|
||||||
monkeypatch.setattr(py.std.__builtin__, 'compile', None)
|
monkeypatch.setattr(py.builtin.builtins, 'compile', None)
|
||||||
py.magic.invoke(compile=True)
|
py.magic.invoke(compile=True)
|
||||||
try:
|
try:
|
||||||
co = compile("""if 1:
|
co = compile("""if 1:
|
||||||
|
|
|
@ -10,7 +10,7 @@ def setup_module(mod):
|
||||||
|
|
||||||
def checkmain(name):
|
def checkmain(name):
|
||||||
main = getattr(py.cmdline, name)
|
main = getattr(py.cmdline, name)
|
||||||
assert callable(main)
|
assert py.builtin.callable(main)
|
||||||
assert name[:2] == "py"
|
assert name[:2] == "py"
|
||||||
scriptname = "py." + name[2:]
|
scriptname = "py." + name[2:]
|
||||||
assert binpath.join(scriptname).check()
|
assert binpath.join(scriptname).check()
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
""" deprecated module for turning on/off some features. """
|
""" deprecated module for turning on/off some features. """
|
||||||
|
|
||||||
import py
|
import py
|
||||||
import __builtin__ as cpy_builtin
|
|
||||||
|
from py.builtin import builtins as cpy_builtin
|
||||||
|
|
||||||
def invoke(assertion=False, compile=False):
|
def invoke(assertion=False, compile=False):
|
||||||
""" (deprecated) invoke magic, currently you can specify:
|
""" (deprecated) invoke magic, currently you can specify:
|
||||||
|
|
|
@ -171,8 +171,8 @@ class ApiModule(ModuleType):
|
||||||
dict = dictdescr.__get__(self)
|
dict = dictdescr.__get__(self)
|
||||||
if dict is not None:
|
if dict is not None:
|
||||||
if '*' not in self.__map__:
|
if '*' not in self.__map__:
|
||||||
for name in self.__map__.keys():
|
for name in list(self.__map__):
|
||||||
hasattr(self, name) # force attribute to be loaded, ignore errors
|
hasattr(self, name) # force attribute load, ignore errors
|
||||||
assert not self.__map__, "%r not empty" % self.__map__
|
assert not self.__map__, "%r not empty" % self.__map__
|
||||||
else:
|
else:
|
||||||
fsname = self.__map__['*'][0]
|
fsname = self.__map__['*'][0]
|
||||||
|
|
|
@ -46,7 +46,7 @@ class ForkedFunc(object):
|
||||||
fdstderr = stderr.fileno()
|
fdstderr = stderr.fileno()
|
||||||
if fdstderr != 2:
|
if fdstderr != 2:
|
||||||
os.dup2(fdstderr, 2)
|
os.dup2(fdstderr, 2)
|
||||||
retvalf = self.RETVAL.open("w")
|
retvalf = self.RETVAL.open("wb")
|
||||||
EXITSTATUS = 0
|
EXITSTATUS = 0
|
||||||
try:
|
try:
|
||||||
if nice_level:
|
if nice_level:
|
||||||
|
@ -79,7 +79,7 @@ class ForkedFunc(object):
|
||||||
exitstatus = 0
|
exitstatus = 0
|
||||||
signal = systemstatus & 0x7f
|
signal = systemstatus & 0x7f
|
||||||
if not exitstatus and not signal:
|
if not exitstatus and not signal:
|
||||||
retval = self.RETVAL.open()
|
retval = self.RETVAL.open('rb')
|
||||||
try:
|
try:
|
||||||
retval_data = retval.read()
|
retval_data = retval.read()
|
||||||
finally:
|
finally:
|
||||||
|
|
417
py/rest/rst.py
417
py/rest/rst.py
|
@ -1,417 +0,0 @@
|
||||||
|
|
||||||
""" reStructuredText generation tools
|
|
||||||
|
|
||||||
provides an api to build a tree from nodes, which can be converted to
|
|
||||||
ReStructuredText on demand
|
|
||||||
|
|
||||||
note that not all of ReST is supported, a usable subset is offered, but
|
|
||||||
certain features aren't supported, and also certain details (like how links
|
|
||||||
are generated, or how escaping is done) can not be controlled
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import generators
|
|
||||||
|
|
||||||
import py
|
|
||||||
|
|
||||||
def escape(txt):
|
|
||||||
"""escape ReST markup"""
|
|
||||||
if not isinstance(txt, str) and not isinstance(txt, unicode):
|
|
||||||
txt = str(txt)
|
|
||||||
# XXX this takes a very naive approach to escaping, but it seems to be
|
|
||||||
# sufficient...
|
|
||||||
for c in '\\*`|:_':
|
|
||||||
txt = txt.replace(c, '\\%s' % (c,))
|
|
||||||
return txt
|
|
||||||
|
|
||||||
class RestError(Exception):
|
|
||||||
""" raised on containment errors (wrong parent) """
|
|
||||||
|
|
||||||
class AbstractMetaclass(type):
|
|
||||||
def __new__(cls, *args):
|
|
||||||
obj = super(AbstractMetaclass, cls).__new__(cls, *args)
|
|
||||||
parent_cls = obj.parentclass
|
|
||||||
if parent_cls is None:
|
|
||||||
return obj
|
|
||||||
if not isinstance(parent_cls, list):
|
|
||||||
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:
|
|
||||||
_class.allowed_child = {obj:True}
|
|
||||||
else:
|
|
||||||
_class.allowed_child[obj] = True
|
|
||||||
return obj
|
|
||||||
|
|
||||||
class AbstractNode(object):
|
|
||||||
""" Base class implementing rest generation
|
|
||||||
"""
|
|
||||||
sep = ''
|
|
||||||
__metaclass__ = AbstractMetaclass
|
|
||||||
parentclass = None # this exists to allow parent to know what
|
|
||||||
# children can exist
|
|
||||||
allow_nesting = False
|
|
||||||
allowed_child = {}
|
|
||||||
defaults = {}
|
|
||||||
|
|
||||||
_reg_whitespace = py.std.re.compile('\s+')
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self.parent = None
|
|
||||||
self.children = []
|
|
||||||
for child in args:
|
|
||||||
self._add(child)
|
|
||||||
for arg in kwargs:
|
|
||||||
setattr(self, arg, kwargs[arg])
|
|
||||||
|
|
||||||
def join(self, *children):
|
|
||||||
""" add child nodes
|
|
||||||
|
|
||||||
returns a reference to self
|
|
||||||
"""
|
|
||||||
for child in children:
|
|
||||||
self._add(child)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def add(self, child):
|
|
||||||
""" adds a child node
|
|
||||||
|
|
||||||
returns a reference to the child
|
|
||||||
"""
|
|
||||||
self._add(child)
|
|
||||||
return child
|
|
||||||
|
|
||||||
def _add(self, child):
|
|
||||||
if child.__class__ not in self.allowed_child:
|
|
||||||
raise RestError("%r cannot be child of %r" % \
|
|
||||||
(child.__class__, self.__class__))
|
|
||||||
self.children.append(child)
|
|
||||||
child.parent = self
|
|
||||||
|
|
||||||
def __getitem__(self, item):
|
|
||||||
return self.children[item]
|
|
||||||
|
|
||||||
def __setitem__(self, item, value):
|
|
||||||
self.children[item] = value
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
""" return a ReST string representation of the node """
|
|
||||||
return self.sep.join([child.text() for child in self.children])
|
|
||||||
|
|
||||||
def wordlist(self):
|
|
||||||
""" return a list of ReST strings for this node and its children """
|
|
||||||
return [self.text()]
|
|
||||||
|
|
||||||
class Rest(AbstractNode):
|
|
||||||
""" Root node of a document """
|
|
||||||
|
|
||||||
sep = "\n\n"
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
AbstractNode.__init__(self, *args, **kwargs)
|
|
||||||
self.links = {}
|
|
||||||
|
|
||||||
def render_links(self, check=False):
|
|
||||||
"""render the link attachments of the document"""
|
|
||||||
assert not check, "Link checking not implemented"
|
|
||||||
if not self.links:
|
|
||||||
return ""
|
|
||||||
link_texts = []
|
|
||||||
# XXX this could check for duplicates and remove them...
|
|
||||||
for link, target in self.links.items():
|
|
||||||
link_texts.append(".. _`%s`: %s" % (escape(link), target))
|
|
||||||
return "\n" + "\n".join(link_texts) + "\n\n"
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
outcome = []
|
|
||||||
if (isinstance(self.children[0], Transition) or
|
|
||||||
isinstance(self.children[-1], Transition)):
|
|
||||||
raise ValueError('document must not begin or end with a '
|
|
||||||
'transition')
|
|
||||||
for child in self.children:
|
|
||||||
outcome.append(child.text())
|
|
||||||
|
|
||||||
# always a trailing newline
|
|
||||||
text = self.sep.join([i for i in outcome if i]) + "\n"
|
|
||||||
return text + self.render_links()
|
|
||||||
|
|
||||||
class Transition(AbstractNode):
|
|
||||||
""" a horizontal line """
|
|
||||||
parentclass = Rest
|
|
||||||
|
|
||||||
def __init__(self, char='-', width=80, *args, **kwargs):
|
|
||||||
self.char = char
|
|
||||||
self.width = width
|
|
||||||
super(Transition, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
return (self.width - 1) * self.char
|
|
||||||
|
|
||||||
class Paragraph(AbstractNode):
|
|
||||||
""" simple paragraph """
|
|
||||||
|
|
||||||
parentclass = Rest
|
|
||||||
sep = " "
|
|
||||||
indent = ""
|
|
||||||
width = 80
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
# make shortcut
|
|
||||||
args = list(args)
|
|
||||||
for num, arg in enumerate(args):
|
|
||||||
if isinstance(arg, str):
|
|
||||||
args[num] = Text(arg)
|
|
||||||
super(Paragraph, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
texts = []
|
|
||||||
for child in self.children:
|
|
||||||
texts += child.wordlist()
|
|
||||||
|
|
||||||
buf = []
|
|
||||||
outcome = []
|
|
||||||
lgt = len(self.indent)
|
|
||||||
|
|
||||||
def grab(buf):
|
|
||||||
outcome.append(self.indent + self.sep.join(buf))
|
|
||||||
|
|
||||||
texts.reverse()
|
|
||||||
while texts:
|
|
||||||
next = texts[-1]
|
|
||||||
if not next:
|
|
||||||
texts.pop()
|
|
||||||
continue
|
|
||||||
if lgt + len(self.sep) + len(next) <= self.width or not buf:
|
|
||||||
buf.append(next)
|
|
||||||
lgt += len(next) + len(self.sep)
|
|
||||||
texts.pop()
|
|
||||||
else:
|
|
||||||
grab(buf)
|
|
||||||
lgt = len(self.indent)
|
|
||||||
buf = []
|
|
||||||
grab(buf)
|
|
||||||
return "\n".join(outcome)
|
|
||||||
|
|
||||||
class SubParagraph(Paragraph):
|
|
||||||
""" indented sub paragraph """
|
|
||||||
|
|
||||||
indent = " "
|
|
||||||
|
|
||||||
class Title(Paragraph):
|
|
||||||
""" title element """
|
|
||||||
|
|
||||||
parentclass = Rest
|
|
||||||
belowchar = "="
|
|
||||||
abovechar = ""
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
txt = self._get_text()
|
|
||||||
lines = []
|
|
||||||
if self.abovechar:
|
|
||||||
lines.append(self.abovechar * len(txt))
|
|
||||||
lines.append(txt)
|
|
||||||
if self.belowchar:
|
|
||||||
lines.append(self.belowchar * len(txt))
|
|
||||||
return "\n".join(lines)
|
|
||||||
|
|
||||||
def _get_text(self):
|
|
||||||
txt = []
|
|
||||||
for node in self.children:
|
|
||||||
txt += node.wordlist()
|
|
||||||
return ' '.join(txt)
|
|
||||||
|
|
||||||
class AbstractText(AbstractNode):
|
|
||||||
parentclass = [Paragraph, Title]
|
|
||||||
start = ""
|
|
||||||
end = ""
|
|
||||||
def __init__(self, _text):
|
|
||||||
self._text = _text
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
text = self.escape(self._text)
|
|
||||||
return self.start + text + self.end
|
|
||||||
|
|
||||||
def escape(self, text):
|
|
||||||
if not isinstance(text, str) and not isinstance(text, unicode):
|
|
||||||
text = str(text)
|
|
||||||
if self.start:
|
|
||||||
text = text.replace(self.start, '\\%s' % (self.start,))
|
|
||||||
if self.end and self.end != self.start:
|
|
||||||
text = text.replace(self.end, '\\%s' % (self.end,))
|
|
||||||
return text
|
|
||||||
|
|
||||||
class Text(AbstractText):
|
|
||||||
def wordlist(self):
|
|
||||||
text = escape(self._text)
|
|
||||||
return self._reg_whitespace.split(text)
|
|
||||||
|
|
||||||
class LiteralBlock(AbstractText):
|
|
||||||
parentclass = Rest
|
|
||||||
start = '::\n\n'
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
if not self._text.strip():
|
|
||||||
return ''
|
|
||||||
text = self.escape(self._text).split('\n')
|
|
||||||
for i, line in enumerate(text):
|
|
||||||
if line.strip():
|
|
||||||
text[i] = ' %s' % (line,)
|
|
||||||
return self.start + '\n'.join(text)
|
|
||||||
|
|
||||||
class Em(AbstractText):
|
|
||||||
start = "*"
|
|
||||||
end = "*"
|
|
||||||
|
|
||||||
class Strong(AbstractText):
|
|
||||||
start = "**"
|
|
||||||
end = "**"
|
|
||||||
|
|
||||||
class Quote(AbstractText):
|
|
||||||
start = '``'
|
|
||||||
end = '``'
|
|
||||||
|
|
||||||
class Anchor(AbstractText):
|
|
||||||
start = '_`'
|
|
||||||
end = '`'
|
|
||||||
|
|
||||||
class Footnote(AbstractText):
|
|
||||||
def __init__(self, note, symbol=False):
|
|
||||||
raise NotImplemented('XXX')
|
|
||||||
|
|
||||||
class Citation(AbstractText):
|
|
||||||
def __init__(self, text, cite):
|
|
||||||
raise NotImplemented('XXX')
|
|
||||||
|
|
||||||
class ListItem(Paragraph):
|
|
||||||
allow_nesting = True
|
|
||||||
item_chars = '*+-'
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
idepth = self.get_indent_depth()
|
|
||||||
indent = self.indent + (idepth + 1) * ' '
|
|
||||||
txt = '\n\n'.join(self.render_children(indent))
|
|
||||||
ret = []
|
|
||||||
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 = []
|
|
||||||
buffer = []
|
|
||||||
def render_buffer(fro, to):
|
|
||||||
if not fro:
|
|
||||||
return
|
|
||||||
p = Paragraph(indent=indent, *fro)
|
|
||||||
p.parent = self.parent
|
|
||||||
to.append(p.text())
|
|
||||||
for child in self.children:
|
|
||||||
if isinstance(child, AbstractText):
|
|
||||||
buffer.append(child)
|
|
||||||
else:
|
|
||||||
if buffer:
|
|
||||||
render_buffer(buffer, txt)
|
|
||||||
buffer = []
|
|
||||||
txt.append(child.text())
|
|
||||||
|
|
||||||
render_buffer(buffer, txt)
|
|
||||||
return txt
|
|
||||||
|
|
||||||
def get_indent_depth(self):
|
|
||||||
depth = 0
|
|
||||||
current = self
|
|
||||||
while (current.parent is not None and
|
|
||||||
isinstance(current.parent, ListItem)):
|
|
||||||
depth += 1
|
|
||||||
current = current.parent
|
|
||||||
return depth
|
|
||||||
|
|
||||||
class OrderedListItem(ListItem):
|
|
||||||
item_chars = ["#."] * 5
|
|
||||||
|
|
||||||
class DListItem(ListItem):
|
|
||||||
item_chars = None
|
|
||||||
def __init__(self, term, definition, *args, **kwargs):
|
|
||||||
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\n'.join(self.render_children(indent))
|
|
||||||
ret = []
|
|
||||||
ret += [indent[2:], self.term, '\n', txt]
|
|
||||||
return ''.join(ret)
|
|
||||||
|
|
||||||
class Link(AbstractText):
|
|
||||||
start = '`'
|
|
||||||
end = '`_'
|
|
||||||
|
|
||||||
def __init__(self, _text, target):
|
|
||||||
self._text = _text
|
|
||||||
self.target = target
|
|
||||||
self.rest = None
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
if self.rest is None:
|
|
||||||
self.rest = self.find_rest()
|
|
||||||
if self.rest.links.get(self._text, self.target) != self.target:
|
|
||||||
raise ValueError('link name %r already in use for a different '
|
|
||||||
'target' % (self.target,))
|
|
||||||
self.rest.links[self._text] = self.target
|
|
||||||
return AbstractText.text(self)
|
|
||||||
|
|
||||||
def find_rest(self):
|
|
||||||
# XXX little overkill, but who cares...
|
|
||||||
next = self
|
|
||||||
while next.parent is not None:
|
|
||||||
next = next.parent
|
|
||||||
return next
|
|
||||||
|
|
||||||
class InternalLink(AbstractText):
|
|
||||||
start = '`'
|
|
||||||
end = '`_'
|
|
||||||
|
|
||||||
class LinkTarget(Paragraph):
|
|
||||||
def __init__(self, name, target):
|
|
||||||
self.name = name
|
|
||||||
self.target = target
|
|
||||||
|
|
||||||
def text(self):
|
|
||||||
return ".. _`%s`:%s\n" % (self.name, self.target)
|
|
||||||
|
|
||||||
class Substitution(AbstractText):
|
|
||||||
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.items()])
|
|
||||||
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
|
|
||||||
|
|
|
@ -1,468 +0,0 @@
|
||||||
|
|
||||||
""" rst generation tests
|
|
||||||
"""
|
|
||||||
import py
|
|
||||||
py.test.importorskip("docutils")
|
|
||||||
from py.__.rest.rst import *
|
|
||||||
from py.__.rest.resthtml import process as restcheck
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
tempdir = py.test.ensuretemp('rest')
|
|
||||||
def checkrest(rest):
|
|
||||||
fname = traceback.extract_stack()[-2][2]
|
|
||||||
i = 0
|
|
||||||
while True:
|
|
||||||
if i == 0:
|
|
||||||
filename = '%s.txt' % (fname,)
|
|
||||||
else:
|
|
||||||
filename = '%s_%s.txt' % (fname, i)
|
|
||||||
tempfile = tempdir.join(filename)
|
|
||||||
if not tempfile.check():
|
|
||||||
break
|
|
||||||
i += 1
|
|
||||||
tempfile.write(rest)
|
|
||||||
restcheck(tempfile)
|
|
||||||
return tempfile.new(ext='.html').read()
|
|
||||||
|
|
||||||
def test_escape_text():
|
|
||||||
txt = Paragraph('*escape* ``test``').text()
|
|
||||||
assert txt == '\\*escape\\* \\`\\`test\\`\\`'
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert '*escape* ``test``' in html
|
|
||||||
|
|
||||||
def test_escape_markup_simple():
|
|
||||||
txt = Paragraph(Em('*em*')).text()
|
|
||||||
assert txt == '*\\*em\\**'
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert '<em>*em*</em>' in html
|
|
||||||
|
|
||||||
def test_escape_underscore():
|
|
||||||
txt = Rest(Paragraph('foo [1]_')).text()
|
|
||||||
assert txt == "foo [1]\\_\n"
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert 'foo [1]_' in html
|
|
||||||
|
|
||||||
def test_escape_markup_spaces_docutils_nastyness():
|
|
||||||
txt = Rest(Paragraph(Em('foo *bar* baz'))).text()
|
|
||||||
assert txt == '*foo \\*bar\\* baz*\n'
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert '<em>foo *bar* baz</em>' in html
|
|
||||||
|
|
||||||
def test_escape_literal():
|
|
||||||
txt = LiteralBlock('*escape* ``test``').text()
|
|
||||||
assert txt == '::\n\n *escape* ``test``'
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert '>\n*escape* ``test``\n</pre>' in html
|
|
||||||
|
|
||||||
def test_escape_markup_obvious():
|
|
||||||
txt = Em('foo*bar').text()
|
|
||||||
assert txt == '*foo\\*bar*'
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert '<em>foo*bar</em>' in html
|
|
||||||
|
|
||||||
def test_escape_markup_text_1():
|
|
||||||
txt = Paragraph(Em('foo'), "*bar").text()
|
|
||||||
assert txt == '*foo* \\*bar'
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert '<em>foo</em> *bar' in html
|
|
||||||
|
|
||||||
def test_escape_markup_text_2():
|
|
||||||
txt = Paragraph(Em('foo'), "bar*").text()
|
|
||||||
assert txt == '*foo* bar\\*'
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert '<em>foo</em> bar*' in html
|
|
||||||
|
|
||||||
def test_illegal_parent():
|
|
||||||
Rest(Paragraph(Text('spam')))
|
|
||||||
py.test.raises(RestError, 'Rest(Text("spam"))')
|
|
||||||
py.test.raises(RestError, 'ListItem(Paragraph(Text("eggs")))')
|
|
||||||
|
|
||||||
def test_text_basic():
|
|
||||||
txt = Text("dupa").text()
|
|
||||||
assert txt == "dupa"
|
|
||||||
|
|
||||||
def test_basic_inline():
|
|
||||||
txt = Em('foo').text()
|
|
||||||
assert txt == '*foo*'
|
|
||||||
|
|
||||||
def test_basic_inline_2():
|
|
||||||
txt = Strong('bar').text()
|
|
||||||
assert txt == '**bar**'
|
|
||||||
|
|
||||||
def test_text_multiple_arguments():
|
|
||||||
txt = Paragraph(Text("dupa"), Text("dupa")).text()
|
|
||||||
assert txt == "dupa dupa"
|
|
||||||
|
|
||||||
def test_text_join():
|
|
||||||
txt = Paragraph(Text("worse things"))
|
|
||||||
txt = txt.join(Text("happen at sea"), Text("you know"))
|
|
||||||
assert txt.text() == "worse things happen at sea you know"
|
|
||||||
|
|
||||||
def test_text_add():
|
|
||||||
p = Paragraph(Text('grmbl'))
|
|
||||||
p2 = p.add(Text('grmbl too'))
|
|
||||||
assert p2.text() == 'grmbl too'
|
|
||||||
assert p.text() == 'grmbl grmbl too'
|
|
||||||
|
|
||||||
def test_paragraph_basic():
|
|
||||||
txt = Paragraph(Text('spam')).text()
|
|
||||||
assert txt == 'spam'
|
|
||||||
|
|
||||||
def test_paragraph_string():
|
|
||||||
txt = Paragraph("eggs").text()
|
|
||||||
assert txt == "eggs"
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_paragraph_join():
|
|
||||||
txt = Rest(Paragraph(Text("a")), Paragraph(Text("b"))).text()
|
|
||||||
assert txt == "a\n\nb\n"
|
|
||||||
|
|
||||||
def test_paragraph_indent():
|
|
||||||
txt = Paragraph(Text("a"), indent=" ").text()
|
|
||||||
assert txt == " a"
|
|
||||||
checkrest(txt)
|
|
||||||
txt = Paragraph(Text(" a "), indent=" ").text()
|
|
||||||
assert txt == " a"
|
|
||||||
|
|
||||||
def test_paragraph_width():
|
|
||||||
txt = Paragraph(Text("a b c d e f"), width=3, indent=" ").text()
|
|
||||||
assert txt == ' a\n b\n c\n d\n e\n f'
|
|
||||||
checkrest(txt)
|
|
||||||
text = """
|
|
||||||
Lorem ipsum dolor sit amet, consectetuer
|
|
||||||
adipiscing elit. Vestibulum malesuada
|
|
||||||
eleifend leo. Sed faucibus commodo libero.
|
|
||||||
Mauris elementum fringilla velit. Ut
|
|
||||||
sem urna, aliquet sed, molestie at, viverra
|
|
||||||
id, justo. In ornare lacinia turpis. Etiam
|
|
||||||
et ipsum. Quisque at lacus. Etiam
|
|
||||||
pellentesque, enim porta pulvinar viverra,
|
|
||||||
libero elit iaculis justo, vitae convallis
|
|
||||||
pede purus vel arcu. Morbi aliquam lacus
|
|
||||||
et urna. Donec commodo pellentesque mi.
|
|
||||||
"""
|
|
||||||
expected = """\
|
|
||||||
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum malesuada
|
|
||||||
eleifend leo. Sed faucibus commodo libero. Mauris elementum fringilla velit. Ut
|
|
||||||
sem urna, aliquet sed, molestie at, viverra id, justo. In ornare lacinia
|
|
||||||
turpis. Etiam et ipsum. Quisque at lacus. Etiam pellentesque, enim porta
|
|
||||||
pulvinar viverra, libero elit iaculis justo, vitae convallis pede purus vel
|
|
||||||
arcu. Morbi aliquam lacus et urna. Donec commodo pellentesque mi."""
|
|
||||||
txt = Paragraph(text, width=80).text()
|
|
||||||
print(repr(txt))
|
|
||||||
print(repr(expected))
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_paragraph_stripping():
|
|
||||||
txt = Paragraph(Text('\n foo bar\t')).text()
|
|
||||||
assert txt == 'foo bar'
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_blockquote():
|
|
||||||
expected = """\
|
|
||||||
Text
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
def fun():
|
|
||||||
some
|
|
||||||
|
|
||||||
Paragraph
|
|
||||||
"""
|
|
||||||
txt = Rest(Paragraph("Text"), LiteralBlock("def fun():\n some"), \
|
|
||||||
Paragraph("Paragraph")).text()
|
|
||||||
print(repr(txt))
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_blockquote_empty():
|
|
||||||
expected = """\
|
|
||||||
Foo
|
|
||||||
|
|
||||||
Bar
|
|
||||||
"""
|
|
||||||
txt = Rest(Paragraph('Foo'), LiteralBlock(''), Paragraph('Bar')).text()
|
|
||||||
print(repr(txt))
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_title():
|
|
||||||
txt = Title(Text("Some title"), belowchar="=").text()
|
|
||||||
assert txt == "Some title\n=========="
|
|
||||||
checkrest(txt)
|
|
||||||
txt = Title("Some title", belowchar="#", abovechar="#").text()
|
|
||||||
assert txt == "##########\nSome title\n##########"
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert '>Some title</h1>' in html
|
|
||||||
|
|
||||||
def test_title_long():
|
|
||||||
txt = Title('Some very long title that doesn\'t fit on a single line '
|
|
||||||
'but still should not be split into multiple lines').text()
|
|
||||||
assert txt == ("Some very long title that doesn't fit on a single line "
|
|
||||||
"but still should not be split into multiple lines\n"
|
|
||||||
"======================================================="
|
|
||||||
"=================================================")
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_title_long_with_markup():
|
|
||||||
txt = Title('Some very long title with', Em('some markup'),
|
|
||||||
'to test whether that works as expected too...').text()
|
|
||||||
assert txt == ("Some very long title with *some markup* to test whether "
|
|
||||||
"that works as expected too...\n"
|
|
||||||
"========================================================"
|
|
||||||
"=============================")
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_title_escaping():
|
|
||||||
txt = Title('foo *bar* baz').text()
|
|
||||||
assert txt == 'foo \\*bar\\* baz\n==============='
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_link():
|
|
||||||
expected = "`some link`_\n\n.. _`some link`: http://codespeak.net\n\n"
|
|
||||||
txt = Rest(Paragraph(Link("some link", "http://codespeak.net"))).text()
|
|
||||||
assert txt == expected
|
|
||||||
html = checkrest(txt)
|
|
||||||
assert ' href="http://codespeak.net">some link</a>' in html
|
|
||||||
|
|
||||||
def test_link_same_text_and_target():
|
|
||||||
txt = Rest(Paragraph(Link('some link', 'bar'), 'foo',
|
|
||||||
Link('some link', 'bar'))
|
|
||||||
).text()
|
|
||||||
expected = '`some link`_ foo `some link`_\n\n.. _`some link`: bar\n\n'
|
|
||||||
assert txt == expected
|
|
||||||
|
|
||||||
def test_link_same_text_different_target():
|
|
||||||
py.test.raises(ValueError, ("Rest(Paragraph(Link('some link', 'foo'),"
|
|
||||||
"Link('some link', 'bar'))).text()"))
|
|
||||||
|
|
||||||
def test_text_multiline():
|
|
||||||
expected = """\
|
|
||||||
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum malesuada
|
|
||||||
eleifend leo. Sed faucibus commodo libero. Mauris elementum fringilla velit. Ut
|
|
||||||
sem urna, aliquet sed, molestie at, viverra id, justo. In ornare lacinia
|
|
||||||
turpis. Etiam et ipsum. Quisque at lacus. Etiam pellentesque, enim porta
|
|
||||||
pulvinar viverra, libero elit iaculis justo, vitae convallis pede purus vel
|
|
||||||
arcu. Morbi aliquam lacus et urna. Donec commodo pellentesque mi.
|
|
||||||
"""
|
|
||||||
txt = Rest(Paragraph('Lorem ipsum dolor sit amet, consectetuer adipiscing '
|
|
||||||
'elit. Vestibulum malesuada eleifend leo. Sed '
|
|
||||||
'faucibus commodo libero. Mauris elementum fringilla '
|
|
||||||
'velit. Ut sem urna, aliquet sed, molestie at, '
|
|
||||||
'viverra id, justo. In ornare lacinia turpis. Etiam '
|
|
||||||
'et ipsum. Quisque at lacus. Etiam pellentesque, '
|
|
||||||
'enim porta pulvinar viverra, libero elit iaculis '
|
|
||||||
'justo, vitae convallis pede purus vel arcu. Morbi '
|
|
||||||
'aliquam lacus et urna. Donec commodo pellentesque '
|
|
||||||
'mi.')).text()
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_text_indented():
|
|
||||||
expected = """\
|
|
||||||
This is a paragraph with some indentation. The indentation should be removed
|
|
||||||
and the lines split up nicely. This is still part of the first paragraph.
|
|
||||||
"""
|
|
||||||
txt = Rest(Paragraph('This is a paragraph with some\n'
|
|
||||||
' indentation. The indentation\n'
|
|
||||||
' should be removed and the lines split up nicely.\n'
|
|
||||||
'\nThis is still part of the first paragraph.')
|
|
||||||
).text()
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_text_strip():
|
|
||||||
expected = "foo\n"
|
|
||||||
txt = Rest(Paragraph(Text(' foo '))).text()
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_list():
|
|
||||||
expected = "* a\n\n* b\n"
|
|
||||||
txt = Rest(ListItem("a"), ListItem("b")).text()
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_list_item_multiple_args():
|
|
||||||
expected = "* foo bar baz\n"
|
|
||||||
txt = Rest(ListItem('foo', 'bar', 'baz')).text()
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_list_multiline():
|
|
||||||
expected = """\
|
|
||||||
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vestibulum
|
|
||||||
malesuada eleifend leo. Sed faucibus commodo libero.
|
|
||||||
|
|
||||||
* Mauris elementum fringilla velit. Ut sem urna, aliquet sed, molestie at,
|
|
||||||
viverra id, justo. In ornare lacinia turpis. Etiam et ipsum. Quisque at
|
|
||||||
lacus.
|
|
||||||
|
|
||||||
* Etiam pellentesque, enim porta pulvinar viverra, libero elit iaculis justo,
|
|
||||||
vitae convallis pede purus vel arcu. Morbi aliquam lacus et urna. Donec
|
|
||||||
commodo pellentesque mi.
|
|
||||||
"""
|
|
||||||
txt = Rest(ListItem('Lorem ipsum dolor sit amet, consectetuer adipiscing '
|
|
||||||
'elit. Vestibulum malesuada eleifend leo. Sed '
|
|
||||||
'faucibus commodo libero.'),
|
|
||||||
ListItem('Mauris elementum fringilla velit. Ut sem urna, '
|
|
||||||
'aliquet sed, molestie at, viverra id, justo. In '
|
|
||||||
'ornare lacinia turpis. Etiam et ipsum. Quisque at '
|
|
||||||
'lacus.'),
|
|
||||||
ListItem('Etiam pellentesque, enim porta pulvinar viverra, '
|
|
||||||
'libero elit iaculis justo, vitae convallis pede '
|
|
||||||
'purus vel arcu. Morbi aliquam lacus et urna. Donec '
|
|
||||||
'commodo pellentesque mi.')).text()
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_list_multiline_no_parent():
|
|
||||||
expected = ("* test **strong**\n thisisaverylongwordthatdoesntfiton"
|
|
||||||
"thepreviouslineandthereforeshouldbeindented")
|
|
||||||
txt = ListItem(Text('test'), Strong('strong'),
|
|
||||||
Text('thisisaverylongwordthatdoesntfitontheprevious'
|
|
||||||
'lineandthereforeshouldbeindented')).text()
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_ordered_list():
|
|
||||||
expected = "#. foo\n\n#. bar\n\n#. baz\n"
|
|
||||||
txt = Rest(OrderedListItem('foo'), OrderedListItem('bar'),
|
|
||||||
OrderedListItem('baz')).text()
|
|
||||||
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_nested_nested_lists():
|
|
||||||
expected = """\
|
|
||||||
* foo
|
|
||||||
|
|
||||||
+ bar
|
|
||||||
|
|
||||||
- baz
|
|
||||||
|
|
||||||
+ qux
|
|
||||||
|
|
||||||
* quux
|
|
||||||
"""
|
|
||||||
txt = Rest(ListItem('foo', ListItem('bar', ListItem('baz')),
|
|
||||||
ListItem('qux')), ListItem('quux')).text()
|
|
||||||
print(txt)
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_definition_list():
|
|
||||||
expected = """\
|
|
||||||
foo
|
|
||||||
bar, baz and qux!
|
|
||||||
|
|
||||||
spam
|
|
||||||
eggs, spam, spam, eggs, spam and spam...
|
|
||||||
"""
|
|
||||||
txt = Rest(DListItem("foo", "bar, baz and qux!"),
|
|
||||||
DListItem("spam", "eggs, spam, spam, eggs, spam and spam...")
|
|
||||||
).text()
|
|
||||||
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,)
|
|
||||||
checkrest(txt)
|
|
||||||
txt = Rest(Paragraph('foo'), Transition('+'), Paragraph('bar')).text()
|
|
||||||
assert txt == 'foo\n\n%s\n\nbar\n' % ('+' * 79,)
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def test_title_following_links_empty_line():
|
|
||||||
expected = """\
|
|
||||||
Foo, bar and `baz`_
|
|
||||||
|
|
||||||
Spam
|
|
||||||
====
|
|
||||||
|
|
||||||
Spam, eggs and spam.
|
|
||||||
|
|
||||||
.. _`baz`: http://www.baz.com
|
|
||||||
|
|
||||||
"""
|
|
||||||
txt = Rest(Paragraph("Foo, bar and ", Link("baz", "http://www.baz.com")),
|
|
||||||
Title('Spam'), Paragraph('Spam, eggs and spam.')).text()
|
|
||||||
assert txt == expected
|
|
||||||
checkrest(txt)
|
|
||||||
|
|
||||||
def test_nonstring_text():
|
|
||||||
expected = """\
|
|
||||||
<foobar>
|
|
||||||
"""
|
|
||||||
class FooBar(object):
|
|
||||||
def __str__(self):
|
|
||||||
return '<foobar>'
|
|
||||||
txt = Rest(Paragraph(Text(FooBar()))).text()
|
|
||||||
assert txt == expected
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
import py
|
|
||||||
from py.__.rest.rst import *
|
|
||||||
from py.__.rest.transform import *
|
|
||||||
|
|
||||||
def convert_to_html(tree):
|
|
||||||
handler = HTMLHandler()
|
|
||||||
t = RestTransformer(tree)
|
|
||||||
t.parse(handler)
|
|
||||||
return handler.html
|
|
||||||
|
|
||||||
class HTMLHandler(py.__.rest.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\tbar')),
|
|
||||||
'<pre>foo\tbar</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>\n <li>foo</li>\n <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>\n <li>foo</li>\n <li>bar\n <ul>'
|
|
||||||
'\n <li>baz</li></ul></li></ul>')
|
|
||||||
|
|
|
@ -1,184 +0,0 @@
|
||||||
import py
|
|
||||||
from py.__.rest import rst
|
|
||||||
from py.xml import html
|
|
||||||
|
|
||||||
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
|
|
||||||
getattr(self, 'handle_%s' % (name,))(node, handler)
|
|
||||||
|
|
||||||
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.root = None
|
|
||||||
self.tagstack = []
|
|
||||||
self._currlist = None
|
|
||||||
|
|
||||||
def startDocument(self):
|
|
||||||
h = html.html()
|
|
||||||
self.head = head = html.head()
|
|
||||||
self.title = title = html.title(self.title)
|
|
||||||
self._push(h)
|
|
||||||
h.append(head)
|
|
||||||
h.append(title)
|
|
||||||
self.body = body = html.body()
|
|
||||||
self._push(body)
|
|
||||||
|
|
||||||
def endDocument(self):
|
|
||||||
self._pop() # body
|
|
||||||
self._pop() # html
|
|
||||||
|
|
||||||
def startTitle(self, depth):
|
|
||||||
h = getattr(html, 'h%s' % (depth,))()
|
|
||||||
self._push(h)
|
|
||||||
|
|
||||||
def endTitle(self, depth):
|
|
||||||
self._pop()
|
|
||||||
|
|
||||||
def startParagraph(self):
|
|
||||||
self._push(html.p())
|
|
||||||
|
|
||||||
def endParagraph(self):
|
|
||||||
self._pop()
|
|
||||||
|
|
||||||
def startSubParagraph(self):
|
|
||||||
self._push(html.p(**{'class': 'sub'}))
|
|
||||||
|
|
||||||
def endSubParagraph(self):
|
|
||||||
self._pop()
|
|
||||||
|
|
||||||
def handleLiteralBlock(self, text):
|
|
||||||
pre = html.pre(text)
|
|
||||||
if self.tagstack:
|
|
||||||
self.tagstack[-1].append(pre)
|
|
||||||
else:
|
|
||||||
self.root = pre
|
|
||||||
|
|
||||||
def handleText(self, text):
|
|
||||||
self.tagstack[-1].append(text)
|
|
||||||
|
|
||||||
def handleEm(self, text):
|
|
||||||
self.tagstack[-1].append(html.em(text))
|
|
||||||
|
|
||||||
def handleStrong(self, text):
|
|
||||||
self.tagstack[-1].append(html.strong(text))
|
|
||||||
|
|
||||||
def startListItem(self, type, startlist):
|
|
||||||
if startlist:
|
|
||||||
nodename = type == 'o' and 'ol' or 'ul'
|
|
||||||
self._push(getattr(html, nodename)())
|
|
||||||
self._push(html.li())
|
|
||||||
|
|
||||||
def endListItem(self, type, closelist):
|
|
||||||
self._pop()
|
|
||||||
if closelist:
|
|
||||||
self._pop()
|
|
||||||
|
|
||||||
def handleLink(self, text, target):
|
|
||||||
self.tagstack[-1].append(html.a(text, href=target))
|
|
||||||
|
|
||||||
def _push(self, el):
|
|
||||||
if self.tagstack:
|
|
||||||
self.tagstack[-1].append(el)
|
|
||||||
else:
|
|
||||||
self.root = el
|
|
||||||
self.tagstack.append(el)
|
|
||||||
|
|
||||||
def _pop(self):
|
|
||||||
self.tagstack.pop()
|
|
||||||
|
|
||||||
def _html(self):
|
|
||||||
return self.root.unicode()
|
|
||||||
html = property(_html)
|
|
||||||
|
|
|
@ -9,9 +9,9 @@ import sys
|
||||||
#
|
#
|
||||||
# ===============================================================================
|
# ===============================================================================
|
||||||
|
|
||||||
import pytest_runner as runner # XXX
|
from py.__.test.plugin.pytest_terminal import TerminalReporter, \
|
||||||
from pytest_terminal import TerminalReporter, CollectonlyReporter
|
CollectonlyReporter, repr_pythonversion, folded_skips
|
||||||
from pytest_terminal import repr_pythonversion, folded_skips
|
from py.__.test.plugin import pytest_runner as runner
|
||||||
|
|
||||||
def basic_run_report(item):
|
def basic_run_report(item):
|
||||||
return runner.call_and_report(item, "call", log=False)
|
return runner.call_and_report(item, "call", log=False)
|
||||||
|
|
Loading…
Reference in New Issue