Skip to content

Commit

Permalink
Add lint section to Ruff configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser committed Sep 22, 2023
1 parent 5dc5178 commit 27cfbe0
Show file tree
Hide file tree
Showing 9 changed files with 1,163 additions and 555 deletions.
105 changes: 64 additions & 41 deletions crates/flake8_to_ruff/src/converter.rs
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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;
Expand All @@ -474,8 +479,8 @@ mod tests {
use super::super::plugin::Plugin;
use super::convert;

fn default_options(plugins: impl IntoIterator<Item = RuleSelector>) -> Options {
Options {
fn lint_default_options(plugins: impl IntoIterator<Item = RuleSelector>) -> LintOptions {
LintOptions {
ignore: Some(vec![]),
select: Some(
DEFAULT_SELECTORS
Expand All @@ -485,7 +490,7 @@ mod tests {
.sorted_by_key(RuleSelector::prefix_and_code)
.collect(),
),
..Options::default()
..LintOptions::default()
}
}

Expand All @@ -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);
}

Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
}

Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions crates/ruff_cli/src/args.rs
Expand Up @@ -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());
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down
16 changes: 8 additions & 8 deletions crates/ruff_dev/src/generate_docs.rs
Expand Up @@ -125,32 +125,32 @@ 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,
);
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
"
);
}
Expand Down
34 changes: 26 additions & 8 deletions crates/ruff_macros/src/config.rs
@@ -1,14 +1,15 @@
use ruff_python_trivia::textwrap::dedent;

use proc_macro2::TokenTree;
use quote::{quote, quote_spanned};
use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned;
use syn::token::Comma;
use syn::{
AngleBracketedGenericArguments, Attribute, Data, DataStruct, DeriveInput, ExprLit, Field,
Fields, Lit, LitStr, Path, PathArguments, PathSegment, Token, Type, TypePath,
Fields, Lit, LitStr, Meta, Path, PathArguments, PathSegment, Token, Type, TypePath,
};

use ruff_python_trivia::textwrap::dedent;

pub(crate) fn derive_impl(input: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
let DeriveInput { ident, data, .. } = input;

Expand Down Expand Up @@ -39,19 +40,36 @@ pub(crate) fn derive_impl(input: DeriveInput) -> syn::Result<proc_macro2::TokenS
.find(|attr| attr.path().is_ident("option"))
{
output.push(handle_option(field, attr, docs)?);
};

if field
} else if field
.attrs
.iter()
.any(|attr| attr.path().is_ident("option_group"))
{
output.push(handle_option_group(field)?);
};
} else if let Some(serde) = field
.attrs
.iter()
.find(|attr| attr.path().is_ident("serde"))
{
// If a field has the `serde(flatten)` attribute, flatten the options into the parent
// by calling `Type::record` instead of `visitor.visit_set`
if let (Type::Path(ty), Meta::List(list)) = (&field.ty, &serde.meta) {
for token in list.tokens.clone() {
if let TokenTree::Ident(ident) = token {
if ident == "flatten" {
let ty_name = ty.path.require_ident()?;
output.push(quote_spanned!(
ident.span() => (#ty_name::record(visit))
));
break;
}
}
}
}
}
}

Ok(quote! {

impl crate::options_base::OptionsMetadata for #ident {
fn record(visit: &mut dyn crate::options_base::Visit) {
#(#output);*
Expand Down

0 comments on commit 27cfbe0

Please sign in to comment.