Skip to content

RUF072: skip formfeeds on dedent - #24308

Merged
MichaReiser merged 7 commits into
astral-sh:mainfrom
second-ed:fix/ruff_24246_formfeed_indent
Apr 2, 2026
Merged

RUF072: skip formfeeds on dedent#24308
MichaReiser merged 7 commits into
astral-sh:mainfrom
second-ed:fix/ruff_24246_formfeed_indent

Conversation

@second-ed

Copy link
Copy Markdown
Contributor

Summary

fixes: #24246

Skips the formfeed on the dedent if the line starts with the formfeed and then readds it back to the start of the line.

Test Plan

Added bug report example to snapshot test cases

@astral-sh-bot
astral-sh-bot Bot requested a review from ntBre March 30, 2026 14:34
@MichaReiser MichaReiser changed the title [RUF072 useless-finally] skip formfeeds on dedent #24246 RUF072: skip formfeeds on dedent Mar 30, 2026
@astral-sh-bot

astral-sh-bot Bot commented Mar 30, 2026

Copy link
Copy Markdown

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

Comment on lines +74 to +80
# Bare try finally with line starting with a formfeed
try:
1
2
finally:
pass

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'll do a full review later. Can you add the new test at the end? It reduces the snapshot diff size, which makes the changes easier to review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah sure, I'll make those changes and push up, I was trying to keep the error cases and ok cases together but agree it makes the diff horrible to read

@MichaReiser MichaReiser added bug Something isn't working fixes Related to suggested fixes for violations labels Mar 30, 2026
/// Lines that are indented by _less_ than the indent of the first line
/// are left unchanged.
///
/// Lines that consist solely of whitespace are trimmed to a blank line.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's update the documentation to explain how form feeds are handled

Comment thread crates/ruff_python_trivia/src/textwrap.rs

#[test]
#[rustfmt::skip]
fn dedent_to_handles_when_multiple_leading_form_feeds_greater_than_dedent_len() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Here's another test case that currently panics:

    #[test]
    #[rustfmt::skip]
    fn dedent_to_ignores_leading_form_feeds_when_checking_indentation() {
        let x = [
            "    1",
            "\x0C\x0C  2",
        ].join("\n");
        let y = [
            "1",
            "\x0C\x0C  2",
        ].join("\n");
        assert_eq!(dedent_to(&x, ""), Some(y));
    }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Cheers, I'll have a look at this after work and see if I can find more test cases to sure it up

" baz"
].join("\n");
let first_result = dedent_to(&x, " ").unwrap();
assert_eq!(dedent_to(&first_result, " "), Some(y));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I found two more failing test cases

#[test]
    #[rustfmt::skip]
    fn dedent_to_preserves_less_indented_later_line() {
        let x = [
            "   foo\n",
            "  bar\n",
        ].join("");
        let y = [
            "foo\n",
            "  bar\n",
        ].join("");
        assert_eq!(dedent_to(&x, ""), Some(y));
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_to_preserves_less_indented_later_line_with_crlf() {
        let x = [
            "   foo\r\n",
            "  bar\r\n",
        ].join("");
        let y = [
            "foo\r\n",
            "  bar\r\n",
        ].join("");
        assert_eq!(dedent_to(&x, ""), Some(y));
    }

@second-ed
second-ed marked this pull request as draft March 31, 2026 21:05
@second-ed
second-ed marked this pull request as ready for review April 1, 2026 15:42
@second-ed
second-ed requested a review from MichaReiser April 2, 2026 10:34

@MichaReiser MichaReiser left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you. This turned out to be trickier than I thought.

@MichaReiser
MichaReiser force-pushed the fix/ruff_24246_formfeed_indent branch from 311bea1 to ced2ffe Compare April 2, 2026 12:21
@second-ed

Copy link
Copy Markdown
Contributor Author

cheers for your help it was a fun one 😄

@MichaReiser
MichaReiser merged commit 37f5d61 into astral-sh:main Apr 2, 2026
48 checks passed
carljm added a commit that referenced this pull request Apr 2, 2026
* main:
  Add a "release-gate" step to the release workflow (#24365)
  Disallow starred expressions as values of starred expressions (#24280)
  [`pyupgrade`] Ignore strings with string-only escapes (`UP012`) (#16058)
  [ty] Improve consistency and quality of diagnostics relating to invalid type forms (#24325)
  [flake8-type-checking] Clarify import cycle wording for TC001/TC002/TC003 (#24322)
  [`flake8-errmsg`] Avoid shadowing existing `msg` in fix for `EM101` (#24363)
  `RUF072`: skip formfeeds on dedent (#24308)
  Replace unmaintained `unic-ucd-category` crate with `icu_properties` (#24344)
  [ty] Replace markdown hard line breaks in snapshot tests (#24361)
  [ty] Move snapshot for code action test with trailing whitespace to external file (#24359)
@second-ed
second-ed deleted the fix/ruff_24246_formfeed_indent branch April 2, 2026 16:31
nicopauss pushed a commit to Intersec/lib-common that referenced this pull request Jun 4, 2026
##### [\`v0.15.10\`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#01510)

Released on 2026-04-09.

##### Preview features

- \[`flake8-logging`] Allow closures in except handlers (`LOG004`) ([#24464](astral-sh/ruff#24464))
- \[`flake8-self`] Make `SLF` diagnostics robust to non-self-named variables ([#24281](astral-sh/ruff#24281))
- \[`flake8-simplify`] Make the fix for `collapsible-if` safe in `preview` (`SIM102`) ([#24371](astral-sh/ruff#24371))

##### Bug fixes

- Avoid emitting multi-line f-string elements before Python 3.12 ([#24377](astral-sh/ruff#24377))
- Avoid syntax error from `E502` fixes in f-strings and t-strings ([#24410](astral-sh/ruff#24410))
- Strip form feeds from indent passed to `dedent_to` ([#24381](astral-sh/ruff#24381))
- \[`pyupgrade`] Fix panic caused by handling of octals (`UP012`) ([#24390](astral-sh/ruff#24390))
- Reject multi-line f-string elements before Python 3.12 ([#24355](astral-sh/ruff#24355))

##### Rule changes

- \[`ruff`] Treat f-string interpolation as potential side effect (`RUF019`) ([#24426](astral-sh/ruff#24426))

##### Server

- Add support for custom file extensions ([#24463](astral-sh/ruff#24463))

##### Documentation

- Document adding fixes in CONTRIBUTING.md ([#24393](astral-sh/ruff#24393))
- Fix JSON typo in settings example ([#24517](astral-sh/ruff#24517))

##### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@dylwil3](https://github.com/dylwil3)
- [@silverstein](https://github.com/silverstein)
- [@anishgirianish](https://github.com/anishgirianish)
- [@shizukushq](https://github.com/shizukushq)
- [@zanieb](https://github.com/zanieb)
- [@AlexWaygood](https://github.com/AlexWaygood)
##### [\`v0.15.9\`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0159)

Released on 2026-04-02.

##### Preview features

- \[`pyflakes`] Flag annotated variable redeclarations as `F811` in preview mode ([#24244](astral-sh/ruff#24244))
- \[`ruff`] Allow dunder-named assignments in non-strict mode for `RUF067` ([#24089](astral-sh/ruff#24089))

##### Bug fixes

- \[`flake8-errmsg`] Avoid shadowing existing `msg` in fix for `EM101` ([#24363](astral-sh/ruff#24363))
- \[`flake8-simplify`] Ignore pre-initialization references in `SIM113` ([#24235](astral-sh/ruff#24235))
- \[`pycodestyle`] Fix `W391` fixes for consecutive empty notebook cells ([#24236](astral-sh/ruff#24236))
- \[`pyupgrade`] Fix `UP008` nested class matching ([#24273](astral-sh/ruff#24273))
- \[`pyupgrade`] Ignore strings with string-only escapes (`UP012`) ([#16058](astral-sh/ruff#16058))
- \[`ruff`] `RUF072`: skip formfeeds on dedent ([#24308](astral-sh/ruff#24308))
- \[`ruff`] Avoid re-using symbol in `RUF024` fix ([#24316](astral-sh/ruff#24316))
- \[`ruff`] Parenthesize expression in `RUF050` fix ([#24234](astral-sh/ruff#24234))
- Disallow starred expressions as values of starred expressions ([#24280](astral-sh/ruff#24280))

##### Rule changes

- \[`flake8-simplify`] Suppress `SIM105` for `except*` before Python 3.12 ([#23869](astral-sh/ruff#23869))
- \[`pyflakes`] Extend `F507` to flag `%`-format strings with zero placeholders ([#24215](astral-sh/ruff#24215))
- \[`pyupgrade`] `UP018` should detect more unnecessarily wrapped literals (UP018) ([#24093](astral-sh/ruff#24093))
- \[`pyupgrade`] Fix `UP008` callable scope handling to support lambdas ([#24274](astral-sh/ruff#24274))
- \[`ruff`] `RUF010`: Mark fix as unsafe when it deletes a comment ([#24270](astral-sh/ruff#24270))

##### Formatter

- Add `nested-string-quote-style` formatting option ([#24312](astral-sh/ruff#24312))

##### Documentation

- \[`flake8-bugbear`] Clarify RUF071 fix safety for non-path string comparisons ([#24149](astral-sh/ruff#24149))
- \[`flake8-type-checking`] Clarify import cycle wording for `TC001`/`TC002`/`TC003` ([#24322](astral-sh/ruff#24322))

##### Other changes

- Avoid rendering fix lines with trailing whitespace after `|` ([#24343](astral-sh/ruff#24343))

##### Contributors

- [@charliermarsh](https://github.com/charliermarsh)
- [@MichaReiser](https://github.com/MichaReiser)
- [@tranhoangtu-it](https://github.com/tranhoangtu-it)
- [@dylwil3](https://github.com/dylwil3)
- [@zsol](https://github.com/zsol)
- [@renovate](https://github.com/renovate)
- [@bitloi](https://github.com/bitloi)
- [@danparizher](https://github.com/danparizher)
- [@chinar-amrutkar](https://github.com/chinar-amrutkar)
- [@second-ed](https://github.com/second-ed)
- [@getehen](https://github.com/getehen)
- [@Redovo1](https://github.com/Redovo1)
- [@matthewlloyd](https://github.com/matthewlloyd)
- [@zanieb](https://github.com/zanieb)
- [@InSyncWithFoo](https://github.com/InSyncWithFoo)
- [@RenzoMXD](https://github.com/RenzoMXD)

Renovate-Branch: renovate/2024.6-ruff-0.15.x
Change-Id: Id4bd542d4f128b509284d9dcda312f2b39c29964
Priv-Id: 28ebcacdeffa50cec7a52eee59091a75ca5e9539
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.

Form feeds make the RUF072 fix introduce syntax errors

3 participants