Repository navigation
Conversation
Signed-off-by: Sebastian Turner <sebastiant3484@gmail.com>
There was a problem hiding this comment.
Code Review
This pull request updates the regular expression for matching quoted elements in Firestore field paths to correctly handle trailing escaped backslashes, and adds corresponding unit tests. The review feedback suggests improving the regex to handle escaped newlines by matching any character (including newlines) instead of using a dot, and renaming a variable in the unit tests to avoid shadowing the imported field_path module.
| PATH_ELEMENT_TOKENS = [ | ||
| ("SIMPLE", r"[_a-zA-Z][_a-zA-Z0-9]*"), # unquoted elements | ||
| ("QUOTED", r"`(?:\\`|[^`])*?`"), # quoted elements, unquoted | ||
| ("QUOTED", r"`(?:\\.|[^`\\])*`"), # quoted elements, unquoted |
There was a problem hiding this comment.
The regex pattern uses \. to match escaped characters. However, in Python, the . character does not match newlines (\n) by default unless the re.DOTALL flag is active. If a field path contains an escaped newline, this pattern will fail to match.
To ensure robustness and handle any escaped character (including newlines) regardless of compilation flags, use \\[\s\S] instead of \. .
| ("QUOTED", r"`(?:\\.|[^`\\])*`"), # quoted elements, unquoted | |
| ("QUOTED", r"`(?:\\[\\s\\S]|[^`\\])*`"), # quoted elements, unquoted |
| field_path = field_path.FieldPath.from_string(path_string) | ||
| assert field_path.parts == ("a\\", "b c") |
There was a problem hiding this comment.
Reassigning the variable field_path shadows the imported field_path module within the function scope. This makes the code fragile and harder to maintain or extend if other module-level attributes or classes need to be accessed later in the test.
Consider renaming the variable to parsed_path to avoid shadowing.
| field_path = field_path.FieldPath.from_string(path_string) | |
| assert field_path.parts == ("a\\", "b c") | |
| parsed_path = field_path.FieldPath.from_string(path_string) | |
| assert parsed_path.parts == ('a\\\\', 'b c') |
FieldPath("dir\\", "file name").to_api_repr()produces`dir\\`.`file name`, but the tokenizer infield_path.pyreads the escaped backslash plus the closing backtick as an escaped backtick.FieldPath.from_api_repr()then raisesValueError, andFieldPath.from_string()(used byupdate()and merge handling) falls back to splitting on.and returns parts that still include the backticks, so the write targets the wrong field.This changes the
QUOTEDtoken pattern fromr"`(?:\\`|[^`])*?`"tor"`(?:\\.|[^`\\])*`", so a backslash always consumes the character after it as an escape. Existing behavior for valid paths is unchanged, and an unterminated quoted name such as`a\`b.c.dis still rejected.Tests added in
tests/unit/v1/test_field_path.pyfor the tokenizer,parse_field_path, and ato_api_repr()/from_string()round trip. All three fail onmainand pass with the change.Fixes #<issue_number_goes_here>
Fixes #18771