Suppression Comments #6338
Replies: 6 comments 6 replies
-
FWIW, as I communicated in DMs, I'm supportive of this proposal. Am I right that there's nothing in the proposed API that would prevent us from expanding to support suppression-with-expressions in the future? (I'm ignoring the implementation cost and details -- I'm just confirming that there's nothing in the API that precludes us from adding that later if needed.) |
Beta Was this translation helpful? Give feedback.
-
Generally I am in support of this, it sounds great. Are the following cases supported? [ # fmt: skip
...
] and [...] # fmt: skip Should
Where would they be considered missing? |
Beta Was this translation helpful? Give feedback.
-
To sum the discussion up to this point:
|
Beta Was this translation helpful? Give feedback.
-
Would like to request that |
Beta Was this translation helpful? Give feedback.
-
I appreciate opinion will be divided over when and if arrays deserve manual layout, but trying out ruff 0.1.3, I see it does not obey examples like this (and related hand-tuned arrays formatted for element alignment): self.assertTrue(
np.array_equal(
alignment.indices,
np.array(
[
# fmt: off
[0, 1, 2, 3, 4, 5, 6, 7, -1, 8, 9, 10],
[0, -1, 1, -1, 2, 3, -1, 4, 5, 6, -1, -1],
# fmt: on
]
),
)
) Referring to the documentation above, I see the suggested alternatives for use with
# Up to user to decide how compact to make this array:
expected = np.array([
[0, 1, 2, 3, 4, 5, 6, 7, -1, 8, 9, 10],
[0, -1, 1, -1, 2, 3, -1, 4, 5, 6, -1, -1],
]) # fmt: skip
self.assertTrue(np.array_equal(alignment.indices, expected)) I'm guessing your preferred alternative for this use-case is the temporary variable? (This example is actually a slight simplification as we also told flake8 to ignore the spaces; examples like this constitute the majority of the deviations from black in the repository concerned) |
Beta Was this translation helpful? Give feedback.
-
I didn't see table-driven tests with It turns out the trailing @pytest.mark.parametrize(
["which_result", "find_uv_bin_result", "expected"],
[
("/usr/bin/uv", UV_IN_PIPX_VENV, (True, "/usr/bin/uv")),
("/usr/bin/uv", FileNotFoundError, (True, "/usr/bin/uv")),
(None, UV_IN_PIPX_VENV, (True, UV_IN_PIPX_VENV)),
(None, FileNotFoundError, (False, "uv")),
],
) # fmt: skip
def test_find_uv(monkeypatch, which_result, find_uv_bin_result, expected):
... |
Beta Was this translation helpful? Give feedback.
-
This discussion proposes a design for suppression-comments in the formatter and documents the decision for the future.
Black
Black supports
fmt: off
followed by an optionalfmt: on
own-line comments. Anything between does not get formatted:The formatting gets automatically re-enabled if there's a dedent decreasing the indention level below the initial indentation of the
fmt: off
comment. The following is semantically identical to the above example:The indentation behavior doesn't apply to parenthesized expressions (any expression enclosed by a
()
,[]
, or{}
pair). Instead, Black re-enables the formatting when reaching the opening parentheses, meaning the following two examples are semantically equivalent:Black further supports trailing
fmt: skip
comments that disable formatting for the preceding line. I haven't been able to figure out fully what the logic is when using inside of expressions. Here a few examples:Proposal
Implementing Black's very flexible
fmt: off
..fmt: on
suppression comments is challenging with our formatter architecture, and I also don't think it is necessary. I analyzed the usages of our ecosystem projects, and the vast majority only use statement-level suppression comments. These are easy to reason about and almost always sufficient.Suppression comments are also a sign that the formatter isn't good enough. I want to focus on improving formatting rather than investing in a very flexible and powerful suppression system. Suppression comments don't just mean that we're back to discussing how the suppressed code should be formatted, but the suppression also decreases readability overall.
What's important from my perspective is that:
Own line
fmt: off
andfmt: on
commentsfmt: off
andfmt: on
comments allow to disable formatting for a range of statements. The statements must have the same or higher indentation level than the statement annotated with thefmt: off
comment. Thefmt: on
is optional, but its best practice to use it.I propose to limit
fmt: off
... andfmt: on
to statement level only. The following examples are all validHowever, the following examples are not valid (but are valid in black)
if..elif
case doesn't fulfill the goal that suppression comments should be intuitive. Does it suppress theelif
body only or all statements with the same indent as theelif
case?That's why I believe
fmt: skip
is usefulTrailing
fmt: skip
orfmt: off
commentsA trailing
fmt: skip
orfmt: off
comment suppresses formatting for the preceding statement, case header, decorator, function definition, or class definition:There are two caveats where the use of
fmt: skip
is not intuitive:a; b; c # fmt skip
suppresses the formatting for the statementc
, and not the whole physical line as one might expect. This is because the AST has no sequence statement.def test(): pass # fmt: skip
suppresses formatting for the whole function and not just thepass
statement.I think this is a shortcoming that we have to accept.
Unsupported Use cases
I went through all
fmt: off
andfmt: skip
usages to identify the uses that either require changing the suppression comments or are entirely unsupported.Between decorators
-> Use a trailing
fmt: skip
Inside Lists
Either use
fmt: skip
, or assign the list to a temporary variable and suppress formatting for the assignment statement.Inside assertions
I've seen both
fmt: off
comments on the statement and expression level. Disallowingfmt: off
on the expression level increases consistency.If Conditions
Inside dictionaries
This seems useful but won't be supported anymore.
Observation
The main use case for suppression comments is when it comes to formatting lists. We should improve list formatting by e.g. using a fill layout when all expressions in a list are simple expressions (numbers, simple strings). The fill layout tries to fit as many items as possible on a line rather than putting each item on its own line.
Open Question
fmt: on
comments?Beta Was this translation helpful? Give feedback.
All reactions