Skip to content

Comments

[pyupgrade] Fix syntax error on string with newline escape and comment (UP037)#22968

Merged
dylwil3 merged 3 commits intoastral-sh:mainfrom
danparizher:fix-19835
Feb 9, 2026
Merged

[pyupgrade] Fix syntax error on string with newline escape and comment (UP037)#22968
dylwil3 merged 3 commits intoastral-sh:mainfrom
danparizher:fix-19835

Conversation

@danparizher
Copy link
Contributor

Summary

Fixes a syntax error introduced by UP037 when a quoted annotation contains a trailing comment.

Fixes #19835.

Problem

The logic for detecting trailing comments in quoted annotations was brittle, relying on a fixed offset (len() - 2) from the end of the token stream. This failed to correctly identify comments in strings like "A\n#", leading to invalid code generation where the closing parenthesis of the function definition was commented out.

Approach

Updated the logic in crates/ruff_linter/src/rules/pyupgrade/rules/quoted_annotation.rs to detect trailing comments. It now iterates backwards through the tokens of the annotation string, skipping any newline tokens, to find if the last significant token is a comment.

Test Plan

Added regression tests to crates/ruff_linter/resources/test/fixtures/pyupgrade/UP037_0.py.
Verified with:
cargo test -p ruff_linter pyupgrade::tests

@astral-sh-bot
Copy link

astral-sh-bot bot commented Jan 30, 2026

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@danparizher danparizher changed the title [pyupgrade] Fix causes syntax error on string with newline escape and comment (UP037) [pyupgrade] Fix syntax error on string with newline escape and comment (UP037) Jan 30, 2026
@ntBre ntBre added bug Something isn't working fixes Related to suggested fixes for violations labels Feb 5, 2026
@ntBre ntBre self-requested a review February 5, 2026 23:03
Copy link
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! This looks good to me, but I'm curious for @dylwil3 to take a quick look since he wrote this comment about the logical newline. I printed out the tokens here, and it seems the last token is a comment instead of a newline:

[crates/ruff_linter/src/rules/pyupgrade/rules/quoted_annotation.rs:116:5] &checker.tokens() = Tokens {
    raw: [
        Name 0..1,
        Newline 1..2,
        Comment 2..3,
    ],
}

I just want to make sure we're not being too permissive here or running into a bug from another part of the code.

Copy link
Collaborator

@dylwil3 dylwil3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks right to me! That old comment of mine was mistaken (though it was true for all the examples in the fixture 😄 )

I guess it's sort of an accident that this example worked before

def f() -> """Literal[0]
    #
    
    """:
    return 0

The resulting fix is the same, but it now hits a different match arm here:

    let new_content = match (spans_multiple_lines, last_token_is_comment) {
        (_, false) if in_parameter_annotation(range.start(), checker.semantic()) => {
            annotation.to_string()
        }
        (false, false) => annotation.to_string(),
        (true, false) => format!("({annotation})"),
        (_, true) => format!("({annotation}\n)"),
    };

In any event, thanks for the fix!

@dylwil3 dylwil3 merged commit afcd781 into astral-sh:main Feb 9, 2026
54 of 55 checks passed
@danparizher danparizher deleted the fix-19835 branch February 9, 2026 15:42
carljm added a commit to Hugo-Polloli/ruff that referenced this pull request Feb 9, 2026
* main: (45 commits)
  [ty] Fix wrong inlay hints for overloaded function arguments (astral-sh#23179)
  [ty] Respect `@no_type_check` when combined with other decorators (astral-sh#23177)
  [ty] Use type context when inferring constructor argument types (astral-sh#23139)
  [`airflow`] Add ruff rules to catch deprecated attribute access from context key for Airflow 3.0 (`AIR301`) (astral-sh#22850)
  Support formatting `pycon` markdown code blocks (astral-sh#23112)
  Markdown formatting in LSP (astral-sh#23063)
  Instruct Claude to use comments more sparingly (astral-sh#23181)
  [`flake8-gettext`] Fix false negatives for plural argument of ngettext (`INT001`, `INT002`, `INT003`) (astral-sh#21078)
  [ty] Invoking goto-def on parentheses of a class constructor call takes you too constructor method
  [ty] Make goto definition on class constructor always go to class definition
  [ty] Assign lower completions ranking to deprecated functions and classes (astral-sh#23089)
  [ty] Fix parameter references across files via keyword args (astral-sh#23012)
  [ty] Exclude enclosing class for base completions (astral-sh#23141)
  [`pyupgrade`] Fix syntax error on string with newline escape and comment (`UP037`) (astral-sh#22968)
  [ty] Improve documentation for `expect_single_definition` method (astral-sh#23175)
  [ty] Configure check mode for all projects
  Add `home-assistant` to ecosystem projects (astral-sh#23132)
  Add tabbed shell completion documentation (astral-sh#23169)
  Bump typing conformance-suite pin (astral-sh#23174)
  [ty] Fix invalid diagnostic location for a sub-call to a specialized ParamSpec (astral-sh#23036)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working fixes Related to suggested fixes for violations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UP037 fix causes syntax error on string with newline escape and comment

3 participants