summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG3
-rw-r--r--bs4/tests/__init__.py35
-rw-r--r--bs4/tests/test_builder_registry.py17
-rw-r--r--bs4/tests/test_html5lib.py14
-rw-r--r--bs4/tests/test_lxml.py30
-rw-r--r--bs4/tests/test_pageelement.py9
-rw-r--r--bs4/tests/test_soup.py44
-rw-r--r--bs4/tests/test_tree.py1
8 files changed, 74 insertions, 79 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5e41731..ec67f5c 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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):