support string attribute on NavigableString objects

Bug #2044794 reported by Chris Papademetrious
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Beautiful Soup
Fix Committed
Wishlist
Unassigned

Bug Description

This is a wishlist item.

Currently, Tag and NavigableString objects use different mechanisms to change their text content:

* Tag objects use the "string" attribute
* NavigableString objects use the "replace_with()" method

For example,

====
>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup('AAA<b>BBB</b>', 'lxml')
>>> soup.find(string=True).replace_with('CCC')
'AAA'
>>> soup.find('b').string = 'DDD'
>>> soup
<html><body><p>CCC<b>DDD</b></p></body></html>
====

It would be nice if NavigableString objects *also* supported the "string" attribute, which would be convenient for code that must handle both object types. (This is how I ran into this; I used conditionals for now.)

This gives no indication of error, but it has no effect:

===
>>> soup.find(string=True).string = 'EEE'
>>> soup
<html><body><p>CCC<b>DDD</b></p></body></html>
===

I think this enhancement request is consistent with the fact that the four basic object types already share many attributes and methods.

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

It turns out this is already done; I implemented this in the 4.13 branch a while ago, while reconciling the type system, but I didn't mention it in the CHANGELOG.

Changed in beautifulsoup:
status: New → Fix Committed
importance: Undecided → Wishlist
Revision history for this message
Chris Papademetrious (chrispitude) wrote (last edit ):

Thanks for this enhancement! If I run the following code in the 4.13 branch:

====
from bs4 import BeautifulSoup
soup = BeautifulSoup('AAA<b>BBB</b>', 'lxml')
tag = soup.find('b')
navstr = soup.find(string=True)
====

I can indeed see that both types now allow .string to be read:

====
>>> tag.string
'BBB'
>>> navstr.string
'AAA'
====

However, only Tag allows .string to be modified:

====
>>> tag.string = 'CCC'
>>> navstr.string = 'DDD'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute 'string'
====

(This is the actual use case I ran into in my code.)

Is it possible to implement this?

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

I could be wrong, but I don't think that's possible. NavigableString doesn't contain a string, it actually is a subclass of str, and Python strings are immutable. It would be like trying to get this to work:

"foo".string = "bar"

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

That makes sense. Thank you!

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.