Skip to content

Commit 8b00e92

Browse files
committed
Avoid duplicating linter-formatter compatibility warnings
1 parent e2b5c6a commit 8b00e92

File tree

2 files changed

+43
-39
lines changed

2 files changed

+43
-39
lines changed

crates/ruff_cli/src/commands/format.rs

+39-37
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::collections::BTreeSet;
12
use std::fmt::{Display, Formatter};
23
use std::fs::File;
34
use std::io;
@@ -695,11 +696,11 @@ pub(super) fn warn_incompatible_formatter_settings(
695696
pyproject_config: &PyprojectConfig,
696697
resolver: Option<&Resolver>,
697698
) {
699+
// First, collect all rules that are incompatible regardless of the linter-specific settings.
700+
let mut incompatible_rules = BTreeSet::new();
698701
for setting in std::iter::once(&pyproject_config.settings)
699702
.chain(resolver.iter().flat_map(|resolver| resolver.settings()))
700703
{
701-
let mut incompatible_rules = Vec::new();
702-
703704
for rule in [
704705
// The formatter might collapse implicit string concatenation on a single line.
705706
Rule::SingleLineImplicitStringConcatenation,
@@ -713,41 +714,41 @@ pub(super) fn warn_incompatible_formatter_settings(
713714
Rule::MissingTrailingComma,
714715
] {
715716
if setting.linter.rules.enabled(rule) {
716-
incompatible_rules.push(rule);
717+
incompatible_rules.insert(rule);
717718
}
718719
}
720+
}
719721

720-
// Rules asserting for space indentation
721-
if setting.formatter.indent_style.is_tab() {
722-
for rule in [Rule::TabIndentation, Rule::IndentWithSpaces] {
723-
if setting.linter.rules.enabled(rule) {
724-
incompatible_rules.push(rule);
725-
}
726-
}
727-
}
722+
if !incompatible_rules.is_empty() {
723+
let mut rule_names: Vec<_> = incompatible_rules
724+
.into_iter()
725+
.map(|rule| format!("`{}`", rule.noqa_code()))
726+
.collect();
727+
rule_names.sort();
728+
warn_user_once!("The following rules may cause conflicts when used with the formatter: {}. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.", rule_names.join(", "));
729+
}
728730

729-
// Rules asserting for indent-width=4
730-
if setting.formatter.indent_width.value() != 4 {
731-
for rule in [
732-
Rule::IndentationWithInvalidMultiple,
733-
Rule::IndentationWithInvalidMultipleComment,
734-
] {
735-
if setting.linter.rules.enabled(rule) {
736-
incompatible_rules.push(rule);
737-
}
738-
}
731+
// Next, validate settings-specific incompatibilities.
732+
for setting in std::iter::once(&pyproject_config.settings)
733+
.chain(resolver.iter().flat_map(|resolver| resolver.settings()))
734+
{
735+
// Validate all rules that rely on tab styles.
736+
if setting.linter.rules.enabled(Rule::TabIndentation)
737+
&& setting.formatter.indent_style.is_tab()
738+
{
739+
warn_user_once!("The `format.indent-style=\"tab\"` option is incompatible with `W191`. We recommend disabling these rules when using the formatter, which enforces a consistent indentation style. Alternatively, set the `format.indent-style` option to `\"space\"`.");
739740
}
740741

741-
if !incompatible_rules.is_empty() {
742-
let mut rule_names: Vec<_> = incompatible_rules
743-
.into_iter()
744-
.map(|rule| format!("`{}`", rule.noqa_code()))
745-
.collect();
746-
rule_names.sort();
747-
warn!("The following rules may cause conflicts when used with the formatter: {}. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.", rule_names.join(", "));
742+
// Validate all rules that rely on custom indent widths.
743+
if setting.linter.rules.any_enabled(&[
744+
Rule::IndentationWithInvalidMultiple,
745+
Rule::IndentationWithInvalidMultipleComment,
746+
]) && setting.formatter.indent_width.value() != 4
747+
{
748+
warn_user_once!("The `format.indent-width` option with a value other than 4 is incompatible with `E111` and `E114`. We recommend disabling these rules when using the formatter, which enforces a consistent indentation width. Alternatively, set the `format.indent-width` option to `4`.");
748749
}
749750

750-
// Rules with different quote styles.
751+
// Validate all rules that rely on quote styles.
751752
if setting
752753
.linter
753754
.rules
@@ -758,10 +759,10 @@ pub(super) fn warn_incompatible_formatter_settings(
758759
setting.formatter.quote_style,
759760
) {
760761
(Quote::Double, QuoteStyle::Single) => {
761-
warn!("The `flake8-quotes.inline-quotes=\"double\"` option is incompatible with the formatter's `format.quote-style=\"single\"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `\"single\"` or `\"double\"`.");
762+
warn_user_once!("The `flake8-quotes.inline-quotes=\"double\"` option is incompatible with the formatter's `format.quote-style=\"single\"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `\"single\"` or `\"double\"`.");
762763
}
763764
(Quote::Single, QuoteStyle::Double) => {
764-
warn!("The `flake8-quotes.inline-quotes=\"single\"` option is incompatible with the formatter's `format.quote-style=\"double\"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `\"single\"` or `\"double\"`.");
765+
warn_user_once!("The `flake8-quotes.inline-quotes=\"single\"` option is incompatible with the formatter's `format.quote-style=\"double\"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `\"single\"` or `\"double\"`.");
765766
}
766767
_ => {}
767768
}
@@ -770,25 +771,26 @@ pub(super) fn warn_incompatible_formatter_settings(
770771
if setting.linter.rules.enabled(Rule::BadQuotesMultilineString)
771772
&& setting.linter.flake8_quotes.multiline_quotes == Quote::Single
772773
{
773-
warn!("The `flake8-quotes.multiline-quotes=\"single\"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `\"double\"`.`");
774+
warn_user_once!("The `flake8-quotes.multiline-quotes=\"single\"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `\"double\"`.`");
774775
}
775776

776777
if setting.linter.rules.enabled(Rule::BadQuotesDocstring)
777778
&& setting.linter.flake8_quotes.docstring_quotes == Quote::Single
778779
{
779-
warn!("The `flake8-quotes.multiline-quotes=\"single\"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `\"double\"`.`");
780+
warn_user_once!("The `flake8-quotes.multiline-quotes=\"single\"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `\"double\"`.`");
780781
}
781782

783+
// Validate all isort settings.
782784
if setting.linter.rules.enabled(Rule::UnsortedImports) {
783785
// The formatter removes empty lines if the value is larger than 2 but always inserts a empty line after imports.
784786
// Two empty lines are okay because `isort` only uses this setting for top-level imports (not in nested blocks).
785787
if !matches!(setting.linter.isort.lines_after_imports, 1 | 2 | -1) {
786-
warn!("The isort option `isort.lines-after-imports` with a value other than `-1`, `1` or `2` is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `2`, `1`, or `-1` (default).");
788+
warn_user_once!("The isort option `isort.lines-after-imports` with a value other than `-1`, `1` or `2` is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `2`, `1`, or `-1` (default).");
787789
}
788790

789791
// Values larger than two get reduced to one line by the formatter if the import is in a nested block.
790792
if setting.linter.isort.lines_between_types > 1 {
791-
warn!("The isort option `isort.lines-between-types` with a value greater than 1 is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `1` or `0` (default).");
793+
warn_user_once!("The isort option `isort.lines-between-types` with a value greater than 1 is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `1` or `0` (default).");
792794
}
793795

794796
// isort inserts a trailing comma which the formatter preserves, but only if `skip-magic-trailing-comma` isn't false.
@@ -797,11 +799,11 @@ pub(super) fn warn_incompatible_formatter_settings(
797799
&& !setting.linter.isort.force_single_line
798800
{
799801
if setting.linter.isort.force_wrap_aliases {
800-
warn!("The isort option `isort.force-wrap-aliases` is incompatible with the formatter `format.skip-magic-trailing-comma=true` option. To avoid unexpected behavior, we recommend either setting `isort.force-wrap-aliases=false` or `format.skip-magic-trailing-comma=false`.");
802+
warn_user_once!("The isort option `isort.force-wrap-aliases` is incompatible with the formatter `format.skip-magic-trailing-comma=true` option. To avoid unexpected behavior, we recommend either setting `isort.force-wrap-aliases=false` or `format.skip-magic-trailing-comma=false`.");
801803
}
802804

803805
if setting.linter.isort.split_on_trailing_comma {
804-
warn!("The isort option `isort.split-on-trailing-comma` is incompatible with the formatter `format.skip-magic-trailing-comma=true` option. To avoid unexpected behavior, we recommend either setting `isort.split-on-trailing-comma=false` or `format.skip-magic-trailing-comma=false`.");
806+
warn_user_once!("The isort option `isort.split-on-trailing-comma` is incompatible with the formatter `format.skip-magic-trailing-comma=true` option. To avoid unexpected behavior, we recommend either setting `isort.split-on-trailing-comma=false` or `format.skip-magic-trailing-comma=false`.");
805807
}
806808
}
807809
}

crates/ruff_cli/tests/format.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,8 @@ def say_hy(name: str):
403403
1 file reformatted
404404
405405
----- stderr -----
406-
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `D206`, `ISC001`, `W191`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.
406+
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `ISC001`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.
407+
warning: The `format.indent-style="tabs"` option is incompatible with `W191`. We recommend disabling these rules when using the formatter, which enforces a consistent indentation style. Alternatively, set the `format.indent-style` option to `"spaces"`.
407408
warning: The `flake8-quotes.inline-quotes="single"` option is incompatible with the formatter's `format.quote-style="double"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `"single"` or `"double"`.
408409
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `"double"`.`
409410
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `"double"`.`
@@ -460,7 +461,8 @@ def say_hy(name: str):
460461
print(f"Hy {name}")
461462
462463
----- stderr -----
463-
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `D206`, `ISC001`, `W191`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.
464+
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `ISC001`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.
465+
warning: The `format.indent-style="tabs"` option is incompatible with `W191`. We recommend disabling these rules when using the formatter, which enforces a consistent indentation style. Alternatively, set the `format.indent-style` option to `"spaces"`.
464466
warning: The `flake8-quotes.inline-quotes="single"` option is incompatible with the formatter's `format.quote-style="double"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `"single"` or `"double"`.
465467
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `"double"`.`
466468
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `"double"`.`

0 commit comments

Comments
 (0)