astral-sh / ruff

An extremely fast Python linter and code formatter, written in Rust.
https://docs.astral.sh/ruff
MIT License
31.22k stars 1.04k forks source link

Option to disable awkward line breaks for assert statements #13386

Open 0xjmux opened 5 days ago

0xjmux commented 5 days ago

Hi, I'm using Ruff on a codebase with a good amount of assert statements - it's non-production code, and they're a good way to find bugs as you're testing things.

However, the way that Black and Ruff format assert statements once they pass a certain length doesn't make sense, as the active issues on Black show:

This seems to be a common issue with black that hasn't been addressed for some time, and the reason I started using Ruff is because I was hoping this behavior was something I could disable.

Example

Input:

    assert Path(filepath).exists(), f'longish assert string with filepath {filepath} not found!'

Formatted output:

    assert Path(
        filepath
    ).exists(), f'longish assert string with filepath {filepath} not found!'

Which is objectively less readable.

Desired behavior: An option to either:

assert Path(filepath).exists(), \
    f'longish assert string with filepath {filepath} not found!'

Ruff Playground output and IR

Pasting the input into the Ruff Playground and checking out the IR gives this output:

Ruff playground output ``` empty_line, source_position(356), "filename = ", best_fit_parenthesize("#5", ["\"hello.txt\""]), source_position(378), empty_line, source_position(384), "assert ", best_fit_parenthesize("#6", [ "Path(", fits_expanded(propagate_expand: false, condition: if_group_fits_on_line("#6"), [ group([indent([soft_line_break, group(["filename"])]), soft_line_break]) ]), ").exists", group(["()"]) ]), ", ", best_fit_parenthesize("#7", [ "f\"longish assert string with filepath {filename} not found!\"" ]), source_position(477) ]), hard_line_break, ```

Other

MichaReiser commented 5 days ago

Hi @0xjmux

I agree that the formatting of asserts isn't ideal. IMO, it tries to hard to avoid parentheses which then leads to very awkward looking code.

I do understand where you're coming from but the solution here isn't to introduce new options. Instead, we should improve how assert is formatted. This will benefit everyone (https://github.com/astral-sh/ruff/issues/8331, https://github.com/astral-sh/ruff/issues/8388).

For now, you can use fmt:skip to disable formatting on a case-per-case basis. I know, it's not ideal.

assert Path(filepath).exists(), f'longish assert string with filepath {filepath} not found!' # fmt: skip

For why I don't want to introduce the above mentioned options:

I don't want to introduce a setting to disable formatting of assert statements entirely. The goal of the formatter is to get consistent code formatting and disabling formatting for a specific syntax misses that goal entirely. It also opens a flood of requests where we get request to add settings to disable formatting for every python-syntax there is. That's a precedence I rather not set. The same applies to having a setting that avoids splitting parentheses for specific keywords. Although that would also be very hard to implement because it is a non-local change (what about nested expressions?)

Option to format assert statements like this, and split the error string instead of the conditional.

Our style guide avoids the use of line continuations \ where this is possible.