Enable customization of autofixable error codes (#811)

This commit is contained in:
Charlie Marsh 2022-11-18 18:49:13 -05:00 committed by GitHub
parent 437b6f23b9
commit 0f34cdb7a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 312 additions and 228 deletions

View file

@ -122,7 +122,7 @@ default configuration is equivalent to:
[tool.ruff] [tool.ruff]
line-length = 88 line-length = 88
# Enable Flake's "E" and "F" codes by default. # Enable Pyflakes `E` and `F` codes by default.
select = ["E", "F"] select = ["E", "F"]
ignore = [] ignore = []
@ -157,18 +157,24 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
target-version = "py310" target-version = "py310"
``` ```
As an example, the following would configure Ruff to (1) avoid checking for line-length As an example, the following would configure Ruff to: (1) avoid checking for line-length
violations (`E501`) and (2) ignore unused import rules in `__init__.py` files: violations (`E501`); (2), always autofix, but never remove unused imports (`F401`); and (3) ignore
import-at-top-of-file errors (`E402`) in `__init__.py` files:
```toml ```toml
[tool.ruff] [tool.ruff]
# Enable Pyflakes and pycodestyle rules.
select = ["E", "F"] select = ["E", "F"]
# Never enforce `E501`. # Never enforce `E501` (line length violations).
ignore = ["E501"] ignore = ["E501"]
# Ignore `F401` violations in any `__init__.py` file, and in `path/to/file.py`. # Always autofix, but never try to fix `F401` (unused imports).
per-file-ignores = {"__init__.py" = ["F401"], "path/to/file.py" = ["F401"]} fix = true
unfixable = ["F401"]
# Ignore `E402` (import violations in any `__init__.py` file, and in `path/to/file.py`.
per-file-ignores = {"__init__.py" = ["E402"], "path/to/file.py" = ["E402"]}
``` ```
Plugin configurations should be expressed as subsections, e.g.: Plugin configurations should be expressed as subsections, e.g.:
@ -227,6 +233,10 @@ Options:
List of paths, used to exclude files and/or directories from checks List of paths, used to exclude files and/or directories from checks
--extend-exclude <EXTEND_EXCLUDE> --extend-exclude <EXTEND_EXCLUDE>
Like --exclude, but adds additional files and directories on top of the excluded ones Like --exclude, but adds additional files and directories on top of the excluded ones
--fixable <FIXABLE>
List of error codes to treat as eligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
--unfixable <UNFIXABLE>
List of error codes to treat as ineligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
--per-file-ignores <PER_FILE_IGNORES> --per-file-ignores <PER_FILE_IGNORES>
List of mappings from file pattern to code to exclude List of mappings from file pattern to code to exclude
--format <FORMAT> --format <FORMAT>

View file

@ -243,23 +243,25 @@ mod tests {
fn it_converts_empty() -> Result<()> { fn it_converts_empty() -> Result<()> {
let actual = convert(&HashMap::from([]), None)?; let actual = convert(&HashMap::from([]), None)?;
let expected = Pyproject::new(Options { let expected = Pyproject::new(Options {
line_length: None, dummy_variable_rgx: None,
src: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: Some(vec![]),
line_length: None,
per_file_ignores: None,
select: Some(vec![ select: Some(vec![
CheckCodePrefix::E, CheckCodePrefix::E,
CheckCodePrefix::F, CheckCodePrefix::F,
CheckCodePrefix::W, CheckCodePrefix::W,
]), ]),
extend_select: None,
ignore: Some(vec![]),
extend_ignore: None,
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None, show_source: None,
src: None,
target_version: None,
unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: None, flake8_quotes: None,
@ -280,23 +282,25 @@ mod tests {
Some(vec![]), Some(vec![]),
)?; )?;
let expected = Pyproject::new(Options { let expected = Pyproject::new(Options {
line_length: Some(100), dummy_variable_rgx: None,
src: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: Some(vec![]),
line_length: Some(100),
per_file_ignores: None,
select: Some(vec![ select: Some(vec![
CheckCodePrefix::E, CheckCodePrefix::E,
CheckCodePrefix::F, CheckCodePrefix::F,
CheckCodePrefix::W, CheckCodePrefix::W,
]), ]),
extend_select: None,
ignore: Some(vec![]),
extend_ignore: None,
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None, show_source: None,
src: None,
target_version: None,
unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: None, flake8_quotes: None,
@ -317,23 +321,25 @@ mod tests {
Some(vec![]), Some(vec![]),
)?; )?;
let expected = Pyproject::new(Options { let expected = Pyproject::new(Options {
line_length: Some(100), dummy_variable_rgx: None,
src: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: Some(vec![]),
line_length: Some(100),
per_file_ignores: None,
select: Some(vec![ select: Some(vec![
CheckCodePrefix::E, CheckCodePrefix::E,
CheckCodePrefix::F, CheckCodePrefix::F,
CheckCodePrefix::W, CheckCodePrefix::W,
]), ]),
extend_select: None,
ignore: Some(vec![]),
extend_ignore: None,
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None, show_source: None,
src: None,
target_version: None,
unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: None, flake8_quotes: None,
@ -354,23 +360,25 @@ mod tests {
Some(vec![]), Some(vec![]),
)?; )?;
let expected = Pyproject::new(Options { let expected = Pyproject::new(Options {
line_length: None, dummy_variable_rgx: None,
src: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: Some(vec![]),
line_length: None,
per_file_ignores: None,
select: Some(vec![ select: Some(vec![
CheckCodePrefix::E, CheckCodePrefix::E,
CheckCodePrefix::F, CheckCodePrefix::F,
CheckCodePrefix::W, CheckCodePrefix::W,
]), ]),
extend_select: None,
ignore: Some(vec![]),
extend_ignore: None,
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None, show_source: None,
src: None,
target_version: None,
unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: None, flake8_quotes: None,
@ -391,23 +399,25 @@ mod tests {
Some(vec![]), Some(vec![]),
)?; )?;
let expected = Pyproject::new(Options { let expected = Pyproject::new(Options {
line_length: None, dummy_variable_rgx: None,
src: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: Some(vec![]),
line_length: None,
per_file_ignores: None,
select: Some(vec![ select: Some(vec![
CheckCodePrefix::E, CheckCodePrefix::E,
CheckCodePrefix::F, CheckCodePrefix::F,
CheckCodePrefix::W, CheckCodePrefix::W,
]), ]),
extend_select: None,
ignore: Some(vec![]),
extend_ignore: None,
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None, show_source: None,
src: None,
target_version: None,
unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: Some(flake8_quotes::settings::Options { flake8_quotes: Some(flake8_quotes::settings::Options {
@ -436,11 +446,16 @@ mod tests {
Some(vec![Plugin::Flake8Docstrings]), Some(vec![Plugin::Flake8Docstrings]),
)?; )?;
let expected = Pyproject::new(Options { let expected = Pyproject::new(Options {
line_length: None, dummy_variable_rgx: None,
src: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: Some(vec![]),
line_length: None,
per_file_ignores: None,
select: Some(vec![ select: Some(vec![
CheckCodePrefix::D100, CheckCodePrefix::D100,
CheckCodePrefix::D101, CheckCodePrefix::D101,
@ -481,13 +496,10 @@ mod tests {
CheckCodePrefix::F, CheckCodePrefix::F,
CheckCodePrefix::W, CheckCodePrefix::W,
]), ]),
extend_select: None,
ignore: Some(vec![]),
extend_ignore: None,
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None, show_source: None,
src: None,
target_version: None,
unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: None, flake8_quotes: None,
@ -508,24 +520,26 @@ mod tests {
None, None,
)?; )?;
let expected = Pyproject::new(Options { let expected = Pyproject::new(Options {
line_length: None, dummy_variable_rgx: None,
src: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: Some(vec![]),
line_length: None,
per_file_ignores: None,
select: Some(vec![ select: Some(vec![
CheckCodePrefix::E, CheckCodePrefix::E,
CheckCodePrefix::F, CheckCodePrefix::F,
CheckCodePrefix::Q, CheckCodePrefix::Q,
CheckCodePrefix::W, CheckCodePrefix::W,
]), ]),
extend_select: None,
ignore: Some(vec![]),
extend_ignore: None,
per_file_ignores: None,
dummy_variable_rgx: None,
target_version: None,
show_source: None, show_source: None,
src: None,
target_version: None,
unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: Some(flake8_quotes::settings::Options { flake8_quotes: Some(flake8_quotes::settings::Options {

View file

@ -152,10 +152,10 @@ impl<'a> Checker<'a> {
/// Return `true` if a patch should be generated under the given autofix /// Return `true` if a patch should be generated under the given autofix
/// `Mode`. /// `Mode`.
pub fn patch(&self) -> bool { pub fn patch(&self, code: &CheckCode) -> bool {
// TODO(charlie): We can't fix errors in f-strings until RustPython adds // TODO(charlie): We can't fix errors in f-strings until RustPython adds
// location data. // location data.
self.autofix.patch() && self.in_f_string.is_none() self.autofix.patch() && self.in_f_string.is_none() && self.settings.fixable.contains(code)
} }
/// Return `true` if the `Expr` is a reference to `typing.${target}`. /// Return `true` if the `Expr` is a reference to `typing.${target}`.
@ -1256,7 +1256,7 @@ where
args, args,
keywords, keywords,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C400),
Range::from_located(expr), Range::from_located(expr),
) { ) {
self.add_check(check); self.add_check(check);
@ -1270,7 +1270,7 @@ where
args, args,
keywords, keywords,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C401),
Range::from_located(expr), Range::from_located(expr),
) { ) {
self.add_check(check); self.add_check(check);
@ -1284,7 +1284,7 @@ where
args, args,
keywords, keywords,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C402),
Range::from_located(expr), Range::from_located(expr),
) { ) {
self.add_check(check); self.add_check(check);
@ -1299,7 +1299,7 @@ where
args, args,
keywords, keywords,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C403),
Range::from_located(expr), Range::from_located(expr),
) )
{ {
@ -1315,7 +1315,7 @@ where
args, args,
keywords, keywords,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C404),
Range::from_located(expr), Range::from_located(expr),
) )
{ {
@ -1330,7 +1330,7 @@ where
args, args,
keywords, keywords,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C405),
Range::from_located(expr), Range::from_located(expr),
) { ) {
self.add_check(check); self.add_check(check);
@ -1344,7 +1344,7 @@ where
args, args,
keywords, keywords,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C406),
Range::from_located(expr), Range::from_located(expr),
) { ) {
self.add_check(check); self.add_check(check);
@ -1358,7 +1358,7 @@ where
args, args,
keywords, keywords,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C408),
Range::from_located(expr), Range::from_located(expr),
) { ) {
self.add_check(check); self.add_check(check);
@ -1372,7 +1372,7 @@ where
func, func,
args, args,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C409),
Range::from_located(expr), Range::from_located(expr),
) )
{ {
@ -1387,7 +1387,7 @@ where
func, func,
args, args,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C410),
Range::from_located(expr), Range::from_located(expr),
) )
{ {
@ -1401,7 +1401,7 @@ where
func, func,
args, args,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C411),
Range::from_located(expr), Range::from_located(expr),
) { ) {
self.add_check(check); self.add_check(check);
@ -1415,7 +1415,7 @@ where
func, func,
args, args,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C413),
Range::from_located(expr), Range::from_located(expr),
) )
{ {
@ -1667,7 +1667,7 @@ where
elt, elt,
generators, generators,
self.locator, self.locator,
self.patch(), self.patch(&CheckCode::C416),
Range::from_located(expr), Range::from_located(expr),
) { ) {
self.add_check(check); self.add_check(check);
@ -2628,7 +2628,7 @@ impl<'a> Checker<'a> {
let child = self.parents[defined_by]; let child = self.parents[defined_by];
let parent = defined_in.map(|defined_in| self.parents[defined_in]); let parent = defined_in.map(|defined_in| self.parents[defined_in]);
let fix = if self.patch() { let fix = if self.patch(&CheckCode::F401) {
let deleted: Vec<&Stmt> = self let deleted: Vec<&Stmt> = self
.deletions .deletions
.iter() .iter()

View file

@ -73,7 +73,7 @@ pub fn check_lines(
end_location: Location::new(lineno + 1, line_length + 1), end_location: Location::new(lineno + 1, line_length + 1),
}, },
); );
if autofix.patch() { if autofix.patch() && settings.fixable.contains(check.kind.code()) {
check.amend(Fix::deletion( check.amend(Fix::deletion(
Location::new(lineno + 1, 0), Location::new(lineno + 1, 0),
Location::new(lineno + 1, line_length + 1), Location::new(lineno + 1, line_length + 1),
@ -195,7 +195,7 @@ pub fn check_lines(
end_location: Location::new(row + 1, end), end_location: Location::new(row + 1, end),
}, },
); );
if autofix.patch() { if autofix.patch() && settings.fixable.contains(check.kind.code()) {
check.amend(Fix::deletion( check.amend(Fix::deletion(
Location::new(row + 1, start), Location::new(row + 1, start),
Location::new(row + 1, lines[row].chars().count()), Location::new(row + 1, lines[row].chars().count()),
@ -223,7 +223,7 @@ pub fn check_lines(
end_location: Location::new(row + 1, end), end_location: Location::new(row + 1, end),
}, },
); );
if autofix.patch() { if autofix.patch() && settings.fixable.contains(check.kind.code()) {
if valid_codes.is_empty() { if valid_codes.is_empty() {
check.amend(Fix::deletion( check.amend(Fix::deletion(
Location::new(row + 1, start), Location::new(row + 1, start),

View file

@ -36,7 +36,7 @@ pub fn check_tokens(
// RUF001, RUF002, RUF003 // RUF001, RUF002, RUF003
if enforce_ambiguous_unicode_character { if enforce_ambiguous_unicode_character {
if matches!(tok, Tok::String { .. } | Tok::Comment) { if matches!(tok, Tok::String { .. } | Tok::Comment) {
for check in rules::checks::ambiguous_unicode_character( checks.extend(rules::checks::ambiguous_unicode_character(
locator, locator,
start, start,
end, end,
@ -49,12 +49,9 @@ pub fn check_tokens(
} else { } else {
Context::Comment Context::Comment
}, },
autofix.patch(), settings,
) { autofix,
if settings.enabled.contains(check.kind.code()) { ));
checks.push(check);
}
}
} }
} }

View file

@ -63,6 +63,14 @@ pub struct Cli {
/// excluded ones. /// excluded ones.
#[arg(long, value_delimiter = ',')] #[arg(long, value_delimiter = ',')]
pub extend_exclude: Vec<String>, pub extend_exclude: Vec<String>,
/// List of error codes to treat as eligible for autofix. Only applicable
/// when autofix itself is enabled (e.g., via `--fix`).
#[arg(long, value_delimiter = ',')]
pub fixable: Vec<CheckCodePrefix>,
/// List of error codes to treat as ineligible for autofix. Only applicable
/// when autofix itself is enabled (e.g., via `--fix`).
#[arg(long, value_delimiter = ',')]
pub unfixable: Vec<CheckCodePrefix>,
/// List of mappings from file pattern to code to exclude /// List of mappings from file pattern to code to exclude
#[arg(long, value_delimiter = ',')] #[arg(long, value_delimiter = ',')]
pub per_file_ignores: Vec<PatternPrefixPair>, pub per_file_ignores: Vec<PatternPrefixPair>,

View file

@ -36,6 +36,7 @@ fn assertion_error(msg: Option<&Expr>) -> Stmt {
) )
} }
/// B011
pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option<&Expr>) { pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option<&Expr>) {
if let ExprKind::Constant { if let ExprKind::Constant {
value: Constant::Bool(false), value: Constant::Bool(false),
@ -43,7 +44,7 @@ pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option
} = &test.node } = &test.node
{ {
let mut check = Check::new(CheckKind::DoNotAssertFalse, Range::from_located(test)); let mut check = Check::new(CheckKind::DoNotAssertFalse, Range::from_located(test));
if checker.patch() { if checker.patch(check.kind.code()) {
let mut generator = SourceGenerator::new(); let mut generator = SourceGenerator::new();
if let Ok(()) = generator.unparse_stmt(&assertion_error(msg)) { if let Ok(()) = generator.unparse_stmt(&assertion_error(msg)) {
if let Ok(content) = generator.generate() { if let Ok(content) = generator.generate() {

View file

@ -54,7 +54,7 @@ fn duplicate_handler_exceptions<'a>(
), ),
Range::from_located(expr), Range::from_located(expr),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// TODO(charlie): If we have a single element, remove the tuple. // TODO(charlie): If we have a single element, remove the tuple.
let mut generator = SourceGenerator::new(); let mut generator = SourceGenerator::new();
if let Ok(()) = generator.unparse_expr(&type_pattern(unique_elts), 0) { if let Ok(()) = generator.unparse_expr(&type_pattern(unique_elts), 0) {

View file

@ -20,6 +20,7 @@ fn attribute(value: &Expr, attr: &str) -> Expr {
) )
} }
/// B009
pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) { pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
if let ExprKind::Name { id, .. } = &func.node { if let ExprKind::Name { id, .. } = &func.node {
if id == "getattr" { if id == "getattr" {
@ -32,7 +33,7 @@ pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
if IDENTIFIER_REGEX.is_match(value) && !KWLIST.contains(&value.as_str()) { if IDENTIFIER_REGEX.is_match(value) && !KWLIST.contains(&value.as_str()) {
let mut check = let mut check =
Check::new(CheckKind::GetAttrWithConstant, Range::from_located(expr)); Check::new(CheckKind::GetAttrWithConstant, Range::from_located(expr));
if checker.patch() { if checker.patch(check.kind.code()) {
let mut generator = SourceGenerator::new(); let mut generator = SourceGenerator::new();
if let Ok(()) = generator.unparse_expr(&attribute(obj, value), 0) { if let Ok(()) = generator.unparse_expr(&attribute(obj, value), 0) {
if let Ok(content) = generator.generate() { if let Ok(content) = generator.generate() {

View file

@ -65,7 +65,7 @@ pub fn unused_loop_control_variable(checker: &mut Checker, target: &Expr, body:
CheckKind::UnusedLoopControlVariable(name.to_string()), CheckKind::UnusedLoopControlVariable(name.to_string()),
Range::from_located(expr), Range::from_located(expr),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Prefix the variable name with an underscore. // Prefix the variable name with an underscore.
check.amend(Fix::replacement( check.amend(Fix::replacement(
format!("_{name}"), format!("_{name}"),

View file

@ -16,7 +16,7 @@ pub fn print_call(checker: &mut Checker, expr: &Expr, func: &Expr) {
checker.settings.enabled.contains(&CheckCode::T203), checker.settings.enabled.contains(&CheckCode::T203),
Range::from_located(expr), Range::from_located(expr),
) { ) {
if checker.patch() { if checker.patch(check.kind.code()) {
let context = checker.binding_context(); let context = checker.binding_context();
if matches!( if matches!(
checker.parents[context.defined_by].node, checker.parents[context.defined_by].node,

View file

@ -91,7 +91,7 @@ pub fn check_imports(
if has_leading_content || has_trailing_content { if has_leading_content || has_trailing_content {
let mut check = Check::new(CheckKind::UnsortedImports, range); let mut check = Check::new(CheckKind::UnsortedImports, range);
if autofix.patch() { if autofix.patch() && settings.fixable.contains(check.kind.code()) {
let mut content = String::new(); let mut content = String::new();
if has_leading_content { if has_leading_content {
content.push('\n'); content.push('\n');
@ -119,7 +119,7 @@ pub fn check_imports(
let actual = dedent(&locator.slice_source_code_range(&range)); let actual = dedent(&locator.slice_source_code_range(&range));
if actual != expected { if actual != expected {
let mut check = Check::new(CheckKind::UnsortedImports, range); let mut check = Check::new(CheckKind::UnsortedImports, range);
if autofix.patch() { if autofix.patch() && settings.fixable.contains(check.kind.code()) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
indent(&expected, &indentation), indent(&expected, &indentation),
range.location, range.location,

View file

@ -251,6 +251,12 @@ fn inner_main() -> Result<ExitCode> {
if !cli.extend_ignore.is_empty() { if !cli.extend_ignore.is_empty() {
configuration.extend_ignore = cli.extend_ignore; configuration.extend_ignore = cli.extend_ignore;
} }
if !cli.fixable.is_empty() {
configuration.fixable = cli.fixable;
}
if !cli.unfixable.is_empty() {
configuration.unfixable = cli.unfixable;
}
if let Some(line_length) = cli.line_length { if let Some(line_length) = cli.line_length {
configuration.line_length = line_length; configuration.line_length = line_length;
} }

View file

@ -62,7 +62,7 @@ pub fn literal_comparisons(
CheckKind::NoneComparison(RejectedCmpop::Eq), CheckKind::NoneComparison(RejectedCmpop::Eq),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Dummy replacement // Dummy replacement
check.amend(Fix::dummy(expr.location)); check.amend(Fix::dummy(expr.location));
bad_ops.insert(0, Cmpop::Is); bad_ops.insert(0, Cmpop::Is);
@ -74,7 +74,7 @@ pub fn literal_comparisons(
CheckKind::NoneComparison(RejectedCmpop::NotEq), CheckKind::NoneComparison(RejectedCmpop::NotEq),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::dummy(expr.location)); check.amend(Fix::dummy(expr.location));
bad_ops.insert(0, Cmpop::IsNot); bad_ops.insert(0, Cmpop::IsNot);
} }
@ -93,7 +93,7 @@ pub fn literal_comparisons(
CheckKind::TrueFalseComparison(value, RejectedCmpop::Eq), CheckKind::TrueFalseComparison(value, RejectedCmpop::Eq),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::dummy(expr.location)); check.amend(Fix::dummy(expr.location));
bad_ops.insert(0, Cmpop::Is); bad_ops.insert(0, Cmpop::Is);
} }
@ -104,7 +104,7 @@ pub fn literal_comparisons(
CheckKind::TrueFalseComparison(value, RejectedCmpop::NotEq), CheckKind::TrueFalseComparison(value, RejectedCmpop::NotEq),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::dummy(expr.location)); check.amend(Fix::dummy(expr.location));
bad_ops.insert(0, Cmpop::IsNot); bad_ops.insert(0, Cmpop::IsNot);
} }
@ -129,7 +129,7 @@ pub fn literal_comparisons(
CheckKind::NoneComparison(RejectedCmpop::Eq), CheckKind::NoneComparison(RejectedCmpop::Eq),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::dummy(expr.location)); check.amend(Fix::dummy(expr.location));
bad_ops.insert(idx, Cmpop::Is); bad_ops.insert(idx, Cmpop::Is);
} }
@ -140,7 +140,7 @@ pub fn literal_comparisons(
CheckKind::NoneComparison(RejectedCmpop::NotEq), CheckKind::NoneComparison(RejectedCmpop::NotEq),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::dummy(expr.location)); check.amend(Fix::dummy(expr.location));
bad_ops.insert(idx, Cmpop::IsNot); bad_ops.insert(idx, Cmpop::IsNot);
} }
@ -159,7 +159,7 @@ pub fn literal_comparisons(
CheckKind::TrueFalseComparison(value, RejectedCmpop::Eq), CheckKind::TrueFalseComparison(value, RejectedCmpop::Eq),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::dummy(expr.location)); check.amend(Fix::dummy(expr.location));
bad_ops.insert(idx, Cmpop::Is); bad_ops.insert(idx, Cmpop::Is);
} }
@ -170,7 +170,7 @@ pub fn literal_comparisons(
CheckKind::TrueFalseComparison(value, RejectedCmpop::NotEq), CheckKind::TrueFalseComparison(value, RejectedCmpop::NotEq),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::dummy(expr.location)); check.amend(Fix::dummy(expr.location));
bad_ops.insert(idx, Cmpop::IsNot); bad_ops.insert(idx, Cmpop::IsNot);
} }
@ -226,7 +226,7 @@ pub fn not_tests(
if check_not_in { if check_not_in {
let mut check = let mut check =
Check::new(CheckKind::NotInTest, Range::from_located(operand)); Check::new(CheckKind::NotInTest, Range::from_located(operand));
if checker.patch() && should_fix { if checker.patch(check.kind.code()) && should_fix {
if let Some(content) = compare(left, &[Cmpop::NotIn], comparators) { if let Some(content) = compare(left, &[Cmpop::NotIn], comparators) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
content, content,
@ -242,7 +242,7 @@ pub fn not_tests(
if check_not_is { if check_not_is {
let mut check = let mut check =
Check::new(CheckKind::NotIsTest, Range::from_located(operand)); Check::new(CheckKind::NotIsTest, Range::from_located(operand));
if checker.patch() && should_fix { if checker.patch(check.kind.code()) && should_fix {
if let Some(content) = compare(left, &[Cmpop::IsNot], comparators) { if let Some(content) = compare(left, &[Cmpop::IsNot], comparators) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
content, content,

View file

@ -179,7 +179,7 @@ pub fn blank_before_after_function(checker: &mut Checker, definition: &Definitio
CheckKind::NoBlankLineBeforeFunction(blank_lines_before), CheckKind::NoBlankLineBeforeFunction(blank_lines_before),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Delete the blank line before the docstring. // Delete the blank line before the docstring.
check.amend(Fix::deletion( check.amend(Fix::deletion(
Location::new(docstring.location.row() - blank_lines_before, 0), Location::new(docstring.location.row() - blank_lines_before, 0),
@ -220,7 +220,7 @@ pub fn blank_before_after_function(checker: &mut Checker, definition: &Definitio
CheckKind::NoBlankLineAfterFunction(blank_lines_after), CheckKind::NoBlankLineAfterFunction(blank_lines_after),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Delete the blank line after the docstring. // Delete the blank line after the docstring.
check.amend(Fix::deletion( check.amend(Fix::deletion(
Location::new(docstring.end_location.unwrap().row() + 1, 0), Location::new(docstring.end_location.unwrap().row() + 1, 0),
@ -269,7 +269,7 @@ pub fn blank_before_after_class(checker: &mut Checker, definition: &Definition)
CheckKind::NoBlankLineBeforeClass(blank_lines_before), CheckKind::NoBlankLineBeforeClass(blank_lines_before),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Delete the blank line before the class. // Delete the blank line before the class.
check.amend(Fix::deletion( check.amend(Fix::deletion(
Location::new(docstring.location.row() - blank_lines_before, 0), Location::new(docstring.location.row() - blank_lines_before, 0),
@ -285,7 +285,7 @@ pub fn blank_before_after_class(checker: &mut Checker, definition: &Definition)
CheckKind::OneBlankLineBeforeClass(blank_lines_before), CheckKind::OneBlankLineBeforeClass(blank_lines_before),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Insert one blank line before the class. // Insert one blank line before the class.
check.amend(Fix::replacement( check.amend(Fix::replacement(
"\n".to_string(), "\n".to_string(),
@ -322,7 +322,7 @@ pub fn blank_before_after_class(checker: &mut Checker, definition: &Definition)
CheckKind::OneBlankLineAfterClass(blank_lines_after), CheckKind::OneBlankLineAfterClass(blank_lines_after),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Insert a blank line before the class (replacing any existing lines). // Insert a blank line before the class (replacing any existing lines).
check.amend(Fix::replacement( check.amend(Fix::replacement(
"\n".to_string(), "\n".to_string(),
@ -364,7 +364,7 @@ pub fn blank_after_summary(checker: &mut Checker, definition: &Definition) {
CheckKind::BlankLineAfterSummary, CheckKind::BlankLineAfterSummary,
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Insert one blank line after the summary (replacing any existing lines). // Insert one blank line after the summary (replacing any existing lines).
check.amend(Fix::replacement( check.amend(Fix::replacement(
"\n".to_string(), "\n".to_string(),
@ -425,7 +425,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
end_location: Location::new(docstring.location.row() + i, 0), end_location: Location::new(docstring.location.row() + i, 0),
}, },
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
helpers::clean(&docstring_indent), helpers::clean(&docstring_indent),
Location::new(docstring.location.row() + i, 0), Location::new(docstring.location.row() + i, 0),
@ -475,7 +475,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
end_location: Location::new(docstring.location.row() + i, 0), end_location: Location::new(docstring.location.row() + i, 0),
}, },
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
helpers::clean(&docstring_indent), helpers::clean(&docstring_indent),
Location::new(docstring.location.row() + i, 0), Location::new(docstring.location.row() + i, 0),
@ -499,7 +499,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
end_location: Location::new(docstring.location.row() + i, 0), end_location: Location::new(docstring.location.row() + i, 0),
}, },
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
helpers::clean(&docstring_indent), helpers::clean(&docstring_indent),
Location::new(docstring.location.row() + i, 0), Location::new(docstring.location.row() + i, 0),
@ -537,7 +537,7 @@ pub fn newline_after_last_paragraph(checker: &mut Checker, definition: &Definiti
CheckKind::NewLineAfterLastParagraph, CheckKind::NewLineAfterLastParagraph,
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Insert a newline just before the end-quote(s). // Insert a newline just before the end-quote(s).
let content = format!( let content = format!(
"\n{}", "\n{}",
@ -580,7 +580,7 @@ pub fn no_surrounding_whitespace(checker: &mut Checker, definition: &Definition)
CheckKind::NoSurroundingWhitespace, CheckKind::NoSurroundingWhitespace,
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
if let Some(first_line) = checker if let Some(first_line) = checker
.locator .locator
.slice_source_code_range(&Range::from_located(docstring)) .slice_source_code_range(&Range::from_located(docstring))
@ -916,7 +916,7 @@ fn blanks_and_section_underline(
CheckKind::DashedUnderlineAfterSection(context.section_name.to_string()), CheckKind::DashedUnderlineAfterSection(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Add a dashed line (of the appropriate length) under the section header. // Add a dashed line (of the appropriate length) under the section header.
let content = format!( let content = format!(
"{}{}\n", "{}{}\n",
@ -950,7 +950,7 @@ fn blanks_and_section_underline(
CheckKind::DashedUnderlineAfterSection(context.section_name.to_string()), CheckKind::DashedUnderlineAfterSection(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Add a dashed line (of the appropriate length) under the section header. // Add a dashed line (of the appropriate length) under the section header.
let content = format!( let content = format!(
"{}{}\n", "{}{}\n",
@ -972,7 +972,7 @@ fn blanks_and_section_underline(
), ),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Delete any blank lines between the header and content. // Delete any blank lines between the header and content.
check.amend(Fix::deletion( check.amend(Fix::deletion(
Location::new(docstring.location.row() + context.original_index + 1, 0), Location::new(docstring.location.row() + context.original_index + 1, 0),
@ -995,7 +995,7 @@ fn blanks_and_section_underline(
CheckKind::SectionUnderlineAfterName(context.section_name.to_string()), CheckKind::SectionUnderlineAfterName(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Delete any blank lines between the header and the underline. // Delete any blank lines between the header and the underline.
check.amend(Fix::deletion( check.amend(Fix::deletion(
Location::new(docstring.location.row() + context.original_index + 1, 0), Location::new(docstring.location.row() + context.original_index + 1, 0),
@ -1026,7 +1026,7 @@ fn blanks_and_section_underline(
), ),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Replace the existing underline with a line of the appropriate length. // Replace the existing underline with a line of the appropriate length.
let content = format!( let content = format!(
"{}{}\n", "{}{}\n",
@ -1064,7 +1064,7 @@ fn blanks_and_section_underline(
CheckKind::SectionUnderlineNotOverIndented(context.section_name.to_string()), CheckKind::SectionUnderlineNotOverIndented(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Replace the existing indentation with whitespace of the appropriate length. // Replace the existing indentation with whitespace of the appropriate length.
check.amend(Fix::replacement( check.amend(Fix::replacement(
helpers::clean(&indentation), helpers::clean(&indentation),
@ -1113,7 +1113,7 @@ fn blanks_and_section_underline(
), ),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Delete any blank lines between the header and content. // Delete any blank lines between the header and content.
check.amend(Fix::deletion( check.amend(Fix::deletion(
Location::new( Location::new(
@ -1172,7 +1172,7 @@ fn common_section(
CheckKind::CapitalizeSectionName(context.section_name.to_string()), CheckKind::CapitalizeSectionName(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Replace the section title with the capitalized variant. This requires // Replace the section title with the capitalized variant. This requires
// locating the start and end of the section name. // locating the start and end of the section name.
if let Some(index) = context.line.find(&context.section_name) { if let Some(index) = context.line.find(&context.section_name) {
@ -1205,7 +1205,7 @@ fn common_section(
CheckKind::SectionNotOverIndented(context.section_name.to_string()), CheckKind::SectionNotOverIndented(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Replace the existing indentation with whitespace of the appropriate length. // Replace the existing indentation with whitespace of the appropriate length.
check.amend(Fix::replacement( check.amend(Fix::replacement(
helpers::clean(&indentation), helpers::clean(&indentation),
@ -1232,7 +1232,7 @@ fn common_section(
CheckKind::BlankLineAfterLastSection(context.section_name.to_string()), CheckKind::BlankLineAfterLastSection(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Add a newline after the section. // Add a newline after the section.
check.amend(Fix::insertion( check.amend(Fix::insertion(
"\n".to_string(), "\n".to_string(),
@ -1253,7 +1253,7 @@ fn common_section(
CheckKind::BlankLineAfterSection(context.section_name.to_string()), CheckKind::BlankLineAfterSection(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Add a newline after the section. // Add a newline after the section.
check.amend(Fix::insertion( check.amend(Fix::insertion(
"\n".to_string(), "\n".to_string(),
@ -1277,7 +1277,7 @@ fn common_section(
CheckKind::BlankLineBeforeSection(context.section_name.to_string()), CheckKind::BlankLineBeforeSection(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Add a blank line before the section. // Add a blank line before the section.
check.amend(Fix::insertion( check.amend(Fix::insertion(
"\n".to_string(), "\n".to_string(),
@ -1444,7 +1444,7 @@ fn numpy_section(checker: &mut Checker, definition: &Definition, context: &Secti
CheckKind::NewLineAfterSectionName(context.section_name.to_string()), CheckKind::NewLineAfterSectionName(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Delete the suffix. This requires locating the end of the section name. // Delete the suffix. This requires locating the end of the section name.
if let Some(index) = context.line.find(&context.section_name) { if let Some(index) = context.line.find(&context.section_name) {
// Map from bytes to characters. // Map from bytes to characters.
@ -1493,7 +1493,7 @@ fn google_section(checker: &mut Checker, definition: &Definition, context: &Sect
CheckKind::SectionNameEndsInColon(context.section_name.to_string()), CheckKind::SectionNameEndsInColon(context.section_name.to_string()),
Range::from_located(docstring), Range::from_located(docstring),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
// Replace the suffix. This requires locating the end of the section name. // Replace the suffix. This requires locating the end of the section name.
if let Some(index) = context.line.find(&context.section_name) { if let Some(index) = context.line.find(&context.section_name) {
// Map from bytes to characters. // Map from bytes to characters.

View file

@ -43,7 +43,7 @@ pub fn invalid_literal_comparison(
&& (is_constant_non_singleton(left) || is_constant_non_singleton(right)) && (is_constant_non_singleton(left) || is_constant_non_singleton(right))
{ {
let mut check = Check::new(CheckKind::IsLiteral, location); let mut check = Check::new(CheckKind::IsLiteral, location);
if checker.patch() { if checker.patch(check.kind.code()) {
match fix_invalid_literal_comparison( match fix_invalid_literal_comparison(
checker.locator, checker.locator,
Range { Range {

View file

@ -28,7 +28,7 @@ fn match_not_implemented(expr: &Expr) -> Option<&Expr> {
pub fn raise_not_implemented(checker: &mut Checker, expr: &Expr) { pub fn raise_not_implemented(checker: &mut Checker, expr: &Expr) {
if let Some(expr) = match_not_implemented(expr) { if let Some(expr) = match_not_implemented(expr) {
let mut check = Check::new(CheckKind::RaiseNotImplemented, Range::from_located(expr)); let mut check = Check::new(CheckKind::RaiseNotImplemented, Range::from_located(expr));
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
"NotImplementedError".to_string(), "NotImplementedError".to_string(),
expr.location, expr.location,

View file

@ -220,7 +220,7 @@ pub fn convert_typed_dict_functional_to_class(
CheckKind::ConvertTypedDictFunctionalToClass, CheckKind::ConvertTypedDictFunctionalToClass,
Range::from_located(stmt), Range::from_located(stmt),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
match convert_to_functional_class(stmt, class_name, body, total_keyword) { match convert_to_functional_class(stmt, class_name, body, total_keyword) {
Ok(fix) => check.amend(fix), Ok(fix) => check.amend(fix),
Err(err) => error!("Failed to convert TypedDict: {}", err), Err(err) => error!("Failed to convert TypedDict: {}", err),

View file

@ -37,7 +37,7 @@ pub fn deprecated_unittest_alias(checker: &mut Checker, expr: &Expr) {
CheckKind::DeprecatedUnittestAlias(attr.to_string(), target.to_string()), CheckKind::DeprecatedUnittestAlias(attr.to_string(), target.to_string()),
Range::from_located(expr), Range::from_located(expr),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
format!("self.{}", target), format!("self.{}", target),
expr.location, expr.location,

View file

@ -17,7 +17,7 @@ pub fn super_call_with_parameters(checker: &mut Checker, expr: &Expr, func: &Exp
.map(|index| checker.parents[*index]) .map(|index| checker.parents[*index])
.collect(); .collect();
if let Some(mut check) = checks::super_args(scope, &parents, expr, func, args) { if let Some(mut check) = checks::super_args(scope, &parents, expr, func, args) {
if checker.patch() { if checker.patch(check.kind.code()) {
if let Some(fix) = pyupgrade::fixes::remove_super_arguments(checker.locator, expr) { if let Some(fix) = pyupgrade::fixes::remove_super_arguments(checker.locator, expr) {
check.amend(fix); check.amend(fix);
} }

View file

@ -9,7 +9,7 @@ use crate::pyupgrade::checks;
/// U003 /// U003
pub fn type_of_primitive(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) { pub fn type_of_primitive(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
if let Some(mut check) = checks::type_of_primitive(func, args, Range::from_located(expr)) { if let Some(mut check) = checks::type_of_primitive(func, args, Range::from_located(expr)) {
if checker.patch() { if checker.patch(check.kind.code()) {
if let CheckKind::TypeOfPrimitive(primitive) = &check.kind { if let CheckKind::TypeOfPrimitive(primitive) = &check.kind {
check.amend(Fix::replacement( check.amend(Fix::replacement(
primitive.builtin(), primitive.builtin(),

View file

@ -3,7 +3,7 @@ use rustpython_ast::{Constant, Expr, ExprKind, Keyword};
use crate::ast::types::Range; use crate::ast::types::Range;
use crate::autofix::Fix; use crate::autofix::Fix;
use crate::check_ast::Checker; use crate::check_ast::Checker;
use crate::checks::{Check, CheckKind}; use crate::checks::{Check, CheckCode, CheckKind};
use crate::source_code_locator::SourceCodeLocator; use crate::source_code_locator::SourceCodeLocator;
const UTF8_LITERALS: &[&str] = &["utf-8", "utf8", "utf_8", "u8", "utf", "cp65001"]; const UTF8_LITERALS: &[&str] = &["utf-8", "utf8", "utf_8", "u8", "utf", "cp65001"];
@ -124,13 +124,16 @@ pub fn unnecessary_encode_utf8(
expr, expr,
variable, variable,
checker.locator, checker.locator,
checker.patch(), checker.patch(&CheckCode::U012),
)); ));
} else { } else {
// "unicode text©".encode("utf-8") // "unicode text©".encode("utf-8")
if let Some(check) = if let Some(check) = delete_default_encode_arg_or_kwarg(
delete_default_encode_arg_or_kwarg(expr, args, kwargs, checker.patch()) expr,
{ args,
kwargs,
checker.patch(&CheckCode::U012),
) {
checker.add_check(check); checker.add_check(check);
} }
} }
@ -139,9 +142,12 @@ pub fn unnecessary_encode_utf8(
// f"foo{bar}".encode(*args, **kwargs) // f"foo{bar}".encode(*args, **kwargs)
ExprKind::JoinedStr { .. } => { ExprKind::JoinedStr { .. } => {
if is_default_encode(args, kwargs) { if is_default_encode(args, kwargs) {
if let Some(check) = if let Some(check) = delete_default_encode_arg_or_kwarg(
delete_default_encode_arg_or_kwarg(expr, args, kwargs, checker.patch()) expr,
{ args,
kwargs,
checker.patch(&CheckCode::U012),
) {
checker.add_check(check); checker.add_check(check);
} }
} }

View file

@ -56,7 +56,7 @@ pub fn unnecessary_future_import(checker: &mut Checker, stmt: &Stmt, names: &[Lo
), ),
Range::from_located(stmt), Range::from_located(stmt),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
let context = checker.binding_context(); let context = checker.binding_context();
let deleted: Vec<&Stmt> = checker let deleted: Vec<&Stmt> = checker
.deletions .deletions

View file

@ -11,7 +11,7 @@ pub fn unnecessary_lru_cache_params(checker: &mut Checker, decorator_list: &[Exp
&checker.from_imports, &checker.from_imports,
&checker.import_aliases, &checker.import_aliases,
) { ) {
if checker.patch() { if checker.patch(check.kind.code()) {
if let Some(fix) = if let Some(fix) =
fixes::remove_unnecessary_lru_cache_params(checker.locator, &check.location) fixes::remove_unnecessary_lru_cache_params(checker.locator, &check.location)
{ {

View file

@ -12,7 +12,7 @@ pub fn use_pep585_annotation(checker: &mut Checker, expr: &Expr, id: &str) {
CheckKind::UsePEP585Annotation(replacement.to_string()), CheckKind::UsePEP585Annotation(replacement.to_string()),
Range::from_located(expr), Range::from_located(expr),
); );
if checker.patch() { if checker.patch(check.kind.code()) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
replacement.to_lowercase(), replacement.to_lowercase(),
expr.location, expr.location,

View file

@ -47,7 +47,7 @@ pub fn use_pep604_annotation(checker: &mut Checker, expr: &Expr, value: &Expr, s
let call_path = dealias_call_path(collect_call_paths(value), &checker.import_aliases); let call_path = dealias_call_path(collect_call_paths(value), &checker.import_aliases);
if checker.match_typing_call_path(&call_path, "Optional") { if checker.match_typing_call_path(&call_path, "Optional") {
let mut check = Check::new(CheckKind::UsePEP604Annotation, Range::from_located(expr)); let mut check = Check::new(CheckKind::UsePEP604Annotation, Range::from_located(expr));
if checker.patch() { if checker.patch(check.kind.code()) {
let mut generator = SourceGenerator::new(); let mut generator = SourceGenerator::new();
if let Ok(()) = generator.unparse_expr(&optional(slice), 0) { if let Ok(()) = generator.unparse_expr(&optional(slice), 0) {
if let Ok(content) = generator.generate() { if let Ok(content) = generator.generate() {
@ -62,7 +62,7 @@ pub fn use_pep604_annotation(checker: &mut Checker, expr: &Expr, value: &Expr, s
checker.add_check(check); checker.add_check(check);
} else if checker.match_typing_call_path(&call_path, "Union") { } else if checker.match_typing_call_path(&call_path, "Union") {
let mut check = Check::new(CheckKind::UsePEP604Annotation, Range::from_located(expr)); let mut check = Check::new(CheckKind::UsePEP604Annotation, Range::from_located(expr));
if checker.patch() { if checker.patch(check.kind.code()) {
match &slice.node { match &slice.node {
ExprKind::Slice { .. } => { ExprKind::Slice { .. } => {
// Invalid type annotation. // Invalid type annotation.

View file

@ -11,7 +11,7 @@ pub fn useless_metaclass_type(checker: &mut Checker, stmt: &Stmt, value: &Expr,
if let Some(mut check) = if let Some(mut check) =
checks::useless_metaclass_type(targets, value, Range::from_located(stmt)) checks::useless_metaclass_type(targets, value, Range::from_located(stmt))
{ {
if checker.patch() { if checker.patch(check.kind.code()) {
let context = checker.binding_context(); let context = checker.binding_context();
let deleted: Vec<&Stmt> = checker let deleted: Vec<&Stmt> = checker
.deletions .deletions

View file

@ -14,7 +14,7 @@ pub fn useless_object_inheritance(
) { ) {
let scope = checker.current_scope(); let scope = checker.current_scope();
if let Some(mut check) = checks::useless_object_inheritance(name, bases, scope) { if let Some(mut check) = checks::useless_object_inheritance(name, bases, scope) {
if checker.patch() { if checker.patch(check.kind.code()) {
if let Some(fix) = pyupgrade::fixes::remove_class_def_base( if let Some(fix) = pyupgrade::fixes::remove_class_def_base(
checker.locator, checker.locator,
&stmt.location, &stmt.location,

View file

@ -3,10 +3,10 @@ use once_cell::sync::Lazy;
use rustpython_ast::Location; use rustpython_ast::Location;
use crate::ast::types::Range; use crate::ast::types::Range;
use crate::autofix::Fix; use crate::autofix::{fixer, Fix};
use crate::checks::CheckKind; use crate::checks::CheckKind;
use crate::source_code_locator::SourceCodeLocator; use crate::source_code_locator::SourceCodeLocator;
use crate::Check; use crate::{Check, Settings};
/// See: https://github.com/microsoft/vscode/blob/095ddabc52b82498ee7f718a34f9dd11d59099a8/src/vs/base/common/strings.ts#L1094 /// See: https://github.com/microsoft/vscode/blob/095ddabc52b82498ee7f718a34f9dd11d59099a8/src/vs/base/common/strings.ts#L1094
static CONFUSABLES: Lazy<FnvHashMap<u32, u32>> = Lazy::new(|| { static CONFUSABLES: Lazy<FnvHashMap<u32, u32>> = Lazy::new(|| {
@ -1606,7 +1606,8 @@ pub fn ambiguous_unicode_character(
start: &Location, start: &Location,
end: &Location, end: &Location,
context: Context, context: Context,
fix: bool, settings: &Settings,
autofix: &fixer::Mode,
) -> Vec<Check> { ) -> Vec<Check> {
let mut checks = vec![]; let mut checks = vec![];
@ -1645,7 +1646,8 @@ pub fn ambiguous_unicode_character(
end_location, end_location,
}, },
); );
if fix { if settings.enabled.contains(check.kind.code()) {
if autofix.patch() && settings.fixable.contains(check.kind.code()) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
representant.to_string(), representant.to_string(),
location, location,
@ -1655,6 +1657,7 @@ pub fn ambiguous_unicode_character(
checks.push(check); checks.push(check);
} }
} }
}
// Track the offset from the start position as we iterate over the body. // Track the offset from the start position as we iterate over the body.
if current_char == '\n' { if current_char == '\n' {

View file

@ -25,13 +25,15 @@ pub struct Configuration {
pub extend_ignore: Vec<CheckCodePrefix>, pub extend_ignore: Vec<CheckCodePrefix>,
pub extend_select: Vec<CheckCodePrefix>, pub extend_select: Vec<CheckCodePrefix>,
pub fix: bool, pub fix: bool,
pub fixable: Vec<CheckCodePrefix>,
pub ignore: Vec<CheckCodePrefix>, pub ignore: Vec<CheckCodePrefix>,
pub line_length: usize, pub line_length: usize,
pub per_file_ignores: Vec<PerFileIgnore>, pub per_file_ignores: Vec<PerFileIgnore>,
pub select: Vec<CheckCodePrefix>, pub select: Vec<CheckCodePrefix>,
pub show_source: bool,
pub src: Vec<PathBuf>, pub src: Vec<PathBuf>,
pub target_version: PythonVersion, pub target_version: PythonVersion,
pub show_source: bool, pub unfixable: Vec<CheckCodePrefix>,
// Plugins // Plugins
pub flake8_annotations: flake8_annotations::settings::Settings, pub flake8_annotations: flake8_annotations::settings::Settings,
pub flake8_bugbear: flake8_bugbear::settings::Settings, pub flake8_bugbear: flake8_bugbear::settings::Settings,
@ -122,6 +124,28 @@ impl Configuration {
.unwrap_or_else(|| vec![CheckCodePrefix::E, CheckCodePrefix::F]), .unwrap_or_else(|| vec![CheckCodePrefix::E, CheckCodePrefix::F]),
extend_select: options.extend_select.unwrap_or_default(), extend_select: options.extend_select.unwrap_or_default(),
fix: options.fix.unwrap_or_default(), fix: options.fix.unwrap_or_default(),
fixable: options.fixable.unwrap_or_else(|| {
// TODO(charlie): Autogenerate this list.
vec![
CheckCodePrefix::A,
CheckCodePrefix::B,
CheckCodePrefix::BLE,
CheckCodePrefix::C,
CheckCodePrefix::D,
CheckCodePrefix::E,
CheckCodePrefix::F,
CheckCodePrefix::I,
CheckCodePrefix::M,
CheckCodePrefix::N,
CheckCodePrefix::Q,
CheckCodePrefix::S,
CheckCodePrefix::T,
CheckCodePrefix::U,
CheckCodePrefix::W,
CheckCodePrefix::YTT,
]
}),
unfixable: options.unfixable.unwrap_or_default(),
ignore: options.ignore.unwrap_or_default(), ignore: options.ignore.unwrap_or_default(),
line_length: options.line_length.unwrap_or(88), line_length: options.line_length.unwrap_or(88),
per_file_ignores: options per_file_ignores: options

View file

@ -30,11 +30,12 @@ pub struct Settings {
pub enabled: FnvHashSet<CheckCode>, pub enabled: FnvHashSet<CheckCode>,
pub exclude: Vec<FilePattern>, pub exclude: Vec<FilePattern>,
pub extend_exclude: Vec<FilePattern>, pub extend_exclude: Vec<FilePattern>,
pub fixable: FnvHashSet<CheckCode>,
pub line_length: usize, pub line_length: usize,
pub per_file_ignores: Vec<PerFileIgnore>, pub per_file_ignores: Vec<PerFileIgnore>,
pub show_source: bool,
pub src: Vec<PathBuf>, pub src: Vec<PathBuf>,
pub target_version: PythonVersion, pub target_version: PythonVersion,
pub show_source: bool,
// Plugins // Plugins
pub flake8_annotations: flake8_annotations::settings::Settings, pub flake8_annotations: flake8_annotations::settings::Settings,
pub flake8_bugbear: flake8_bugbear::settings::Settings, pub flake8_bugbear: flake8_bugbear::settings::Settings,
@ -50,13 +51,20 @@ impl Settings {
Self { Self {
dummy_variable_rgx: config.dummy_variable_rgx, dummy_variable_rgx: config.dummy_variable_rgx,
enabled: resolve_codes( enabled: resolve_codes(
&config.select, &config
&config.extend_select, .select
&config.ignore, .into_iter()
&config.extend_ignore, .chain(config.extend_select.into_iter())
.collect::<Vec<_>>(),
&config
.ignore
.into_iter()
.chain(config.extend_ignore.into_iter())
.collect::<Vec<_>>(),
), ),
exclude: config.exclude, exclude: config.exclude,
extend_exclude: config.extend_exclude, extend_exclude: config.extend_exclude,
fixable: resolve_codes(&config.fixable, &config.unfixable),
flake8_annotations: config.flake8_annotations, flake8_annotations: config.flake8_annotations,
flake8_bugbear: config.flake8_bugbear, flake8_bugbear: config.flake8_bugbear,
flake8_quotes: config.flake8_quotes, flake8_quotes: config.flake8_quotes,
@ -75,7 +83,8 @@ impl Settings {
pub fn for_rule(check_code: CheckCode) -> Self { pub fn for_rule(check_code: CheckCode) -> Self {
Self { Self {
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(), dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
enabled: FnvHashSet::from_iter([check_code]), enabled: FnvHashSet::from_iter([check_code.clone()]),
fixable: FnvHashSet::from_iter([check_code]),
exclude: Default::default(), exclude: Default::default(),
extend_exclude: Default::default(), extend_exclude: Default::default(),
line_length: 88, line_length: 88,
@ -96,7 +105,8 @@ impl Settings {
pub fn for_rules(check_codes: Vec<CheckCode>) -> Self { pub fn for_rules(check_codes: Vec<CheckCode>) -> Self {
Self { Self {
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(), dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
enabled: FnvHashSet::from_iter(check_codes), enabled: FnvHashSet::from_iter(check_codes.clone()),
fixable: FnvHashSet::from_iter(check_codes),
exclude: Default::default(), exclude: Default::default(),
extend_exclude: Default::default(), extend_exclude: Default::default(),
line_length: 88, line_length: 88,
@ -122,6 +132,9 @@ impl Hash for Settings {
for value in self.enabled.iter() { for value in self.enabled.iter() {
value.hash(state); value.hash(state);
} }
for value in self.fixable.iter() {
value.hash(state);
}
self.line_length.hash(state); self.line_length.hash(state);
for value in self.per_file_ignores.iter() { for value in self.per_file_ignores.iter() {
value.hash(state); value.hash(state);
@ -141,12 +154,7 @@ impl Hash for Settings {
/// Given a set of selected and ignored prefixes, resolve the set of enabled /// Given a set of selected and ignored prefixes, resolve the set of enabled
/// error codes. /// error codes.
fn resolve_codes( fn resolve_codes(select: &[CheckCodePrefix], ignore: &[CheckCodePrefix]) -> FnvHashSet<CheckCode> {
select: &[CheckCodePrefix],
extend_select: &[CheckCodePrefix],
ignore: &[CheckCodePrefix],
extend_ignore: &[CheckCodePrefix],
) -> FnvHashSet<CheckCode> {
let mut codes: FnvHashSet<CheckCode> = FnvHashSet::default(); let mut codes: FnvHashSet<CheckCode> = FnvHashSet::default();
for specificity in [ for specificity in [
PrefixSpecificity::Category, PrefixSpecificity::Category,
@ -159,11 +167,6 @@ fn resolve_codes(
codes.extend(prefix.codes()); codes.extend(prefix.codes());
} }
} }
for prefix in extend_select {
if prefix.specificity() == specificity {
codes.extend(prefix.codes());
}
}
for prefix in ignore { for prefix in ignore {
if prefix.specificity() == specificity { if prefix.specificity() == specificity {
for code in prefix.codes() { for code in prefix.codes() {
@ -171,13 +174,6 @@ fn resolve_codes(
} }
} }
} }
for prefix in extend_ignore {
if prefix.specificity() == specificity {
for code in prefix.codes() {
codes.remove(&code);
}
}
}
} }
codes codes
} }
@ -192,19 +188,19 @@ mod tests {
#[test] #[test]
fn resolver() { fn resolver() {
let actual = resolve_codes(&[CheckCodePrefix::W], &[], &[], &[]); let actual = resolve_codes(&[CheckCodePrefix::W], &[]);
let expected = FnvHashSet::from_iter([CheckCode::W292, CheckCode::W605]); let expected = FnvHashSet::from_iter([CheckCode::W292, CheckCode::W605]);
assert_eq!(actual, expected); assert_eq!(actual, expected);
let actual = resolve_codes(&[CheckCodePrefix::W6], &[], &[], &[]); let actual = resolve_codes(&[CheckCodePrefix::W6], &[]);
let expected = FnvHashSet::from_iter([CheckCode::W605]); let expected = FnvHashSet::from_iter([CheckCode::W605]);
assert_eq!(actual, expected); assert_eq!(actual, expected);
let actual = resolve_codes(&[CheckCodePrefix::W], &[], &[CheckCodePrefix::W292], &[]); let actual = resolve_codes(&[CheckCodePrefix::W], &[CheckCodePrefix::W292]);
let expected = FnvHashSet::from_iter([CheckCode::W605]); let expected = FnvHashSet::from_iter([CheckCode::W605]);
assert_eq!(actual, expected); assert_eq!(actual, expected);
let actual = resolve_codes(&[CheckCodePrefix::W605], &[], &[CheckCodePrefix::W605], &[]); let actual = resolve_codes(&[CheckCodePrefix::W605], &[CheckCodePrefix::W605]);
let expected = FnvHashSet::from_iter([]); let expected = FnvHashSet::from_iter([]);
assert_eq!(actual, expected); assert_eq!(actual, expected);
} }

View file

@ -19,12 +19,14 @@ pub struct Options {
pub extend_ignore: Option<Vec<CheckCodePrefix>>, pub extend_ignore: Option<Vec<CheckCodePrefix>>,
pub extend_select: Option<Vec<CheckCodePrefix>>, pub extend_select: Option<Vec<CheckCodePrefix>>,
pub fix: Option<bool>, pub fix: Option<bool>,
pub fixable: Option<Vec<CheckCodePrefix>>,
pub ignore: Option<Vec<CheckCodePrefix>>, pub ignore: Option<Vec<CheckCodePrefix>>,
pub line_length: Option<usize>, pub line_length: Option<usize>,
pub select: Option<Vec<CheckCodePrefix>>, pub select: Option<Vec<CheckCodePrefix>>,
pub show_source: Option<bool>,
pub src: Option<Vec<String>>, pub src: Option<Vec<String>>,
pub target_version: Option<PythonVersion>, pub target_version: Option<PythonVersion>,
pub show_source: Option<bool>, pub unfixable: Option<Vec<CheckCodePrefix>>,
// Plugins // Plugins
pub flake8_annotations: Option<flake8_annotations::settings::Options>, pub flake8_annotations: Option<flake8_annotations::settings::Options>,
pub flake8_bugbear: Option<flake8_bugbear::settings::Options>, pub flake8_bugbear: Option<flake8_bugbear::settings::Options>,

View file

@ -134,19 +134,21 @@ mod tests {
pyproject.tool, pyproject.tool,
Some(Tools { Some(Tools {
ruff: Some(Options { ruff: Some(Options {
line_length: None, dummy_variable_rgx: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
select: None,
extend_select: None,
ignore: None,
extend_ignore: None, extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: None,
line_length: None,
per_file_ignores: None, per_file_ignores: None,
dummy_variable_rgx: None, select: None,
show_source: None,
src: None, src: None,
target_version: None, target_version: None,
show_source: None, unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: None, flake8_quotes: None,
@ -169,19 +171,21 @@ line-length = 79
pyproject.tool, pyproject.tool,
Some(Tools { Some(Tools {
ruff: Some(Options { ruff: Some(Options {
line_length: Some(79), dummy_variable_rgx: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
select: None,
extend_select: None,
ignore: None,
extend_ignore: None, extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: None,
line_length: Some(79),
per_file_ignores: None, per_file_ignores: None,
dummy_variable_rgx: None, select: None,
show_source: None,
src: None, src: None,
target_version: None, target_version: None,
show_source: None, unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: None, flake8_quotes: None,
@ -212,6 +216,8 @@ exclude = ["foo.py"]
extend_select: None, extend_select: None,
ignore: None, ignore: None,
extend_ignore: None, extend_ignore: None,
fixable: None,
unfixable: None,
per_file_ignores: None, per_file_ignores: None,
dummy_variable_rgx: None, dummy_variable_rgx: None,
src: None, src: None,
@ -239,19 +245,21 @@ select = ["E501"]
pyproject.tool, pyproject.tool,
Some(Tools { Some(Tools {
ruff: Some(Options { ruff: Some(Options {
line_length: None, dummy_variable_rgx: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
select: Some(vec![CheckCodePrefix::E501]),
extend_select: None,
ignore: None,
extend_ignore: None, extend_ignore: None,
extend_select: None,
fix: None,
fixable: None,
ignore: None,
line_length: None,
per_file_ignores: None, per_file_ignores: None,
dummy_variable_rgx: None, select: Some(vec![CheckCodePrefix::E501]),
show_source: None,
src: None, src: None,
target_version: None, target_version: None,
show_source: None, unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: None, flake8_quotes: None,
@ -275,19 +283,21 @@ ignore = ["E501"]
pyproject.tool, pyproject.tool,
Some(Tools { Some(Tools {
ruff: Some(Options { ruff: Some(Options {
line_length: None, dummy_variable_rgx: None,
fix: None,
exclude: None, exclude: None,
extend_exclude: None, extend_exclude: None,
select: None,
extend_select: Some(vec![CheckCodePrefix::M001]),
ignore: Some(vec![CheckCodePrefix::E501]),
extend_ignore: None, extend_ignore: None,
extend_select: Some(vec![CheckCodePrefix::M001]),
fix: None,
fixable: None,
ignore: Some(vec![CheckCodePrefix::E501]),
line_length: None,
per_file_ignores: None, per_file_ignores: None,
dummy_variable_rgx: None, select: None,
show_source: None,
src: None, src: None,
target_version: None, target_version: None,
show_source: None, unfixable: None,
flake8_annotations: None, flake8_annotations: None,
flake8_bugbear: None, flake8_bugbear: None,
flake8_quotes: None, flake8_quotes: None,
@ -362,6 +372,8 @@ other-attribute = 1
extend_select: None, extend_select: None,
ignore: None, ignore: None,
extend_ignore: None, extend_ignore: None,
fixable: None,
unfixable: None,
per_file_ignores: Some(FnvHashMap::from_iter([( per_file_ignores: Some(FnvHashMap::from_iter([(
"__init__.py".to_string(), "__init__.py".to_string(),
vec![CheckCodePrefix::F401] vec![CheckCodePrefix::F401]

View file

@ -43,13 +43,15 @@ pub struct UserConfiguration {
pub extend_ignore: Vec<CheckCodePrefix>, pub extend_ignore: Vec<CheckCodePrefix>,
pub extend_select: Vec<CheckCodePrefix>, pub extend_select: Vec<CheckCodePrefix>,
pub fix: bool, pub fix: bool,
pub fixable: Vec<CheckCodePrefix>,
pub ignore: Vec<CheckCodePrefix>, pub ignore: Vec<CheckCodePrefix>,
pub line_length: usize, pub line_length: usize,
pub per_file_ignores: Vec<(Exclusion, Vec<CheckCode>)>, pub per_file_ignores: Vec<(Exclusion, Vec<CheckCode>)>,
pub select: Vec<CheckCodePrefix>, pub select: Vec<CheckCodePrefix>,
pub show_source: bool,
pub src: Vec<PathBuf>, pub src: Vec<PathBuf>,
pub target_version: PythonVersion, pub target_version: PythonVersion,
pub show_source: bool, pub unfixable: Vec<CheckCodePrefix>,
// Plugins // Plugins
pub flake8_annotations: flake8_annotations::settings::Settings, pub flake8_annotations: flake8_annotations::settings::Settings,
pub flake8_quotes: flake8_quotes::settings::Settings, pub flake8_quotes: flake8_quotes::settings::Settings,
@ -82,6 +84,8 @@ impl UserConfiguration {
extend_ignore: configuration.extend_ignore, extend_ignore: configuration.extend_ignore,
extend_select: configuration.extend_select, extend_select: configuration.extend_select,
fix: configuration.fix, fix: configuration.fix,
fixable: configuration.fixable,
unfixable: configuration.unfixable,
ignore: configuration.ignore, ignore: configuration.ignore,
line_length: configuration.line_length, line_length: configuration.line_length,
per_file_ignores: configuration per_file_ignores: configuration