From ebaddfcd6f6fe874d911e7409deb18bea2d99b0d Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 10 Jul 2023 13:21:19 +0100 Subject: [PATCH 1/4] fix: leading slash in pattern matching path function --- .../private/path_pattern.py | 10 ++++++--- tests/test_path_pattern.py | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/firebase_functions/private/path_pattern.py b/src/firebase_functions/private/path_pattern.py index 78b61f0..c1444a3 100644 --- a/src/firebase_functions/private/path_pattern.py +++ b/src/firebase_functions/private/path_pattern.py @@ -164,14 +164,18 @@ def has_captures(self) -> bool: for segment in self.segments) def extract_matches(self, path: str) -> dict[str, str]: + segments = self.segments + if self.segments[0].value == "": + # if leading slash, there will be an empty segment which increases the path index, we pop to remove it + segments.pop(0) matches: dict[str, str] = {} if not self.has_captures: return matches path_segments = path_parts(path) path_ndx = 0 - for segment_ndx in range(len(self.segments)): - segment = self.segments[segment_ndx] - remaining_segments = len(self.segments) - 1 - segment_ndx + for segment_ndx in range(len(segments)): + segment = segments[segment_ndx] + remaining_segments = len(segments) - 1 - segment_ndx next_path_ndx = len(path_segments) - remaining_segments if segment.name == SegmentName.SINGLE_CAPTURE: matches[segment.trimmed] = path_segments[path_ndx] diff --git a/tests/test_path_pattern.py b/tests/test_path_pattern.py index 5248b02..3513e34 100644 --- a/tests/test_path_pattern.py +++ b/tests/test_path_pattern.py @@ -41,6 +41,28 @@ def test_trim_param(self): self.assertEqual(trim_param("{something=*}"), "something") def test_extract_matches(self): + # parse single-capture segments with leading slash + pp = PathPattern("/messages/{a}/{b}/{c}") + self.assertEqual( + pp.extract_matches("messages/match_a/match_b/match_c"), + { + "a": "match_a", + "b": "match_b", + "c": "match_c", + }, + ) + + # parse single-capture segments without leading slash + pp = PathPattern("messages/{a}/{b}/{c}") + self.assertEqual( + pp.extract_matches("messages/match_a/match_b/match_c"), + { + "a": "match_a", + "b": "match_b", + "c": "match_c", + }, + ) + # parse without multi-capture segments pp = PathPattern("{a}/something/else/{b}/end/{c}") self.assertEqual( From 8691a3f7dfd1e7885cd5449df8a3165ff39a08b1 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 10 Jul 2023 13:29:45 +0100 Subject: [PATCH 2/4] make comment two lines --- src/firebase_functions/private/path_pattern.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/firebase_functions/private/path_pattern.py b/src/firebase_functions/private/path_pattern.py index c1444a3..584e9a4 100644 --- a/src/firebase_functions/private/path_pattern.py +++ b/src/firebase_functions/private/path_pattern.py @@ -166,7 +166,8 @@ def has_captures(self) -> bool: def extract_matches(self, path: str) -> dict[str, str]: segments = self.segments if self.segments[0].value == "": - # if leading slash, there will be an empty segment which increases the path index, we pop to remove it + # if leading slash, there will be an empty segment which increases + # the path index, we pop to remove it segments.pop(0) matches: dict[str, str] = {} if not self.has_captures: From ebb62e74ed92c8701c09d9fdb2ac842eb7fa9c20 Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 10 Jul 2023 13:29:59 +0100 Subject: [PATCH 3/4] remove whitespace --- src/firebase_functions/private/path_pattern.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/firebase_functions/private/path_pattern.py b/src/firebase_functions/private/path_pattern.py index 584e9a4..ccb8d2e 100644 --- a/src/firebase_functions/private/path_pattern.py +++ b/src/firebase_functions/private/path_pattern.py @@ -166,7 +166,7 @@ def has_captures(self) -> bool: def extract_matches(self, path: str) -> dict[str, str]: segments = self.segments if self.segments[0].value == "": - # if leading slash, there will be an empty segment which increases + # if leading slash, there will be an empty segment which increases # the path index, we pop to remove it segments.pop(0) matches: dict[str, str] = {} From 9bca662a528d17d6166cb5db7f24e14d1455dfdd Mon Sep 17 00:00:00 2001 From: russellwheatley Date: Mon, 10 Jul 2023 13:54:33 +0100 Subject: [PATCH 4/4] improve implementation --- src/firebase_functions/private/path_pattern.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/firebase_functions/private/path_pattern.py b/src/firebase_functions/private/path_pattern.py index ccb8d2e..bcf8bf6 100644 --- a/src/firebase_functions/private/path_pattern.py +++ b/src/firebase_functions/private/path_pattern.py @@ -129,9 +129,10 @@ class PathPattern: segments: list[PathSegment] def __init__(self, raw_path: str): - self.raw = raw_path + normalized_path = raw_path.strip("/") + self.raw = normalized_path self.segments = [] - self.init_path_segments(raw_path) + self.init_path_segments(normalized_path) def init_path_segments(self, raw: str): parts = raw.split("/") @@ -164,19 +165,14 @@ def has_captures(self) -> bool: for segment in self.segments) def extract_matches(self, path: str) -> dict[str, str]: - segments = self.segments - if self.segments[0].value == "": - # if leading slash, there will be an empty segment which increases - # the path index, we pop to remove it - segments.pop(0) matches: dict[str, str] = {} if not self.has_captures: return matches path_segments = path_parts(path) path_ndx = 0 - for segment_ndx in range(len(segments)): - segment = segments[segment_ndx] - remaining_segments = len(segments) - 1 - segment_ndx + for segment_ndx in range(len(self.segments)): + segment = self.segments[segment_ndx] + remaining_segments = len(self.segments) - 1 - segment_ndx next_path_ndx = len(path_segments) - remaining_segments if segment.name == SegmentName.SINGLE_CAPTURE: matches[segment.trimmed] = path_segments[path_ndx]