diff --git a/changelog/14474.bugfix.rst b/changelog/14474.bugfix.rst new file mode 100644 index 00000000000..333d4d34d9a --- /dev/null +++ b/changelog/14474.bugfix.rst @@ -0,0 +1 @@ +Fixed a regression where ``-k`` and ``-m`` expressions containing both backslash characters in identifiers and string literal arguments would incorrectly raise a ``SyntaxError`` about escaping. diff --git a/src/_pytest/mark/expression.py b/src/_pytest/mark/expression.py index 3bdbd03c2b5..4b4a68d8a74 100644 --- a/src/_pytest/mark/expression.py +++ b/src/_pytest/mark/expression.py @@ -102,10 +102,10 @@ def lex(self, input: str) -> Iterator[Token]: (FILE_NAME, 1, pos + 1, input), ) value = input[pos : end_quote_pos + 1] - if (backslash_pos := input.find("\\")) != -1: + if (backslash_pos := value.find("\\")) != -1: raise SyntaxError( r'escaping with "\" not supported in marker expression', - (FILE_NAME, 1, backslash_pos + 1, input), + (FILE_NAME, 1, pos + backslash_pos + 1, input), ) yield Token(TokenType.STRING, value, pos) pos += len(value) diff --git a/testing/test_mark_expression.py b/testing/test_mark_expression.py index 1e3c769347c..3a606bac17c 100644 --- a/testing/test_mark_expression.py +++ b/testing/test_mark_expression.py @@ -86,6 +86,20 @@ def matcher(name: str, /, **kwargs: str | int | bool | None) -> bool: evaluate("\nfoo\n", matcher) +def test_backslash_in_identifier_with_string_literal() -> None: + r"""Backslashes in identifiers should not cause false rejections when the + expression also contains string literals. Regression test for a bug where + the scanner searched the entire input for backslashes instead of only the + current string literal value.""" + + def matcher(name: str, /, **kwargs: str | int | bool | None) -> bool: + return {r"\nfoo\n", r"test\case", "mark"}.__contains__(name) + + assert evaluate(r'\nfoo\n and mark(x="y")', matcher) + assert evaluate(r'mark(x="y") and \nfoo\n', matcher) + assert evaluate(r'test\case and mark(x="y")', matcher) + + @pytest.mark.parametrize( ("expr", "column", "message"), (