|
From: <mi...@us...> - 2022-06-10 11:08:49
|
Revision: 9067
http://sourceforge.net/p/docutils/code/9067
Author: milde
Date: 2022-06-10 11:08:46 +0000 (Fri, 10 Jun 2022)
Log Message:
-----------
Fix `nodes.Node.findall()` for Text nodes.
As `nodes.Text` inherits from `str`, Text nodes with the same content
are considered equal and ``nodes.Element.index(Text('sample'))``
may return a preceding Text node with content "sample".
Therefore, Node.findall() must perform an additional test for identity
with the start node.
Fixes bug #448.
Thanks to Adam Turner.
Modified Paths:
--------------
trunk/docutils/docutils/nodes.py
trunk/docutils/test/test_nodes.py
Modified: trunk/docutils/docutils/nodes.py
===================================================================
--- trunk/docutils/docutils/nodes.py 2022-06-10 11:08:38 UTC (rev 9066)
+++ trunk/docutils/docutils/nodes.py 2022-06-10 11:08:46 UTC (rev 9067)
@@ -297,6 +297,9 @@
node = self
while node.parent:
index = node.parent.index(node)
+ # extra check since Text nodes have value-equality
+ while node.parent[index] is not node:
+ index = node.parent.index(node, index + 1)
for sibling in node.parent[index+1:]:
yield from sibling.findall(
condition=condition,
@@ -734,8 +737,8 @@
def remove(self, item):
self.children.remove(item)
- def index(self, item):
- return self.children.index(item)
+ def index(self, item, start=0, stop=sys.maxsize):
+ return self.children.index(item, start, stop)
def is_not_default(self, key):
if self[key] == [] and key in self.list_attributes:
Modified: trunk/docutils/test/test_nodes.py
===================================================================
--- trunk/docutils/test/test_nodes.py 2022-06-10 11:08:38 UTC (rev 9066)
+++ trunk/docutils/test/test_nodes.py 2022-06-10 11:08:46 UTC (rev 9067)
@@ -64,6 +64,11 @@
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, 'Line 1.\nLine 2.')
+ self.assertEqual(self.text, nodes.Text('Line 1.\nLine 2.'))
+
def test_Text_rawsource_deprection_warning(self):
with self.assertWarnsRegex(DeprecationWarning,
'"rawsource" is ignored'):
@@ -119,6 +124,22 @@
self.assertEqual(element.pformat(),
'<Element attr="1">\n text\n more\n')
+ def test_index(self):
+ # Element.index() behaves like list.index() on the element's children
+ e = nodes.Element()
+ e += nodes.Element()
+ e += nodes.Text('sample')
+ e += nodes.Element()
+ e += nodes.Text('other sample')
+ e += nodes.Text('sample')
+ # return element's index for the first four children:
+ for i in range(4):
+ self.assertEqual(e.index(e[i]), i)
+ # Caution: mismatches are possible for Text nodes
+ # as they are compared by value (like `str` instances)
+ self.assertEqual(e.index(e[4]), 1)
+ self.assertEqual(e.index(e[4], start=2), 4)
+
def test_clear(self):
element = nodes.Element()
element += nodes.Element()
@@ -545,6 +566,24 @@
[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()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|