Skip to content

Commit f7bdc18

Browse files
committed
Check regex patterns against I-Regexp if available
1 parent 833a6d6 commit f7bdc18

File tree

4 files changed

+66
-5
lines changed

4 files changed

+66
-5
lines changed

jsonpath/function_extensions/match.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99

1010
REGEX_AVAILABLE = False
1111

12+
try:
13+
from iregexp_check import check
14+
15+
IREGEXP_AVAILABLE = True
16+
except ImportError:
17+
IREGEXP_AVAILABLE = False
18+
1219
from jsonpath.function_extensions import ExpressionType
1320
from jsonpath.function_extensions import FilterFunction
1421

@@ -23,8 +30,14 @@ class Match(FilterFunction):
2330

2431
def __call__(self, string: str, pattern: str) -> bool:
2532
"""Return `True` if _string_ matches _pattern_, or `False` otherwise."""
26-
# XXX: re.fullmatch caches compiled patterns internally, but `map_re` is not
27-
# cached.
33+
# TODO: re.match caches compiled patterns internally, but `map_re` and `check`
34+
# are not cached.
35+
36+
# TODO: validate literal patterns ar compile time?
37+
38+
if IREGEXP_AVAILABLE and (not isinstance(pattern, str) or not check(pattern)):
39+
return False
40+
2841
if REGEX_AVAILABLE:
2942
try:
3043
pattern = map_re(pattern)

jsonpath/function_extensions/search.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99

1010
REGEX_AVAILABLE = False
1111

12+
try:
13+
from iregexp_check import check
14+
15+
IREGEXP_AVAILABLE = True
16+
except ImportError:
17+
IREGEXP_AVAILABLE = False
18+
1219
from jsonpath.function_extensions import ExpressionType
1320
from jsonpath.function_extensions import FilterFunction
1421

@@ -23,8 +30,14 @@ class Search(FilterFunction):
2330

2431
def __call__(self, string: str, pattern: str) -> bool:
2532
"""Return `True` if _string_ contains _pattern_, or `False` otherwise."""
26-
# XXX: re.search caches compiled patterns internally, but `map_re` is not
27-
# cached.
33+
# TODO: re.search caches compiled patterns internally, but `map_re` and `check`
34+
# are not cached.
35+
36+
# TODO: validate literal patterns ar compile time?
37+
38+
if IREGEXP_AVAILABLE and (not isinstance(pattern, str) or not check(pattern)):
39+
return False
40+
2841
if REGEX_AVAILABLE:
2942
try:
3043
pattern = map_re(pattern)

jsonpath/parse.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,8 @@ def _decode_string_literal(self, token: Token) -> str:
860860
assert isinstance(rv, str)
861861
return rv
862862
except json.JSONDecodeError as err:
863-
raise JSONPathSyntaxError(str(err).split(":")[1], token=token) from None
863+
message = f"decode error: {str(err).split(':')[1]}"
864+
raise JSONPathSyntaxError(message, token=token) from None
864865

865866
return token.value
866867

tests/test_iregexp.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import pytest
2+
3+
try:
4+
import iregexp_check # noqa: F401
5+
6+
IREGEXP_AVAILABLE = True
7+
except ImportError:
8+
IREGEXP_AVAILABLE = False
9+
10+
import jsonpath
11+
12+
13+
@pytest.mark.skipif(IREGEXP_AVAILABLE is False, reason="requires iregexp_check")
14+
def test_iregexp_check() -> None:
15+
# Character classes are OK.
16+
query = "$[?match(@, '[0-9]+')]"
17+
data = ["123", "abc", "abc123"]
18+
assert jsonpath.findall(query, data) == ["123"]
19+
20+
# Multi character escapes are not.
21+
query = "$[?match(@, '\\\\d+')]"
22+
assert jsonpath.findall(query, data) == []
23+
24+
25+
@pytest.mark.skipif(IREGEXP_AVAILABLE, reason="iregexp_check is available")
26+
def test_no_iregexp_check() -> None:
27+
# Character classes are OK.
28+
query = "$[?match(@, '[0-9]+')]"
29+
data = ["123", "abc", "abc123"]
30+
assert jsonpath.findall(query, data) == ["123"]
31+
32+
# Multi character escapes are OK when iregexp_check is not installed.
33+
query = "$[?match(@, '\\\\d+')]"
34+
assert jsonpath.findall(query, data) == ["123"]

0 commit comments

Comments
 (0)