|
import pytest |
|
|
|
from bs4.element import Tag |
|
from bs4.formatter import ( |
|
Formatter, |
|
HTMLFormatter, |
|
XMLFormatter, |
|
) |
|
from . import SoupTest |
|
|
|
class TestFormatter(SoupTest): |
|
|
|
def test_default_attributes(self): |
|
|
|
formatter = Formatter() |
|
tag = Tag(name="tag") |
|
tag['b'] = 1 |
|
tag['a'] = 2 |
|
|
|
|
|
|
|
|
|
assert [('a', 2), ('b', 1)] == formatter.attributes(tag) |
|
|
|
|
|
|
|
tag.attrs = None |
|
assert [] == formatter.attributes(tag) |
|
|
|
assert ' ' == formatter.indent |
|
|
|
def test_sort_attributes(self): |
|
|
|
|
|
class UnsortedFormatter(Formatter): |
|
def attributes(self, tag): |
|
self.called_with = tag |
|
for k, v in sorted(tag.attrs.items()): |
|
if k == 'ignore': |
|
continue |
|
yield k,v |
|
|
|
soup = self.soup('<p cval="1" aval="2" ignore="ignored"></p>') |
|
formatter = UnsortedFormatter() |
|
decoded = soup.decode(formatter=formatter) |
|
|
|
|
|
|
|
assert formatter.called_with == soup.p |
|
assert '<p aval="2" cval="1"></p>' == decoded |
|
|
|
def test_empty_attributes_are_booleans(self): |
|
|
|
|
|
|
|
for name in ('html', 'minimal', None): |
|
formatter = HTMLFormatter.REGISTRY[name] |
|
assert False == formatter.empty_attributes_are_booleans |
|
|
|
formatter = XMLFormatter.REGISTRY[None] |
|
assert False == formatter.empty_attributes_are_booleans |
|
|
|
formatter = HTMLFormatter.REGISTRY['html5'] |
|
assert True == formatter.empty_attributes_are_booleans |
|
|
|
|
|
formatter = Formatter(empty_attributes_are_booleans=True) |
|
assert True == formatter.empty_attributes_are_booleans |
|
|
|
|
|
for markup in ( |
|
"<option selected></option>", |
|
'<option selected=""></option>' |
|
): |
|
soup = self.soup(markup) |
|
for formatter in ('html', 'minimal', 'xml', None): |
|
assert b'<option selected=""></option>' == soup.option.encode(formatter='html') |
|
assert b'<option selected></option>' == soup.option.encode(formatter='html5') |
|
|
|
@pytest.mark.parametrize( |
|
"indent,expect", |
|
[ |
|
(None, '<a>\n<b>\ntext\n</b>\n</a>\n'), |
|
(-1, '<a>\n<b>\ntext\n</b>\n</a>\n'), |
|
(0, '<a>\n<b>\ntext\n</b>\n</a>\n'), |
|
("", '<a>\n<b>\ntext\n</b>\n</a>\n'), |
|
|
|
(1, '<a>\n <b>\n text\n </b>\n</a>\n'), |
|
(2, '<a>\n <b>\n text\n </b>\n</a>\n'), |
|
|
|
("\t", '<a>\n\t<b>\n\t\ttext\n\t</b>\n</a>\n'), |
|
('abc', '<a>\nabc<b>\nabcabctext\nabc</b>\n</a>\n'), |
|
|
|
|
|
(object(), '<a>\n <b>\n text\n </b>\n</a>\n'), |
|
(b'bytes', '<a>\n <b>\n text\n </b>\n</a>\n'), |
|
] |
|
) |
|
def test_indent(self, indent, expect): |
|
|
|
|
|
soup = self.soup("<a><b>text</b></a>") |
|
formatter = Formatter(indent=indent) |
|
assert soup.prettify(formatter=formatter) == expect |
|
|
|
|
|
|
|
assert soup.encode(formatter=formatter) != expect |
|
|
|
def test_default_indent_value(self): |
|
formatter = Formatter() |
|
assert formatter.indent == ' ' |
|
|
|
|