diff options
-rw-r--r-- | CHANGELOG | 3 | ||||
-rw-r--r-- | bs4/tests/__init__.py | 35 | ||||
-rw-r--r-- | bs4/tests/test_builder_registry.py | 17 | ||||
-rw-r--r-- | bs4/tests/test_html5lib.py | 14 | ||||
-rw-r--r-- | bs4/tests/test_lxml.py | 30 | ||||
-rw-r--r-- | bs4/tests/test_pageelement.py | 9 | ||||
-rw-r--r-- | bs4/tests/test_soup.py | 44 | ||||
-rw-r--r-- | bs4/tests/test_tree.py | 1 |
8 files changed, 74 insertions, 79 deletions
@@ -1,8 +1,7 @@ Beautiful Soup's official support for Python 2 ended on January 1st, 2021. The final release to support Python 2 was Beautiful Soup 4.9.3. In the Launchpad Git repository, the final revision to support -Python 2 was revision 70f546b1e689a70e2f103795efce6d261a3dadf7. In the -Bazaar repository, the final revision to support Python 2 was 605. +Python 2 was revision 70f546b1e689a70e2f103795efce6d261a3dadf7. = 4.11.2 (Unreleased) diff --git a/bs4/tests/__init__.py b/bs4/tests/__init__.py index 406ab81..f4d62db 100644 --- a/bs4/tests/__init__.py +++ b/bs4/tests/__init__.py @@ -29,6 +29,29 @@ from bs4.builder import ( ) default_builder = HTMLParserTreeBuilder +# Some tests depend on specific third-party libraries. We use +# @pytest.mark.skipIf on the following conditionals to skip them +# if the libraries are not installed. +try: + from soupsieve import SelectorSyntaxError + SOUP_SIEVE_PRESENT = True +except ImportError: + SOUP_SIEVE_PRESENT = False + +try: + import html5lib + HTML5LIB_PRESENT = True +except ImportError: + HTML5LIB_PRESENT = False + +try: + import lxml.etree + LXML_PRESENT = True + LXML_VERSION = lxml.etree.LXML_VERSION +except ImportError: + LXML_PRESENT = False + LXML_VERSION = (0,) + BAD_DOCUMENT = """A bare string <!DOCTYPE xsl:stylesheet SYSTEM "htmlent.dtd"> <!DOCTYPE xsl:stylesheet PUBLIC "htmlent.dtd"> @@ -1178,15 +1201,3 @@ class HTML5TreeBuilderSmokeTest(HTMLTreeBuilderSmokeTest): assert isinstance(soup.contents[0], Comment) assert soup.contents[0] == '?xml version="1.0" encoding="utf-8"?' assert "html" == soup.contents[0].next_element.name - -def skipIf(condition, reason): - def nothing(test, *args, **kwargs): - return None - - def decorator(test_item): - if condition: - return nothing - else: - return test_item - - return decorator diff --git a/bs4/tests/test_builder_registry.py b/bs4/tests/test_builder_registry.py index 5fa874c..9327174 100644 --- a/bs4/tests/test_builder_registry.py +++ b/bs4/tests/test_builder_registry.py @@ -10,22 +10,23 @@ from bs4.builder import ( TreeBuilderRegistry, ) -try: +from . import ( + HTML5LIB_PRESENT, + LXML_PRESENT, +) + +if HTML5LIB_PRESENT: from bs4.builder import HTML5TreeBuilder - HTML5LIB_PRESENT = True -except ImportError: - HTML5LIB_PRESENT = False -try: +if LXML_PRESENT: from bs4.builder import ( LXMLTreeBuilderForXML, LXMLTreeBuilder, ) - LXML_PRESENT = True -except ImportError: - LXML_PRESENT = False +# TODO: Split out the lxml and html5lib tests into their own classes +# and gate with pytest.mark.skipIf. class TestBuiltInRegistry(object): """Test the built-in registry with the default builders registered.""" diff --git a/bs4/tests/test_html5lib.py b/bs4/tests/test_html5lib.py index de30bc8..4197720 100644 --- a/bs4/tests/test_html5lib.py +++ b/bs4/tests/test_html5lib.py @@ -1,28 +1,26 @@ """Tests to ensure that the html5lib tree builder generates good trees.""" +import pytest import warnings -try: - from bs4.builder import HTML5TreeBuilder - HTML5LIB_PRESENT = True -except ImportError as e: - HTML5LIB_PRESENT = False from bs4 import BeautifulSoup from bs4.element import SoupStrainer from . import ( + HTML5LIB_PRESENT, HTML5TreeBuilderSmokeTest, SoupTest, - skipIf, ) -@skipIf( +@pytest.mark.skipif( not HTML5LIB_PRESENT, - "html5lib seems not to be present, not testing its tree builder.") + reason="html5lib seems not to be present, not testing its tree builder." +) class TestHTML5LibBuilder(SoupTest, HTML5TreeBuilderSmokeTest): """See ``HTML5TreeBuilderSmokeTest``.""" @property def default_builder(self): + from bs4.builder import HTML5TreeBuilder return HTML5TreeBuilder def test_soupstrainer(self): diff --git a/bs4/tests/test_lxml.py b/bs4/tests/test_lxml.py index e88515c..c7bf45d 100644 --- a/bs4/tests/test_lxml.py +++ b/bs4/tests/test_lxml.py @@ -1,16 +1,10 @@ """Tests to ensure that the lxml tree builder generates good trees.""" import pickle +import pytest import re import warnings - -try: - import lxml.etree - LXML_PRESENT = True - LXML_VERSION = lxml.etree.LXML_VERSION -except ImportError as e: - LXML_PRESENT = False - LXML_VERSION = (0,) +from . import LXML_PRESENT, LXML_VERSION if LXML_PRESENT: from bs4.builder import LXMLTreeBuilder, LXMLTreeBuilderForXML @@ -23,13 +17,14 @@ from bs4.element import Comment, Doctype, SoupStrainer from . import ( HTMLTreeBuilderSmokeTest, XMLTreeBuilderSmokeTest, + SOUP_SIEVE_PRESENT, SoupTest, - skipIf, ) -@skipIf( +@pytest.mark.skipif( not LXML_PRESENT, - "lxml seems not to be present, not testing its tree builder.") + reason="lxml seems not to be present, not testing its tree builder." +) class TestLXMLTreeBuilder(SoupTest, HTMLTreeBuilderSmokeTest): """See ``HTMLTreeBuilderSmokeTest``.""" @@ -54,9 +49,10 @@ class TestLXMLTreeBuilder(SoupTest, HTMLTreeBuilderSmokeTest): # In lxml < 2.3.5, an empty doctype causes a segfault. Skip this # test if an old version of lxml is installed. - @skipIf( + @pytest.mark.skipif( not LXML_PRESENT or LXML_VERSION < (2,3,5,0), - "Skipping doctype test for old version of lxml to avoid segfault.") + reason="Skipping doctype test for old version of lxml to avoid segfault." + ) def test_empty_doctype(self): soup = self.soup("<!DOCTYPE>") doctype = soup.contents[0] @@ -87,9 +83,10 @@ class TestLXMLTreeBuilder(SoupTest, HTMLTreeBuilderSmokeTest): assert "sourceline" == soup.p.sourceline.name assert "sourcepos" == soup.p.sourcepos.name -@skipIf( +@pytest.mark.skipif( not LXML_PRESENT, - "lxml seems not to be present, not testing its XML tree builder.") + reason="lxml seems not to be present, not testing its XML tree builder." +) class TestLXMLXMLTreeBuilder(SoupTest, XMLTreeBuilderSmokeTest): """See ``HTMLTreeBuilderSmokeTest``.""" @@ -150,6 +147,9 @@ class TestLXMLXMLTreeBuilder(SoupTest, XMLTreeBuilderSmokeTest): } + @pytest.mark.skipif( + not SOUP_SIEVE_PRESENT, reason="Soup Sieve not installed" + ) def test_namespace_interaction_with_select_and_find(self): # Demonstrate how namespaces interact with select* and # find* methods. diff --git a/bs4/tests/test_pageelement.py b/bs4/tests/test_pageelement.py index 75bab04..44c0c45 100644 --- a/bs4/tests/test_pageelement.py +++ b/bs4/tests/test_pageelement.py @@ -3,15 +3,15 @@ import copy import pickle import pytest -from soupsieve import SelectorSyntaxError - from bs4 import BeautifulSoup from bs4.element import ( Comment, SoupStrainer, ) -from . import SoupTest - +from . import ( + SoupTest, + SOUP_SIEVE_PRESENT, +) class TestEncoding(SoupTest): """Test the ability to encode objects into strings.""" @@ -213,6 +213,7 @@ class TestFormatters(SoupTest): assert soup.contents[0].name == 'pre' +@pytest.mark.skipif(not SOUP_SIEVE_PRESENT, reason="Soup Sieve not installed") class TestCSSSelectors(SoupTest): """Test basic CSS selector functionality. diff --git a/bs4/tests/test_soup.py b/bs4/tests/test_soup.py index 857f1f4..64b8cf1 100644 --- a/bs4/tests/test_soup.py +++ b/bs4/tests/test_soup.py @@ -30,19 +30,11 @@ from bs4.element import ( from . import ( default_builder, + LXML_PRESENT, SoupTest, - skipIf, ) import warnings - -try: - from bs4.builder import LXMLTreeBuilder, LXMLTreeBuilderForXML - LXML_PRESENT = True -except ImportError as e: - LXML_PRESENT = False -PYTHON_3_PRE_3_2 = (sys.version_info[0] == 3 and sys.version_info < (3,2)) - class TestConstructor(SoupTest): def test_short_unicode_input(self): @@ -361,18 +353,22 @@ class TestNewTag(SoupTest): assert "foo" == new_tag.name assert dict(bar="baz", name="a name") == new_tag.attrs assert None == new_tag.parent - - def test_tag_inherits_self_closing_rules_from_builder(self): - if LXML_PRESENT: - xml_soup = BeautifulSoup("", "lxml-xml") - xml_br = xml_soup.new_tag("br") - xml_p = xml_soup.new_tag("p") - # Both the <br> and <p> tag are empty-element, just because - # they have no contents. - assert b"<br/>" == xml_br.encode() - assert b"<p/>" == xml_p.encode() + @pytest.mark.skipif( + not LXML_PRESENT, + reason="lxml not installed, cannot parse XML document" + ) + def test_xml_tag_inherits_self_closing_rules_from_builder(self): + xml_soup = BeautifulSoup("", "xml") + xml_br = xml_soup.new_tag("br") + xml_p = xml_soup.new_tag("p") + + # Both the <br> and <p> tag are empty-element, just because + # they have no contents. + assert b"<br/>" == xml_br.encode() + assert b"<p/>" == xml_p.encode() + def test_tag_inherits_self_closing_rules_from_builder(self): html_soup = BeautifulSoup("", "html.parser") html_br = html_soup.new_tag("br") html_p = html_soup.new_tag("p") @@ -464,13 +460,3 @@ class TestEncodingConversion(SoupTest): # The internal data structures can be encoded as UTF-8. soup_from_unicode = self.soup(self.unicode_data) assert soup_from_unicode.encode('utf-8') == self.utf8_data - - @skipIf( - PYTHON_3_PRE_3_2, - "Bad HTMLParser detected; skipping test of non-ASCII characters in attribute name.") - def test_attribute_name_containing_unicode_characters(self): - markup = '<div><a \N{SNOWMAN}="snowman"></a></div>' - assert self.soup(markup).div.encode("utf8") == markup.encode("utf8") - - - diff --git a/bs4/tests/test_tree.py b/bs4/tests/test_tree.py index dcd06ab..26995f9 100644 --- a/bs4/tests/test_tree.py +++ b/bs4/tests/test_tree.py @@ -33,7 +33,6 @@ from bs4.element import ( ) from . import ( SoupTest, - skipIf, ) class TestFind(SoupTest): |