Skip to content

Commit d7c4784

Browse files
authored
Attribute pattern fix (#289)
1 parent 09e106d commit d7c4784

4 files changed

Lines changed: 20 additions & 4 deletions

File tree

docs/src/markdown/about/changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ icon: lucide/scroll-text
33
---
44
# Changelog
55

6+
## 2.8.3
7+
8+
- **FIX**: Fix inefficient attribute pattern.
9+
610
## 2.8.2
711

812
- **FIX**: Ensure custom selectors or namespace dictionaries reject non-string keys (@mundanevision20).

soupsieve/__meta__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,5 @@ def parse_version(ver: str) -> Version:
193193
return Version(major, minor, micro, release, pre, post, dev)
194194

195195

196-
__version_info__ = Version(2, 8, 2, "final")
196+
__version_info__ = Version(2, 8, 3, "final")
197197
__version__ = __version_info__._get_canonical()

soupsieve/css_parser.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@
118118
# `nth` content
119119
NTH = fr'(?:[-+])?(?:[0-9]+n?|n)(?:(?<=n){WSC}*(?:[-+]){WSC}*(?:[0-9]+))?'
120120
# Value: quoted string or identifier
121-
VALUE = fr'''(?:"(?:\\(?:.|{NEWLINE})|[^\\"\r\n\f]+)*?"|'(?:\\(?:.|{NEWLINE})|[^\\'\r\n\f]+)*?'|{IDENTIFIER}+)'''
121+
VALUE = fr'''(?:"(?:\\(?:.|{NEWLINE})|[^\\"\r\n\f]+)*?"|'(?:\\(?:.|{NEWLINE})|[^\\'\r\n\f]+)*?'|{IDENTIFIER})'''
122122
# Attribute value comparison. `!=` is handled special as it is non-standard.
123-
ATTR = fr'(?:{WSC}*(?P<cmp>[!~^|*$]?=){WSC}*(?P<value>{VALUE})(?:{WSC}*(?P<case>[is]))?)?{WSC}*\]'
123+
ATTR = fr'(?:{WSC}*(?P<cmp>[!~^|*$]?=){WSC}*(?P<value>{VALUE})(?:{WSC}*(?P<case>[is]))?)?{WSC}*'
124124

125125
# Selector patterns
126126
# IDs (`#id`)
@@ -130,7 +130,7 @@
130130
# Prefix:Tag (`prefix|tag`)
131131
PAT_TAG = fr'(?P<tag_ns>(?:{IDENTIFIER}|\*)?\|)?(?P<tag_name>{IDENTIFIER}|\*)'
132132
# Attributes (`[attr]`, `[attr=value]`, etc.)
133-
PAT_ATTR = fr'\[{WSC}*(?P<attr_ns>(?:{IDENTIFIER}|\*)?\|)?(?P<attr_name>{IDENTIFIER}){ATTR}'
133+
PAT_ATTR = fr'\[{WSC}*(?P<attr_ns>(?:{IDENTIFIER}|\*)?\|)?(?P<attr_name>{IDENTIFIER}){ATTR}\]'
134134
# Pseudo class (`:pseudo-class`, `:pseudo-class(`)
135135
PAT_PSEUDO_CLASS = fr'(?P<name>:{IDENTIFIER})(?P<open>\({WSC}*)?'
136136
# Pseudo class special patterns. Matches `:pseudo-class(` for special case pseudo classes.

tests/test_extra/test_attribute.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Test attribute selectors."""
22
from .. import util
3+
import soupsieve as sv
34

45

56
class TestAttribute(util.TestCase):
@@ -50,3 +51,14 @@ def test_attribute_not_equal_double_quotes(self):
5051
["div", "0", "1", "2", "3", "pre", "4", "6"],
5152
flags=util.HTML5
5253
)
54+
55+
def test_bad_attribute(self):
56+
"""Test bad attribute fails."""
57+
58+
with self.assertRaises(sv.SelectorSyntaxError) as cm:
59+
sv.compile(r"[\]!=D4XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
60+
61+
e = cm.exception
62+
self.assertEqual(e.context, '[\\]!=D4XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n^')
63+
self.assertEqual(e.line, 1)
64+
self.assertEqual(e.col, 1)

0 commit comments

Comments
 (0)