Skip to content

Commit 61401ae

Browse files
authored
Deprecate commentsiter and selectiter (#4)
* Deprecate commentsiter and selectiter Use iselect and icomments instead as they are shorter and easier to read * Add codecov config
1 parent fd8d0a2 commit 61401ae

File tree

11 files changed

+273
-49
lines changed

11 files changed

+273
-49
lines changed

.codecov.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
comment: false
2+
3+
coverage:
4+
status:
5+
patch: false

docs/src/dictionary/en-custom.txt

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ WIP
1919
XHTML
2020
accessor
2121
builtin
22+
deprecations
2223
html
2324
iterable
2425
linter

docs/src/markdown/about/changelog.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.5.0
4+
5+
- **NEW**: Deprecate `commentsiter` and `selectiter` in favor of `icomments` and `iselect`. Expect removal in version 1.0.
6+
37
## 0.4.0
48

59
- **NEW**: Initial prerelease.

docs/src/markdown/api.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ def select(select, node, namespaces=None, limit=0, mode=HTML5):
3737
[<p class="a">Cat</p>, <p class="b">Dog</p>, <p class="c">Mouse</p>]
3838
```
3939

40-
### `soupsieve.selectiter()`
40+
### `soupsieve.iselect()`
4141

4242
```py3
43-
def selectiter(select, node, namespaces=None, limit=0, mode=HTML5):
43+
def iselect(select, node, namespaces=None, limit=0, mode=HTML5):
4444
"""Select the specified tags."""
4545
```
4646

47-
`selectiter` is exactly like `select` except that it returns a generator instead of a list.
47+
`iselect` is exactly like `select` except that it returns a generator instead of a list.
4848

4949
### `soupsieve.match()`
5050

@@ -92,14 +92,14 @@ def comments(node, limit=0, mode=HTML5):
9292

9393
`comments` accepts a `node` or element, a `limit`, and a document mode.
9494

95-
### `soupsieve.commentsiter()`
95+
### `soupsieve.icomments()`
9696

9797
```
98-
def comments(node, limit=0, mode=HTML5):
98+
def icomments(node, limit=0, mode=HTML5):
9999
"""Get comments only."""
100100
```
101101

102-
`commentsiter` is exactly like `comments` except that it returns a generator instead of a list.
102+
`icomments` is exactly like `comments` except that it returns a generator instead of a list.
103103

104104
### `soupsieve.compile()`
105105

soupsieve/__init__.py

+21-5
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@
2727
"""
2828
from .__meta__ import __version__, __version_info__ # noqa: F401
2929
from . import css_parser as cp
30-
from .util import HTML, HTML5, XHTML, XML
30+
from .util import HTML, HTML5, XHTML, XML, deprecated
3131

3232
__all__ = (
3333
'HTML', 'HTML5', 'XHTML', 'XML',
34-
'SoupSieve', 'compile', 'purge', 'comments', 'select', 'match', 'filter'
34+
'SoupSieve', 'compile', 'purge',
35+
'comments', 'icomments', 'select', 'iselect', 'match', 'filter'
3536
)
3637

3738
SoupSieve = cp.SoupSieve
@@ -79,10 +80,10 @@ def comments(node, limit=0, mode=HTML5):
7980
return compile("", None, mode).comments(node, limit)
8081

8182

82-
def commentsiter(node, limit=0, mode=HTML5):
83+
def icomments(node, limit=0, mode=HTML5):
8384
"""Iterate comments only."""
8485

85-
yield from compile("", None, mode).commentsiter(node, limit)
86+
yield from compile("", None, mode).icomments(node, limit)
8687

8788

8889
def select(select, node, namespaces=None, limit=0, mode=HTML5):
@@ -91,7 +92,22 @@ def select(select, node, namespaces=None, limit=0, mode=HTML5):
9192
return compile(select, namespaces, mode).select(node, limit)
9293

9394

95+
def iselect(select, node, namespaces=None, limit=0, mode=HTML5):
96+
"""Iterate the specified tags."""
97+
98+
yield from compile(select, namespaces, mode).iselect(node, limit)
99+
100+
101+
# ====== Deprecated ======
102+
@deprecated("Use 'icomments' instead.")
103+
def commentsiter(node, limit=0, mode=HTML5):
104+
"""Iterate comments only."""
105+
106+
yield from icomments(node, limit, mode)
107+
108+
109+
@deprecated("Use 'iselect' instead.")
94110
def selectiter(select, node, namespaces=None, limit=0, mode=HTML5):
95111
"""Iterate the specified tags."""
96112

97-
yield from compile(select, namespaces, mode).selectiter(node, limit)
113+
yield from iselect(select, node, namespaces, limit, mode)

soupsieve/__meta__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,5 +186,5 @@ def parse_version(ver, pre=False):
186186
return Version(major, minor, micro, release, pre, post, dev)
187187

188188

189-
__version_info__ = Version(0, 4, 0, "final")
189+
__version_info__ = Version(0, 5, 0, "final")
190190
__version__ = __version_info__._get_canonical()

soupsieve/css_parser.py

+24-10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from functools import lru_cache
66
from . import util
77
from . import css_match as cm
8+
from .util import deprecated
89

910

1011
# Selector patterns
@@ -590,25 +591,25 @@ def filter(self, nodes): # noqa A001
590591
else:
591592
return [node for node in nodes if self.match(node)]
592593

593-
def commentsiter(self, node, limit=0):
594-
"""Iterate comments only."""
595-
596-
yield from self._sieve(node, capture=False, comments=True, limit=limit)
597-
598594
def comments(self, node, limit=0):
599595
"""Get comments only."""
600596

601-
return list(self.commentsiter(node, limit))
597+
return list(self.icomments(node, limit))
602598

603-
def selectiter(self, node, limit=0):
604-
"""Iterate the specified tags."""
599+
def icomments(self, node, limit=0):
600+
"""Iterate comments only."""
605601

606-
yield from self._sieve(node, limit=limit)
602+
yield from self._sieve(node, capture=False, comments=True, limit=limit)
607603

608604
def select(self, node, limit=0):
609605
"""Select the specified tags."""
610606

611-
return list(self.selectiter(node, limit))
607+
return list(self.iselect(node, limit))
608+
609+
def iselect(self, node, limit=0):
610+
"""Iterate the specified tags."""
611+
612+
yield from self._sieve(node, limit=limit)
612613

613614
def __repr__(self):
614615
"""Representation."""
@@ -617,6 +618,19 @@ def __repr__(self):
617618

618619
__str__ = __repr__
619620

621+
# ====== Deprecated ======
622+
@deprecated("Use 'SoupSieve.icomments' instead.")
623+
def commentsiter(self, node, limit=0):
624+
"""Iterate comments only."""
625+
626+
yield from self.icomments(node, limit)
627+
628+
@deprecated("Use 'SoupSieve.iselect' instead.")
629+
def selectiter(self, node, limit=0):
630+
"""Iterate the specified tags."""
631+
632+
yield from self.iselect(node, limit)
633+
620634

621635
def _pickle(p):
622636
return SoupSieve, (p.pattern, p.namespaces, p.mode)

soupsieve/util.py

+22
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from collections import Mapping
33
from collections.abc import Hashable
44
import bs4
5+
from functools import wraps
6+
import warnings
57

68
HTML5 = 0x1
79
HTML = 0x2
@@ -126,3 +128,23 @@ def __repr__(self):
126128
return "%r" % self._d
127129

128130
__str__ = __repr__
131+
132+
133+
def deprecated(message, stacklevel=2):
134+
"""
135+
Raise a `DeprecationWarning` when wrapped function/method is called.
136+
137+
Borrowed from https://stackoverflow.com/a/48632082/866026
138+
"""
139+
140+
def _decorator(func):
141+
@wraps(func)
142+
def _func(*args, **kwargs):
143+
warnings.warn(
144+
"'{}' is deprecated. {}".format(func.__name__, message),
145+
category=DeprecationWarning,
146+
stacklevel=stacklevel
147+
)
148+
return func(*args, **kwargs)
149+
return _func
150+
return _decorator

tests/test_level1.py

+20
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,23 @@ def test_class(self):
119119
["2"],
120120
mode=sv.HTML5
121121
)
122+
123+
def test_classes(self):
124+
"""Test classes."""
125+
126+
markup = """
127+
<div>
128+
<p>Some text <span id="1" class="foo"> in a paragraph</span>.
129+
<a id="2" class="bar" href="http://google.com">Link</a>
130+
<a id="3" class="foo" href="http://google.com">Link</a>
131+
<a id="4" class="foo bar" href="http://google.com">Link</a>
132+
</p>
133+
</div>
134+
"""
135+
136+
self.assert_selector(
137+
markup,
138+
"a.foo.bar",
139+
["4"],
140+
mode=sv.HTML5
141+
)

tests/test_level2.py

+76-24
Original file line numberDiff line numberDiff line change
@@ -32,45 +32,75 @@ class TestLevel2(util.TestCase):
3232
def test_direct_child(self):
3333
"""Test direct child."""
3434

35+
markup = """
36+
<div>
37+
<p id="0">Some text <span id="1"> in a paragraph</span>.</p>
38+
<a id="2" href="http://google.com">Link</a>
39+
<span id="3">Direct child</span>
40+
<pre>
41+
<span id="4">Child 1</span>
42+
<span id="5">Child 2</span>
43+
<span id="6">Child 3</span>
44+
</pre>
45+
</div>
46+
"""
47+
48+
# Spaces
3549
self.assert_selector(
36-
"""
37-
<div>
38-
<p id="0">Some text <span id="1"> in a paragraph</span>.</p>
39-
<a id="2" href="http://google.com">Link</a>
40-
<span id="3">Direct child</span>
41-
<pre>
42-
<span id="4">Child 1</span>
43-
<span id="5">Child 2</span>
44-
<span id="6">Child 3</span>
45-
</pre>
46-
</div>
47-
""",
50+
markup,
4851
"div > span",
4952
["3"],
5053
mode=sv.HTML5
5154
)
5255

56+
# No spaces
57+
self.assert_selector(
58+
markup,
59+
"div>span",
60+
["3"],
61+
mode=sv.HTML5
62+
)
63+
5364
def test_direct_sibling(self):
5465
"""Test direct sibling."""
5566

67+
markup = """
68+
<div>
69+
<p id="0">Some text <span id="1"> in a paragraph</span>.</p>
70+
<a id="2" href="http://google.com">Link</a>
71+
<span id="3">Direct child</span>
72+
<pre>
73+
<span id="4">Child 1</span>
74+
<span id="5">Child 2</span>
75+
<span id="6">Child 3</span>
76+
</pre>
77+
</div>
78+
"""
79+
80+
# Spaces
5681
self.assert_selector(
57-
"""
58-
<div>
59-
<p id="0">Some text <span id="1"> in a paragraph</span>.</p>
60-
<a id="2" href="http://google.com">Link</a>
61-
<span id="3">Direct child</span>
62-
<pre>
63-
<span id="4">Child 1</span>
64-
<span id="5">Child 2</span>
65-
<span id="6">Child 3</span>
66-
</pre>
67-
</div>
68-
""",
82+
markup,
6983
"span + span",
7084
["5", "6"],
7185
mode=sv.HTML5
7286
)
7387

88+
# No spaces
89+
self.assert_selector(
90+
markup,
91+
"span+span",
92+
["5", "6"],
93+
mode=sv.HTML5
94+
)
95+
96+
# Complex
97+
self.assert_selector(
98+
markup,
99+
"span#4 + span#5",
100+
["5"],
101+
mode=sv.HTML5
102+
)
103+
74104
def test_wild_tag(self):
75105
"""Test wild tag."""
76106

@@ -113,6 +143,28 @@ def test_attribute(self):
113143
mode=sv.HTML5
114144
)
115145

146+
def test_multi_attribute(self):
147+
"""Test multiple attribute."""
148+
149+
self.assert_selector(
150+
"""
151+
<div id="div">
152+
<p id="0">Some text <span id="1"> in a paragraph</span>.</p>
153+
<a id="2" href="http://google.com">Link</a>
154+
<span id="3">Direct child</span>
155+
<pre id="pre">
156+
<span id="4" class="test">Child 1</span>
157+
<span id="5" class="test" data-test="test">Child 2</span>
158+
<span id="6">Child 3</span>
159+
<span id="6">Child 3</span>
160+
</pre>
161+
</div>
162+
""",
163+
"span[id].test[data-test=test]",
164+
["5"],
165+
mode=sv.HTML5
166+
)
167+
116168
def test_attribute_equal(self):
117169
"""Test attribute with value that equals specified value."""
118170

0 commit comments

Comments
 (0)