summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeonard Richardson <leonardr@segfault.org>2018-12-31 11:26:32 -0500
committerLeonard Richardson <leonardr@segfault.org>2018-12-31 11:26:32 -0500
commit5e6b30dec003ecd5ebdde3f1b5a1b11210c9210e (patch)
tree8eaa43a713c982ddb2f6357d25f3d4d663a889e7
parentd420395d8c70794d64efe07448283946ee5b074e (diff)
parent429ad00b6203e19ad88bc334138151034ef61420 (diff)
downloadbeautifulsoup4-5e6b30dec003ecd5ebdde3f1b5a1b11210c9210e.tar.gz
Merging Isaac Muse's branch that implements PageElement.extend() and makes insert_* take *args. [bug=1514970]
-rw-r--r--bs4/element.py74
-rw-r--r--bs4/tests/test_tree.py28
2 files changed, 70 insertions, 32 deletions
diff --git a/bs4/element.py b/bs4/element.py
index fb74f9c..c959c3e 100644
--- a/bs4/element.py
+++ b/bs4/element.py
@@ -440,43 +440,53 @@ class PageElement(object):
"""Appends the given tag to the contents of this tag."""
self.insert(len(self.contents), tag)
- def insert_before(self, predecessor):
- """Makes the given element the immediate predecessor of this one.
+ def extend(self, tags):
+ """Appends the given tags to the contents of this tag."""
+ for tag in tags:
+ self.append(tag)
- The two elements will have the same parent, and the given element
+ def insert_before(self, *args):
+ """Makes the given element(s) the immediate predecessor of this one.
+
+ The elements will have the same parent, and the given elements
will be immediately before this one.
"""
- if self is predecessor:
- raise ValueError("Can't insert an element before itself.")
- parent = self.parent
- if parent is None:
- raise ValueError(
- "Element has no parent, so 'before' has no meaning.")
- # Extract first so that the index won't be screwed up if they
- # are siblings.
- if isinstance(predecessor, PageElement):
- predecessor.extract()
- index = parent.index(self)
- parent.insert(index, predecessor)
-
- def insert_after(self, successor):
- """Makes the given element the immediate successor of this one.
-
- The two elements will have the same parent, and the given element
+ for predecessor in args:
+ if self is predecessor:
+ raise ValueError("Can't insert an element before itself.")
+ parent = self.parent
+ if parent is None:
+ raise ValueError(
+ "Element has no parent, so 'before' has no meaning.")
+ # Extract first so that the index won't be screwed up if they
+ # are siblings.
+ if isinstance(predecessor, PageElement):
+ predecessor.extract()
+ index = parent.index(self)
+ parent.insert(index, predecessor)
+
+ def insert_after(self, *args):
+ """Makes the given element(s) the immediate successor of this one.
+
+ The elements will have the same parent, and the given elements
will be immediately after this one.
"""
- if self is successor:
- raise ValueError("Can't insert an element after itself.")
- parent = self.parent
- if parent is None:
- raise ValueError(
- "Element has no parent, so 'after' has no meaning.")
- # Extract first so that the index won't be screwed up if they
- # are siblings.
- if isinstance(successor, PageElement):
- successor.extract()
- index = parent.index(self)
- parent.insert(index+1, successor)
+
+ offset = 0
+ for successor in args:
+ if self is successor:
+ raise ValueError("Can't insert an element after itself.")
+ parent = self.parent
+ if parent is None:
+ raise ValueError(
+ "Element has no parent, so 'after' has no meaning.")
+ # Extract first so that the index won't be screwed up if they
+ # are siblings.
+ if isinstance(successor, PageElement):
+ successor.extract()
+ index = parent.index(self)
+ parent.insert(index+1+offset, successor)
+ offset += 1
def find_next(self, name=None, attrs={}, text=None, **kwargs):
"""Returns the first item that matches the given criteria and
diff --git a/bs4/tests/test_tree.py b/bs4/tests/test_tree.py
index f1af6ce..e6c07aa 100644
--- a/bs4/tests/test_tree.py
+++ b/bs4/tests/test_tree.py
@@ -931,6 +931,13 @@ class TestTreeModification(SoupTest):
soup.a.append(soup.b)
self.assertEqual(data, soup.decode())
+ def test_extend(self):
+ data = "<a><b><c><d><e><f><g></g></f></e></d></c></b></a>"
+ soup = self.soup(data)
+ l = [soup.g, soup.f, soup.e, soup.d, soup.c, soup.b]
+ soup.a.extend(l)
+ self.assertEqual("<a><g></g><f></f><e></e><d></d><c></c><b></b></a>", soup.decode())
+
def test_move_tag_to_beginning_of_parent(self):
data = "<a><b></b><c></c><d></d></a>"
soup = self.soup(data)
@@ -957,6 +964,17 @@ class TestTreeModification(SoupTest):
self.assertEqual(
soup.decode(), self.document_for("QUUX<b>bar</b><a>foo</a>BAZ"))
+ def test_insert_multiple_before(self):
+ soup = self.soup("<a>foo</a><b>bar</b>")
+ soup.b.insert_before("BAZ", " ", "QUUX")
+ soup.a.insert_before("QUUX", " ", "BAZ")
+ self.assertEqual(
+ soup.decode(), self.document_for("QUUX BAZ<a>foo</a>BAZ QUUX<b>bar</b>"))
+
+ soup.a.insert_before(soup.b, "FOO")
+ self.assertEqual(
+ soup.decode(), self.document_for("QUUX BAZ<b>bar</b>FOO<a>foo</a>BAZ QUUX"))
+
def test_insert_after(self):
soup = self.soup("<a>foo</a><b>bar</b>")
soup.b.insert_after("BAZ")
@@ -967,6 +985,16 @@ class TestTreeModification(SoupTest):
self.assertEqual(
soup.decode(), self.document_for("QUUX<b>bar</b><a>foo</a>BAZ"))
+ def test_insert_multiple_after(self):
+ soup = self.soup("<a>foo</a><b>bar</b>")
+ soup.b.insert_after("BAZ", " ", "QUUX")
+ soup.a.insert_after("QUUX", " ", "BAZ")
+ self.assertEqual(
+ soup.decode(), self.document_for("<a>foo</a>QUUX BAZ<b>bar</b>BAZ QUUX"))
+ soup.b.insert_after(soup.a, "FOO ")
+ self.assertEqual(
+ soup.decode(), self.document_for("QUUX BAZ<b>bar</b><a>foo</a>FOO BAZ QUUX"))
+
def test_insert_after_raises_exception_if_after_has_no_meaning(self):
soup = self.soup("")
tag = soup.new_tag("a")