Hello community,
here is the log from the commit of package python-soupsieve for
openSUSE:Factory checked in at 2019-07-30 13:04:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-soupsieve (Old)
and /work/SRC/openSUSE:Factory/.python-soupsieve.new.4126 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-soupsieve"
Tue Jul 30 13:04:54 2019 rev:5 rq:717581 version:1.9.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-soupsieve/python-soupsieve.changes
2019-05-22 10:54:35.607151662 +0200
+++
/work/SRC/openSUSE:Factory/.python-soupsieve.new.4126/python-soupsieve.changes
2019-07-30 13:04:55.662395156 +0200
@@ -1,0 +2,8 @@
+Mon Jul 22 12:54:14 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Update to 1.9.2:
+ * FIX: Shortcut last descendant calculation if possible for performance.
+ * FIX: Fix issue where Doctype strings can be mistaken for a normal text
node in some cases.
+ * FIX: A top level tag is not a :root tag if it has sibling text nodes or
tag nodes. This is an issue that mostly manifests when using html.parser as the
parser will allow multiple root nodes.
+
+-------------------------------------------------------------------
Old:
----
soupsieve-1.9.1.tar.gz
New:
----
soupsieve-1.9.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-soupsieve.spec ++++++
--- /var/tmp/diff_new_pack.lzneg2/_old 2019-07-30 13:04:56.442394989 +0200
+++ /var/tmp/diff_new_pack.lzneg2/_new 2019-07-30 13:04:56.442394989 +0200
@@ -26,12 +26,12 @@
%bcond_with test
%endif
Name: python-soupsieve%{psuffix}
-Version: 1.9.1
+Version: 1.9.2
Release: 0
Summary: A modern CSS selector implementation for BeautifulSoup
License: MIT
Group: Development/Libraries/Python
-URL: http://facelessuser.github.io/soupsieve/
+URL: https://github.com/facelessuser/soupsieve
Source:
https://files.pythonhosted.org/packages/source/s/soupsieve/soupsieve-%{version}.tar.gz
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
@@ -58,13 +58,12 @@
%install
%if !%{with test}
%python_install
-%python_expand rm -rf %{buildroot}%{$python_sitelib}/tests
%python_expand %fdupes %{buildroot}%{$python_sitelib}
%endif
%check
%if %{with test}
-%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib}
py.test-%{$python_bin_suffix} -v tests
+%pytest tests
%endif
%if !%{with test}
++++++ soupsieve-1.9.1.tar.gz -> soupsieve-1.9.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/soupsieve-1.9.1/PKG-INFO new/soupsieve-1.9.2/PKG-INFO
--- old/soupsieve-1.9.1/PKG-INFO 2019-04-13 23:14:18.000000000 +0200
+++ new/soupsieve-1.9.2/PKG-INFO 2019-06-23 23:55:59.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: soupsieve
-Version: 1.9.1
+Version: 1.9.2
Summary: A modern CSS selector implementation for Beautiful Soup.
Home-page: https://github.com/facelessuser/soupsieve
Author: Isaac Muse
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/soupsieve-1.9.1/docs/src/markdown/about/changelog.md
new/soupsieve-1.9.2/docs/src/markdown/about/changelog.md
--- old/soupsieve-1.9.1/docs/src/markdown/about/changelog.md 2019-04-13
23:13:06.000000000 +0200
+++ new/soupsieve-1.9.2/docs/src/markdown/about/changelog.md 2019-06-23
23:54:37.000000000 +0200
@@ -1,5 +1,11 @@
# Changelog
+## 1.9.2
+
+- **FIX**: Shortcut last descendant calculation if possible for performance.
+- **FIX**: Fix issue where `Doctype` strings can be mistaken for a normal text
node in some cases.
+- **FIX**: A top level tag is not a `:root` tag if it has sibling text nodes
or tag nodes. This is an issue that mostly manifests when using `html.parser`
as the parser will allow multiple root nodes.
+
## 1.9.1
- **FIX**: `:root`, `:contains()`, `:default`, `:indeterminate`, `:lang()`,
and `:dir()` will properly account for HTML
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/soupsieve-1.9.1/docs/src/markdown/api.md
new/soupsieve-1.9.2/docs/src/markdown/api.md
--- old/soupsieve-1.9.1/docs/src/markdown/api.md 2019-04-13
23:13:06.000000000 +0200
+++ new/soupsieve-1.9.2/docs/src/markdown/api.md 2019-06-23
23:54:37.000000000 +0200
@@ -31,11 +31,8 @@
special. The `type` attribute's value is always case insensitive. This is
generally how most browsers treat `type`. If
you need `type` to be sensitive, you can use the `s` flag: `#!css
[type="submit" s]`.
-As far as the API is concerned, Soup Sieve mimics Beautiful Soup's original
API at the time of writing this, which is
-why the names `select` and `select_one` are used. As of today, Beautiful Soup
has agreed to include Soup Sieve as the
-official select library which is slated for the 4.7.0 release.
-
-Soup Sieve will always be available as an external API as well for more
controlled tag selection if needed.
+While Soup Sieve access is exposed through Beautiful Soup's API, Soup Sieve's
API can always be imported and accessed
+directly for more controlled tag selection if needed.
## Flags
@@ -62,19 +59,6 @@
SoupSieve(pattern='p:has(#id) > span.some-class:contains(text)',
namespaces=None, custom=None, flags=1)
```
-### `soupsieve.REVERSE`
-
-When calling `filter`, `select`, `iselect`, or `select_one`, searches will be
preformed in reverse order, causing the
-elements to be returned/yielded in reverse order.
-
-```pycon3
->>> import soupsieve as sv
->>> sv.select('p', soup)
-[<p class="a">Cat</p>, <p class="b">Dog</p>, <p class='c"'>Mouse</p>]
->>> sv.select('p', soup, flags=sv.REVERSE)
-[<p class='c"'>Mouse</p>, <p class="b">Dog</p>, <p class="a">Cat</p>]
-```
-
## `soupsieve.select_one()`
```py3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/soupsieve-1.9.1/soupsieve/__meta__.py
new/soupsieve-1.9.2/soupsieve/__meta__.py
--- old/soupsieve-1.9.1/soupsieve/__meta__.py 2019-04-13 23:13:06.000000000
+0200
+++ new/soupsieve-1.9.2/soupsieve/__meta__.py 2019-06-23 23:54:37.000000000
+0200
@@ -186,5 +186,5 @@
return Version(major, minor, micro, release, pre, post, dev)
-__version_info__ = Version(1, 9, 1, "final")
+__version_info__ = Version(1, 9, 2, "final")
__version__ = __version_info__._get_canonical()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/soupsieve-1.9.1/soupsieve/css_match.py
new/soupsieve-1.9.2/soupsieve/css_match.py
--- old/soupsieve-1.9.1/soupsieve/css_match.py 2019-04-13 23:13:06.000000000
+0200
+++ new/soupsieve-1.9.2/soupsieve/css_match.py 2019-06-23 23:54:37.000000000
+0200
@@ -113,11 +113,11 @@
return isinstance(obj, bs4.Declaration)
@staticmethod
- def is_cdata(obj): # pragma: no cover
+ def is_cdata(obj):
"""Is CDATA."""
import bs4
- return isinstance(obj, bs4.Declaration)
+ return isinstance(obj, bs4.CData)
@staticmethod
def is_processing_instruction(obj): # pragma: no cover
@@ -138,7 +138,7 @@
"""Is special string."""
import bs4
- return isinstance(obj, (bs4.Comment, bs4.Declaration, bs4.CData,
bs4.ProcessingInstruction))
+ return isinstance(obj, (bs4.Comment, bs4.Declaration, bs4.CData,
bs4.ProcessingInstruction, bs4.Doctype))
@classmethod
def is_content_string(cls, obj):
@@ -217,10 +217,13 @@
is_tag = self.is_tag(child)
if no_iframe and is_tag and self.is_iframe(child):
- last_child = child
- while self.is_tag(last_child) and last_child.contents:
- last_child = last_child.contents[-1]
- next_good = last_child.next_element
+ if child.next_sibling is not None:
+ next_good = child.next_sibling
+ else:
+ last_child = child
+ while self.is_tag(last_child) and last_child.contents:
+ last_child = last_child.contents[-1]
+ next_good = last_child.next_element
yield child
if next_good is None:
break
@@ -251,20 +254,20 @@
return el.prefix
@classmethod
- def get_next_tag(cls, el):
+ def get_next(cls, el, tags=True):
"""Get next sibling tag."""
sibling = el.next_sibling
- while not cls.is_tag(sibling) and sibling is not None:
+ while tags and not cls.is_tag(sibling) and sibling is not None:
sibling = sibling.next_sibling
return sibling
@classmethod
- def get_previous_tag(cls, el):
+ def get_previous(cls, el, tags=True):
"""Get previous sibling tag."""
sibling = el.previous_sibling
- while not cls.is_tag(sibling) and sibling is not None:
+ while tags and not cls.is_tag(sibling) and sibling is not None:
sibling = sibling.previous_sibling
return sibling
@@ -660,12 +663,12 @@
if parent:
found = self.match_selectors(parent, relation)
elif relation[0].rel_type == REL_SIBLING:
- sibling = self.get_previous_tag(el)
+ sibling = self.get_previous(el)
while not found and sibling:
found = self.match_selectors(sibling, relation)
- sibling = self.get_previous_tag(sibling)
+ sibling = self.get_previous(sibling)
elif relation[0].rel_type == REL_CLOSE_SIBLING:
- sibling = self.get_previous_tag(el)
+ sibling = self.get_previous(el)
if sibling and self.is_tag(sibling):
found = self.match_selectors(sibling, relation)
return found
@@ -690,12 +693,12 @@
elif relation[0].rel_type == REL_HAS_CLOSE_PARENT:
found = self.match_future_child(el, relation)
elif relation[0].rel_type == REL_HAS_SIBLING:
- sibling = self.get_next_tag(el)
+ sibling = self.get_next(el)
while not found and sibling:
found = self.match_selectors(sibling, relation)
- sibling = self.get_next_tag(sibling)
+ sibling = self.get_next(sibling)
elif relation[0].rel_type == REL_HAS_CLOSE_SIBLING:
- sibling = self.get_next_tag(el)
+ sibling = self.get_next(el)
if sibling and self.is_tag(sibling):
found = self.match_selectors(sibling, relation)
return found
@@ -736,7 +739,28 @@
def match_root(self, el):
"""Match element as root."""
- return self.is_root(el)
+ is_root = self.is_root(el)
+ if is_root:
+ sibling = self.get_previous(el, tags=False)
+ while is_root and sibling is not None:
+ if (
+ self.is_tag(sibling) or (self.is_content_string(sibling)
and sibling.strip()) or
+ self.is_cdata(sibling)
+ ):
+ is_root = False
+ else:
+ sibling = self.get_previous(sibling, tags=False)
+ if is_root:
+ sibling = self.get_next(el, tags=False)
+ while is_root and sibling is not None:
+ if (
+ self.is_tag(sibling) or (self.is_content_string(sibling)
and sibling.strip()) or
+ self.is_cdata(sibling)
+ ):
+ is_root = False
+ else:
+ sibling = self.get_next(sibling, tags=False)
+ return is_root
def match_scope(self, el):
"""Match element as scope."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/soupsieve-1.9.1/soupsieve.egg-info/PKG-INFO
new/soupsieve-1.9.2/soupsieve.egg-info/PKG-INFO
--- old/soupsieve-1.9.1/soupsieve.egg-info/PKG-INFO 2019-04-13
23:14:18.000000000 +0200
+++ new/soupsieve-1.9.2/soupsieve.egg-info/PKG-INFO 2019-06-23
23:55:59.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: soupsieve
-Version: 1.9.1
+Version: 1.9.2
Summary: A modern CSS selector implementation for Beautiful Soup.
Home-page: https://github.com/facelessuser/soupsieve
Author: Isaac Muse
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/soupsieve-1.9.1/tests/test_level3/test_root.py
new/soupsieve-1.9.2/tests/test_level3/test_root.py
--- old/soupsieve-1.9.1/tests/test_level3/test_root.py 2019-04-13
23:13:06.000000000 +0200
+++ new/soupsieve-1.9.2/tests/test_level3/test_root.py 2019-06-23
23:54:37.000000000 +0200
@@ -118,6 +118,82 @@
ids.append(el['id'])
self.assertEqual(sorted(ids), sorted(['div2']))
+ def test_no_root_double_tag(self):
+ """Test when there is no root due to double root tags."""
+
+ markup = """
+ <div id="1"></div>
+ <div id="2"></div>
+ """
+
+ soup = self.soup(markup, 'html.parser')
+ self.assertEqual(soup.select(':root'), [])
+
+ def test_no_root_text(self):
+ """Test when there is no root due to HTML text."""
+
+ markup = """
+ text
+ <div id="1"></div>
+ """
+
+ soup = self.soup(markup, 'html.parser')
+ self.assertEqual(soup.select(':root'), [])
+
+ def test_no_root_cdata(self):
+ """Test when there is no root due to CDATA and tag."""
+
+ markup = """
+ <![CDATA[test]]>
+ <div id="1"></div>
+ """
+
+ soup = self.soup(markup, 'html.parser')
+ self.assertEqual(soup.select(':root'), [])
+
+ def test_root_whitespace(self):
+ """Test when there is root and white space."""
+
+ markup = """
+
+ <div id="1"></div>
+ """
+
+ ids = []
+ soup = self.soup(markup, 'html.parser')
+ for el in soup.select(':root'):
+ ids.append(el['id'])
+ self.assertEqual(sorted(ids), sorted(['1']))
+
+ def test_root_preprocess(self):
+ """Test when there is root and pre-processing statement."""
+
+ markup = """
+ <?php ?>
+ <div id="1"></div>
+ """
+
+ ids = []
+ soup = self.soup(markup, 'html.parser')
+ for el in soup.select(':root'):
+ ids.append(el['id'])
+ self.assertEqual(sorted(ids), sorted(['1']))
+
+ def test_root_doctype(self):
+ """Test when there is root and doc type."""
+
+ markup = """
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+ <div id="1"></div>
+ """
+
+ ids = []
+ soup = self.soup(markup, 'html.parser')
+ for el in soup.select(':root'):
+ ids.append(el['id'])
+ self.assertEqual(sorted(ids), sorted(['1']))
+
class TestRootQuirks(TestRoot):
"""Test root selectors with quirks."""