|
From: <mi...@us...> - 2024-05-04 08:58:11
|
Revision: 9680
http://sourceforge.net/p/docutils/code/9680
Author: milde
Date: 2024-05-04 08:58:09 +0000 (Sat, 04 May 2024)
Log Message:
-----------
Sort "nodes" and "test_nodes".
Sort definitions in "nodes.py" to get a clearer structure.
Move `TextElement` to the end of "Element Categories", so that
the Inline Element Category class can be declared as valid child
element (for use with the to-be-defined `Element.validate()` method.
Sort tests to better match the structure of "nodes.py".
Modified Paths:
--------------
trunk/docutils/docutils/nodes.py
trunk/docutils/test/test_nodes.py
Modified: trunk/docutils/docutils/nodes.py
===================================================================
--- trunk/docutils/docutils/nodes.py 2024-05-04 08:58:00 UTC (rev 9679)
+++ trunk/docutils/docutils/nodes.py 2024-05-04 08:58:09 UTC (rev 9680)
@@ -215,18 +215,6 @@
for child in self.children:
yield from child._superfast_findall()
- def traverse(self, condition=None, include_self=True, descend=True,
- siblings=False, ascend=False):
- """Return list of nodes following `self`.
-
- For looping, Node.findall() is faster and more memory efficient.
- """
- # traverse() may be eventually removed:
- warnings.warn('nodes.Node.traverse() is obsoleted by Node.findall().',
- PendingDeprecationWarning, stacklevel=2)
- return list(self.findall(condition, include_self, descend,
- siblings, ascend))
-
def findall(self, condition=None, include_self=True, descend=True,
siblings=False, ascend=False):
"""
@@ -310,6 +298,18 @@
else:
node = node.parent
+ def traverse(self, condition=None, include_self=True, descend=True,
+ siblings=False, ascend=False):
+ """Return list of nodes following `self`.
+
+ For looping, Node.findall() is faster and more memory efficient.
+ """
+ # traverse() may be eventually removed:
+ warnings.warn('nodes.Node.traverse() is obsoleted by Node.findall().',
+ PendingDeprecationWarning, stacklevel=2)
+ return list(self.findall(condition, include_self, descend,
+ siblings, ascend))
+
def next_node(self, condition=None, include_self=False, descend=True,
siblings=False, ascend=False):
"""
@@ -326,21 +326,6 @@
return None
-# definition moved here from `utils` to avoid circular import dependency
-def unescape(text, restore_backslashes=False, respect_whitespace=False):
- """
- Return a string with nulls removed or restored to backslashes.
- Backslash-escaped spaces are also removed.
- """
- # `respect_whitespace` is ignored (since introduction 2016-12-16)
- if restore_backslashes:
- return text.replace('\x00', '\\')
- else:
- for sep in ['\x00 ', '\x00\n', '\x00']:
- text = ''.join(text.split(sep))
- return text
-
-
class Text(Node, str):
"""
@@ -377,12 +362,12 @@
def __repr__(self):
return self.shortrepr(maxlen=68)
+ def astext(self):
+ return str(unescape(self))
+
def _dom_node(self, domroot):
return domroot.createTextNode(str(self))
- def astext(self):
- return str(unescape(self))
-
def copy(self):
return self.__class__(str(self))
@@ -1087,49 +1072,6 @@
return attr not in cls.known_attributes
-class TextElement(Element):
-
- """
- An element which directly contains text.
-
- Its children are all `Text` or `Inline` subclass nodes. You can
- check whether an element's context is inline simply by checking whether
- its immediate parent is a `TextElement` instance (including subclasses).
- This is handy for nodes like `image` that can appear both inline and as
- standalone body elements.
-
- If passing children to `__init__()`, make sure to set `text` to
- ``''`` or some other suitable value.
- """
-
- child_text_separator = ''
- """Separator for child nodes, used by `astext()` method."""
-
- def __init__(self, rawsource='', text='', *children, **attributes):
- if text != '':
- textnode = Text(text)
- Element.__init__(self, rawsource, textnode, *children,
- **attributes)
- else:
- Element.__init__(self, rawsource, *children, **attributes)
-
-
-class FixedTextElement(TextElement):
-
- """An element which directly contains preformatted text."""
-
- def __init__(self, rawsource='', text='', *children, **attributes):
- super().__init__(rawsource, text, *children, **attributes)
- self.attributes['xml:space'] = 'preserve'
-
-
-# TODO: PureTextElement(TextElement):
-# """An element which only contains text, no children."""
-# For elements in the DTD that directly employ #PCDATA in their definition:
-# citation_reference, comment, footnote_reference, label, math, math_block,
-# option_argument, option_string, raw,
-
-
# ========
# Mixins
# ========
@@ -1161,6 +1103,10 @@
"""Category of Node which may occur before Bibliographic Nodes."""
+class Invisible(PreBibliographic):
+ """Internal elements that don't appear in output."""
+
+
class Bibliographic:
pass
@@ -1192,10 +1138,6 @@
"""Special internal body elements."""
-class Invisible(PreBibliographic):
- """Internal elements that don't appear in output."""
-
-
class Part:
pass
@@ -1221,6 +1163,49 @@
"""Contains a `label` as its first element."""
+class TextElement(Element):
+
+ """
+ An element which directly contains text.
+
+ Its children are all `Text` or `Inline` subclass nodes. You can
+ check whether an element's context is inline simply by checking whether
+ its immediate parent is a `TextElement` instance (including subclasses).
+ This is handy for nodes like `image` that can appear both inline and as
+ standalone body elements.
+
+ If passing children to `__init__()`, make sure to set `text` to
+ ``''`` or some other suitable value.
+ """
+
+ child_text_separator = ''
+ """Separator for child nodes, used by `astext()` method."""
+
+ def __init__(self, rawsource='', text='', *children, **attributes):
+ if text != '':
+ textnode = Text(text)
+ Element.__init__(self, rawsource, textnode, *children,
+ **attributes)
+ else:
+ Element.__init__(self, rawsource, *children, **attributes)
+
+
+class FixedTextElement(TextElement):
+
+ """An element which directly contains preformatted text."""
+
+ def __init__(self, rawsource='', text='', *children, **attributes):
+ super().__init__(rawsource, text, *children, **attributes)
+ self.attributes['xml:space'] = 'preserve'
+
+
+# TODO: PureTextElement(TextElement):
+# """An element which only contains text, no children."""
+# For elements in the DTD that directly employ #PCDATA in their definition:
+# citation_reference, comment, footnote_reference, label, math, math_block,
+# option_argument, option_string, raw,
+
+
# ==============
# Root Element
# ==============
@@ -2179,6 +2164,21 @@
"""
+# definition moved here from `utils` to avoid circular import dependency
+def unescape(text, restore_backslashes=False, respect_whitespace=False):
+ """
+ Return a string with nulls removed or restored to backslashes.
+ Backslash-escaped spaces are also removed.
+ """
+ # `respect_whitespace` is ignored (since introduction 2016-12-16)
+ if restore_backslashes:
+ return text.replace('\x00', '\\')
+ else:
+ for sep in ['\x00 ', '\x00\n', '\x00']:
+ text = ''.join(text.split(sep))
+ return text
+
+
def make_id(string):
"""
Convert `string` into an identifier and return it.
Modified: trunk/docutils/test/test_nodes.py
===================================================================
--- trunk/docutils/test/test_nodes.py 2024-05-04 08:58:00 UTC (rev 9679)
+++ trunk/docutils/test/test_nodes.py 2024-05-04 08:58:09 UTC (rev 9680)
@@ -21,22 +21,123 @@
debug = False
+class NodeTests(unittest.TestCase):
+
+ def not_in_testlist(self, x):
+ # function to use in `condition` argument in findall() and next_node()
+ return x not in self.testlist
+
+ def test_findall(self):
+ # `findall()` is defined in class Node,
+ # we test with a tree of Element instances (simpler setup)
+ e = nodes.Element()
+ e += nodes.Element()
+ e[0] += nodes.Element()
+ e[0] += nodes.TextElement()
+ e[0][1] += nodes.Text('some text')
+ e += nodes.Element()
+ e += nodes.Element()
+ self.assertEqual(list(e.findall()),
+ [e, e[0], e[0][0], e[0][1], e[0][1][0], e[1], e[2]])
+ self.assertEqual(list(e.findall(include_self=False)),
+ [e[0], e[0][0], e[0][1], e[0][1][0], e[1], e[2]])
+ self.assertEqual(list(e.findall(descend=False)),
+ [e])
+ self.assertEqual(list(e[0].findall(descend=False, ascend=True)),
+ [e[0], e[1], e[2]])
+ self.assertEqual(list(e[0][0].findall(descend=False, ascend=True)),
+ [e[0][0], e[0][1], e[1], e[2]])
+ self.assertEqual(list(e[0][0].findall(descend=False, siblings=True)),
+ [e[0][0], e[0][1]])
+ self.testlist = e[0:2]
+ self.assertEqual(list(e.findall(condition=self.not_in_testlist)),
+ [e, e[0][0], e[0][1], e[0][1][0], e[2]])
+ # Return siblings despite siblings=False because ascend is true.
+ self.assertEqual(list(e[1].findall(ascend=True, siblings=False)),
+ [e[1], e[2]])
+ self.assertEqual(list(e[0].findall()),
+ [e[0], e[0][0], e[0][1], e[0][1][0]])
+ self.testlist = [e[0][0], e[0][1]]
+ self.assertEqual(list(e[0].findall(condition=self.not_in_testlist)),
+ [e[0], e[0][1][0]])
+ self.testlist.append(e[0][1][0])
+ self.assertEqual(list(e[0].findall(condition=self.not_in_testlist)),
+ [e[0]])
+ self.assertEqual(list(e.findall(nodes.TextElement)), [e[0][1]])
+
+ def test_findall_duplicate_texts(self):
+ e = nodes.Element()
+ e += nodes.TextElement()
+ e[0] += nodes.Text('one') # e[0][0]
+ e[0] += nodes.Text('two') # e[0][1]
+ e[0] += nodes.Text('three') # e[0][2]
+ e[0] += nodes.Text('two') # e[0][3] same value as e[0][1]
+ e[0] += nodes.Text('five') # e[0][4]
+ full_list = list(e[0][0].findall(siblings=True))
+ self.assertEqual(len(full_list), 5)
+ for i in range(5):
+ self.assertIs(full_list[i], e[0][i])
+
+ partial_list = list(e[0][3].findall(siblings=True))
+ self.assertEqual(len(partial_list), 2)
+ self.assertIs(partial_list[0], e[0][3])
+ self.assertIs(partial_list[1], e[0][4])
+
+ def test_next_node(self):
+ e = nodes.Element()
+ e += nodes.Element()
+ e[0] += nodes.Element()
+ e[0] += nodes.TextElement()
+ e[0][1] += nodes.Text('some text')
+ e += nodes.Element()
+ e += nodes.Element()
+ self.testlist = [e[0], e[0][1], e[1]]
+ compare = [(e, e[0][0]),
+ (e[0], e[0][0]),
+ (e[0][0], e[0][1][0]),
+ (e[0][1], e[0][1][0]),
+ (e[0][1][0], e[2]),
+ (e[1], e[2]),
+ (e[2], None)]
+ for node, next_node in compare:
+ self.assertEqual(node.next_node(self.not_in_testlist, ascend=True),
+ next_node)
+ self.assertEqual(e[0][0].next_node(ascend=True), e[0][1])
+ self.assertEqual(e[2].next_node(), None)
+
+
class TextTests(unittest.TestCase):
- def setUp(self):
- self.text = nodes.Text('Line 1.\n\x00rad två.')
- self.longtext = nodes.Text('Mary had a little lamb whose '
- 'fleece was white as snow and '
- 'everwhere that Mary went the '
- 'lamb was sure to go.')
+ text = nodes.Text('Line 1.\n\x00rad två.')
+ longtext = nodes.Text('Mary had a little lamb '
+ 'whose fleece was white as snow '
+ 'and everwhere that Mary went '
+ 'the lamb was sure to go.')
+ def test_value_type_check(self):
+ # data must by `str` instance, no `bytes` allowed
+ with self.assertRaises(TypeError):
+ nodes.Text(b'hol')
+
+ def test_Text_rawsource_deprection_warning(self):
+ with self.assertWarnsRegex(DeprecationWarning,
+ '"rawsource" is ignored'):
+ nodes.Text('content', rawsource='content')
+
+ def test_str(self):
+ self.assertEqual(str(self.text), 'Line 1.\n\x00rad två.')
+
def test_repr(self):
self.assertEqual(repr(self.text), r"<#text: 'Line 1.\n\x00rad två.'>")
self.assertEqual(self.text.shortrepr(),
r"<#text: 'Line 1.\n\x00rad två.'>")
- def test_str(self):
- self.assertEqual(str(self.text), 'Line 1.\n\x00rad två.')
+ def test_repr_long_text(self):
+ self.assertEqual(repr(self.longtext), r"<#text: 'Mary had a "
+ r"little lamb whose fleece was white as snow "
+ r"and everwh ...'>")
+ self.assertEqual(self.longtext.shortrepr(),
+ r"<#text: 'Mary had a lit ...'>")
def test_astext(self):
self.assertEqual(self.text.astext(), 'Line 1.\nrad två.')
@@ -52,27 +153,11 @@
self.assertEqual(stripped, 'was noch')
self.assertEqual(stripped2, 's noc')
- def test_asciirestriction(self):
- # no bytes at all allowed
- self.assertRaises(TypeError, nodes.Text, b'hol')
-
- def test_longrepr(self):
- self.assertEqual(repr(self.longtext), r"<#text: 'Mary had a "
- r"little lamb whose fleece was white as snow "
- r"and everwh ...'>")
- self.assertEqual(self.longtext.shortrepr(),
- r"<#text: 'Mary had a lit ...'>")
-
def test_comparison(self):
# Text nodes are compared by value
self.assertEqual(self.text, nodes.Text('Line 1.\n\x00rad två.'))
- def test_Text_rawsource_deprection_warning(self):
- with self.assertWarnsRegex(DeprecationWarning,
- '"rawsource" is ignored'):
- nodes.Text('content', rawsource='content')
-
class ElementTests(unittest.TestCase):
def test_empty(self):
@@ -296,6 +381,46 @@
# 'll' is extended
self.assertEqual(element1['ll'], ['A', 'B'])
+ def test_copy(self):
+ # Shallow copy:
+ grandchild = nodes.Text('grandchild text')
+ child = nodes.emphasis('childtext', grandchild, att='child')
+ e = nodes.Element('raw text', child, att='e')
+ e_copy = e.copy()
+ self.assertTrue(e is not e_copy)
+ # Internal attributes (like `rawsource`) are also copied.
+ self.assertEqual(e.rawsource, 'raw text')
+ self.assertEqual(e_copy.rawsource, e.rawsource)
+ self.assertEqual(e_copy['att'], 'e')
+ self.assertEqual(e_copy.document, e.document)
+ self.assertEqual(e_copy.source, e.source)
+ self.assertEqual(e_copy.line, e.line)
+ # Children are not copied.
+ self.assertEqual(len(e_copy), 0)
+
+ def test_deepcopy(self):
+ # Deep copy:
+ grandchild = nodes.Text('grandchild text')
+ child = nodes.emphasis('childtext', grandchild, att='child')
+ e = nodes.Element('raw text', child, att='e')
+ e_deepcopy = e.deepcopy()
+ self.assertEqual(e_deepcopy.rawsource, e.rawsource)
+ self.assertEqual(e_deepcopy['att'], 'e')
+ # Children are copied recursively.
+ self.assertEqual(e_deepcopy[0][0], grandchild)
+ self.assertTrue(e_deepcopy[0][0] is not grandchild)
+ self.assertEqual(e_deepcopy[0]['att'], 'child')
+
+ def test_system_message_copy(self):
+ e = nodes.system_message('mytext', att='e', rawsource='raw text')
+ # Shallow copy:
+ e_copy = e.copy()
+ self.assertTrue(e is not e_copy)
+ # Internal attributes (like `rawsource`) are also copied.
+ self.assertEqual(e.rawsource, 'raw text')
+ self.assertEqual(e_copy.rawsource, e.rawsource)
+ self.assertEqual(e_copy['att'], 'e')
+
def test_replace_self(self):
parent = nodes.Element(ids=['parent'])
child1 = nodes.Element(ids=['child1'])
@@ -359,11 +484,124 @@
nodes.node_class_names.sort()
self.assertEqual(node_class_names, nodes.node_class_names)
+
+class TreeCopyVisitorTests(unittest.TestCase):
+
+ def setUp(self):
+ document = utils.new_document('test data')
+ document += nodes.paragraph('', 'Paragraph 1.')
+ blist = nodes.bullet_list()
+ for i in range(1, 6):
+ item = nodes.list_item()
+ for j in range(1, 4):
+ item += nodes.paragraph('', 'Item %s, paragraph %s.' % (i, j))
+ blist += item
+ document += blist
+ self.document = document
+
+ def compare_trees(self, one, two):
+ self.assertEqual(one.__class__, two.__class__)
+ self.assertNotEqual(id(one), id(two))
+ self.assertEqual(len(one.children), len(two.children))
+ for i in range(len(one.children)):
+ self.compare_trees(one.children[i], two.children[i])
+
+ def test_copy_whole(self):
+ visitor = nodes.TreeCopyVisitor(self.document)
+ self.document.walkabout(visitor)
+ newtree = visitor.get_tree_copy()
+ self.assertEqual(self.document.pformat(), newtree.pformat())
+ self.compare_trees(self.document, newtree)
+
+
+class SetIdTests(unittest.TestCase):
+
+ def setUp(self):
+ self.document = utils.new_document('test')
+ self.elements = [nodes.Element(names=['test']),
+ nodes.section(), # Name empty
+ nodes.section(names=['Test']), # duplicate id
+ nodes.footnote(names=['2019-10-30']), # id empty
+ ]
+
+ def test_set_id_default(self):
+ # Default prefixes.
+ for element in self.elements:
+ self.document.set_id(element)
+ ids = [element['ids'] for element in self.elements]
+ self.assertEqual(ids, [['test'], ['section-1'],
+ ['test-1'], ['footnote-1']])
+
+ def test_set_id_custom(self):
+ # Custom prefixes.
+
+ # Change settings.
+ self.document.settings.id_prefix = 'P-'
+ self.document.settings.auto_id_prefix = 'auto'
+
+ for element in self.elements:
+ self.document.set_id(element)
+ ids = [element['ids'] for element in self.elements]
+ self.assertEqual(ids, [['P-test'],
+ ['P-auto1'],
+ ['P-auto2'],
+ ['P-2019-10-30']])
+
+ def test_set_id_descriptive_auto_id(self):
+ # Use name or tag-name for auto-id.
+
+ # Change setting.
+ self.document.settings.auto_id_prefix = '%'
+
+ for element in self.elements:
+ self.document.set_id(element)
+ ids = [element['ids'] for element in self.elements]
+ self.assertEqual(ids, [['test'],
+ ['section-1'],
+ ['test-1'],
+ ['footnote-1']])
+
+ def test_set_id_custom_descriptive_auto_id(self):
+ # Custom prefixes and name or tag-name for auto-id.
+
+ # Change settings.
+ self.document.settings.id_prefix = 'P:'
+ self.document.settings.auto_id_prefix = 'a-%'
+
+ for element in self.elements:
+ self.document.set_id(element)
+ ids = [element['ids'] for element in self.elements]
+ self.assertEqual(ids, [['P:test'],
+ ['P:a-section-1'],
+ ['P:test-1'],
+ ['P:2019-10-30']])
+
+
+class NodeVisitorTests(unittest.TestCase):
+ def setUp(self):
+ self.document = utils.new_document('test')
+ self.element = nodes.Element()
+ self.visitor = nodes.NodeVisitor(self.document)
+
+ def test_dispatch_visit_unknown(self):
+ # raise exception if no visit/depart methods are defined for node class
+ with self.assertRaises(NotImplementedError):
+ self.visitor.dispatch_visit(self.element)
+
+ def test_dispatch_visit_optional(self):
+ # silently skip nodes of a calss in tuple nodes.NodeVisitor.optional
+ rv = self.visitor.dispatch_visit(nodes.meta())
+ self.assertIsNone(rv)
+
+
+class MiscFunctionTests(unittest.TestCase):
+
ids = [('a', 'a'), ('A', 'a'), ('', ''), ('a b \n c', 'a-b-c'),
('a.b.c', 'a-b-c'), (' - a - b - c - ', 'a-b-c'), (' - ', ''),
('\u2020\u2066', ''), ('a \xa7 b \u2020 c', 'a-b-c'),
('1', ''), ('1abc', 'abc'),
]
+
ids_unicode_all = [
('\u00f8 o with stroke', 'o-o-with-stroke'),
('\u0111 d with stroke', 'd-d-with-stroke'),
@@ -539,232 +777,6 @@
self.fail(f'{len(failures)} failures in {len(self.ids)} ids\n'
+ "\n".join(failures))
- def test_findall(self):
- e = nodes.Element()
- e += nodes.Element()
- e[0] += nodes.Element()
- e[0] += nodes.TextElement()
- e[0][1] += nodes.Text('some text')
- e += nodes.Element()
- e += nodes.Element()
- self.assertEqual(list(e.findall()),
- [e, e[0], e[0][0], e[0][1], e[0][1][0], e[1], e[2]])
- self.assertEqual(list(e.findall(include_self=False)),
- [e[0], e[0][0], e[0][1], e[0][1][0], e[1], e[2]])
- self.assertEqual(list(e.findall(descend=False)),
- [e])
- self.assertEqual(list(e[0].findall(descend=False, ascend=True)),
- [e[0], e[1], e[2]])
- self.assertEqual(list(e[0][0].findall(descend=False, ascend=True)),
- [e[0][0], e[0][1], e[1], e[2]])
- self.assertEqual(list(e[0][0].findall(descend=False, siblings=True)),
- [e[0][0], e[0][1]])
- self.testlist = e[0:2]
- self.assertEqual(list(e.findall(condition=self.not_in_testlist)),
- [e, e[0][0], e[0][1], e[0][1][0], e[2]])
- # Return siblings despite siblings=False because ascend is true.
- self.assertEqual(list(e[1].findall(ascend=True, siblings=False)),
- [e[1], e[2]])
- self.assertEqual(list(e[0].findall()),
- [e[0], e[0][0], e[0][1], e[0][1][0]])
- self.testlist = [e[0][0], e[0][1]]
- self.assertEqual(list(e[0].findall(condition=self.not_in_testlist)),
- [e[0], e[0][1][0]])
- self.testlist.append(e[0][1][0])
- self.assertEqual(list(e[0].findall(condition=self.not_in_testlist)),
- [e[0]])
- self.assertEqual(list(e.findall(nodes.TextElement)), [e[0][1]])
-
- def test_findall_duplicate_texts(self):
- e = nodes.Element()
- e += nodes.TextElement()
- e[0] += nodes.Text('one')
- e[0] += nodes.Text('two')
- e[0] += nodes.Text('three')
- e[0] += nodes.Text('two')
- e[0] += nodes.Text('five')
- full_list = list(e[0][0].findall(siblings=True))
- self.assertEqual(len(full_list), 5)
- for i in range(5):
- self.assertIs(full_list[i], e[0][i])
-
- partial_list = list(e[0][3].findall(siblings=True))
- self.assertEqual(len(partial_list), 2)
- self.assertIs(partial_list[0], e[0][3])
- self.assertIs(partial_list[1], e[0][4])
-
- def test_next_node(self):
- e = nodes.Element()
- e += nodes.Element()
- e[0] += nodes.Element()
- e[0] += nodes.TextElement()
- e[0][1] += nodes.Text('some text')
- e += nodes.Element()
- e += nodes.Element()
- self.testlist = [e[0], e[0][1], e[1]]
- compare = [(e, e[0][0]),
- (e[0], e[0][0]),
- (e[0][0], e[0][1][0]),
- (e[0][1], e[0][1][0]),
- (e[0][1][0], e[2]),
- (e[1], e[2]),
- (e[2], None)]
- for node, next_node in compare:
- self.assertEqual(node.next_node(self.not_in_testlist, ascend=True),
- next_node)
- self.assertEqual(e[0][0].next_node(ascend=True), e[0][1])
- self.assertEqual(e[2].next_node(), None)
-
- def not_in_testlist(self, x):
- return x not in self.testlist
-
- def test_copy(self):
- grandchild = nodes.Text('grandchild text')
- child = nodes.emphasis('childtext', grandchild, att='child')
- e = nodes.Element('raw text', child, att='e')
- # Shallow copy:
- e_copy = e.copy()
- self.assertTrue(e is not e_copy)
- # Internal attributes (like `rawsource`) are also copied.
- self.assertEqual(e.rawsource, 'raw text')
- self.assertEqual(e_copy.rawsource, e.rawsource)
- self.assertEqual(e_copy['att'], 'e')
- self.assertEqual(e_copy.document, e.document)
- self.assertEqual(e_copy.source, e.source)
- self.assertEqual(e_copy.line, e.line)
- # Children are not copied.
- self.assertEqual(len(e_copy), 0)
- # Deep copy:
- e_deepcopy = e.deepcopy()
- self.assertEqual(e_deepcopy.rawsource, e.rawsource)
- self.assertEqual(e_deepcopy['att'], 'e')
- # Children are copied recursively.
- self.assertEqual(e_deepcopy[0][0], grandchild)
- self.assertTrue(e_deepcopy[0][0] is not grandchild)
- self.assertEqual(e_deepcopy[0]['att'], 'child')
-
- def test_system_message_copy(self):
- e = nodes.system_message('mytext', att='e', rawsource='raw text')
- # Shallow copy:
- e_copy = e.copy()
- self.assertTrue(e is not e_copy)
- # Internal attributes (like `rawsource`) are also copied.
- self.assertEqual(e.rawsource, 'raw text')
- self.assertEqual(e_copy.rawsource, e.rawsource)
- self.assertEqual(e_copy['att'], 'e')
-
-
-class TreeCopyVisitorTests(unittest.TestCase):
-
- def setUp(self):
- document = utils.new_document('test data')
- document += nodes.paragraph('', 'Paragraph 1.')
- blist = nodes.bullet_list()
- for i in range(1, 6):
- item = nodes.list_item()
- for j in range(1, 4):
- item += nodes.paragraph('', 'Item %s, paragraph %s.' % (i, j))
- blist += item
- document += blist
- self.document = document
-
- def compare_trees(self, one, two):
- self.assertEqual(one.__class__, two.__class__)
- self.assertNotEqual(id(one), id(two))
- self.assertEqual(len(one.children), len(two.children))
- for i in range(len(one.children)):
- self.compare_trees(one.children[i], two.children[i])
-
- def test_copy_whole(self):
- visitor = nodes.TreeCopyVisitor(self.document)
- self.document.walkabout(visitor)
- newtree = visitor.get_tree_copy()
- self.assertEqual(self.document.pformat(), newtree.pformat())
- self.compare_trees(self.document, newtree)
-
-
-class SetIdTests(unittest.TestCase):
-
- def setUp(self):
- self.document = utils.new_document('test')
- self.elements = [nodes.Element(names=['test']),
- nodes.section(), # Name empty
- nodes.section(names=['Test']), # duplicate id
- nodes.footnote(names=['2019-10-30']), # id empty
- ]
-
- def test_set_id_default(self):
- # Default prefixes.
- for element in self.elements:
- self.document.set_id(element)
- ids = [element['ids'] for element in self.elements]
- self.assertEqual(ids, [['test'], ['section-1'],
- ['test-1'], ['footnote-1']])
-
- def test_set_id_custom(self):
- # Custom prefixes.
-
- # Change settings.
- self.document.settings.id_prefix = 'P-'
- self.document.settings.auto_id_prefix = 'auto'
-
- for element in self.elements:
- self.document.set_id(element)
- ids = [element['ids'] for element in self.elements]
- self.assertEqual(ids, [['P-test'],
- ['P-auto1'],
- ['P-auto2'],
- ['P-2019-10-30']])
-
- def test_set_id_descriptive_auto_id(self):
- # Use name or tag-name for auto-id.
-
- # Change setting.
- self.document.settings.auto_id_prefix = '%'
-
- for element in self.elements:
- self.document.set_id(element)
- ids = [element['ids'] for element in self.elements]
- self.assertEqual(ids, [['test'],
- ['section-1'],
- ['test-1'],
- ['footnote-1']])
-
- def test_set_id_custom_descriptive_auto_id(self):
- # Custom prefixes and name or tag-name for auto-id.
-
- # Change settings.
- self.document.settings.id_prefix = 'P:'
- self.document.settings.auto_id_prefix = 'a-%'
-
- for element in self.elements:
- self.document.set_id(element)
- ids = [element['ids'] for element in self.elements]
- self.assertEqual(ids, [['P:test'],
- ['P:a-section-1'],
- ['P:test-1'],
- ['P:2019-10-30']])
-
-
-class NodeVisitorTests(unittest.TestCase):
- def setUp(self):
- self.document = utils.new_document('test')
- self.element = nodes.Element()
- self.visitor = nodes.NodeVisitor(self.document)
-
- def test_dispatch_visit_unknown(self):
- # raise exception if no visit/depart methods are defined for node class
- with self.assertRaises(NotImplementedError):
- self.visitor.dispatch_visit(self.element)
-
- def test_dispatch_visit_optional(self):
- # silently skip nodes of a calss in tuple nodes.NodeVisitor.optional
- rv = self.visitor.dispatch_visit(nodes.meta())
- self.assertIsNone(rv)
-
-
-class MiscFunctionTests(unittest.TestCase):
-
names = [ # sample, whitespace_normalized, fully_normalized
('a', 'a', 'a'),
('A', 'A', 'a'),
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|