mirror of
https://git.launchpad.net/beautifulsoup
synced 2025-10-06 00:12:49 +02:00
Consistently use pytest.mark.skipif to skip tests when the corresponding libraries are not installed.
This commit is contained in:
@@ -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)
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -10,22 +10,23 @@ from bs4.builder import (
|
||||
TreeBuilderRegistry,
|
||||
)
|
||||
|
||||
try:
|
||||
from bs4.builder import HTML5TreeBuilder
|
||||
HTML5LIB_PRESENT = True
|
||||
except ImportError:
|
||||
HTML5LIB_PRESENT = False
|
||||
from . import (
|
||||
HTML5LIB_PRESENT,
|
||||
LXML_PRESENT,
|
||||
)
|
||||
|
||||
try:
|
||||
if HTML5LIB_PRESENT:
|
||||
from bs4.builder import HTML5TreeBuilder
|
||||
|
||||
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."""
|
||||
|
||||
|
@@ -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):
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
||||
@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):
|
||||
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()
|
||||
|
||||
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")
|
||||
|
||||
|
||||
|
||||
|
@@ -33,7 +33,6 @@ from bs4.element import (
|
||||
)
|
||||
from . import (
|
||||
SoupTest,
|
||||
skipIf,
|
||||
)
|
||||
|
||||
class TestFind(SoupTest):
|
||||
|
Reference in New Issue
Block a user