Skip to content

Commit 1383959

Browse files
authored
fix: anchor string patterns in match() to consume full keypath. (#579)
String patterns like '*a' were matched with regex.match() which only checks a prefix, so '(.)*a' matched 'ab' (consuming just 'a', leaving 'b' unconsumed). Fix by appending '$' to string-derived patterns so the entire keypath must be consumed. Raw compiled-regex patterns are unaffected and continue to use match() as before.
1 parent c437b99 commit 1383959

2 files changed

Lines changed: 13 additions & 0 deletions

File tree

benedict/core/match.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ def match(
2121
pattern = re.sub(r"([\*]{1})", "(.)*", pattern)
2222
# escape square brackets
2323
pattern = re.sub(r"(\[([^\[\]]*)\])", "\\[\\g<2>\\]", pattern)
24+
# anchor to end so the full keypath must be consumed
25+
pattern = pattern + "$"
2426
regex = re.compile(pattern, flags=re.DOTALL)
2527
else:
2628
raise ValueError(f"Expected regex or string, found: {type(pattern)}")

tests/core/test_match.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ def test_match_with_regex_pattern(self) -> None:
5757
]
5858
self.assertEqual(values, expected_values)
5959

60+
def test_match_with_suffix_wildcard(self) -> None:
61+
# Suffix wildcard like "*.jpg" must not match "IMG_0001.jpg.bak" –
62+
# i.e. the full keypath must be consumed, not just a prefix.
63+
d = {
64+
"IMG_0001.jpg": "IMG_0001.jpg",
65+
"IMG_0001.jpg.bak": "IMG_0001.jpg.bak",
66+
"DOC_0001.pdf": "DOC_0001.pdf",
67+
}
68+
values = _match(d, "*.jpg")
69+
self.assertEqual(values, ["IMG_0001.jpg"])
70+
6071
def test_match_with_invalid_pattern(self) -> None:
6172
d = self._get_dict()
6273
with self.assertRaises(ValueError):

0 commit comments

Comments
 (0)