Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/14474.bugfix.rst
Original file line number Diff line number Diff line change
@@ -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 -- the backslash check was searching the entire input instead of only the string literal value.
Comment thread
bluetech marked this conversation as resolved.
Outdated
4 changes: 2 additions & 2 deletions src/_pytest/mark/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions testing/test_mark_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
(
Expand Down
Loading