Hi Leonard,
WebTest uses BeautifulSoup to parse a page and find forms, then
stringifies each of them. See
https://github.com/Pylons/webtest/blob/master/webtest/response.py#L75
The problem is that entity-encoded entities aren't preserved
through this process, because BeautifulSoup makes a guess and
gets it wrong. It seems to me that BeautifulSoup should be able
to assume that text nodes need to be escaped without guessing,
since they were almost certainly creating as a result of parsing.
I'm currently using the monkey patch below in my application to
work around the problem. Is this something you'd consider
changing in BeautifulSoup4 proper?
Thanks,
Aron
# Patch BeautifulSoup4 to escape XML entities properly in textarea
#
# A browser will decode HTML entities on display in <textarea>, then
# submit the content back without encoding. This asymmetrical behavior
# serves a purpose: It allows the browser to parse where the <textarea>
# starts and ends without worrying about the content of the textarea
# itself. And then on submit, the browser assumes the form handler needs
# no special treatment, because it is not parsing HTML at that point.
#
# WebTest relies on BeautifulSoup4 to find forms in the document, then
# stringifies each form prior to parsing out the fields. Unfortunately
# BeautifulSoup4 tries to be smart in its serialization, so it sees
# & and declines to re-escape the ampersand. Then the second parse
# turns what started as "&amp;" into "&".
#
# Since the content was previously parsed by bs4, the ampersand should
# clearly be re-encoded regardless.
import re
from bs4.dammit import EntitySubstitution
if EntitySubstitution.substitute_xml('&') == EntitySubstitution.substitute_xml('&'):
EntitySubstitution.BARE_AMPERSAND_OR_BRACKET = re.compile(r'[<>&]')
assert EntitySubstitution.substitute_xml('&') != EntitySubstitution.substitute_xml('&')