diff --git a/crates/flake8_to_ruff/src/converter.rs b/crates/flake8_to_ruff/src/converter.rs index 0caafa0b54df5..4b6693d9c4d96 100644 --- a/crates/flake8_to_ruff/src/converter.rs +++ b/crates/flake8_to_ruff/src/converter.rs @@ -16,8 +16,8 @@ use ruff_linter::settings::types::PythonVersion; use ruff_linter::warn_user; use ruff_workspace::options::{ Flake8AnnotationsOptions, Flake8BugbearOptions, Flake8BuiltinsOptions, Flake8ErrMsgOptions, - Flake8PytestStyleOptions, Flake8QuotesOptions, Flake8TidyImportsOptions, McCabeOptions, - Options, Pep8NamingOptions, PydocstyleOptions, + Flake8PytestStyleOptions, Flake8QuotesOptions, Flake8TidyImportsOptions, LintOptions, + McCabeOptions, Options, Pep8NamingOptions, PydocstyleOptions, }; use ruff_workspace::pyproject::Pyproject; @@ -103,6 +103,7 @@ pub(crate) fn convert( // Parse each supported option. let mut options = Options::default(); + let mut lint_options = LintOptions::default(); let mut flake8_annotations = Flake8AnnotationsOptions::default(); let mut flake8_bugbear = Flake8BugbearOptions::default(); let mut flake8_builtins = Flake8BuiltinsOptions::default(); @@ -150,7 +151,7 @@ pub(crate) fn convert( "per-file-ignores" | "per_file_ignores" => { match parser::parse_files_to_codes_mapping(value.as_ref()) { Ok(per_file_ignores) => { - options.per_file_ignores = + lint_options.per_file_ignores = Some(parser::collect_per_file_ignores(per_file_ignores)); } Err(e) => { @@ -358,47 +359,47 @@ pub(crate) fn convert( } // Deduplicate and sort. - options.select = Some( + lint_options.select = Some( select .into_iter() .sorted_by_key(RuleSelector::prefix_and_code) .collect(), ); - options.ignore = Some( + lint_options.ignore = Some( ignore .into_iter() .sorted_by_key(RuleSelector::prefix_and_code) .collect(), ); if flake8_annotations != Flake8AnnotationsOptions::default() { - options.flake8_annotations = Some(flake8_annotations); + lint_options.flake8_annotations = Some(flake8_annotations); } if flake8_bugbear != Flake8BugbearOptions::default() { - options.flake8_bugbear = Some(flake8_bugbear); + lint_options.flake8_bugbear = Some(flake8_bugbear); } if flake8_builtins != Flake8BuiltinsOptions::default() { - options.flake8_builtins = Some(flake8_builtins); + lint_options.flake8_builtins = Some(flake8_builtins); } if flake8_errmsg != Flake8ErrMsgOptions::default() { - options.flake8_errmsg = Some(flake8_errmsg); + lint_options.flake8_errmsg = Some(flake8_errmsg); } if flake8_pytest_style != Flake8PytestStyleOptions::default() { - options.flake8_pytest_style = Some(flake8_pytest_style); + lint_options.flake8_pytest_style = Some(flake8_pytest_style); } if flake8_quotes != Flake8QuotesOptions::default() { - options.flake8_quotes = Some(flake8_quotes); + lint_options.flake8_quotes = Some(flake8_quotes); } if flake8_tidy_imports != Flake8TidyImportsOptions::default() { - options.flake8_tidy_imports = Some(flake8_tidy_imports); + lint_options.flake8_tidy_imports = Some(flake8_tidy_imports); } if mccabe != McCabeOptions::default() { - options.mccabe = Some(mccabe); + lint_options.mccabe = Some(mccabe); } if pep8_naming != Pep8NamingOptions::default() { - options.pep8_naming = Some(pep8_naming); + lint_options.pep8_naming = Some(pep8_naming); } if pydocstyle != PydocstyleOptions::default() { - options.pydocstyle = Some(pydocstyle); + lint_options.pydocstyle = Some(pydocstyle); } // Extract any settings from the existing `pyproject.toml`. @@ -436,6 +437,10 @@ pub(crate) fn convert( } } + if lint_options != LintOptions::default() { + options.lint = Some(lint_options); + } + // Create the pyproject.toml. Pyproject::new(options) } @@ -464,7 +469,7 @@ mod tests { use ruff_linter::rules::flake8_quotes; use ruff_linter::rules::pydocstyle::settings::Convention; use ruff_linter::settings::types::PythonVersion; - use ruff_workspace::options::{Flake8QuotesOptions, Options, PydocstyleOptions}; + use ruff_workspace::options::{Flake8QuotesOptions, LintOptions, Options, PydocstyleOptions}; use ruff_workspace::pyproject::Pyproject; use crate::converter::DEFAULT_SELECTORS; @@ -474,8 +479,8 @@ mod tests { use super::super::plugin::Plugin; use super::convert; - fn default_options(plugins: impl IntoIterator) -> Options { - Options { + fn lint_default_options(plugins: impl IntoIterator) -> LintOptions { + LintOptions { ignore: Some(vec![]), select: Some( DEFAULT_SELECTORS @@ -485,7 +490,7 @@ mod tests { .sorted_by_key(RuleSelector::prefix_and_code) .collect(), ), - ..Options::default() + ..LintOptions::default() } } @@ -496,7 +501,10 @@ mod tests { &ExternalConfig::default(), None, ); - let expected = Pyproject::new(default_options([])); + let expected = Pyproject::new(Options { + lint: Some(lint_default_options([])), + ..Options::default() + }); assert_eq!(actual, expected); } @@ -512,7 +520,8 @@ mod tests { ); let expected = Pyproject::new(Options { line_length: Some(LineLength::try_from(100).unwrap()), - ..default_options([]) + lint: Some(lint_default_options([])), + ..Options::default() }); assert_eq!(actual, expected); } @@ -529,7 +538,8 @@ mod tests { ); let expected = Pyproject::new(Options { line_length: Some(LineLength::try_from(100).unwrap()), - ..default_options([]) + lint: Some(lint_default_options([])), + ..Options::default() }); assert_eq!(actual, expected); } @@ -544,7 +554,10 @@ mod tests { &ExternalConfig::default(), Some(vec![]), ); - let expected = Pyproject::new(default_options([])); + let expected = Pyproject::new(Options { + lint: Some(lint_default_options([])), + ..Options::default() + }); assert_eq!(actual, expected); } @@ -559,13 +572,16 @@ mod tests { Some(vec![]), ); let expected = Pyproject::new(Options { - flake8_quotes: Some(Flake8QuotesOptions { - inline_quotes: Some(flake8_quotes::settings::Quote::Single), - multiline_quotes: None, - docstring_quotes: None, - avoid_escape: None, + lint: Some(LintOptions { + flake8_quotes: Some(Flake8QuotesOptions { + inline_quotes: Some(flake8_quotes::settings::Quote::Single), + multiline_quotes: None, + docstring_quotes: None, + avoid_escape: None, + }), + ..lint_default_options([]) }), - ..default_options([]) + ..Options::default() }); assert_eq!(actual, expected); } @@ -584,12 +600,15 @@ mod tests { Some(vec![Plugin::Flake8Docstrings]), ); let expected = Pyproject::new(Options { - pydocstyle: Some(PydocstyleOptions { - convention: Some(Convention::Numpy), - ignore_decorators: None, - property_decorators: None, + lint: Some(LintOptions { + pydocstyle: Some(PydocstyleOptions { + convention: Some(Convention::Numpy), + ignore_decorators: None, + property_decorators: None, + }), + ..lint_default_options([Linter::Pydocstyle.into()]) }), - ..default_options([Linter::Pydocstyle.into()]) + ..Options::default() }); assert_eq!(actual, expected); } @@ -605,13 +624,16 @@ mod tests { None, ); let expected = Pyproject::new(Options { - flake8_quotes: Some(Flake8QuotesOptions { - inline_quotes: Some(flake8_quotes::settings::Quote::Single), - multiline_quotes: None, - docstring_quotes: None, - avoid_escape: None, + lint: Some(LintOptions { + flake8_quotes: Some(Flake8QuotesOptions { + inline_quotes: Some(flake8_quotes::settings::Quote::Single), + multiline_quotes: None, + docstring_quotes: None, + avoid_escape: None, + }), + ..lint_default_options([Linter::Flake8Quotes.into()]) }), - ..default_options([Linter::Flake8Quotes.into()]) + ..Options::default() }); assert_eq!(actual, expected); } @@ -630,7 +652,8 @@ mod tests { ); let expected = Pyproject::new(Options { target_version: Some(PythonVersion::Py38), - ..default_options([]) + lint: Some(lint_default_options([])), + ..Options::default() }); assert_eq!(actual, expected); diff --git a/crates/ruff_cli/src/args.rs b/crates/ruff_cli/src/args.rs index b3159f4eb6ab5..06eadb86b3e44 100644 --- a/crates/ruff_cli/src/args.rs +++ b/crates/ruff_cli/src/args.rs @@ -610,7 +610,7 @@ impl ConfigurationTransformer for CliOverrides { config.cache_dir = Some(cache_dir.clone()); } if let Some(dummy_variable_rgx) = &self.dummy_variable_rgx { - config.dummy_variable_rgx = Some(dummy_variable_rgx.clone()); + config.lint.dummy_variable_rgx = Some(dummy_variable_rgx.clone()); } if let Some(exclude) = &self.exclude { config.exclude = Some(exclude.clone()); @@ -624,7 +624,7 @@ impl ConfigurationTransformer for CliOverrides { if let Some(fix_only) = &self.fix_only { config.fix_only = Some(*fix_only); } - config.rule_selections.push(RuleSelection { + config.lint.rule_selections.push(RuleSelection { select: self.select.clone(), ignore: self .ignore @@ -657,7 +657,7 @@ impl ConfigurationTransformer for CliOverrides { config.preview = Some(*preview); } if let Some(per_file_ignores) = &self.per_file_ignores { - config.per_file_ignores = Some(collect_per_file_ignores(per_file_ignores.clone())); + config.lint.per_file_ignores = Some(collect_per_file_ignores(per_file_ignores.clone())); } if let Some(respect_gitignore) = &self.respect_gitignore { config.respect_gitignore = Some(*respect_gitignore); diff --git a/crates/ruff_cli/tests/snapshots/integration_test__explain_status_codes_f401.snap b/crates/ruff_cli/tests/snapshots/integration_test__explain_status_codes_f401.snap index 17615bf57049e..21f4c24801fb5 100644 --- a/crates/ruff_cli/tests/snapshots/integration_test__explain_status_codes_f401.snap +++ b/crates/ruff_cli/tests/snapshots/integration_test__explain_status_codes_f401.snap @@ -51,7 +51,7 @@ else: ``` ## Options -- `pyflakes.extend-generics` +- `lint.pyflakes.extend-generics` ## References - [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement) diff --git a/crates/ruff_dev/src/generate_docs.rs b/crates/ruff_dev/src/generate_docs.rs index 3cbb295509513..00a52ac36c97b 100644 --- a/crates/ruff_dev/src/generate_docs.rs +++ b/crates/ruff_dev/src/generate_docs.rs @@ -127,13 +127,13 @@ mod tests { let mut output = String::new(); process_documentation( " -See also [`mccabe.max-complexity`] and [`task-tags`]. +See also [`lint.mccabe.max-complexity`] and [`lint.task-tags`]. Something [`else`][other]. ## Options -- `task-tags` -- `mccabe.max-complexity` +- `lint.task-tags` +- `lint.mccabe.max-complexity` [other]: http://example.com.", &mut output, @@ -141,18 +141,18 @@ Something [`else`][other]. assert_eq!( output, " -See also [`mccabe.max-complexity`][mccabe.max-complexity] and [`task-tags`][task-tags]. +See also [`lint.mccabe.max-complexity`][lint.mccabe.max-complexity] and [`lint.task-tags`][lint.task-tags]. Something [`else`][other]. ## Options -- [`task-tags`][task-tags] -- [`mccabe.max-complexity`][mccabe.max-complexity] +- [`lint.task-tags`][lint.task-tags] +- [`lint.mccabe.max-complexity`][lint.mccabe.max-complexity] [other]: http://example.com. -[task-tags]: ../settings.md#task-tags -[mccabe.max-complexity]: ../settings.md#mccabe-max-complexity +[lint.task-tags]: ../settings.md#lint-task-tags +[lint.mccabe.max-complexity]: ../settings.md#lint-mccabe-max-complexity " ); } diff --git a/crates/ruff_linter/src/rules/eradicate/rules/commented_out_code.rs b/crates/ruff_linter/src/rules/eradicate/rules/commented_out_code.rs index 7c712f20a167e..220929dfb1288 100644 --- a/crates/ruff_linter/src/rules/eradicate/rules/commented_out_code.rs +++ b/crates/ruff_linter/src/rules/eradicate/rules/commented_out_code.rs @@ -21,7 +21,7 @@ use super::super::detection::comment_contains_code; /// ``` /// /// ## Options -/// - `task-tags` +/// - `lint.task-tags` #[violation] pub struct CommentedOutCode; diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/function_call_in_argument_default.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/function_call_in_argument_default.rs index 964026d5f09e0..2950c56a5d20f 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/function_call_in_argument_default.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/function_call_in_argument_default.rs @@ -51,7 +51,7 @@ use crate::checkers::ast::Checker; /// ``` /// /// ## Options -/// - `flake8-bugbear.extend-immutable-calls` +/// - `lint.flake8-bugbear.extend-immutable-calls` #[violation] pub struct FunctionCallInDefaultArgument { name: Option, diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/mutable_argument_default.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/mutable_argument_default.rs index f604d18d0c887..b0d0a78cb2af3 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/mutable_argument_default.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/mutable_argument_default.rs @@ -56,7 +56,7 @@ use crate::registry::AsRule; /// ``` /// /// ## Options -/// - `flake8-bugbear.extend-immutable-calls` +/// - `lint.flake8-bugbear.extend-immutable-calls` /// /// ## References /// - [Python documentation: Default Argument Values](https://docs.python.org/3/tutorial/controlflow.html#default-argument-values) diff --git a/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_argument_shadowing.rs b/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_argument_shadowing.rs index 9406879f2fff5..6e91d458e2021 100644 --- a/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_argument_shadowing.rs +++ b/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_argument_shadowing.rs @@ -44,7 +44,7 @@ use super::super::helpers::shadows_builtin; /// ``` /// /// ## Options -/// - `flake8-builtins.builtins-ignorelist` +/// - `lint.flake8-builtins.builtins-ignorelist` /// /// ## References /// - [_Is it bad practice to use a built-in function name as an attribute or method identifier?_](https://stackoverflow.com/questions/9109333/is-it-bad-practice-to-use-a-built-in-function-name-as-an-attribute-or-method-ide) diff --git a/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_attribute_shadowing.rs b/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_attribute_shadowing.rs index baf682a11011d..25ef826cd756a 100644 --- a/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_attribute_shadowing.rs +++ b/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_attribute_shadowing.rs @@ -49,7 +49,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin; /// ``` /// /// ## Options -/// - `flake8-builtins.builtins-ignorelist` +/// - `lint.flake8-builtins.builtins-ignorelist` /// /// ## References /// - [_Is it bad practice to use a built-in function name as an attribute or method identifier?_](https://stackoverflow.com/questions/9109333/is-it-bad-practice-to-use-a-built-in-function-name-as-an-attribute-or-method-ide) diff --git a/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_variable_shadowing.rs b/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_variable_shadowing.rs index 74aa7c2e25f0a..b8bc9110e1820 100644 --- a/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_variable_shadowing.rs +++ b/crates/ruff_linter/src/rules/flake8_builtins/rules/builtin_variable_shadowing.rs @@ -41,7 +41,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin; /// ``` /// /// ## Options -/// - `flake8-builtins.builtins-ignorelist` +/// - `lint.flake8-builtins.builtins-ignorelist` /// /// ## References /// - [_Why is it a bad idea to name a variable `id` in Python?_](https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python) diff --git a/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/implicit.rs b/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/implicit.rs index 0a2e381a55a9a..8718863fb2215 100644 --- a/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/implicit.rs +++ b/crates/ruff_linter/src/rules/flake8_implicit_str_concat/rules/implicit.rs @@ -75,7 +75,7 @@ impl Violation for SingleLineImplicitStringConcatenation { /// ``` /// /// ## Options -/// - `flake8-implicit-str-concat.allow-multiline` +/// - `lint.flake8-implicit-str-concat.allow-multiline` /// /// [PEP 8]: https://peps.python.org/pep-0008/#maximum-line-length #[violation] diff --git a/crates/ruff_linter/src/rules/flake8_logging_format/violations.rs b/crates/ruff_linter/src/rules/flake8_logging_format/violations.rs index 77a96c7fce53f..1662aa2e22c32 100644 --- a/crates/ruff_linter/src/rules/flake8_logging_format/violations.rs +++ b/crates/ruff_linter/src/rules/flake8_logging_format/violations.rs @@ -68,7 +68,7 @@ use ruff_macros::{derive_message_formats, violation}; /// ``` /// /// ## Options -/// - `logger-objects` +/// - `lint.logger-objects` /// /// ## References /// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html) @@ -152,7 +152,7 @@ impl Violation for LoggingStringFormat { /// ``` /// /// ## Options -/// - `logger-objects` +/// - `lint.logger-objects` /// /// ## References /// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html) @@ -235,7 +235,7 @@ impl Violation for LoggingPercentFormat { /// ``` /// /// ## Options -/// - `logger-objects` +/// - `lint.logger-objects` /// /// ## References /// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html) @@ -317,7 +317,7 @@ impl Violation for LoggingStringConcat { /// ``` /// /// ## Options -/// - `logger-objects` +/// - `lint.logger-objects` /// /// ## References /// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html) @@ -368,7 +368,7 @@ impl Violation for LoggingFString { /// ``` /// /// ## Options -/// - `logger-objects` +/// - `lint.logger-objects` /// /// ## References /// - [Python documentation: `logging.warning`](https://docs.python.org/3/library/logging.html#logging.warning) @@ -436,7 +436,7 @@ impl AlwaysAutofixableViolation for LoggingWarn { /// ``` /// /// ## Options -/// - `logger-objects` +/// - `lint.logger-objects` /// /// ## References /// - [Python documentation: LogRecord attributes](https://docs.python.org/3/library/logging.html#logrecord-attributes) @@ -495,7 +495,7 @@ impl Violation for LoggingExtraAttrClash { /// ``` /// /// ## Options -/// - `logger-objects` +/// - `lint.logger-objects` /// /// ## References /// - [Python documentation: `logging.exception`](https://docs.python.org/3/library/logging.html#logging.exception) @@ -556,7 +556,7 @@ impl Violation for LoggingExcInfo { /// ``` /// /// ## Options -/// - `logger-objects` +/// - `lint.logger-objects` /// /// ## References /// - [Python documentation: `logging.exception`](https://docs.python.org/3/library/logging.html#logging.exception) diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/fixture.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/fixture.rs index 4e401c6b44d12..ff805cd7e38ad 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/fixture.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/fixture.rs @@ -55,7 +55,7 @@ use super::helpers::{ /// ``` /// /// ## Options -/// - `flake8-pytest-style.fixture-parentheses` +/// - `lint.flake8-pytest-style.fixture-parentheses` /// /// ## References /// - [`pytest` documentation: API Reference: Fixtures](https://docs.pytest.org/en/latest/reference/reference.html#fixtures-api) diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/marks.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/marks.rs index 01a3d3fc60da4..619db8f87cce7 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/marks.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/marks.rs @@ -43,7 +43,7 @@ use super::helpers::get_mark_decorators; /// ``` /// /// ## Options -/// - `flake8-pytest-style.mark-parentheses` +/// - `lint.flake8-pytest-style.mark-parentheses` /// /// ## References /// - [`pytest` documentation: Marks](https://docs.pytest.org/en/latest/reference/reference.html#marks) diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs index 293c4b8f08c75..b09919773f9f9 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/parametrize.rs @@ -67,7 +67,7 @@ use super::helpers::{is_pytest_parametrize, split_names}; /// ``` /// /// ## Options -/// - `flake8-pytest-style.parametrize-names-type` +/// - `lint.flake8-pytest-style.parametrize-names-type` /// /// ## References /// - [`pytest` documentation: How to parametrize fixtures and test functions](https://docs.pytest.org/en/latest/how-to/parametrize.html#pytest-mark-parametrize) @@ -170,8 +170,8 @@ impl Violation for PytestParametrizeNamesWrongType { /// ``` /// /// ## Options -/// - `flake8-pytest-style.parametrize-values-type` -/// - `flake8-pytest-style.parametrize-values-row-type` +/// - `lint.flake8-pytest-style.parametrize-values-type` +/// - `lint.flake8-pytest-style.parametrize-values-row-type` /// /// ## References /// - [`pytest` documentation: How to parametrize fixtures and test functions](https://docs.pytest.org/en/latest/how-to/parametrize.html#pytest-mark-parametrize) diff --git a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/raises.rs b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/raises.rs index ec457155bd1e4..88852b1fa10a2 100644 --- a/crates/ruff_linter/src/rules/flake8_pytest_style/rules/raises.rs +++ b/crates/ruff_linter/src/rules/flake8_pytest_style/rules/raises.rs @@ -92,8 +92,8 @@ impl Violation for PytestRaisesWithMultipleStatements { /// ``` /// /// ## Options -/// - `flake8-pytest-style.raises-require-match-for` -/// - `flake8-pytest-style.raises-extend-require-match-for` +/// - `lint.flake8-pytest-style.raises-require-match-for` +/// - `lint.flake8-pytest-style.raises-extend-require-match-for` /// /// ## References /// - [`pytest` documentation: `pytest.raises`](https://docs.pytest.org/en/latest/reference/reference.html#pytest-raises) diff --git a/crates/ruff_linter/src/rules/flake8_quotes/rules/from_tokens.rs b/crates/ruff_linter/src/rules/flake8_quotes/rules/from_tokens.rs index 7cb159008147a..a218d45dd38b7 100644 --- a/crates/ruff_linter/src/rules/flake8_quotes/rules/from_tokens.rs +++ b/crates/ruff_linter/src/rules/flake8_quotes/rules/from_tokens.rs @@ -31,7 +31,7 @@ use super::super::settings::Quote; /// ``` /// /// ## Options -/// - `flake8-quotes.inline-quotes` +/// - `lint.flake8-quotes.inline-quotes` #[violation] pub struct BadQuotesInlineString { quote: Quote, @@ -80,7 +80,7 @@ impl AlwaysAutofixableViolation for BadQuotesInlineString { /// ``` /// /// ## Options -/// - `flake8-quotes.multiline-quotes` +/// - `lint.flake8-quotes.multiline-quotes` #[violation] pub struct BadQuotesMultilineString { quote: Quote, @@ -128,7 +128,7 @@ impl AlwaysAutofixableViolation for BadQuotesMultilineString { /// ``` /// /// ## Options -/// - `flake8-quotes.docstring-quotes` +/// - `lint.flake8-quotes.docstring-quotes` #[violation] pub struct BadQuotesDocstring { quote: Quote, diff --git a/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs b/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs index 543c4d36d7348..473d0355ab28c 100644 --- a/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs +++ b/crates/ruff_linter/src/rules/flake8_self/rules/private_member_access.rs @@ -43,7 +43,7 @@ use crate::checkers::ast::Checker; /// ``` /// /// ## Options -/// - `flake8-self.ignore-names` +/// - `lint.flake8-self.ignore-names` /// /// ## References /// - [_What is the meaning of single or double underscores before an object name?_](https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-single-and-double-underscore-before-an-object-name) diff --git a/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/banned_api.rs b/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/banned_api.rs index 98ea3ab488887..fe3bdbada0a91 100644 --- a/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/banned_api.rs +++ b/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/banned_api.rs @@ -24,7 +24,7 @@ use crate::rules::flake8_tidy_imports::matchers::NameMatchPolicy; /// automatic way. /// /// ## Options -/// - `flake8-tidy-imports.banned-api` +/// - `lint.flake8-tidy-imports.banned-api` #[violation] pub struct BannedApi { name: String, diff --git a/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/banned_module_level_imports.rs b/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/banned_module_level_imports.rs index 61c0006544553..53b2601bea26e 100644 --- a/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/banned_module_level_imports.rs +++ b/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/banned_module_level_imports.rs @@ -38,7 +38,7 @@ use crate::rules::flake8_tidy_imports::matchers::NameMatchPolicy; /// ``` /// /// ## Options -/// - `flake8-tidy-imports.banned-module-level-imports` +/// - `lint.flake8-tidy-imports.banned-module-level-imports` #[violation] pub struct BannedModuleLevelImports { name: String, diff --git a/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/relative_imports.rs b/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/relative_imports.rs index 30947874c9b47..20236415c7f93 100644 --- a/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/relative_imports.rs +++ b/crates/ruff_linter/src/rules/flake8_tidy_imports/rules/relative_imports.rs @@ -42,7 +42,7 @@ use crate::rules::flake8_tidy_imports::settings::Strictness; /// ``` /// /// ## Options -/// - `flake8-tidy-imports.ban-relative-imports` +/// - `lint.flake8-tidy-imports.ban-relative-imports` /// /// [PEP 8]: https://peps.python.org/pep-0008/#imports #[violation] diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs b/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs index eb933f2c31e9a..42b9f8a2ee05e 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/rules/typing_only_runtime_import.rs @@ -56,8 +56,8 @@ use crate::rules::isort::{categorize, ImportSection, ImportType}; /// ``` /// /// ## Options -/// - `flake8-type-checking.runtime-evaluated-base-classes` -/// - `flake8-type-checking.runtime-evaluated-decorators` +/// - `lint.flake8-type-checking.runtime-evaluated-base-classes` +/// - `lint.flake8-type-checking.runtime-evaluated-decorators` /// /// ## References /// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking) @@ -124,8 +124,8 @@ impl Violation for TypingOnlyFirstPartyImport { /// ``` /// /// ## Options -/// - `flake8-type-checking.runtime-evaluated-base-classes` -/// - `flake8-type-checking.runtime-evaluated-decorators` +/// - `lint.flake8-type-checking.runtime-evaluated-base-classes` +/// - `lint.flake8-type-checking.runtime-evaluated-decorators` /// /// ## References /// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking) @@ -192,8 +192,8 @@ impl Violation for TypingOnlyThirdPartyImport { /// ``` /// /// ## Options -/// - `flake8-type-checking.runtime-evaluated-base-classes` -/// - `flake8-type-checking.runtime-evaluated-decorators` +/// - `lint.flake8-type-checking.runtime-evaluated-base-classes` +/// - `lint.flake8-type-checking.runtime-evaluated-decorators` /// /// ## References /// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking) diff --git a/crates/ruff_linter/src/rules/mccabe/rules/function_is_too_complex.rs b/crates/ruff_linter/src/rules/mccabe/rules/function_is_too_complex.rs index c56ae7e2ed4ab..165c7ada10a78 100644 --- a/crates/ruff_linter/src/rules/mccabe/rules/function_is_too_complex.rs +++ b/crates/ruff_linter/src/rules/mccabe/rules/function_is_too_complex.rs @@ -44,7 +44,7 @@ use ruff_python_ast::identifier::Identifier; /// ``` /// /// ## Options -/// - `mccabe.max-complexity` +/// - `lint.mccabe.max-complexity` #[violation] pub struct ComplexStructure { name: String, diff --git a/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs b/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs index ff0846786d5ee..f09e0b499acff 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs +++ b/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_first_argument_name_for_class_method.rs @@ -39,9 +39,9 @@ use crate::checkers::ast::Checker; /// ``` /// /// ## Options -/// - `pep8-naming.classmethod-decorators` -/// - `pep8-naming.staticmethod-decorators` -/// - `pep8-naming.ignore-names` +/// - `lint.pep8-naming.classmethod-decorators` +/// - `lint.pep8-naming.staticmethod-decorators` +/// - `lint.pep8-naming.ignore-names` /// /// [PEP 8]: https://peps.python.org/pep-0008/#function-and-method-arguments #[violation] diff --git a/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs b/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs index 4e18781e624e6..a691b90c96f34 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs +++ b/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_first_argument_name_for_method.rs @@ -37,9 +37,9 @@ use crate::checkers::ast::Checker; /// ``` /// /// ## Options -/// - `pep8-naming.classmethod-decorators` -/// - `pep8-naming.staticmethod-decorators` -/// - `pep8-naming.ignore-names` +/// - `lint.pep8-naming.classmethod-decorators` +/// - `lint.pep8-naming.staticmethod-decorators` +/// - `lint.pep8-naming.ignore-names` /// /// [PEP 8]: https://peps.python.org/pep-0008/#function-and-method-arguments #[violation] diff --git a/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_function_name.rs b/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_function_name.rs index 468b29dc7a2c4..4e8b429e21a8f 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_function_name.rs +++ b/crates/ruff_linter/src/rules/pep8_naming/rules/invalid_function_name.rs @@ -33,7 +33,7 @@ use crate::settings::types::IdentifierPattern; /// ``` /// /// ## Options -/// - `pep8-naming.ignore-names` +/// - `lint.pep8-naming.ignore-names` /// /// [PEP 8]: https://peps.python.org/pep-0008/#function-and-variable-names #[violation] diff --git a/crates/ruff_linter/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs b/crates/ruff_linter/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs index e8bae1c0eee3c..d190f9ba85990 100644 --- a/crates/ruff_linter/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs +++ b/crates/ruff_linter/src/rules/pep8_naming/rules/non_lowercase_variable_in_function.rs @@ -34,7 +34,7 @@ use crate::rules::pep8_naming::helpers; /// ``` /// /// ## Options -/// - `pep8-naming.ignore-names` +/// - `lint.pep8-naming.ignore-names` /// /// [PEP 8]: https://peps.python.org/pep-0008/#function-and-variable-names #[violation] diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/doc_line_too_long.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/doc_line_too_long.rs index efa002ab84177..40744ef9e9e46 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/doc_line_too_long.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/doc_line_too_long.rs @@ -44,9 +44,9 @@ use crate::settings::LinterSettings; /// ``` /// /// ## Options -/// - `task-tags` -/// - `pycodestyle.max-doc-length` -/// - `pycodestyle.ignore-overlong-task-comments` +/// - `lint.task-tags` +/// - `lint.pycodestyle.max-doc-length` +/// - `lint.pycodestyle.ignore-overlong-task-comments` /// /// [PEP 8]: https://peps.python.org/pep-0008/#maximum-line-length #[violation] diff --git a/crates/ruff_linter/src/rules/pycodestyle/rules/line_too_long.rs b/crates/ruff_linter/src/rules/pycodestyle/rules/line_too_long.rs index db18c37f1e662..16c79ffac2f0b 100644 --- a/crates/ruff_linter/src/rules/pycodestyle/rules/line_too_long.rs +++ b/crates/ruff_linter/src/rules/pycodestyle/rules/line_too_long.rs @@ -39,8 +39,8 @@ use crate::settings::LinterSettings; /// /// ## Options /// - `line-length` -/// - `task-tags` -/// - `pycodestyle.ignore-overlong-task-comments` +/// - `lint.task-tags` +/// - `lint.pycodestyle.ignore-overlong-task-comments` /// /// [PEP 8]: https://peps.python.org/pep-0008/#maximum-line-length #[violation] diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/blank_before_after_class.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/blank_before_after_class.rs index 4f74fb736dc2d..fe388f8aaa724 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/blank_before_after_class.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/blank_before_after_class.rs @@ -37,7 +37,7 @@ use crate::registry::{AsRule, Rule}; /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// [D211]: https://docs.astral.sh/ruff/rules/blank-line-before-class #[violation] @@ -84,7 +84,7 @@ impl AlwaysAutofixableViolation for OneBlankLineBeforeClass { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -134,7 +134,7 @@ impl AlwaysAutofixableViolation for OneBlankLineAfterClass { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// [D203]: https://docs.astral.sh/ruff/rules/one-blank-line-before-class #[violation] diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/ends_with_period.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/ends_with_period.rs index 57c2b63fd0016..13069e48c1297 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/ends_with_period.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/ends_with_period.rs @@ -36,7 +36,7 @@ use crate::rules::pydocstyle::helpers::logical_line; /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/ends_with_punctuation.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/ends_with_punctuation.rs index 05ec17ddb1500..0168a171d1c98 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/ends_with_punctuation.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/ends_with_punctuation.rs @@ -37,7 +37,7 @@ use crate::rules::pydocstyle::helpers::logical_line; /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/no_signature.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/no_signature.rs index b9e186c0929e9..bbd492cad10d2 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/no_signature.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/no_signature.rs @@ -32,7 +32,7 @@ use crate::docstrings::Docstring; /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/non_imperative_mood.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/non_imperative_mood.rs index ca6f210d0abd8..5d779ba1db6d9 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/non_imperative_mood.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/non_imperative_mood.rs @@ -43,7 +43,7 @@ static MOOD: Lazy = Lazy::new(Mood::new); /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/sections.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/sections.rs index 34f78655c89ca..a9f96f1ad9a2d 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/sections.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/sections.rs @@ -76,7 +76,7 @@ use crate::rules::pydocstyle::settings::Convention; /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -175,7 +175,7 @@ impl AlwaysAutofixableViolation for SectionNotOverIndented { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -253,7 +253,7 @@ impl AlwaysAutofixableViolation for SectionUnderlineNotOverIndented { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -350,7 +350,7 @@ impl AlwaysAutofixableViolation for CapitalizeSectionName { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -446,7 +446,7 @@ impl AlwaysAutofixableViolation for NewLineAfterSectionName { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -548,7 +548,7 @@ impl AlwaysAutofixableViolation for DashedUnderlineAfterSection { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -647,7 +647,7 @@ impl AlwaysAutofixableViolation for SectionUnderlineAfterName { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -741,7 +741,7 @@ impl AlwaysAutofixableViolation for SectionUnderlineMatchesSectionLength { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -835,7 +835,7 @@ impl AlwaysAutofixableViolation for NoBlankLineAfterSection { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -931,7 +931,7 @@ impl AlwaysAutofixableViolation for NoBlankLineBeforeSection { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -1021,7 +1021,7 @@ impl AlwaysAutofixableViolation for BlankLineAfterLastSection { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -1098,7 +1098,7 @@ impl Violation for EmptyDocstringSection { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -1180,7 +1180,7 @@ impl AlwaysAutofixableViolation for SectionNameEndsInColon { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) @@ -1264,7 +1264,7 @@ impl Violation for UndocumentedParam { /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/starts_with_this.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/starts_with_this.rs index 0cd38e1114c3a..2d9034a2b0991 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/starts_with_this.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/starts_with_this.rs @@ -33,7 +33,7 @@ use crate::rules::pydocstyle::helpers::normalize_word; /// ``` /// /// ## Options -/// - `pydocstyle.convention` +/// - `lint.pydocstyle.convention` /// /// ## References /// - [PEP 257 – Docstring Conventions](https://peps.python.org/pep-0257/) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs index d9899a483f1cd..85ffe2f4282dc 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_import.rs @@ -54,7 +54,7 @@ enum UnusedImportContext { /// ``` /// /// ## Options -/// - `pyflakes.extend-generics` +/// - `lint.pyflakes.extend-generics` /// /// ## References /// - [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement) diff --git a/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs b/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs index 64aaa16e757dc..d151259e35025 100644 --- a/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs +++ b/crates/ruff_linter/src/rules/pyflakes/rules/unused_variable.rs @@ -41,7 +41,7 @@ use crate::registry::AsRule; /// ``` /// /// ## Options -/// - `dummy-variable-rgx` +/// - `lint.dummy-variable-rgx` #[violation] pub struct UnusedVariable { pub name: String, diff --git a/crates/ruff_linter/src/rules/pylint/rules/too_many_arguments.rs b/crates/ruff_linter/src/rules/pylint/rules/too_many_arguments.rs index 8948aeb0cc152..44af3c77367cf 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/too_many_arguments.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/too_many_arguments.rs @@ -42,7 +42,7 @@ use crate::checkers::ast::Checker; /// ``` /// /// ## Options -/// - `pylint.max-args` +/// - `lint.pylint.max-args` #[violation] pub struct TooManyArguments { c_args: usize, diff --git a/crates/ruff_linter/src/rules/pylint/rules/too_many_branches.rs b/crates/ruff_linter/src/rules/pylint/rules/too_many_branches.rs index 7c083b10f7654..a62fc93c6b996 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/too_many_branches.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/too_many_branches.rs @@ -67,7 +67,7 @@ use ruff_python_ast::identifier::Identifier; /// ``` /// /// ## Options -/// - `pylint.max-branches` +/// - `lint.pylint.max-branches` #[violation] pub struct TooManyBranches { branches: usize, diff --git a/crates/ruff_linter/src/rules/pylint/rules/too_many_public_methods.rs b/crates/ruff_linter/src/rules/pylint/rules/too_many_public_methods.rs index 7e7c113d80ad4..9caa94f4624d4 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/too_many_public_methods.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/too_many_public_methods.rs @@ -81,7 +81,7 @@ use crate::checkers::ast::Checker; /// ``` /// /// ## Options -/// - `pylint.max-public-methods` +/// - `lint.pylint.max-public-methods` #[violation] pub struct TooManyPublicMethods { methods: usize, diff --git a/crates/ruff_linter/src/rules/pylint/rules/too_many_return_statements.rs b/crates/ruff_linter/src/rules/pylint/rules/too_many_return_statements.rs index 8fc7fe16e6134..fc776a75a9115 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/too_many_return_statements.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/too_many_return_statements.rs @@ -50,7 +50,7 @@ use ruff_python_ast::statement_visitor::StatementVisitor; /// ``` /// /// ## Options -/// - `pylint.max-returns` +/// - `lint.pylint.max-returns` #[violation] pub struct TooManyReturnStatements { returns: usize, diff --git a/crates/ruff_linter/src/rules/pylint/rules/too_many_statements.rs b/crates/ruff_linter/src/rules/pylint/rules/too_many_statements.rs index 406f5959fc33a..9e313980addae 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/too_many_statements.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/too_many_statements.rs @@ -44,7 +44,7 @@ use ruff_python_ast::identifier::Identifier; /// ``` /// /// ## Options -/// - `pylint.max-statements` +/// - `lint.pylint.max-statements` #[violation] pub struct TooManyStatements { statements: usize, diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs index aaeef4bba0ffb..5c12f5a09da82 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs @@ -46,7 +46,7 @@ use crate::registry::AsRule; /// /// ## Options /// - `target-version` -/// - `pyupgrade.keep-runtime-typing` +/// - `lint.pyupgrade.keep-runtime-typing` /// /// [PEP 585]: https://peps.python.org/pep-0585/ #[violation] diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs index c1fbbfa6cec22..8e9111d799049 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs @@ -38,7 +38,7 @@ use crate::registry::AsRule; /// /// ## Options /// - `target-version` -/// - `pyupgrade.keep-runtime-typing` +/// - `lint.pyupgrade.keep-runtime-typing` /// /// [PEP 604]: https://peps.python.org/pep-0604/ #[violation] diff --git a/crates/ruff_linter/src/rules/ruff/rules/function_call_in_dataclass_default.rs b/crates/ruff_linter/src/rules/ruff/rules/function_call_in_dataclass_default.rs index f8d5af0672698..5e23bcb9ab368 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/function_call_in_dataclass_default.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/function_call_in_dataclass_default.rs @@ -53,7 +53,7 @@ use crate::rules::ruff::rules::helpers::{ /// ``` /// /// ## Options -/// - `flake8-bugbear.extend-immutable-calls` +/// - `lint.flake8-bugbear.extend-immutable-calls` #[violation] pub struct FunctionCallInDataclassDefaultArgument { name: Option, diff --git a/crates/ruff_wasm/src/lib.rs b/crates/ruff_wasm/src/lib.rs index e3a6974e6b28c..789d233ee11d6 100644 --- a/crates/ruff_wasm/src/lib.rs +++ b/crates/ruff_wasm/src/lib.rs @@ -6,11 +6,9 @@ use wasm_bindgen::prelude::*; use ruff_formatter::{FormatResult, Formatted}; use ruff_linter::directives; -use ruff_linter::line_width::{LineLength, TabSize}; use ruff_linter::linter::{check_path, LinterResult}; use ruff_linter::registry::AsRule; -use ruff_linter::settings::types::PythonVersion; -use ruff_linter::settings::{flags, DUMMY_VARIABLE_RGX, PREFIXES}; +use ruff_linter::settings::flags; use ruff_linter::source_kind::SourceKind; use ruff_python_ast::{Mod, PySourceType}; use ruff_python_codegen::Stylist; @@ -22,7 +20,7 @@ use ruff_python_trivia::CommentRanges; use ruff_source_file::{Locator, SourceLocation}; use ruff_text_size::Ranged; use ruff_workspace::configuration::Configuration; -use ruff_workspace::options::Options; +use ruff_workspace::options::{LintOptions, Options}; use ruff_workspace::Settings; #[wasm_bindgen(typescript_custom_section)] @@ -119,46 +117,34 @@ impl Workspace { #[wasm_bindgen(js_name = defaultSettings)] pub fn default_settings() -> Result { serde_wasm_bindgen::to_value(&Options { - // Propagate defaults. - allowed_confusables: Some(Vec::default()), - builtins: Some(Vec::default()), - dummy_variable_rgx: Some(DUMMY_VARIABLE_RGX.as_str().to_string()), - extend_fixable: Some(Vec::default()), - extend_ignore: Some(Vec::default()), - extend_select: Some(Vec::default()), - extend_unfixable: Some(Vec::default()), - external: Some(Vec::default()), - ignore: Some(Vec::default()), - line_length: Some(LineLength::default()), - preview: Some(false), - select: Some(PREFIXES.to_vec()), - tab_size: Some(TabSize::default()), - target_version: Some(PythonVersion::default()), // Ignore a bunch of options that don't make sense in a single-file editor. cache_dir: None, exclude: None, extend: None, extend_exclude: None, extend_include: None, - extend_per_file_ignores: None, fix: None, fix_only: None, - fixable: None, + lint: Some(LintOptions { + extend_per_file_ignores: None, + fixable: None, + logger_objects: None, + per_file_ignores: None, + task_tags: None, + unfixable: None, + ignore_init_module_imports: None, + ..LintOptions::default() + }), force_exclude: None, output_format: None, - ignore_init_module_imports: None, include: None, - logger_objects: None, namespace_packages: None, - per_file_ignores: None, required_version: None, respect_gitignore: None, show_fixes: None, show_source: None, src: None, - task_tags: None, typing_modules: None, - unfixable: None, ..Options::default() }) .map_err(into_error) diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index 3ea2bf9e1cfd5..6b1186d6169f9 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -39,9 +39,9 @@ use crate::options::{ Flake8ComprehensionsOptions, Flake8CopyrightOptions, Flake8ErrMsgOptions, Flake8GetTextOptions, Flake8ImplicitStrConcatOptions, Flake8ImportConventionsOptions, Flake8PytestStyleOptions, Flake8QuotesOptions, Flake8SelfOptions, Flake8TidyImportsOptions, Flake8TypeCheckingOptions, - Flake8UnusedArgumentsOptions, FormatOptions, FormatOrOutputFormat, IsortOptions, McCabeOptions, - Options, Pep8NamingOptions, PyUpgradeOptions, PycodestyleOptions, PydocstyleOptions, - PyflakesOptions, PylintOptions, + Flake8UnusedArgumentsOptions, FormatOptions, FormatOrOutputFormat, IsortOptions, LintOptions, + McCabeOptions, Options, Pep8NamingOptions, PyUpgradeOptions, PycodestyleOptions, + PydocstyleOptions, PyflakesOptions, PylintOptions, }; use crate::settings::{ FileResolverSettings, FormatterSettings, LineEnding, Settings, EXCLUDE, INCLUDE, @@ -59,64 +59,37 @@ pub struct RuleSelection { #[derive(Debug, Default)] pub struct Configuration { - pub rule_selections: Vec, - pub per_file_ignores: Option>, - - pub allowed_confusables: Option>, - pub builtins: Option>, + // Global options pub cache_dir: Option, - pub dummy_variable_rgx: Option, - pub exclude: Option>, + pub output_format: Option, + pub fix: Option, + pub fix_only: Option, + pub show_fixes: Option, + pub show_source: Option, + pub required_version: Option, + pub preview: Option, pub extend: Option, + + // File resolver options + pub exclude: Option>, pub extend_exclude: Vec, pub extend_include: Vec, - pub extend_per_file_ignores: Vec, - pub external: Option>, - pub fix: Option, - pub fix_only: Option, pub force_exclude: Option, - pub output_format: Option, - pub ignore_init_module_imports: Option, pub include: Option>, - pub line_length: Option, - pub logger_objects: Option>, - pub namespace_packages: Option>, - pub preview: Option, - pub required_version: Option, pub respect_gitignore: Option, - pub show_fixes: Option, - pub show_source: Option, - pub src: Option>, - pub tab_size: Option, + + // Generic python options settings + pub builtins: Option>, + pub namespace_packages: Option>, pub target_version: Option, - pub task_tags: Option>, + pub src: Option>, pub typing_modules: Option>, - // Plugins - pub flake8_annotations: Option, - pub flake8_bandit: Option, - pub flake8_bugbear: Option, - pub flake8_builtins: Option, - pub flake8_comprehensions: Option, - pub flake8_copyright: Option, - pub flake8_errmsg: Option, - pub flake8_gettext: Option, - pub flake8_implicit_str_concat: Option, - pub flake8_import_conventions: Option, - pub flake8_pytest_style: Option, - pub flake8_quotes: Option, - pub flake8_self: Option, - pub flake8_tidy_imports: Option, - pub flake8_type_checking: Option, - pub flake8_unused_arguments: Option, - pub isort: Option, - pub mccabe: Option, - pub pep8_naming: Option, - pub pycodestyle: Option, - pub pydocstyle: Option, - pub pyflakes: Option, - pub pylint: Option, - pub pyupgrade: Option, + // Global formatting options + pub line_length: Option, + pub tab_size: Option, + + pub lint: LintConfiguration, pub format: Option, } @@ -133,11 +106,10 @@ impl Configuration { } let target_version = self.target_version.unwrap_or_default(); - let rules = self.as_rule_table(); let preview = self.preview.unwrap_or_default(); let formatter = if let Some(format) = self.format { - let default = FormatterSettings::default(); + let formatter_defaults = FormatterSettings::default(); // TODO(micha): Support changing the tab-width but disallow changing the number of spaces FormatterSettings { @@ -146,20 +118,26 @@ impl Configuration { PreviewMode::Disabled => ruff_python_formatter::PreviewMode::Disabled, PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled, }, - line_width: self.line_length.map_or(default.line_width, |length| { - LineWidth::from(NonZeroU16::from(length)) - }), - line_ending: format.line_ending.unwrap_or(default.line_ending), - indent_style: format.indent_style.unwrap_or(default.indent_style), - quote_style: format.quote_style.unwrap_or(default.quote_style), + line_width: self + .line_length + .map_or(formatter_defaults.line_width, |length| { + LineWidth::from(NonZeroU16::from(length)) + }), + line_ending: format.line_ending.unwrap_or(formatter_defaults.line_ending), + indent_style: format + .indent_style + .unwrap_or(formatter_defaults.indent_style), + quote_style: format.quote_style.unwrap_or(formatter_defaults.quote_style), magic_trailing_comma: format .magic_trailing_comma - .unwrap_or(default.magic_trailing_comma), + .unwrap_or(formatter_defaults.magic_trailing_comma), } } else { FormatterSettings::default() }; + let lint = self.lint; + Ok(Settings { cache_dir: self .cache_dir @@ -186,135 +164,135 @@ impl Configuration { }, linter: LinterSettings { + rules: lint.as_rule_table(preview), target_version, project_root: project_root.to_path_buf(), - rules, - allowed_confusables: self + allowed_confusables: lint .allowed_confusables .map(FxHashSet::from_iter) .unwrap_or_default(), builtins: self.builtins.unwrap_or_default(), - dummy_variable_rgx: self + dummy_variable_rgx: lint .dummy_variable_rgx .unwrap_or_else(|| DUMMY_VARIABLE_RGX.clone()), - external: FxHashSet::from_iter(self.external.unwrap_or_default()), - ignore_init_module_imports: self.ignore_init_module_imports.unwrap_or_default(), + external: FxHashSet::from_iter(lint.external.unwrap_or_default()), + ignore_init_module_imports: lint.ignore_init_module_imports.unwrap_or_default(), line_length: self.line_length.unwrap_or_default(), tab_size: self.tab_size.unwrap_or_default(), namespace_packages: self.namespace_packages.unwrap_or_default(), per_file_ignores: resolve_per_file_ignores( - self.per_file_ignores + lint.per_file_ignores .unwrap_or_default() .into_iter() - .chain(self.extend_per_file_ignores) + .chain(lint.extend_per_file_ignores) .collect(), )?, src: self.src.unwrap_or_else(|| vec![project_root.to_path_buf()]), - task_tags: self + task_tags: lint .task_tags .unwrap_or_else(|| TASK_TAGS.iter().map(ToString::to_string).collect()), - logger_objects: self.logger_objects.unwrap_or_default(), + logger_objects: lint.logger_objects.unwrap_or_default(), preview, typing_modules: self.typing_modules.unwrap_or_default(), // Plugins - flake8_annotations: self + flake8_annotations: lint .flake8_annotations .map(Flake8AnnotationsOptions::into_settings) .unwrap_or_default(), - flake8_bandit: self + flake8_bandit: lint .flake8_bandit .map(Flake8BanditOptions::into_settings) .unwrap_or_default(), - flake8_bugbear: self + flake8_bugbear: lint .flake8_bugbear .map(Flake8BugbearOptions::into_settings) .unwrap_or_default(), - flake8_builtins: self + flake8_builtins: lint .flake8_builtins .map(Flake8BuiltinsOptions::into_settings) .unwrap_or_default(), - flake8_comprehensions: self + flake8_comprehensions: lint .flake8_comprehensions .map(Flake8ComprehensionsOptions::into_settings) .unwrap_or_default(), - flake8_copyright: self + flake8_copyright: lint .flake8_copyright .map(Flake8CopyrightOptions::try_into_settings) .transpose()? .unwrap_or_default(), - flake8_errmsg: self + flake8_errmsg: lint .flake8_errmsg .map(Flake8ErrMsgOptions::into_settings) .unwrap_or_default(), - flake8_implicit_str_concat: self + flake8_implicit_str_concat: lint .flake8_implicit_str_concat .map(Flake8ImplicitStrConcatOptions::into_settings) .unwrap_or_default(), - flake8_import_conventions: self + flake8_import_conventions: lint .flake8_import_conventions .map(Flake8ImportConventionsOptions::into_settings) .unwrap_or_default(), - flake8_pytest_style: self + flake8_pytest_style: lint .flake8_pytest_style .map(Flake8PytestStyleOptions::try_into_settings) .transpose()? .unwrap_or_default(), - flake8_quotes: self + flake8_quotes: lint .flake8_quotes .map(Flake8QuotesOptions::into_settings) .unwrap_or_default(), - flake8_self: self + flake8_self: lint .flake8_self .map(Flake8SelfOptions::into_settings) .unwrap_or_default(), - flake8_tidy_imports: self + flake8_tidy_imports: lint .flake8_tidy_imports .map(Flake8TidyImportsOptions::into_settings) .unwrap_or_default(), - flake8_type_checking: self + flake8_type_checking: lint .flake8_type_checking .map(Flake8TypeCheckingOptions::into_settings) .unwrap_or_default(), - flake8_unused_arguments: self + flake8_unused_arguments: lint .flake8_unused_arguments .map(Flake8UnusedArgumentsOptions::into_settings) .unwrap_or_default(), - flake8_gettext: self + flake8_gettext: lint .flake8_gettext .map(Flake8GetTextOptions::into_settings) .unwrap_or_default(), - isort: self + isort: lint .isort .map(IsortOptions::try_into_settings) .transpose()? .unwrap_or_default(), - mccabe: self + mccabe: lint .mccabe .map(McCabeOptions::into_settings) .unwrap_or_default(), - pep8_naming: self + pep8_naming: lint .pep8_naming .map(Pep8NamingOptions::try_into_settings) .transpose()? .unwrap_or_default(), - pycodestyle: self + pycodestyle: lint .pycodestyle .map(PycodestyleOptions::into_settings) .unwrap_or_default(), - pydocstyle: self + pydocstyle: lint .pydocstyle .map(PydocstyleOptions::into_settings) .unwrap_or_default(), - pyflakes: self + pyflakes: lint .pyflakes .map(PyflakesOptions::into_settings) .unwrap_or_default(), - pylint: self + pylint: lint .pylint .map(PylintOptions::into_settings) .unwrap_or_default(), - pyupgrade: self + pyupgrade: lint .pyupgrade .map(PyUpgradeOptions::into_settings) .unwrap_or_default(), @@ -325,26 +303,14 @@ impl Configuration { } pub fn from_options(options: Options, project_root: &Path) -> Result { + // TODO warn about legacy options + let lint = if let Some(lint) = options.lint { + lint.combine(options.lint_legacy) + } else { + options.lint_legacy + }; + Ok(Self { - rule_selections: vec![RuleSelection { - select: options.select, - ignore: options - .ignore - .into_iter() - .flatten() - .chain(options.extend_ignore.into_iter().flatten()) - .collect(), - extend_select: options.extend_select.unwrap_or_default(), - fixable: options.fixable, - unfixable: options - .unfixable - .into_iter() - .flatten() - .chain(options.extend_unfixable.into_iter().flatten()) - .collect(), - extend_fixable: options.extend_fixable.unwrap_or_default(), - }], - allowed_confusables: options.allowed_confusables, builtins: options.builtins, cache_dir: options .cache_dir @@ -354,11 +320,7 @@ impl Configuration { }) .transpose() .map_err(|e| anyhow!("Invalid `cache-dir` value: {e}"))?, - dummy_variable_rgx: options - .dummy_variable_rgx - .map(|pattern| Regex::new(&pattern)) - .transpose() - .map_err(|e| anyhow!("Invalid `dummy-variable-rgx` value: {e}"))?, + exclude: options.exclude.map(|paths| { paths .into_iter() @@ -400,28 +362,6 @@ impl Configuration { .collect() }) .unwrap_or_default(), - extend_per_file_ignores: options - .extend_per_file_ignores - .map(|per_file_ignores| { - per_file_ignores - .into_iter() - .map(|(pattern, prefixes)| { - PerFileIgnore::new(pattern, &prefixes, Some(project_root)) - }) - .collect() - }) - .unwrap_or_default(), - external: options.external, - fix: options.fix, - fix_only: options.fix_only, - output_format: options.output_format.or_else(|| { - options - .format - .as_ref() - .and_then(FormatOrOutputFormat::as_output_format) - }), - force_exclude: options.force_exclude, - ignore_init_module_imports: options.ignore_init_module_imports, include: options.include.map(|paths| { paths .into_iter() @@ -431,6 +371,15 @@ impl Configuration { }) .collect() }), + fix: options.fix, + fix_only: options.fix_only, + output_format: options.output_format.or_else(|| { + options + .format + .as_ref() + .and_then(FormatOrOutputFormat::as_output_format) + }), + force_exclude: options.force_exclude, line_length: options.line_length, tab_size: options.tab_size, namespace_packages: options @@ -438,14 +387,6 @@ impl Configuration { .map(|namespace_package| resolve_src(&namespace_package, project_root)) .transpose()?, preview: options.preview.map(PreviewMode::from), - per_file_ignores: options.per_file_ignores.map(|per_file_ignores| { - per_file_ignores - .into_iter() - .map(|(pattern, prefixes)| { - PerFileIgnore::new(pattern, &prefixes, Some(project_root)) - }) - .collect() - }), required_version: options.required_version, respect_gitignore: options.respect_gitignore, show_source: options.show_source, @@ -455,9 +396,156 @@ impl Configuration { .map(|src| resolve_src(&src, project_root)) .transpose()?, target_version: options.target_version, + typing_modules: options.typing_modules, + + lint: LintConfiguration::from_options(lint, project_root)?, + + format: if let Some(FormatOrOutputFormat::Format(format)) = options.format { + Some(FormatConfiguration::from_options(format, project_root)?) + } else { + None + }, + }) + } + + #[must_use] + pub fn combine(self, config: Self) -> Self { + Self { + builtins: self.builtins.or(config.builtins), + cache_dir: self.cache_dir.or(config.cache_dir), + exclude: self.exclude.or(config.exclude), + extend: self.extend.or(config.extend), + extend_exclude: config + .extend_exclude + .into_iter() + .chain(self.extend_exclude) + .collect(), + extend_include: config + .extend_include + .into_iter() + .chain(self.extend_include) + .collect(), + include: self.include.or(config.include), + fix: self.fix.or(config.fix), + fix_only: self.fix_only.or(config.fix_only), + output_format: self.output_format.or(config.output_format), + force_exclude: self.force_exclude.or(config.force_exclude), + line_length: self.line_length.or(config.line_length), + tab_size: self.tab_size.or(config.tab_size), + namespace_packages: self.namespace_packages.or(config.namespace_packages), + required_version: self.required_version.or(config.required_version), + respect_gitignore: self.respect_gitignore.or(config.respect_gitignore), + show_source: self.show_source.or(config.show_source), + show_fixes: self.show_fixes.or(config.show_fixes), + src: self.src.or(config.src), + target_version: self.target_version.or(config.target_version), + preview: self.preview.or(config.preview), + typing_modules: self.typing_modules.or(config.typing_modules), + + lint: self.lint.combine(config.lint), + + format: match (self.format, config.format) { + (Some(format), Some(other_format)) => Some(format.combine(other_format)), + (Some(format), None) => Some(format), + (None, Some(format)) => Some(format), + (None, None) => None, + }, + } + } +} + +#[derive(Debug, Default)] +pub struct LintConfiguration { + // Rule selection + pub rule_selections: Vec, + pub per_file_ignores: Option>, + pub extend_per_file_ignores: Vec, + + // Global lint settings + pub dummy_variable_rgx: Option, + pub allowed_confusables: Option>, + pub external: Option>, + pub ignore_init_module_imports: Option, + pub logger_objects: Option>, + pub task_tags: Option>, + + // Plugins + pub flake8_annotations: Option, + pub flake8_bandit: Option, + pub flake8_bugbear: Option, + pub flake8_builtins: Option, + pub flake8_comprehensions: Option, + pub flake8_copyright: Option, + pub flake8_errmsg: Option, + pub flake8_gettext: Option, + pub flake8_implicit_str_concat: Option, + pub flake8_import_conventions: Option, + pub flake8_pytest_style: Option, + pub flake8_quotes: Option, + pub flake8_self: Option, + pub flake8_tidy_imports: Option, + pub flake8_type_checking: Option, + pub flake8_unused_arguments: Option, + pub isort: Option, + pub mccabe: Option, + pub pep8_naming: Option, + pub pycodestyle: Option, + pub pydocstyle: Option, + pub pyflakes: Option, + pub pylint: Option, + pub pyupgrade: Option, +} + +impl LintConfiguration { + fn from_options(options: LintOptions, project_root: &Path) -> Result { + Ok(LintConfiguration { + rule_selections: vec![RuleSelection { + select: options.select, + ignore: options + .ignore + .into_iter() + .flatten() + .chain(options.extend_ignore.into_iter().flatten()) + .collect(), + extend_select: options.extend_select.unwrap_or_default(), + fixable: options.fixable, + unfixable: options + .unfixable + .into_iter() + .flatten() + .chain(options.extend_unfixable.into_iter().flatten()) + .collect(), + extend_fixable: options.extend_fixable.unwrap_or_default(), + }], + allowed_confusables: options.allowed_confusables, + dummy_variable_rgx: options + .dummy_variable_rgx + .map(|pattern| Regex::new(&pattern)) + .transpose() + .map_err(|e| anyhow!("Invalid `dummy-variable-rgx` value: {e}"))?, + extend_per_file_ignores: options + .extend_per_file_ignores + .map(|per_file_ignores| { + per_file_ignores + .into_iter() + .map(|(pattern, prefixes)| { + PerFileIgnore::new(pattern, &prefixes, Some(project_root)) + }) + .collect() + }) + .unwrap_or_default(), + external: options.external, + ignore_init_module_imports: options.ignore_init_module_imports, + per_file_ignores: options.per_file_ignores.map(|per_file_ignores| { + per_file_ignores + .into_iter() + .map(|(pattern, prefixes)| { + PerFileIgnore::new(pattern, &prefixes, Some(project_root)) + }) + .collect() + }), task_tags: options.task_tags, logger_objects: options.logger_objects, - typing_modules: options.typing_modules, // Plugins flake8_annotations: options.flake8_annotations, flake8_bandit: options.flake8_bandit, @@ -483,18 +571,10 @@ impl Configuration { pyflakes: options.pyflakes, pylint: options.pylint, pyupgrade: options.pyupgrade, - - format: if let Some(FormatOrOutputFormat::Format(format)) = options.format { - Some(FormatConfiguration::from_options(format, project_root)?) - } else { - None - }, }) } - pub fn as_rule_table(&self) -> RuleTable { - let preview = self.preview.unwrap_or_default(); - + fn as_rule_table(&self, preview: PreviewMode) -> RuleTable { // The select_set keeps track of which rules have been selected. let mut select_set: RuleSet = PREFIXES .iter() @@ -734,49 +814,19 @@ impl Configuration { .chain(self.rule_selections) .collect(), allowed_confusables: self.allowed_confusables.or(config.allowed_confusables), - builtins: self.builtins.or(config.builtins), - cache_dir: self.cache_dir.or(config.cache_dir), dummy_variable_rgx: self.dummy_variable_rgx.or(config.dummy_variable_rgx), - exclude: self.exclude.or(config.exclude), - extend: self.extend.or(config.extend), - extend_exclude: config - .extend_exclude - .into_iter() - .chain(self.extend_exclude) - .collect(), - extend_include: config - .extend_include - .into_iter() - .chain(self.extend_include) - .collect(), extend_per_file_ignores: config .extend_per_file_ignores .into_iter() .chain(self.extend_per_file_ignores) .collect(), external: self.external.or(config.external), - fix: self.fix.or(config.fix), - fix_only: self.fix_only.or(config.fix_only), - output_format: self.output_format.or(config.output_format), - force_exclude: self.force_exclude.or(config.force_exclude), - include: self.include.or(config.include), ignore_init_module_imports: self .ignore_init_module_imports .or(config.ignore_init_module_imports), - line_length: self.line_length.or(config.line_length), logger_objects: self.logger_objects.or(config.logger_objects), - tab_size: self.tab_size.or(config.tab_size), - namespace_packages: self.namespace_packages.or(config.namespace_packages), per_file_ignores: self.per_file_ignores.or(config.per_file_ignores), - required_version: self.required_version.or(config.required_version), - respect_gitignore: self.respect_gitignore.or(config.respect_gitignore), - show_source: self.show_source.or(config.show_source), - show_fixes: self.show_fixes.or(config.show_fixes), - src: self.src.or(config.src), - target_version: self.target_version.or(config.target_version), - preview: self.preview.or(config.preview), task_tags: self.task_tags.or(config.task_tags), - typing_modules: self.typing_modules.or(config.typing_modules), // Plugins flake8_annotations: self.flake8_annotations.combine(config.flake8_annotations), flake8_bandit: self.flake8_bandit.combine(config.flake8_bandit), @@ -812,13 +862,6 @@ impl Configuration { pyflakes: self.pyflakes.combine(config.pyflakes), pylint: self.pylint.combine(config.pylint), pyupgrade: self.pyupgrade.combine(config.pyupgrade), - - format: match (self.format, config.format) { - (Some(format), Some(other_format)) => Some(format.combine(other_format)), - (Some(format), None) => Some(format), - (None, Some(format)) => Some(format), - (None, None) => None, - }, } } } @@ -876,7 +919,6 @@ impl FormatConfiguration { } } } - pub(crate) trait CombinePluginOptions { #[must_use] fn combine(self, other: Self) -> Self; @@ -920,7 +962,7 @@ mod tests { use ruff_linter::settings::types::PreviewMode; use ruff_linter::RuleSelector; - use crate::configuration::{Configuration, RuleSelection}; + use crate::configuration::{LintConfiguration, RuleSelection}; const NURSERY_RULES: &[Rule] = &[ Rule::MissingCopyrightNotice, @@ -984,12 +1026,11 @@ mod tests { selections: impl IntoIterator, preview: Option, ) -> RuleSet { - Configuration { + LintConfiguration { rule_selections: selections.into_iter().collect(), - preview, - ..Configuration::default() + ..LintConfiguration::default() } - .as_rule_table() + .as_rule_table(preview.unwrap_or_default()) .iter_enabled() // Filter out rule gated behind `#[cfg(feature = "unreachable-code")]`, which is off-by-default .filter(|rule| rule.noqa_code() != "RUF014") diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index c1e1e67f6b7bf..b9fd3e7ad7abb 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -35,30 +35,6 @@ use crate::settings::LineEnding; #[serde(deny_unknown_fields, rename_all = "kebab-case")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct Options { - /// A list of allowed "confusable" Unicode characters to ignore when - /// enforcing `RUF001`, `RUF002`, and `RUF003`. - #[option( - default = r#"[]"#, - value_type = "list[str]", - example = r#" - # Allow minus-sign (U+2212), greek-small-letter-rho (U+03C1), and the asterisk-operator (U+2217), - # which could be confused for "-", "p", and "*", respectively. - allowed-confusables = ["−", "ρ", "∗"] - "# - )] - pub allowed_confusables: Option>, - - /// A list of builtins to treat as defined references, in addition to the - /// system builtins. - #[option( - default = r#"[]"#, - value_type = "list[str]", - example = r#" - builtins = ["_"] - "# - )] - pub builtins: Option>, - /// A path to the cache directory. /// /// By default, Ruff stores cache results in a `.ruff_cache` directory in @@ -76,19 +52,113 @@ pub struct Options { )] pub cache_dir: Option, - /// A regular expression used to identify "dummy" variables, or those which - /// should be ignored when enforcing (e.g.) unused-variable rules. The - /// default expression matches `_`, `__`, and `_var`, but not `_var_`. + /// A path to a local `pyproject.toml` file to merge into this + /// configuration. User home directory and environment variables will be + /// expanded. + /// + /// To resolve the current `pyproject.toml` file, Ruff will first resolve + /// this base configuration file, then merge in any properties defined + /// in the current configuration file. #[option( - default = r#""^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$""#, - value_type = "re.Pattern", + default = r#"None"#, + value_type = "str", example = r#" - # Only ignore variables named "_". - dummy-variable-rgx = "^_$" + # Extend the `pyproject.toml` file in the parent directory. + extend = "../pyproject.toml" + # But use a different line length. + line-length = 100 "# )] - pub dummy_variable_rgx: Option, + pub extend: Option, + + /// Options to configure the code formatting. + /// + /// Previously: + /// The style in which violation messages should be formatted: `"text"` + /// (default), `"grouped"` (group messages by file), `"json"` + /// (machine-readable), `"junit"` (machine-readable XML), `"github"` (GitHub + /// Actions annotations), `"gitlab"` (GitLab CI code quality report), + /// `"pylint"` (Pylint text format) or `"azure"` (Azure Pipeline logging commands). + /// + /// This option has been **deprecated** in favor of `output-format` + /// to avoid ambiguity with Ruff's upcoming formatter. + #[option_group] + #[cfg_attr(feature = "schemars", schemars(skip))] + pub format: Option, + + /// The style in which violation messages should be formatted: `"text"` + /// (default), `"grouped"` (group messages by file), `"json"` + /// (machine-readable), `"junit"` (machine-readable XML), `"github"` (GitHub + /// Actions annotations), `"gitlab"` (GitLab CI code quality report), + /// `"pylint"` (Pylint text format) or `"azure"` (Azure Pipeline logging commands). + #[option( + default = r#""text""#, + value_type = r#""text" | "json" | "junit" | "github" | "gitlab" | "pylint" | "azure""#, + example = r#" + # Group violations by containing file. + output-format = "grouped" + "# + )] + pub output_format: Option, + + /// Enable autofix behavior by-default when running `ruff` (overridden + /// by the `--fix` and `--no-fix` command-line flags). + #[option(default = "false", value_type = "bool", example = "fix = true")] + pub fix: Option, + + /// Like `fix`, but disables reporting on leftover violation. Implies `fix`. + #[option(default = "false", value_type = "bool", example = "fix-only = true")] + pub fix_only: Option, + + /// Whether to show source code snippets when reporting lint violations + /// (overridden by the `--show-source` command-line flag). + #[option( + default = "false", + value_type = "bool", + example = r#" + # By default, always show source code snippets. + show-source = true + "# + )] + pub show_source: Option, + + /// Whether to show an enumeration of all autofixed lint violations + /// (overridden by the `--show-fixes` command-line flag). + #[option( + default = "false", + value_type = "bool", + example = r#" + # Enumerate all fixed violations. + show-fixes = true + "# + )] + pub show_fixes: Option, + + /// Require a specific version of Ruff to be running (useful for unifying + /// results across many environments, e.g., with a `pyproject.toml` + /// file). + #[option( + default = "None", + value_type = "str", + example = r#" + required-version = "0.0.193" + "# + )] + pub required_version: Option, + + /// Whether to enable preview mode. When preview mode is enabled, Ruff will + /// use unstable rules and fixes. + #[option( + default = "false", + value_type = "bool", + example = r#" + # Enable preview features + preview = true + "# + )] + pub preview: Option, + // File resolver options /// A list of file patterns to exclude from linting. /// /// Exclusions are based on globs, and can be either: @@ -114,65 +184,265 @@ pub struct Options { )] pub exclude: Option>, - /// A path to a local `pyproject.toml` file to merge into this - /// configuration. User home directory and environment variables will be - /// expanded. + /// A list of file patterns to omit from linting, in addition to those + /// specified by `exclude`. /// - /// To resolve the current `pyproject.toml` file, Ruff will first resolve - /// this base configuration file, then merge in any properties defined - /// in the current configuration file. + /// Exclusions are based on globs, and can be either: + /// + /// - Single-path patterns, like `.mypy_cache` (to exclude any directory + /// named `.mypy_cache` in the tree), `foo.py` (to exclude any file named + /// `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). + /// - Relative patterns, like `directory/foo.py` (to exclude that specific + /// file) or `directory/*.py` (to exclude any Python files in + /// `directory`). Note that these paths are relative to the project root + /// (e.g., the directory containing your `pyproject.toml`). + /// + /// For more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax). #[option( - default = r#"None"#, - value_type = "str", + default = "[]", + value_type = "list[str]", example = r#" - # Extend the `pyproject.toml` file in the parent directory. - extend = "../pyproject.toml" - # But use a different line length. - line-length = 100 + # In addition to the standard set of exclusions, omit all tests, plus a specific file. + extend-exclude = ["tests", "src/bad.py"] + "# + )] + pub extend_exclude: Option>, + + /// A list of file patterns to include when linting, in addition to those + /// specified by `include`. + /// + /// Inclusion are based on globs, and should be single-path patterns, like + /// `*.pyw`, to include any file with the `.pyw` extension. + /// + /// For more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax). + #[option( + default = "[]", + value_type = "list[str]", + example = r#" + # In addition to the standard set of inclusions, include `.pyw` files. + extend-include = ["*.pyw"] + "# + )] + pub extend_include: Option>, + + #[option( + default = r#"false"#, + value_type = "bool", + example = r#" + force-exclude = true + "# + )] + /// Whether to enforce `exclude` and `extend-exclude` patterns, even for + /// paths that are passed to Ruff explicitly. Typically, Ruff will lint + /// any paths passed in directly, even if they would typically be + /// excluded. Setting `force-exclude = true` will cause Ruff to + /// respect these exclusions unequivocally. + /// + /// This is useful for [`pre-commit`](https://pre-commit.com/), which explicitly passes all + /// changed files to the [`ruff-pre-commit`](https://github.com/astral-sh/ruff-pre-commit) + /// plugin, regardless of whether they're marked as excluded by Ruff's own + /// settings. + #[option( + default = r#"false"#, + value_type = "bool", + example = r#" + force-exclude = true + "# + )] + pub force_exclude: Option, + + /// A list of file patterns to include when linting. + /// + /// Inclusion are based on globs, and should be single-path patterns, like + /// `*.pyw`, to include any file with the `.pyw` extension. `pyproject.toml` is + /// included here not for configuration but because we lint whether e.g. the + /// `[project]` matches the schema. + /// + /// For more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax). + #[option( + default = r#"["*.py", "*.pyi", "**/pyproject.toml"]"#, + value_type = "list[str]", + example = r#" + include = ["*.py"] + "# + )] + pub include: Option>, + + /// Whether to automatically exclude files that are ignored by `.ignore`, + /// `.gitignore`, `.git/info/exclude`, and global `gitignore` files. + /// Enabled by default. + #[option( + default = "true", + value_type = "bool", + example = r#" + respect-gitignore = false + "# + )] + pub respect_gitignore: Option, + + // Generic python options + /// A list of builtins to treat as defined references, in addition to the + /// system builtins. + #[option( + default = r#"[]"#, + value_type = "list[str]", + example = r#" + builtins = ["_"] + "# + )] + pub builtins: Option>, + + /// Mark the specified directories as namespace packages. For the purpose of + /// module resolution, Ruff will treat those directories as if they + /// contained an `__init__.py` file. + #[option( + default = r#"[]"#, + value_type = "list[str]", + example = r#" + namespace-packages = ["airflow/providers"] + "# + )] + pub namespace_packages: Option>, + + /// The minimum Python version to target, e.g., when considering automatic + /// code upgrades, like rewriting type annotations. Ruff will not propose + /// changes using features that are not available in the given version. + /// + /// For example, to represent supporting Python >=3.10 or ==3.10 + /// specify `target-version = "py310"`. + /// + /// If omitted, and Ruff is configured via a `pyproject.toml` file, the + /// target version will be inferred from its `project.requires-python` + /// field (e.g., `requires-python = ">=3.8"`). If Ruff is configured via + /// `ruff.toml` or `.ruff.toml`, no such inference will be performed. + #[option( + default = r#""py38""#, + value_type = r#""py37" | "py38" | "py39" | "py310" | "py311" | "py312""#, + example = r#" + # Always generate Python 3.7-compatible code. + target-version = "py37" + "# + )] + pub target_version: Option, + + /// The directories to consider when resolving first- vs. third-party + /// imports. + /// + /// As an example: given a Python package structure like: + /// + /// ```text + /// my_project + /// ├── pyproject.toml + /// └── src + /// └── my_package + /// ├── __init__.py + /// ├── foo.py + /// └── bar.py + /// ``` + /// + /// The `./src` directory should be included in the `src` option + /// (e.g., `src = ["src"]`), such that when resolving imports, + /// `my_package.foo` is considered a first-party import. + /// + /// When omitted, the `src` directory will typically default to the + /// directory containing the nearest `pyproject.toml`, `ruff.toml`, or + /// `.ruff.toml` file (the "project root"), unless a configuration file + /// is explicitly provided (e.g., via the `--config` command-line flag). + /// + /// This field supports globs. For example, if you have a series of Python + /// packages in a `python_modules` directory, `src = ["python_modules/*"]` + /// would expand to incorporate all of the packages in that directory. User + /// home directory and environment variables will also be expanded. + #[option( + default = r#"["."]"#, + value_type = "list[str]", + example = r#" + # Allow imports relative to the "src" and "test" directories. + src = ["src", "test"] + "# + )] + pub src: Option>, + + /// A list of modules whose exports should be treated equivalently to + /// members of the `typing` module. + /// + /// This is useful for ensuring proper type annotation inference for + /// projects that re-export `typing` and `typing_extensions` members + /// from a compatibility module. If omitted, any members imported from + /// modules apart from `typing` and `typing_extensions` will be treated + /// as ordinary Python objects. + #[option( + default = r#"[]"#, + value_type = "list[str]", + example = r#"typing-modules = ["airflow.typing_compat"]"# + )] + pub typing_modules: Option>, + + // Global Formatting options + /// The line length to use when enforcing long-lines violations (like + /// `E501`). Must be greater than `0` and less than or equal to `320`. + #[option( + default = "88", + value_type = "int", + example = r#" + # Allow lines to be as long as 120 characters. + line-length = 120 + "# + )] + #[cfg_attr(feature = "schemars", schemars(range(min = 1, max = 320)))] + pub line_length: Option, + + /// The tabulation size to calculate line length. + #[option( + default = "4", + value_type = "int", + example = r#" + tab-size = 8 "# )] - pub extend: Option, + pub tab_size: Option, - /// A list of file patterns to omit from linting, in addition to those - /// specified by `exclude`. - /// - /// Exclusions are based on globs, and can be either: - /// - /// - Single-path patterns, like `.mypy_cache` (to exclude any directory - /// named `.mypy_cache` in the tree), `foo.py` (to exclude any file named - /// `foo.py`), or `foo_*.py` (to exclude any file matching `foo_*.py` ). - /// - Relative patterns, like `directory/foo.py` (to exclude that specific - /// file) or `directory/*.py` (to exclude any Python files in - /// `directory`). Note that these paths are relative to the project root - /// (e.g., the directory containing your `pyproject.toml`). - /// - /// For more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax). + // Lint options + /// Options for the Ruff linter + #[option_group] + pub lint: Option, + + /// Doc + #[serde(flatten)] + pub lint_legacy: LintOptions, +} + +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[derive( + Debug, PartialEq, Eq, Default, ConfigurationOptions, CombineOptions, Serialize, Deserialize, +)] +#[serde(deny_unknown_fields, rename_all = "kebab-case")] +pub struct LintOptions { + /// A list of allowed "confusable" Unicode characters to ignore when + /// enforcing `RUF001`, `RUF002`, and `RUF003`. #[option( - default = "[]", + default = r#"[]"#, value_type = "list[str]", example = r#" - # In addition to the standard set of exclusions, omit all tests, plus a specific file. - extend-exclude = ["tests", "src/bad.py"] + # Allow minus-sign (U+2212), greek-small-letter-rho (U+03C1), and the asterisk-operator (U+2217), + # which could be confused for "-", "p", and "*", respectively. + allowed-confusables = ["−", "ρ", "∗"] "# )] - pub extend_exclude: Option>, + pub allowed_confusables: Option>, - /// A list of file patterns to include when linting, in addition to those - /// specified by `include`. - /// - /// Inclusion are based on globs, and should be single-path patterns, like - /// `*.pyw`, to include any file with the `.pyw` extension. - /// - /// For more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax). + /// A regular expression used to identify "dummy" variables, or those which + /// should be ignored when enforcing (e.g.) unused-variable rules. The + /// default expression matches `_`, `__`, and `_var`, but not `_var_`. #[option( - default = "[]", - value_type = "list[str]", + default = r#""^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$""#, + value_type = "re.Pattern", example = r#" - # In addition to the standard set of inclusions, include `.pyw` files. - extend-include = ["*.pyw"] + # Only ignore variables named "_". + dummy-variable-rgx = "^_$" "# )] - pub extend_include: Option>, + pub dummy_variable_rgx: Option, /// A list of rule codes or prefixes to ignore, in addition to those /// specified by `ignore`. @@ -237,15 +507,6 @@ pub struct Options { )] pub external: Option>, - /// Enable autofix behavior by-default when running `ruff` (overridden - /// by the `--fix` and `--no-fix` command-line flags). - #[option(default = "false", value_type = "bool", example = "fix = true")] - pub fix: Option, - - /// Like `fix`, but disables reporting on leftover violation. Implies `fix`. - #[option(default = "false", value_type = "bool", example = "fix-only = true")] - pub fix_only: Option, - /// A list of rule codes or prefixes to consider autofixable. By default, /// all rules are considered autofixable. #[option( @@ -329,46 +590,6 @@ pub struct Options { )] pub ignore_init_module_imports: Option, - /// A list of file patterns to include when linting. - /// - /// Inclusion are based on globs, and should be single-path patterns, like - /// `*.pyw`, to include any file with the `.pyw` extension. `pyproject.toml` is - /// included here not for configuration but because we lint whether e.g. the - /// `[project]` matches the schema. - /// - /// For more information on the glob syntax, refer to the [`globset` documentation](https://docs.rs/globset/latest/globset/#syntax). - #[option( - default = r#"["*.py", "*.pyi", "**/pyproject.toml"]"#, - value_type = "list[str]", - example = r#" - include = ["*.py"] - "# - )] - pub include: Option>, - - /// The line length to use when enforcing long-lines violations (like - /// `E501`). Must be greater than `0` and less than or equal to `320`. - #[option( - default = "88", - value_type = "int", - example = r#" - # Allow lines to be as long as 120 characters. - line-length = 120 - "# - )] - #[cfg_attr(feature = "schemars", schemars(range(min = 1, max = 320)))] - pub line_length: Option, - - /// The tabulation size to calculate line length. - #[option( - default = "4", - value_type = "int", - example = r#" - tab-size = 8 - "# - )] - pub tab_size: Option, - /// A list of objects that should be treated equivalently to a /// `logging.Logger` object. /// @@ -394,30 +615,6 @@ pub struct Options { )] pub logger_objects: Option>, - /// Require a specific version of Ruff to be running (useful for unifying - /// results across many environments, e.g., with a `pyproject.toml` - /// file). - #[option( - default = "None", - value_type = "str", - example = r#" - required-version = "0.0.193" - "# - )] - pub required_version: Option, - - /// Whether to automatically exclude files that are ignored by `.ignore`, - /// `.gitignore`, `.git/info/exclude`, and global `gitignore` files. - /// Enabled by default. - #[option( - default = "true", - value_type = "bool", - example = r#" - respect-gitignore = false - "# - )] - pub respect_gitignore: Option, - /// A list of rule codes or prefixes to enable. Prefixes can specify exact /// rules (like `F841`), entire categories (like `F`), or anything in /// between. @@ -435,113 +632,6 @@ pub struct Options { )] pub select: Option>, - /// Whether to show source code snippets when reporting lint violations - /// (overridden by the `--show-source` command-line flag). - #[option( - default = "false", - value_type = "bool", - example = r#" - # By default, always show source code snippets. - show-source = true - "# - )] - pub show_source: Option, - - /// Whether to show an enumeration of all autofixed lint violations - /// (overridden by the `--show-fixes` command-line flag). - #[option( - default = "false", - value_type = "bool", - example = r#" - # Enumerate all fixed violations. - show-fixes = true - "# - )] - pub show_fixes: Option, - - /// The directories to consider when resolving first- vs. third-party - /// imports. - /// - /// As an example: given a Python package structure like: - /// - /// ```text - /// my_project - /// ├── pyproject.toml - /// └── src - /// └── my_package - /// ├── __init__.py - /// ├── foo.py - /// └── bar.py - /// ``` - /// - /// The `./src` directory should be included in the `src` option - /// (e.g., `src = ["src"]`), such that when resolving imports, - /// `my_package.foo` is considered a first-party import. - /// - /// When omitted, the `src` directory will typically default to the - /// directory containing the nearest `pyproject.toml`, `ruff.toml`, or - /// `.ruff.toml` file (the "project root"), unless a configuration file - /// is explicitly provided (e.g., via the `--config` command-line flag). - /// - /// This field supports globs. For example, if you have a series of Python - /// packages in a `python_modules` directory, `src = ["python_modules/*"]` - /// would expand to incorporate all of the packages in that directory. User - /// home directory and environment variables will also be expanded. - #[option( - default = r#"["."]"#, - value_type = "list[str]", - example = r#" - # Allow imports relative to the "src" and "test" directories. - src = ["src", "test"] - "# - )] - pub src: Option>, - - /// Mark the specified directories as namespace packages. For the purpose of - /// module resolution, Ruff will treat those directories as if they - /// contained an `__init__.py` file. - #[option( - default = r#"[]"#, - value_type = "list[str]", - example = r#" - namespace-packages = ["airflow/providers"] - "# - )] - pub namespace_packages: Option>, - - /// The minimum Python version to target, e.g., when considering automatic - /// code upgrades, like rewriting type annotations. Ruff will not propose - /// changes using features that are not available in the given version. - /// - /// For example, to represent supporting Python >=3.10 or ==3.10 - /// specify `target-version = "py310"`. - /// - /// If omitted, and Ruff is configured via a `pyproject.toml` file, the - /// target version will be inferred from its `project.requires-python` - /// field (e.g., `requires-python = ">=3.8"`). If Ruff is configured via - /// `ruff.toml` or `.ruff.toml`, no such inference will be performed. - #[option( - default = r#""py38""#, - value_type = r#""py37" | "py38" | "py39" | "py310" | "py311" | "py312""#, - example = r#" - # Always generate Python 3.7-compatible code. - target-version = "py37" - "# - )] - pub target_version: Option, - - /// Whether to enable preview mode. When preview mode is enabled, Ruff will - /// use unstable rules and fixes. - #[option( - default = "false", - value_type = "bool", - example = r#" - # Enable preview features - preview = true - "# - )] - pub preview: Option, - /// A list of task tags to recognize (e.g., "TODO", "FIXME", "XXX"). /// /// Comments starting with these tags will be ignored by commented-out code @@ -550,25 +640,13 @@ pub struct Options { #[option( default = r#"["TODO", "FIXME", "XXX"]"#, value_type = "list[str]", - example = r#"task-tags = ["HACK"]"# + example = r#" + [lint] + task-tags = ["HACK"] + "# )] pub task_tags: Option>, - /// A list of modules whose exports should be treated equivalently to - /// members of the `typing` module. - /// - /// This is useful for ensuring proper type annotation inference for - /// projects that re-export `typing` and `typing_extensions` members - /// from a compatibility module. If omitted, any members imported from - /// modules apart from `typing` and `typing_extensions` will be treated - /// as ordinary Python objects. - #[option( - default = r#"[]"#, - value_type = "list[str]", - example = r#"typing-modules = ["airflow.typing_compat"]"# - )] - pub typing_modules: Option>, - /// A list of rule codes or prefixes to consider non-autofix-able. #[option( default = "[]", diff --git a/crates/ruff_workspace/src/pyproject.rs b/crates/ruff_workspace/src/pyproject.rs index cf6fb30893b2e..0e821655c4c8d 100644 --- a/crates/ruff_workspace/src/pyproject.rs +++ b/crates/ruff_workspace/src/pyproject.rs @@ -161,7 +161,7 @@ mod tests { use ruff_linter::line_width::LineLength; use ruff_linter::settings::types::PatternPrefixPair; - use crate::options::Options; + use crate::options::{LintOptions, Options}; use crate::pyproject::{find_settings_toml, parse_pyproject_toml, Pyproject, Tools}; use crate::tests::test_resource_path; @@ -236,7 +236,10 @@ select = ["E501"] pyproject.tool, Some(Tools { ruff: Some(Options { - select: Some(vec![codes::Pycodestyle::E501.into()]), + lint_legacy: LintOptions { + select: Some(vec![codes::Pycodestyle::E501.into()]), + ..LintOptions::default() + }, ..Options::default() }) }) @@ -254,8 +257,11 @@ ignore = ["E501"] pyproject.tool, Some(Tools { ruff: Some(Options { - extend_select: Some(vec![codes::Ruff::_100.into()]), - ignore: Some(vec![codes::Pycodestyle::E501.into()]), + lint_legacy: LintOptions { + extend_select: Some(vec![codes::Ruff::_100.into()]), + ignore: Some(vec![codes::Pycodestyle::E501.into()]), + ..LintOptions::default() + }, ..Options::default() }) }) @@ -308,10 +314,14 @@ other-attribute = 1 "migrations".to_string(), "with_excluded_file/other_excluded_file.py".to_string(), ]), - per_file_ignores: Some(FxHashMap::from_iter([( - "__init__.py".to_string(), - vec![codes::Pyflakes::_401.into()] - )])), + + lint_legacy: LintOptions { + per_file_ignores: Some(FxHashMap::from_iter([( + "__init__.py".to_string(), + vec![codes::Pyflakes::_401.into()] + )])), + ..LintOptions::default() + }, ..Options::default() } ); diff --git a/ruff.schema.json b/ruff.schema.json index cfe3bdc0bcca7..f19fd258f10c2 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -388,6 +388,17 @@ "maximum": 320.0, "minimum": 1.0 }, + "lint": { + "description": "Options for the Ruff linter", + "anyOf": [ + { + "$ref": "#/definitions/LintOptions" + }, + { + "type": "null" + } + ] + }, "logger-objects": { "description": "A list of objects that should be treated equivalently to a `logging.Logger` object.\n\nThis is useful for ensuring proper diagnostics (e.g., to identify `logging` deprecations and other best-practices) for projects that re-export a `logging.Logger` object from a common module.\n\nFor example, if you have a module `logging_setup.py` with the following contents: ```python import logging\n\nlogger = logging.getLogger(__name__) ```\n\nAdding `\"logging_setup.logger\"` to `logger-objects` will ensure that `logging_setup.logger` is treated as a `logging.Logger` object when imported from other modules (e.g., `from logging_setup import logger`).", "type": [ @@ -1544,6 +1555,447 @@ "format": "uint16", "minimum": 1.0 }, + "LintOptions": { + "type": "object", + "properties": { + "allowed-confusables": { + "description": "A list of allowed \"confusable\" Unicode characters to ignore when enforcing `RUF001`, `RUF002`, and `RUF003`.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string", + "maxLength": 1, + "minLength": 1 + } + }, + "dummy-variable-rgx": { + "description": "A regular expression used to identify \"dummy\" variables, or those which should be ignored when enforcing (e.g.) unused-variable rules. The default expression matches `_`, `__`, and `_var`, but not `_var_`.", + "type": [ + "string", + "null" + ] + }, + "extend-fixable": { + "description": "A list of rule codes or prefixes to consider autofixable, in addition to those specified by `fixable`.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/RuleSelector" + } + }, + "extend-per-file-ignores": { + "description": "A list of mappings from file pattern to rule codes or prefixes to exclude, in addition to any rules excluded by `per-file-ignores`.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/RuleSelector" + } + } + }, + "extend-select": { + "description": "A list of rule codes or prefixes to enable, in addition to those specified by `select`.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/RuleSelector" + } + }, + "external": { + "description": "A list of rule codes that are unsupported by Ruff, but should be preserved when (e.g.) validating `# noqa` directives. Useful for retaining `# noqa` directives that cover plugins not yet implemented by Ruff.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "fixable": { + "description": "A list of rule codes or prefixes to consider autofixable. By default, all rules are considered autofixable.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/RuleSelector" + } + }, + "flake8-annotations": { + "description": "Options for the `flake8-annotations` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8AnnotationsOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-bandit": { + "description": "Options for the `flake8-bandit` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8BanditOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-bugbear": { + "description": "Options for the `flake8-bugbear` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8BugbearOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-builtins": { + "description": "Options for the `flake8-builtins` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8BuiltinsOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-comprehensions": { + "description": "Options for the `flake8-comprehensions` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8ComprehensionsOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-copyright": { + "description": "Options for the `flake8-copyright` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8CopyrightOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-errmsg": { + "description": "Options for the `flake8-errmsg` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8ErrMsgOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-gettext": { + "description": "Options for the `flake8-gettext` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8GetTextOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-implicit-str-concat": { + "description": "Options for the `flake8-implicit-str-concat` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8ImplicitStrConcatOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-import-conventions": { + "description": "Options for the `flake8-import-conventions` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8ImportConventionsOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-pytest-style": { + "description": "Options for the `flake8-pytest-style` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8PytestStyleOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-quotes": { + "description": "Options for the `flake8-quotes` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8QuotesOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-self": { + "description": "Options for the `flake8_self` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8SelfOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-tidy-imports": { + "description": "Options for the `flake8-tidy-imports` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8TidyImportsOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-type-checking": { + "description": "Options for the `flake8-type-checking` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8TypeCheckingOptions" + }, + { + "type": "null" + } + ] + }, + "flake8-unused-arguments": { + "description": "Options for the `flake8-unused-arguments` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Flake8UnusedArgumentsOptions" + }, + { + "type": "null" + } + ] + }, + "force-exclude": { + "description": "Whether to enforce `exclude` and `extend-exclude` patterns, even for paths that are passed to Ruff explicitly. Typically, Ruff will lint any paths passed in directly, even if they would typically be excluded. Setting `force-exclude = true` will cause Ruff to respect these exclusions unequivocally.\n\nThis is useful for [`pre-commit`](https://pre-commit.com/), which explicitly passes all changed files to the [`ruff-pre-commit`](https://github.com/astral-sh/ruff-pre-commit) plugin, regardless of whether they're marked as excluded by Ruff's own settings.", + "type": [ + "boolean", + "null" + ] + }, + "format": { + "description": "Options to configure the code formatting.\n\nPreviously: The style in which violation messages should be formatted: `\"text\"` (default), `\"grouped\"` (group messages by file), `\"json\"` (machine-readable), `\"junit\"` (machine-readable XML), `\"github\"` (GitHub Actions annotations), `\"gitlab\"` (GitLab CI code quality report), `\"pylint\"` (Pylint text format) or `\"azure\"` (Azure Pipeline logging commands).\n\nThis option has been **deprecated** in favor of `output-format` to avoid ambiguity with Ruff's upcoming formatter.", + "anyOf": [ + { + "$ref": "#/definitions/FormatOrOutputFormat" + }, + { + "type": "null" + } + ] + }, + "ignore": { + "description": "A list of rule codes or prefixes to ignore. Prefixes can specify exact rules (like `F841`), entire categories (like `F`), or anything in between.\n\nWhen breaking ties between enabled and disabled rules (via `select` and `ignore`, respectively), more specific prefixes override less specific prefixes.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/RuleSelector" + } + }, + "ignore-init-module-imports": { + "description": "Avoid automatically removing unused imports in `__init__.py` files. Such imports will still be flagged, but with a dedicated message suggesting that the import is either added to the module's `__all__` symbol, or re-exported with a redundant alias (e.g., `import os as os`).", + "type": [ + "boolean", + "null" + ] + }, + "isort": { + "description": "Options for the `isort` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/IsortOptions" + }, + { + "type": "null" + } + ] + }, + "logger-objects": { + "description": "A list of objects that should be treated equivalently to a `logging.Logger` object.\n\nThis is useful for ensuring proper diagnostics (e.g., to identify `logging` deprecations and other best-practices) for projects that re-export a `logging.Logger` object from a common module.\n\nFor example, if you have a module `logging_setup.py` with the following contents: ```python import logging\n\nlogger = logging.getLogger(__name__) ```\n\nAdding `\"logging_setup.logger\"` to `logger-objects` will ensure that `logging_setup.logger` is treated as a `logging.Logger` object when imported from other modules (e.g., `from logging_setup import logger`).", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "mccabe": { + "description": "Options for the `mccabe` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/McCabeOptions" + }, + { + "type": "null" + } + ] + }, + "output-format": { + "description": "The style in which violation messages should be formatted: `\"text\"` (default), `\"grouped\"` (group messages by file), `\"json\"` (machine-readable), `\"junit\"` (machine-readable XML), `\"github\"` (GitHub Actions annotations), `\"gitlab\"` (GitLab CI code quality report), `\"pylint\"` (Pylint text format) or `\"azure\"` (Azure Pipeline logging commands).", + "anyOf": [ + { + "$ref": "#/definitions/SerializationFormat" + }, + { + "type": "null" + } + ] + }, + "pep8-naming": { + "description": "Options for the `pep8-naming` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/Pep8NamingOptions" + }, + { + "type": "null" + } + ] + }, + "per-file-ignores": { + "description": "A list of mappings from file pattern to rule codes or prefixes to exclude, when considering any matching files.", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/definitions/RuleSelector" + } + } + }, + "pycodestyle": { + "description": "Options for the `pycodestyle` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/PycodestyleOptions" + }, + { + "type": "null" + } + ] + }, + "pydocstyle": { + "description": "Options for the `pydocstyle` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/PydocstyleOptions" + }, + { + "type": "null" + } + ] + }, + "pyflakes": { + "description": "Options for the `pyflakes` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/PyflakesOptions" + }, + { + "type": "null" + } + ] + }, + "pylint": { + "description": "Options for the `pylint` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/PylintOptions" + }, + { + "type": "null" + } + ] + }, + "pyupgrade": { + "description": "Options for the `pyupgrade` plugin.", + "anyOf": [ + { + "$ref": "#/definitions/PyUpgradeOptions" + }, + { + "type": "null" + } + ] + }, + "select": { + "description": "A list of rule codes or prefixes to enable. Prefixes can specify exact rules (like `F841`), entire categories (like `F`), or anything in between.\n\nWhen breaking ties between enabled and disabled rules (via `select` and `ignore`, respectively), more specific prefixes override less specific prefixes.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/RuleSelector" + } + }, + "task-tags": { + "description": "A list of task tags to recognize (e.g., \"TODO\", \"FIXME\", \"XXX\").\n\nComments starting with these tags will be ignored by commented-out code detection (`ERA`), and skipped by line-length rules (`E501`) if `ignore-overlong-task-comments` is set to `true`.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "unfixable": { + "description": "A list of rule codes or prefixes to consider non-autofix-able.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/RuleSelector" + } + } + }, + "additionalProperties": false + }, "McCabeOptions": { "type": "object", "properties": {