Merge ~chrispitude/beautifulsoup:new-tag-allow-text into beautifulsoup:master

Proposed by Chris Papademetrious
Status: Merged
Merge reported by: Leonard Richardson
Merged at revision: b3e3474bdf663cb7bb0bdbfce0a73f2d0a9c6f8d
Proposed branch: ~chrispitude/beautifulsoup:new-tag-allow-text
Merge into: beautifulsoup:master
Diff against target: 68 lines (+9/-8)
3 files modified
bs4/__init__.py (+6/-2)
bs4/tests/test_soup.py (+2/-1)
doc/source/index.rst (+1/-5)
Reviewer Review Type Date Requested Status
Leonard Richardson Pending
Review via email: mp+457198@code.launchpad.net

Commit message

allow string text specification in new_tag()

Description of the change

This change allows new text to be specified in the new_tag() method:

>>> title = soup.new_tag('title', 'My Title Text', ...)

or, alternatively as a named argument:

>>> title = soup.new_tag('title', string='My Title Text', ...)

This, together with the `return-inserted-element` merge request, allows much easier element creation and insertion like this:

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup('<html/>')
>>> html = soup.find('html')
>>> #
>>> head = html.insert(0, soup.new_tag('head'))
>>> title = head.append(soup.new_tag('title', 'My Title Text'))
>>> meta = head.append(soup.new_tag('meta', charset='UTF-8'))
>>> #
>>> print(html) # manually prettified
<html>
 <head>
  <title>My Title Text</title>
  <meta charset="UTF-8"/>
 </head>
</html>

To post a comment you must log in.
Revision history for this message
Leonard Richardson (leonardr) wrote :

This looks good for the next feature release. The only change I plan to make is to move 'string' to the end of the argument list to maintain backwards compatibility. Otherwise existing code that uses positional arguments (like the tree builder code you had to change) will break.

b3e3474... by Chris Papademetrious

allow string text specification in new_tag()

Signed-off-by: Chris Papademetrious <email address hidden>

Revision history for this message
Chris Papademetrious (chrispitude) wrote :

Thanks Leonard! I force-pushed an update to restore the original new_tag() argument list order. It also reverts the test modifications and updates the documentation example.

Revision history for this message
Leonard Richardson (leonardr) wrote (last edit ):

Merged into the 4.13 branch. I made a minor change to handle the case where the empty string was passed in.

Revision history for this message
Chris Papademetrious (chrispitude) wrote :

Thank you!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/bs4/__init__.py b/bs4/__init__.py
2index 3d2ab09..3cb8561 100644
3--- a/bs4/__init__.py
4+++ b/bs4/__init__.py
5@@ -498,7 +498,7 @@ class BeautifulSoup(Tag):
6 self.pushTag(self)
7
8 def new_tag(self, name, namespace=None, nsprefix=None, attrs={},
9- sourceline=None, sourcepos=None, **kwattrs):
10+ sourceline=None, sourcepos=None, string=None, **kwattrs):
11 """Create a new Tag associated with this BeautifulSoup object.
12
13 :param name: The name of the new Tag.
14@@ -511,14 +511,18 @@ class BeautifulSoup(Tag):
15 (purportedly) found in its source document.
16 :param sourcepos: The character position within `sourceline` where this
17 tag was (purportedly) found.
18+ :param string: Text content for the new Tag, if any.
19 :param kwattrs: Keyword arguments for the new Tag's attribute values.
20
21 """
22 kwattrs.update(attrs)
23- return self.element_classes.get(Tag, Tag)(
24+ tag = self.element_classes.get(Tag, Tag)(
25 None, self.builder, name, namespace, nsprefix, kwattrs,
26 sourceline=sourceline, sourcepos=sourcepos
27 )
28+ if string:
29+ tag.string = string
30+ return tag
31
32 def string_container(self, base_class=None):
33 container = base_class or NavigableString
34diff --git a/bs4/tests/test_soup.py b/bs4/tests/test_soup.py
35index 28013b8..3639c28 100644
36--- a/bs4/tests/test_soup.py
37+++ b/bs4/tests/test_soup.py
38@@ -390,9 +390,10 @@ class TestNewTag(SoupTest):
39 """Test the BeautifulSoup.new_tag() method."""
40 def test_new_tag(self):
41 soup = self.soup("")
42- new_tag = soup.new_tag("foo", bar="baz", attrs={"name": "a name"})
43+ new_tag = soup.new_tag("foo", string="txt", bar="baz", attrs={"name": "a name"})
44 assert isinstance(new_tag, Tag)
45 assert "foo" == new_tag.name
46+ assert new_tag.string == "txt"
47 assert dict(bar="baz", name="a name") == new_tag.attrs
48 assert None == new_tag.parent
49
50diff --git a/doc/source/index.rst b/doc/source/index.rst
51index aedfdfc..106dfc8 100644
52--- a/doc/source/index.rst
53+++ b/doc/source/index.rst
54@@ -2035,13 +2035,9 @@ call the factory method ``BeautifulSoup.new_tag()``::
55 soup = BeautifulSoup("<b></b>", 'html.parser')
56 original_tag = soup.b
57
58- new_tag = soup.new_tag("a", href="http://www.example.com")
59+ new_tag = soup.new_tag("a", string="Link text.", href="http://www.example.com")
60 original_tag.append(new_tag)
61 original_tag
62- # <b><a href="http://www.example.com"></a></b>
63-
64- new_tag.string = "Link text."
65- original_tag
66 # <b><a href="http://www.example.com">Link text.</a></b>
67
68 Only the first argument, the tag name, is required.

Subscribers

People subscribed via source and target branches