Skip to content

Commit

Permalink
Refine the warnings about incompatible linter options
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser committed Oct 25, 2023
1 parent e0f34f9 commit 142cc30
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 31 deletions.
90 changes: 69 additions & 21 deletions crates/ruff_cli/src/commands/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ use ruff_diagnostics::SourceMap;
use ruff_linter::fs;
use ruff_linter::logging::LogLevel;
use ruff_linter::registry::Rule;
use ruff_linter::settings::rule_table::RuleTable;
use ruff_linter::rules::flake8_quotes::settings::Quote;
use ruff_linter::source_kind::{SourceError, SourceKind};
use ruff_linter::warn_user_once;
use ruff_python_ast::{PySourceType, SourceType};
use ruff_python_formatter::{format_module_source, FormatModuleError};
use ruff_python_formatter::{format_module_source, FormatModuleError, QuoteStyle};
use ruff_text_size::{TextLen, TextRange, TextSize};
use ruff_workspace::resolver::{
match_exclusion, python_files_in_path, PyprojectConfig, ResolvedFile, Resolver,
Expand Down Expand Up @@ -685,31 +685,79 @@ pub(super) fn warn_incompatible_formatter_settings(
{
let mut incompatible_rules = Vec::new();

for incompatible_rule in RuleTable::from_iter([
Rule::LineTooLong,
Rule::TabIndentation,
Rule::IndentationWithInvalidMultiple,
Rule::IndentationWithInvalidMultipleComment,
Rule::OverIndented,
Rule::IndentWithSpaces,
for rule in [
// The formatter might collapse implicit string concatenation on a single line.
Rule::SingleLineImplicitStringConcatenation,
// Flags missing trailing commas when all arguments are on its own line:
// ```python
// def args(
// aaaaaaaa, bbbbbbbbb, cccccccccc, ddddddddd, eeeeeeee, ffffff, gggggggggggg, hhhh
// ):
// pass
// ```
Rule::MissingTrailingComma,
Rule::ProhibitedTrailingComma,
Rule::BadQuotesInlineString,
Rule::BadQuotesMultilineString,
Rule::BadQuotesDocstring,
Rule::AvoidableEscapedQuote,
])
.iter_enabled()
{
if setting.linter.rules.enabled(incompatible_rule) {
incompatible_rules.push(format!("'{}'", incompatible_rule.noqa_code()));
] {
if setting.linter.rules.enabled(rule) {
incompatible_rules.push(rule);
}
}

// Rules assuming indent style space
if setting.formatter.indent_style.is_tab() {
for rule in [Rule::TabIndentation, Rule::IndentWithSpaces] {
if setting.linter.rules.enabled(rule) {
incompatible_rules.push(rule);
}
}
}

// Rules assuming an indent width of 4
if setting.formatter.indent_width.value() != 4 {
for rule in [
Rule::IndentationWithInvalidMultiple,
Rule::IndentationWithInvalidMultipleComment,
Rule::OverIndented,
] {
if setting.linter.rules.enabled(rule) {
incompatible_rules.push(rule);
}
}
}

if !incompatible_rules.is_empty() {
incompatible_rules.sort();
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.", incompatible_rules.join(", "));
let mut rule_names: Vec<_> = incompatible_rules
.into_iter()
.map(|rule| format!("'{}'", rule.noqa_code()))
.collect();
rule_names.sort();
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(", "));
}

// Rules with different quote styles.
if matches!(
(
setting.formatter.quote_style,
setting.linter.flake8_quotes.inline_quotes
),
(QuoteStyle::Single, Quote::Double) | (QuoteStyle::Double, Quote::Single)
) && setting
.linter
.rules
.any_enabled(&[Rule::BadQuotesInlineString, Rule::AvoidableEscapedQuote])
{
warn!("The `flake8-quotes.inline-quotes` option is incompatible with the formatter's `format.quote-style` option. Change your configuration and either set both options to single or double quotes.");
}

if setting.linter.rules.enabled(Rule::BadQuotesMultilineString)
&& setting.linter.flake8_quotes.multiline_quotes == Quote::Single
{
warn!("The `flake8-quotes.multiline-quotes` option is incompatible with the formatter that always uses double quotes for multiline strings. Please change the `flake8-quotes.multiline-quotes` option to use double quotes.`");
}

if setting.linter.rules.enabled(Rule::BadQuotesDocstring)
&& setting.linter.flake8_quotes.docstring_quotes == Quote::Single
{
warn!("The `flake8-quotes.docstring-quotes` option is incompatible with the formatter's that always uses double quotes. Please change the `flake8-quotes.docstring-quotes` to use double quotes.");
}

if setting.linter.rules.enabled(Rule::UnsortedImports) {
Expand Down
91 changes: 81 additions & 10 deletions crates/ruff_cli/tests/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ fn format_option_inheritance() -> Result<()> {
&ruff_toml,
r#"
extend = "base.toml"
extend-select = ["Q000"]
[lint]
extend-select = ["COM812"]
[format]
quote-style = "single"
Expand Down Expand Up @@ -273,7 +275,7 @@ if condition:
print('Should change quotes')
----- stderr -----
warning: The following rules may cause conflicts when used with the formatter: 'Q000'. 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.
warning: The following rules may cause conflicts when used with the formatter: 'COM812'. 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.
"###);
Ok(())
}
Expand Down Expand Up @@ -359,17 +361,26 @@ fn conflicting_options() -> Result<()> {
fs::write(
&ruff_toml,
r#"
indent-width = 2
[lint]
select = ["ALL"]
ignore = ["D203", "D212"]
[isort]
[lint.isort]
lines-after-imports = 3
lines-between-types = 2
force-wrap-aliases = true
combine-as-imports = true
[lint.flake8-quotes]
inline-quotes = "single"
docstring-quotes = "single"
multiline-quotes = "single"
[format]
skip-magic-trailing-comma = true
indent-style = "tab"
"#,
)?;

Expand All @@ -391,7 +402,10 @@ def say_hy(name: str):
1 file reformatted
----- stderr -----
warning: The following rules may cause conflicts when used with the formatter: 'COM812', 'COM819', 'D206', 'E501', 'ISC001', 'Q000', 'Q001', 'Q002', 'Q003', '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.
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.
warning: The `flake8-quotes.inline-quotes` option is incompatible with the formatter's `format.quote-style` option. Change your configuration and either set both options to single or double quotes.
warning: The `flake8-quotes.multiline-quotes` option is incompatible with the formatter that always uses double quotes for multiline strings. Please change the `flake8-quotes.multiline-quotes` option to use double quotes.`
warning: The `flake8-quotes.docstring-quotes` option is incompatible with the formatter's that always uses double quotes. Please change the `flake8-quotes.docstring-quotes` to use double quotes.
warning: 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).
warning: The isort option 'isort.lines-between-types' with a value larger than 1 is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `1` or `0` (default).
warning: 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=true'.
Expand All @@ -406,17 +420,26 @@ fn conflicting_options_stdin() -> Result<()> {
fs::write(
&ruff_toml,
r#"
indent-width = 2
[lint]
select = ["ALL"]
ignore = ["D203", "D212"]
[isort]
[lint.isort]
lines-after-imports = 3
lines-between-types = 2
force-wrap-aliases = true
combine-as-imports = true
[lint.flake8-quotes]
inline-quotes = "single"
docstring-quotes = "single"
multiline-quotes = "single"
[format]
skip-magic-trailing-comma = true
indent-style = "tab"
"#,
)?;

Expand All @@ -431,10 +454,13 @@ def say_hy(name: str):
exit_code: 0
----- stdout -----
def say_hy(name: str):
print(f"Hy {name}")
print(f"Hy {name}")
----- stderr -----
warning: The following rules may cause conflicts when used with the formatter: 'COM812', 'COM819', 'D206', 'E501', 'ISC001', 'Q000', 'Q001', 'Q002', 'Q003', '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.
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.
warning: The `flake8-quotes.inline-quotes` option is incompatible with the formatter's `format.quote-style` option. Change your configuration and either set both options to single or double quotes.
warning: The `flake8-quotes.multiline-quotes` option is incompatible with the formatter that always uses double quotes for multiline strings. Please change the `flake8-quotes.multiline-quotes` option to use double quotes.`
warning: The `flake8-quotes.docstring-quotes` option is incompatible with the formatter's that always uses double quotes. Please change the `flake8-quotes.docstring-quotes` to use double quotes.
warning: 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).
warning: The isort option 'isort.lines-between-types' with a value larger than 1 is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `1` or `0` (default).
warning: 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=true'.
Expand All @@ -449,17 +475,59 @@ fn valid_linter_options() -> Result<()> {
fs::write(
&ruff_toml,
r#"
[lint]
select = ["ALL"]
ignore = ["D203", "D212"]
ignore = ["D203", "D212", "COM812", "ISC001"]
[isort]
[lint.isort]
lines-after-imports = 2
lines-between-types = 1
force-wrap-aliases = true
combine-as-imports = true
[lint.flake8-quotes]
inline-quotes = "single"
docstring-quotes = "double"
multiline-quotes = "double"
[format]
skip-magic-trailing-comma = false
quote-style = "single"
"#,
)?;

let test_path = tempdir.path().join("test.py");
fs::write(
&test_path,
r#"
def say_hy(name: str):
print(f"Hy {name}")"#,
)?;

assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(["format", "--no-cache", "--config"])
.arg(&ruff_toml)
.arg(test_path), @r###"
success: true
exit_code: 0
----- stdout -----
1 file reformatted
----- stderr -----
"###);
Ok(())
}

#[test]
fn all_rules_default_options() -> Result<()> {
let tempdir = TempDir::new()?;
let ruff_toml = tempdir.path().join("ruff.toml");

fs::write(
&ruff_toml,
r#"
[lint]
select = ["ALL"]
"#,
)?;

Expand All @@ -481,10 +549,13 @@ def say_hy(name: str):
1 file reformatted
----- stderr -----
warning: The following rules may cause conflicts when used with the formatter: 'COM812', 'COM819', 'D206', 'E501', 'ISC001', 'Q000', 'Q001', 'Q002', 'Q003', '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.
warning: `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible. Ignoring `one-blank-line-before-class`.
warning: `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible. Ignoring `multi-line-summary-second-line`.
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.
"###);
Ok(())
}

#[test]
fn test_diff() {
let args = ["format", "--no-cache", "--isolated", "--diff"];
Expand Down

0 comments on commit 142cc30

Please sign in to comment.