Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/soupsieve/__init__.py: 68%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

38 statements  

1""" 

2Soup Sieve. 

3 

4A CSS selector filter for BeautifulSoup4. 

5 

6MIT License 

7 

8Copyright (c) 2018 Isaac Muse 

9 

10Permission is hereby granted, free of charge, to any person obtaining a copy 

11of this software and associated documentation files (the "Software"), to deal 

12in the Software without restriction, including without limitation the rights 

13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 

14copies of the Software, and to permit persons to whom the Software is 

15furnished to do so, subject to the following conditions: 

16 

17The above copyright notice and this permission notice shall be included in all 

18copies or substantial portions of the Software. 

19 

20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 

21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 

23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 

24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 

25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 

26SOFTWARE. 

27""" 

28from __future__ import annotations 

29from .__meta__ import __version__, __version_info__ # noqa: F401 

30from . import css_parser as cp 

31from . import css_match as cm 

32from . import css_types as ct 

33from .util import DEBUG, NOCACHE, NOSTRICT, SelectorSyntaxError # noqa: F401 

34import bs4 

35from typing import Any, Mapping, Iterator, Iterable, cast 

36 

37__all__ = ( 

38 'DEBUG', 'NOCACHE', 'NOSTRICT', 'SelectorSyntaxError', 'CustomSelectors', 'SoupSieve', 

39 'closest', 'compile', 'filter', 'iselect', 'match', 'select', 'select_one' 

40) 

41 

42SoupSieve = cm.SoupSieve 

43CustomSelectors = ct.CustomSelectors 

44 

45 

46def compile( # noqa: A001 

47 pattern: str, 

48 namespaces: dict[str, str] | None = None, 

49 flags: int = 0, 

50 *, 

51 custom: Mapping[str, str | ct.SelectorList] | None = None, 

52 ignore: Iterable[str] | None = None, 

53 max_selectors: int = cp.SELECTOR_LIMIT, 

54 **kwargs: Any 

55) -> cm.SoupSieve: 

56 """Compile CSS pattern.""" 

57 

58 if isinstance(pattern, SoupSieve): 

59 if flags: 

60 raise ValueError("Cannot process 'flags' argument on a compiled selector list") 

61 elif namespaces is not None: 

62 raise ValueError("Cannot process 'namespaces' argument on a compiled selector list") 

63 elif custom is not None: 

64 raise ValueError("Cannot process 'custom' argument on a compiled selector list") 

65 return pattern 

66 

67 return cp._cached_css_compile( 

68 pattern, 

69 ct.Namespaces(namespaces) if namespaces is not None else namespaces, 

70 ct.CustomSelectors( 

71 cast('dict[str, str | ct.SelectorList]', custom), max_selectors=max_selectors 

72 ) if custom is not None and not isinstance(custom, ct.CustomSelectors) else custom, 

73 tuple(i.lower() for i in ignore) if ignore is not None else ignore, 

74 flags, 

75 max_selectors 

76 ) 

77 

78 

79def purge() -> None: 

80 """Purge cached patterns.""" 

81 

82 cp._purge_cache() 

83 

84 

85def closest( 

86 select: str, 

87 tag: bs4.Tag, 

88 namespaces: dict[str, str] | None = None, 

89 flags: int = 0, 

90 *, 

91 custom: Mapping[str, str | ct.SelectorList] | None = None, 

92 ignore: Iterable[str] | None = None, 

93 max_selectors: int = cp.SELECTOR_LIMIT, 

94 **kwargs: Any 

95) -> bs4.Tag | None: 

96 """Match closest ancestor.""" 

97 

98 return compile( 

99 select, 

100 namespaces, 

101 flags, 

102 custom=custom, 

103 ignore=ignore, 

104 max_selectors=max_selectors, 

105 **kwargs 

106 ).closest(tag) 

107 

108 

109def match( 

110 select: str, 

111 tag: bs4.Tag, 

112 namespaces: dict[str, str] | None = None, 

113 flags: int = 0, 

114 *, 

115 custom: Mapping[str, str | ct.SelectorList] | None = None, 

116 ignore: Iterable[str] | None = None, 

117 max_selectors: int = cp.SELECTOR_LIMIT, 

118 **kwargs: Any 

119) -> bool: 

120 """Match node.""" 

121 

122 return compile( 

123 select, 

124 namespaces, 

125 flags, 

126 custom=custom, 

127 ignore=ignore, 

128 max_selectors=max_selectors, 

129 **kwargs 

130 ).match(tag) 

131 

132 

133def filter( # noqa: A001 

134 select: str, 

135 iterable: Iterable[bs4.Tag], 

136 namespaces: dict[str, str] | None = None, 

137 flags: int = 0, 

138 *, 

139 custom: Mapping[str, str | ct.SelectorList] | None = None, 

140 ignore: Iterable[str] | None = None, 

141 max_selectors: int = cp.SELECTOR_LIMIT, 

142 **kwargs: Any 

143) -> list[bs4.Tag]: 

144 """Filter list of nodes.""" 

145 

146 return compile( 

147 select, 

148 namespaces, 

149 flags, 

150 custom=custom, 

151 ignore=ignore, 

152 max_selectors=max_selectors, 

153 **kwargs 

154 ).filter(iterable) 

155 

156 

157def select_one( 

158 select: str, 

159 tag: bs4.Tag, 

160 namespaces: dict[str, str] | None = None, 

161 flags: int = 0, 

162 *, 

163 custom: Mapping[str, str | ct.SelectorList] | None = None, 

164 ignore: Iterable[str] | None = None, 

165 max_selectors: int = cp.SELECTOR_LIMIT, 

166 **kwargs: Any 

167) -> bs4.Tag | None: 

168 """Select a single tag.""" 

169 

170 return compile( 

171 select, 

172 namespaces, 

173 flags, 

174 custom=custom, 

175 ignore=ignore, 

176 max_selectors=max_selectors, 

177 **kwargs 

178 ).select_one(tag) 

179 

180 

181def select( 

182 select: str, 

183 tag: bs4.Tag, 

184 namespaces: dict[str, str] | None = None, 

185 limit: int = 0, 

186 flags: int = 0, 

187 *, 

188 custom: Mapping[str, str | ct.SelectorList] | None = None, 

189 ignore: Iterable[str] | None = None, 

190 max_selectors: int = cp.SELECTOR_LIMIT, 

191 **kwargs: Any 

192) -> list[bs4.Tag]: 

193 """Select the specified tags.""" 

194 

195 return compile( 

196 select, 

197 namespaces, 

198 flags, 

199 custom=custom, 

200 ignore=ignore, 

201 max_selectors=max_selectors, 

202 **kwargs 

203 ).select(tag, limit) 

204 

205 

206def iselect( 

207 select: str, 

208 tag: bs4.Tag, 

209 namespaces: dict[str, str] | None = None, 

210 limit: int = 0, 

211 flags: int = 0, 

212 *, 

213 custom: Mapping[str, str | ct.SelectorList] | None = None, 

214 ignore: Iterable[str] | None = None, 

215 max_selectors: int = cp.SELECTOR_LIMIT, 

216 **kwargs: Any 

217) -> Iterator[bs4.Tag]: 

218 """Iterate the specified tags.""" 

219 

220 yield from compile( 

221 select, 

222 namespaces, 

223 flags, 

224 custom=custom, 

225 ignore=ignore, 

226 max_selectors=max_selectors, 

227 **kwargs 

228 ).iselect(tag, limit) 

229 

230 

231def escape(ident: str) -> str: 

232 """Escape identifier.""" 

233 

234 return cp.escape(ident)