Add a "fix message" to every autofix-able check (#1489)

This commit is contained in:
Charlie Marsh 2022-12-30 23:16:03 -05:00 committed by GitHub
parent 1e3cf87f67
commit 01c74e0629
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 594 additions and 166 deletions

View File

@ -545,7 +545,7 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/) on PyPI.
| F621 | ExpressionsInStarAssignment | Too many expressions in star-unpacking assignment | | | F621 | ExpressionsInStarAssignment | Too many expressions in star-unpacking assignment | |
| F622 | TwoStarredExpressions | Two starred expressions in assignment | | | F622 | TwoStarredExpressions | Two starred expressions in assignment | |
| F631 | AssertTuple | Assert test is a non-empty tuple, which is always `True` | | | F631 | AssertTuple | Assert test is a non-empty tuple, which is always `True` | |
| F632 | IsLiteral | Use `==` and `!=` to compare constant literals | 🛠 | | F632 | IsLiteral | Use `==` to compare constant literals | 🛠 |
| F633 | InvalidPrintSyntax | Use of `>>` is invalid with `print` function | | | F633 | InvalidPrintSyntax | Use of `>>` is invalid with `print` function | |
| F634 | IfTuple | If test is a tuple, which is always `True` | | | F634 | IfTuple | If test is a tuple, which is always `True` | |
| F701 | BreakOutsideLoop | `break` outside loop | | | F701 | BreakOutsideLoop | `break` outside loop | |
@ -578,7 +578,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI
| E714 | NotIsTest | Test for object identity should be `is not` | 🛠 | | E714 | NotIsTest | Test for object identity should be `is not` | 🛠 |
| E721 | TypeComparison | Do not compare types, use `isinstance()` | | | E721 | TypeComparison | Do not compare types, use `isinstance()` | |
| E722 | DoNotUseBareExcept | Do not use bare `except` | | | E722 | DoNotUseBareExcept | Do not use bare `except` | |
| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | 🛠 | | E731 | DoNotAssignLambda | Do not assign a `lambda` expression, use a `def` | 🛠 |
| E741 | AmbiguousVariableName | Ambiguous variable name: `...` | | | E741 | AmbiguousVariableName | Ambiguous variable name: `...` | |
| E742 | AmbiguousClassName | Ambiguous class name: `...` | | | E742 | AmbiguousClassName | Ambiguous class name: `...` | |
| E743 | AmbiguousFunctionName | Ambiguous function name: `...` | | | E743 | AmbiguousFunctionName | Ambiguous function name: `...` | |
@ -663,7 +663,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| UP001 | UselessMetaclassType | `__metaclass__ = type` is implied | 🛠 | | UP001 | UselessMetaclassType | `__metaclass__ = type` is implied | 🛠 |
| UP003 | TypeOfPrimitive | Use `str` instead of `type(...)` | 🛠 | | UP003 | TypeOfPrimitive | Use `str` instead of `type(...)` | 🛠 |
| UP004 | UselessObjectInheritance | Class `...` inherits from object | 🛠 | | UP004 | UselessObjectInheritance | Class `...` inherits from `object` | 🛠 |
| UP005 | DeprecatedUnittestAlias | `assertEquals` is deprecated, use `assertEqual` | 🛠 | | UP005 | DeprecatedUnittestAlias | `assertEquals` is deprecated, use `assertEqual` | 🛠 |
| UP006 | UsePEP585Annotation | Use `list` instead of `List` for type annotations | 🛠 | | UP006 | UsePEP585Annotation | Use `list` instead of `List` for type annotations | 🛠 |
| UP007 | UsePEP604Annotation | Use `X \| Y` for type annotations | 🛠 | | UP007 | UsePEP604Annotation | Use `X \| Y` for type annotations | 🛠 |
@ -677,7 +677,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
| UP015 | RedundantOpenModes | Unnecessary open mode parameters | 🛠 | | UP015 | RedundantOpenModes | Unnecessary open mode parameters | 🛠 |
| UP016 | RemoveSixCompat | Unnecessary `six` compatibility usage | 🛠 | | UP016 | RemoveSixCompat | Unnecessary `six` compatibility usage | 🛠 |
| UP017 | DatetimeTimezoneUTC | Use `datetime.UTC` alias | 🛠 | | UP017 | DatetimeTimezoneUTC | Use `datetime.UTC` alias | 🛠 |
| UP018 | NativeLiterals | Unnecessary call to `str` and `bytes` | 🛠 | | UP018 | NativeLiterals | Unnecessary call to `str` | 🛠 |
| UP019 | TypingTextStrAlias | `typing.Text` is deprecated, use `str` | 🛠 | | UP019 | TypingTextStrAlias | `typing.Text` is deprecated, use `str` | 🛠 |
| UP020 | OpenAlias | Use builtin `open` | 🛠 | | UP020 | OpenAlias | Use builtin `open` | 🛠 |
| UP021 | ReplaceUniversalNewlines | `universal_newlines` is deprecated, use `text` | 🛠 | | UP021 | ReplaceUniversalNewlines | `universal_newlines` is deprecated, use `text` | 🛠 |
@ -1018,7 +1018,7 @@ For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI.
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| RUF001 | AmbiguousUnicodeCharacterString | String contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 | | RUF001 | AmbiguousUnicodeCharacterString | String contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 |
| RUF002 | AmbiguousUnicodeCharacterDocstring | Docstring contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 | | RUF002 | AmbiguousUnicodeCharacterDocstring | Docstring contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 |
| RUF003 | AmbiguousUnicodeCharacterComment | Comment contains ambiguous unicode character '𝐁' (did you mean 'B'?) | | | RUF003 | AmbiguousUnicodeCharacterComment | Comment contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 |
| RUF004 | KeywordArgumentBeforeStarArgument | Keyword argument `...` must come after starred arguments | | | RUF004 | KeywordArgumentBeforeStarArgument | Keyword argument `...` must come after starred arguments | |
| RUF100 | UnusedNOQA | Unused blanket `noqa` directive | 🛠 | | RUF100 | UnusedNOQA | Unused blanket `noqa` directive | 🛠 |

View File

@ -56,7 +56,9 @@ export default function SourceEditor({
.filter((check) => position.startLineNumber === check.location.row) .filter((check) => position.startLineNumber === check.location.row)
.filter((check) => check.fix) .filter((check) => check.fix)
.map((check) => ({ .map((check) => ({
title: `Fix ${check.code}`, title: check.fix
? check.fix.message ?? `Fix ${check.code}`
: "Autofix",
id: `fix-${check.code}`, id: `fix-${check.code}`,
kind: "quickfix", kind: "quickfix",
edit: check.fix edit: check.fix

View File

@ -3735,9 +3735,10 @@ impl<'a> Checker<'a> {
None None
}; };
let multiple = unused_imports.len() > 1;
for (full_name, range) in unused_imports { for (full_name, range) in unused_imports {
let mut check = Check::new( let mut check = Check::new(
CheckKind::UnusedImport(full_name.clone(), ignore_init), CheckKind::UnusedImport(full_name.clone(), ignore_init, multiple),
*range, *range,
); );
if matches!(child.node, StmtKind::ImportFrom { .. }) if matches!(child.node, StmtKind::ImportFrom { .. })
@ -3756,9 +3757,10 @@ impl<'a> Checker<'a> {
.sorted_by_key(|((defined_by, _), _)| defined_by.0.location) .sorted_by_key(|((defined_by, _), _)| defined_by.0.location)
{ {
let child = defined_by.0; let child = defined_by.0;
let multiple = unused_imports.len() > 1;
for (full_name, range) in unused_imports { for (full_name, range) in unused_imports {
let mut check = Check::new( let mut check = Check::new(
CheckKind::UnusedImport(full_name.clone(), ignore_init), CheckKind::UnusedImport(full_name.clone(), ignore_init, multiple),
*range, *range,
); );
if matches!(child.node, StmtKind::ImportFrom { .. }) if matches!(child.node, StmtKind::ImportFrom { .. })

View File

@ -3,6 +3,7 @@ use std::fmt;
use itertools::Itertools; use itertools::Itertools;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use rustpython_ast::Cmpop;
use rustpython_parser::ast::Location; use rustpython_parser::ast::Location;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use strum_macros::{AsRefStr, Display, EnumIter, EnumString}; use strum_macros::{AsRefStr, Display, EnumIter, EnumString};
@ -618,11 +619,37 @@ pub enum LintSource {
} }
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum RejectedCmpop { pub enum EqCmpop {
Eq, Eq,
NotEq, NotEq,
} }
impl From<&Cmpop> for EqCmpop {
fn from(cmpop: &Cmpop) -> Self {
match cmpop {
Cmpop::Eq => EqCmpop::Eq,
Cmpop::NotEq => EqCmpop::NotEq,
_ => unreachable!("Expected Cmpop::Eq | Cmpop::NotEq"),
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum IsCmpop {
Is,
IsNot,
}
impl From<&Cmpop> for IsCmpop {
fn from(cmpop: &Cmpop) -> Self {
match cmpop {
Cmpop::Is => IsCmpop::Is,
Cmpop::IsNot => IsCmpop::IsNot,
_ => unreachable!("Expected Cmpop::Is | Cmpop::IsNot"),
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum DeferralKeyword { pub enum DeferralKeyword {
Yield, Yield,
@ -655,6 +682,21 @@ impl fmt::Display for Branch {
} }
} }
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum LiteralType {
Str,
Bytes,
}
impl fmt::Display for LiteralType {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
LiteralType::Str => fmt.write_str("str"),
LiteralType::Bytes => fmt.write_str("bytes"),
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct UnusedCodes { pub struct UnusedCodes {
pub unknown: Vec<String>, pub unknown: Vec<String>,
@ -668,17 +710,17 @@ pub enum CheckKind {
AmbiguousClassName(String), AmbiguousClassName(String),
AmbiguousFunctionName(String), AmbiguousFunctionName(String),
AmbiguousVariableName(String), AmbiguousVariableName(String),
DoNotAssignLambda, DoNotAssignLambda(String),
DoNotUseBareExcept, DoNotUseBareExcept,
IOError(String), IOError(String),
LineTooLong(usize, usize), LineTooLong(usize, usize),
ModuleImportNotAtTopOfFile, ModuleImportNotAtTopOfFile,
MultipleImportsOnOneLine, MultipleImportsOnOneLine,
NoneComparison(RejectedCmpop), NoneComparison(EqCmpop),
NotInTest, NotInTest,
NotIsTest, NotIsTest,
SyntaxError(String), SyntaxError(String),
TrueFalseComparison(bool, RejectedCmpop), TrueFalseComparison(bool, EqCmpop),
TypeComparison, TypeComparison,
// pycodestyle warnings // pycodestyle warnings
NoNewLineAtEndOfFile, NoNewLineAtEndOfFile,
@ -699,7 +741,7 @@ pub enum CheckKind {
ImportStarUsage(String, Vec<String>), ImportStarUsage(String, Vec<String>),
ImportStarUsed(String), ImportStarUsed(String),
InvalidPrintSyntax, InvalidPrintSyntax,
IsLiteral, IsLiteral(IsCmpop),
LateFutureImport, LateFutureImport,
MultiValueRepeatedKeyLiteral, MultiValueRepeatedKeyLiteral,
MultiValueRepeatedKeyVariable(String), MultiValueRepeatedKeyVariable(String),
@ -725,7 +767,7 @@ pub enum CheckKind {
UndefinedLocal(String), UndefinedLocal(String),
UnusedAnnotation(String), UnusedAnnotation(String),
UndefinedName(String), UndefinedName(String),
UnusedImport(String, bool), UnusedImport(String, bool, bool),
UnusedVariable(String), UnusedVariable(String),
YieldOutsideFunction(DeferralKeyword), YieldOutsideFunction(DeferralKeyword),
// pylint // pylint
@ -859,10 +901,10 @@ pub enum CheckKind {
UnnecessaryEncodeUTF8, UnnecessaryEncodeUTF8,
ConvertTypedDictFunctionalToClass(String), ConvertTypedDictFunctionalToClass(String),
ConvertNamedTupleFunctionalToClass(String), ConvertNamedTupleFunctionalToClass(String),
RedundantOpenModes, RedundantOpenModes(Option<String>),
RemoveSixCompat, RemoveSixCompat,
DatetimeTimezoneUTC, DatetimeTimezoneUTC,
NativeLiterals, NativeLiterals(LiteralType),
OpenAlias, OpenAlias,
ReplaceUniversalNewlines, ReplaceUniversalNewlines,
ReplaceStdoutStderr, ReplaceStdoutStderr,
@ -1030,13 +1072,13 @@ impl CheckCode {
CheckCode::E401 => CheckKind::MultipleImportsOnOneLine, CheckCode::E401 => CheckKind::MultipleImportsOnOneLine,
CheckCode::E402 => CheckKind::ModuleImportNotAtTopOfFile, CheckCode::E402 => CheckKind::ModuleImportNotAtTopOfFile,
CheckCode::E501 => CheckKind::LineTooLong(89, 88), CheckCode::E501 => CheckKind::LineTooLong(89, 88),
CheckCode::E711 => CheckKind::NoneComparison(RejectedCmpop::Eq), CheckCode::E711 => CheckKind::NoneComparison(EqCmpop::Eq),
CheckCode::E712 => CheckKind::TrueFalseComparison(true, RejectedCmpop::Eq), CheckCode::E712 => CheckKind::TrueFalseComparison(true, EqCmpop::Eq),
CheckCode::E713 => CheckKind::NotInTest, CheckCode::E713 => CheckKind::NotInTest,
CheckCode::E714 => CheckKind::NotIsTest, CheckCode::E714 => CheckKind::NotIsTest,
CheckCode::E721 => CheckKind::TypeComparison, CheckCode::E721 => CheckKind::TypeComparison,
CheckCode::E722 => CheckKind::DoNotUseBareExcept, CheckCode::E722 => CheckKind::DoNotUseBareExcept,
CheckCode::E731 => CheckKind::DoNotAssignLambda, CheckCode::E731 => CheckKind::DoNotAssignLambda("...".to_string()),
CheckCode::E741 => CheckKind::AmbiguousVariableName("...".to_string()), CheckCode::E741 => CheckKind::AmbiguousVariableName("...".to_string()),
CheckCode::E742 => CheckKind::AmbiguousClassName("...".to_string()), CheckCode::E742 => CheckKind::AmbiguousClassName("...".to_string()),
CheckCode::E743 => CheckKind::AmbiguousFunctionName("...".to_string()), CheckCode::E743 => CheckKind::AmbiguousFunctionName("...".to_string()),
@ -1046,7 +1088,7 @@ impl CheckCode {
CheckCode::W292 => CheckKind::NoNewLineAtEndOfFile, CheckCode::W292 => CheckKind::NoNewLineAtEndOfFile,
CheckCode::W605 => CheckKind::InvalidEscapeSequence('c'), CheckCode::W605 => CheckKind::InvalidEscapeSequence('c'),
// pyflakes // pyflakes
CheckCode::F401 => CheckKind::UnusedImport("...".to_string(), false), CheckCode::F401 => CheckKind::UnusedImport("...".to_string(), false, false),
CheckCode::F402 => CheckKind::ImportShadowedByLoopVar("...".to_string(), 1), CheckCode::F402 => CheckKind::ImportShadowedByLoopVar("...".to_string(), 1),
CheckCode::F403 => CheckKind::ImportStarUsed("...".to_string()), CheckCode::F403 => CheckKind::ImportStarUsed("...".to_string()),
CheckCode::F404 => CheckKind::LateFutureImport, CheckCode::F404 => CheckKind::LateFutureImport,
@ -1079,7 +1121,7 @@ impl CheckCode {
CheckCode::F621 => CheckKind::ExpressionsInStarAssignment, CheckCode::F621 => CheckKind::ExpressionsInStarAssignment,
CheckCode::F622 => CheckKind::TwoStarredExpressions, CheckCode::F622 => CheckKind::TwoStarredExpressions,
CheckCode::F631 => CheckKind::AssertTuple, CheckCode::F631 => CheckKind::AssertTuple,
CheckCode::F632 => CheckKind::IsLiteral, CheckCode::F632 => CheckKind::IsLiteral(IsCmpop::Is),
CheckCode::F633 => CheckKind::InvalidPrintSyntax, CheckCode::F633 => CheckKind::InvalidPrintSyntax,
CheckCode::F634 => CheckKind::IfTuple, CheckCode::F634 => CheckKind::IfTuple,
CheckCode::F701 => CheckKind::BreakOutsideLoop, CheckCode::F701 => CheckKind::BreakOutsideLoop,
@ -1253,10 +1295,10 @@ impl CheckCode {
CheckCode::UP012 => CheckKind::UnnecessaryEncodeUTF8, CheckCode::UP012 => CheckKind::UnnecessaryEncodeUTF8,
CheckCode::UP013 => CheckKind::ConvertTypedDictFunctionalToClass("...".to_string()), CheckCode::UP013 => CheckKind::ConvertTypedDictFunctionalToClass("...".to_string()),
CheckCode::UP014 => CheckKind::ConvertNamedTupleFunctionalToClass("...".to_string()), CheckCode::UP014 => CheckKind::ConvertNamedTupleFunctionalToClass("...".to_string()),
CheckCode::UP015 => CheckKind::RedundantOpenModes, CheckCode::UP015 => CheckKind::RedundantOpenModes(None),
CheckCode::UP016 => CheckKind::RemoveSixCompat, CheckCode::UP016 => CheckKind::RemoveSixCompat,
CheckCode::UP017 => CheckKind::DatetimeTimezoneUTC, CheckCode::UP017 => CheckKind::DatetimeTimezoneUTC,
CheckCode::UP018 => CheckKind::NativeLiterals, CheckCode::UP018 => CheckKind::NativeLiterals(LiteralType::Str),
CheckCode::UP019 => CheckKind::TypingTextStrAlias, CheckCode::UP019 => CheckKind::TypingTextStrAlias,
CheckCode::UP020 => CheckKind::OpenAlias, CheckCode::UP020 => CheckKind::OpenAlias,
CheckCode::UP021 => CheckKind::ReplaceUniversalNewlines, CheckCode::UP021 => CheckKind::ReplaceUniversalNewlines,
@ -1724,7 +1766,7 @@ impl CheckKind {
CheckKind::BreakOutsideLoop => &CheckCode::F701, CheckKind::BreakOutsideLoop => &CheckCode::F701,
CheckKind::ContinueOutsideLoop => &CheckCode::F702, CheckKind::ContinueOutsideLoop => &CheckCode::F702,
CheckKind::DefaultExceptNotLast => &CheckCode::F707, CheckKind::DefaultExceptNotLast => &CheckCode::F707,
CheckKind::DoNotAssignLambda => &CheckCode::E731, CheckKind::DoNotAssignLambda(..) => &CheckCode::E731,
CheckKind::DoNotUseBareExcept => &CheckCode::E722, CheckKind::DoNotUseBareExcept => &CheckCode::E722,
CheckKind::DuplicateArgumentName => &CheckCode::F831, CheckKind::DuplicateArgumentName => &CheckCode::F831,
CheckKind::FStringMissingPlaceholders => &CheckCode::F541, CheckKind::FStringMissingPlaceholders => &CheckCode::F541,
@ -1737,7 +1779,7 @@ impl CheckKind {
CheckKind::ImportStarUsage(..) => &CheckCode::F405, CheckKind::ImportStarUsage(..) => &CheckCode::F405,
CheckKind::ImportStarUsed(..) => &CheckCode::F403, CheckKind::ImportStarUsed(..) => &CheckCode::F403,
CheckKind::InvalidPrintSyntax => &CheckCode::F633, CheckKind::InvalidPrintSyntax => &CheckCode::F633,
CheckKind::IsLiteral => &CheckCode::F632, CheckKind::IsLiteral(..) => &CheckCode::F632,
CheckKind::LateFutureImport => &CheckCode::F404, CheckKind::LateFutureImport => &CheckCode::F404,
CheckKind::LineTooLong(..) => &CheckCode::E501, CheckKind::LineTooLong(..) => &CheckCode::E501,
CheckKind::MultipleImportsOnOneLine => &CheckCode::E401, CheckKind::MultipleImportsOnOneLine => &CheckCode::E401,
@ -1909,10 +1951,10 @@ impl CheckKind {
CheckKind::UnnecessaryEncodeUTF8 => &CheckCode::UP012, CheckKind::UnnecessaryEncodeUTF8 => &CheckCode::UP012,
CheckKind::ConvertTypedDictFunctionalToClass(..) => &CheckCode::UP013, CheckKind::ConvertTypedDictFunctionalToClass(..) => &CheckCode::UP013,
CheckKind::ConvertNamedTupleFunctionalToClass(..) => &CheckCode::UP014, CheckKind::ConvertNamedTupleFunctionalToClass(..) => &CheckCode::UP014,
CheckKind::RedundantOpenModes => &CheckCode::UP015, CheckKind::RedundantOpenModes(..) => &CheckCode::UP015,
CheckKind::RemoveSixCompat => &CheckCode::UP016, CheckKind::RemoveSixCompat => &CheckCode::UP016,
CheckKind::DatetimeTimezoneUTC => &CheckCode::UP017, CheckKind::DatetimeTimezoneUTC => &CheckCode::UP017,
CheckKind::NativeLiterals => &CheckCode::UP018, CheckKind::NativeLiterals(..) => &CheckCode::UP018,
CheckKind::TypingTextStrAlias => &CheckCode::UP019, CheckKind::TypingTextStrAlias => &CheckCode::UP019,
CheckKind::OpenAlias => &CheckCode::UP020, CheckKind::OpenAlias => &CheckCode::UP020,
CheckKind::ReplaceUniversalNewlines => &CheckCode::UP021, CheckKind::ReplaceUniversalNewlines => &CheckCode::UP021,
@ -2068,8 +2110,8 @@ impl CheckKind {
CheckKind::DefaultExceptNotLast => { CheckKind::DefaultExceptNotLast => {
"An `except` block as not the last exception handler".to_string() "An `except` block as not the last exception handler".to_string()
} }
CheckKind::DoNotAssignLambda => { CheckKind::DoNotAssignLambda(..) => {
"Do not assign a lambda expression, use a def".to_string() "Do not assign a `lambda` expression, use a `def`".to_string()
} }
CheckKind::DoNotUseBareExcept => "Do not use bare `except`".to_string(), CheckKind::DoNotUseBareExcept => "Do not use bare `except`".to_string(),
CheckKind::DuplicateArgumentName => { CheckKind::DuplicateArgumentName => {
@ -2105,7 +2147,10 @@ impl CheckKind {
.join(", "); .join(", ");
format!("`{name}` may be undefined, or defined from star imports: {sources}") format!("`{name}` may be undefined, or defined from star imports: {sources}")
} }
CheckKind::IsLiteral => "Use `==` and `!=` to compare constant literals".to_string(), CheckKind::IsLiteral(cmpop) => match cmpop {
IsCmpop::Is => "Use `==` to compare constant literals".to_string(),
IsCmpop::IsNot => "Use `!=` to compare constant literals".to_string(),
},
CheckKind::LateFutureImport => { CheckKind::LateFutureImport => {
"`from __future__` imports must occur at the beginning of the file".to_string() "`from __future__` imports must occur at the beginning of the file".to_string()
} }
@ -2123,10 +2168,8 @@ impl CheckKind {
format!("Dictionary key `{name}` repeated") format!("Dictionary key `{name}` repeated")
} }
CheckKind::NoneComparison(op) => match op { CheckKind::NoneComparison(op) => match op {
RejectedCmpop::Eq => "Comparison to `None` should be `cond is None`".to_string(), EqCmpop::Eq => "Comparison to `None` should be `cond is None`".to_string(),
RejectedCmpop::NotEq => { EqCmpop::NotEq => "Comparison to `None` should be `cond is not None`".to_string(),
"Comparison to `None` should be `cond is not None`".to_string()
}
}, },
CheckKind::NotInTest => "Test for membership should be `not in`".to_string(), CheckKind::NotInTest => "Test for membership should be `not in`".to_string(),
CheckKind::NotIsTest => "Test for object identity should be `is not`".to_string(), CheckKind::NotIsTest => "Test for object identity should be `is not`".to_string(),
@ -2190,16 +2233,16 @@ impl CheckKind {
CheckKind::ExpressionsInStarAssignment => { CheckKind::ExpressionsInStarAssignment => {
"Too many expressions in star-unpacking assignment".to_string() "Too many expressions in star-unpacking assignment".to_string()
} }
CheckKind::TrueFalseComparison(true, RejectedCmpop::Eq) => { CheckKind::TrueFalseComparison(true, EqCmpop::Eq) => {
"Comparison to `True` should be `cond is True`".to_string() "Comparison to `True` should be `cond is True`".to_string()
} }
CheckKind::TrueFalseComparison(true, RejectedCmpop::NotEq) => { CheckKind::TrueFalseComparison(true, EqCmpop::NotEq) => {
"Comparison to `True` should be `cond is not True`".to_string() "Comparison to `True` should be `cond is not True`".to_string()
} }
CheckKind::TrueFalseComparison(false, RejectedCmpop::Eq) => { CheckKind::TrueFalseComparison(false, EqCmpop::Eq) => {
"Comparison to `False` should be `cond is False`".to_string() "Comparison to `False` should be `cond is False`".to_string()
} }
CheckKind::TrueFalseComparison(false, RejectedCmpop::NotEq) => { CheckKind::TrueFalseComparison(false, EqCmpop::NotEq) => {
"Comparison to `False` should be `cond is not False`".to_string() "Comparison to `False` should be `cond is not False`".to_string()
} }
CheckKind::TwoStarredExpressions => "Two starred expressions in assignment".to_string(), CheckKind::TwoStarredExpressions => "Two starred expressions in assignment".to_string(),
@ -2216,7 +2259,7 @@ impl CheckKind {
CheckKind::UnusedAnnotation(name) => { CheckKind::UnusedAnnotation(name) => {
format!("Local variable `{name}` is annotated but never used") format!("Local variable `{name}` is annotated but never used")
} }
CheckKind::UnusedImport(name, ignore_init) => { CheckKind::UnusedImport(name, ignore_init, ..) => {
if *ignore_init { if *ignore_init {
format!( format!(
"`{name}` imported but unused; consider adding to `__all__` or using a \ "`{name}` imported but unused; consider adding to `__all__` or using a \
@ -2627,7 +2670,7 @@ impl CheckKind {
format!("`{alias}` is deprecated, use `{target}`") format!("`{alias}` is deprecated, use `{target}`")
} }
CheckKind::UselessObjectInheritance(name) => { CheckKind::UselessObjectInheritance(name) => {
format!("Class `{name}` inherits from object") format!("Class `{name}` inherits from `object`")
} }
CheckKind::UsePEP585Annotation(name) => { CheckKind::UsePEP585Annotation(name) => {
format!( format!(
@ -2653,14 +2696,24 @@ impl CheckKind {
"Unnecessary parameters to `functools.lru_cache`".to_string() "Unnecessary parameters to `functools.lru_cache`".to_string()
} }
CheckKind::UnnecessaryEncodeUTF8 => "Unnecessary call to `encode` as UTF-8".to_string(), CheckKind::UnnecessaryEncodeUTF8 => "Unnecessary call to `encode` as UTF-8".to_string(),
CheckKind::RedundantOpenModes => "Unnecessary open mode parameters".to_string(), CheckKind::RedundantOpenModes(replacement) => match replacement {
None => "Unnecessary open mode parameters".to_string(),
Some(replacement) => {
format!("Unnecessary open mode parameters, use \"{replacement}\"")
}
},
CheckKind::RemoveSixCompat => "Unnecessary `six` compatibility usage".to_string(), CheckKind::RemoveSixCompat => "Unnecessary `six` compatibility usage".to_string(),
CheckKind::DatetimeTimezoneUTC => "Use `datetime.UTC` alias".to_string(), CheckKind::DatetimeTimezoneUTC => "Use `datetime.UTC` alias".to_string(),
CheckKind::NativeLiterals => "Unnecessary call to `str` and `bytes`".to_string(), CheckKind::NativeLiterals(literal_type) => {
format!("Unnecessary call to `{literal_type}`")
}
CheckKind::OpenAlias => "Use builtin `open`".to_string(), CheckKind::OpenAlias => "Use builtin `open`".to_string(),
CheckKind::ConvertTypedDictFunctionalToClass(name) => { CheckKind::ConvertTypedDictFunctionalToClass(name) => {
format!("Convert `{name}` from `TypedDict` functional to class syntax") format!("Convert `{name}` from `TypedDict` functional to class syntax")
} }
CheckKind::ConvertNamedTupleFunctionalToClass(name) => {
format!("Convert `{name}` from `NamedTuple` functional to class syntax")
}
CheckKind::ReplaceUniversalNewlines => { CheckKind::ReplaceUniversalNewlines => {
"`universal_newlines` is deprecated, use `text`".to_string() "`universal_newlines` is deprecated, use `text`".to_string()
} }
@ -2671,9 +2724,6 @@ impl CheckKind {
"`cElementTree` is deprecated, use `ElementTree`".to_string() "`cElementTree` is deprecated, use `ElementTree`".to_string()
} }
CheckKind::RewriteUnicodeLiteral => "Remove unicode literals from strings".to_string(), CheckKind::RewriteUnicodeLiteral => "Remove unicode literals from strings".to_string(),
CheckKind::ConvertNamedTupleFunctionalToClass(name) => {
format!("Convert `{name}` from `NamedTuple` functional to class syntax")
}
// pydocstyle // pydocstyle
CheckKind::FitsOnOneLine => "One-line docstring should fit on one line".to_string(), CheckKind::FitsOnOneLine => "One-line docstring should fit on one line".to_string(),
CheckKind::BlankLineAfterSummary => { CheckKind::BlankLineAfterSummary => {
@ -3088,6 +3138,7 @@ impl CheckKind {
self, self,
CheckKind::AmbiguousUnicodeCharacterString(..) CheckKind::AmbiguousUnicodeCharacterString(..)
| CheckKind::AmbiguousUnicodeCharacterDocstring(..) | CheckKind::AmbiguousUnicodeCharacterDocstring(..)
| CheckKind::AmbiguousUnicodeCharacterComment(..)
| CheckKind::BlankLineAfterLastSection(..) | CheckKind::BlankLineAfterLastSection(..)
| CheckKind::BlankLineAfterSection(..) | CheckKind::BlankLineAfterSection(..)
| CheckKind::BlankLineAfterSummary | CheckKind::BlankLineAfterSummary
@ -3100,7 +3151,7 @@ impl CheckKind {
| CheckKind::DatetimeTimezoneUTC | CheckKind::DatetimeTimezoneUTC
| CheckKind::DeprecatedUnittestAlias(..) | CheckKind::DeprecatedUnittestAlias(..)
| CheckKind::DoNotAssertFalse | CheckKind::DoNotAssertFalse
| CheckKind::DoNotAssignLambda | CheckKind::DoNotAssignLambda(..)
| CheckKind::DuplicateHandlerException(..) | CheckKind::DuplicateHandlerException(..)
| CheckKind::EndsInPeriod | CheckKind::EndsInPeriod
| CheckKind::EndsInPunctuation | CheckKind::EndsInPunctuation
@ -3108,11 +3159,11 @@ impl CheckKind {
| CheckKind::ImplicitReturn | CheckKind::ImplicitReturn
| CheckKind::ImplicitReturnValue | CheckKind::ImplicitReturnValue
| CheckKind::InvalidEscapeSequence(..) | CheckKind::InvalidEscapeSequence(..)
| CheckKind::IsLiteral | CheckKind::IsLiteral(..)
| CheckKind::KeyInDict(..) | CheckKind::KeyInDict(..)
| CheckKind::MisplacedComparisonConstant(..) | CheckKind::MisplacedComparisonConstant(..)
| CheckKind::MissingReturnTypeSpecialMethod(..) | CheckKind::MissingReturnTypeSpecialMethod(..)
| CheckKind::NativeLiterals | CheckKind::NativeLiterals(..)
| CheckKind::OpenAlias | CheckKind::OpenAlias
| CheckKind::NewLineAfterLastParagraph | CheckKind::NewLineAfterLastParagraph
| CheckKind::ReplaceUniversalNewlines | CheckKind::ReplaceUniversalNewlines
@ -3135,10 +3186,10 @@ impl CheckKind {
| CheckKind::OneBlankLineBeforeClass(..) | CheckKind::OneBlankLineBeforeClass(..)
| CheckKind::PEP3120UnnecessaryCodingComment | CheckKind::PEP3120UnnecessaryCodingComment
| CheckKind::PPrintFound | CheckKind::PPrintFound
| CheckKind::PercentFormatExtraNamedArguments(..)
| CheckKind::PrintFound | CheckKind::PrintFound
| CheckKind::PercentFormatExtraNamedArguments(..)
| CheckKind::RaiseNotImplemented | CheckKind::RaiseNotImplemented
| CheckKind::RedundantOpenModes | CheckKind::RedundantOpenModes(..)
| CheckKind::RedundantTupleInExceptionHandler(..) | CheckKind::RedundantTupleInExceptionHandler(..)
| CheckKind::RemoveSixCompat | CheckKind::RemoveSixCompat
| CheckKind::SectionNameEndsInColon(..) | CheckKind::SectionNameEndsInColon(..)
@ -3170,7 +3221,7 @@ impl CheckKind {
| CheckKind::UnnecessaryLiteralWithinTupleCall(..) | CheckKind::UnnecessaryLiteralWithinTupleCall(..)
| CheckKind::UnnecessaryReturnNone | CheckKind::UnnecessaryReturnNone
| CheckKind::UnsortedImports | CheckKind::UnsortedImports
| CheckKind::UnusedImport(_, false) | CheckKind::UnusedImport(_, false, _)
| CheckKind::UnusedLoopControlVariable(..) | CheckKind::UnusedLoopControlVariable(..)
| CheckKind::UnusedNOQA(..) | CheckKind::UnusedNOQA(..)
| CheckKind::UsePEP585Annotation(..) | CheckKind::UsePEP585Annotation(..)
@ -3181,6 +3232,235 @@ impl CheckKind {
| CheckKind::UselessObjectInheritance(..) | CheckKind::UselessObjectInheritance(..)
) )
} }
/// The message used to describe the fix action for a given `CheckKind`.
pub fn commit(&self) -> Option<String> {
match self {
CheckKind::AmbiguousUnicodeCharacterString(confusable, representant)
| CheckKind::AmbiguousUnicodeCharacterDocstring(confusable, representant)
| CheckKind::AmbiguousUnicodeCharacterComment(confusable, representant) => {
Some(format!("Replace '{confusable}' with '{representant}'"))
}
CheckKind::BlankLineAfterLastSection(name) => {
Some(format!("Add blank line after \"{name}\""))
}
CheckKind::BlankLineAfterSection(name) => {
Some(format!("Add blank line after \"{name}\""))
}
CheckKind::BlankLineAfterSummary => Some("Insert single blank line".to_string()),
CheckKind::BlankLineBeforeSection(name) => {
Some(format!("Add blank line before \"{name}\""))
}
CheckKind::CapitalizeSectionName(name) => Some(format!("Capitalize \"{name}\"")),
CheckKind::CommentedOutCode => Some("Remove commented-out code".to_string()),
CheckKind::ConvertTypedDictFunctionalToClass(name)
| CheckKind::ConvertNamedTupleFunctionalToClass(name) => {
Some(format!("Convert `{name}` to class syntax"))
}
CheckKind::DashedUnderlineAfterSection(name) => {
Some(format!("Add dashed line under \"{name}\""))
}
CheckKind::DatetimeTimezoneUTC => Some("Convert to `datetime.UTC` alias".to_string()),
CheckKind::DeprecatedUnittestAlias(alias, target) => {
Some(format!("Replace `{target}` with `{alias}`"))
}
CheckKind::DoNotAssertFalse => Some("Replace `assert False`".to_string()),
CheckKind::DoNotAssignLambda(name) => Some(format!("Rewrite `{name}` as a `def`")),
CheckKind::DuplicateHandlerException(..) => Some("De-duplicate exceptions".to_string()),
CheckKind::EndsInPeriod => Some("Add period".to_string()),
CheckKind::EndsInPunctuation => Some("Add closing punctuation".to_string()),
CheckKind::GetAttrWithConstant => {
Some("Replace `getattr` with attribute access".to_string())
}
CheckKind::ImplicitReturnValue => Some("Add explicit `None` return value".to_string()),
CheckKind::ImplicitReturn => Some("Add explicit `return` statement".to_string()),
CheckKind::InvalidEscapeSequence(..) => {
Some("Add backslash to escape sequence".to_string())
}
CheckKind::IsLiteral(cmpop) => Some(match cmpop {
IsCmpop::Is => "Replace `is` with `==`".to_string(),
IsCmpop::IsNot => "Replace `is not` with `!=`".to_string(),
}),
CheckKind::KeyInDict(key, dict) => Some(format!("Convert to `{key} in {dict}`")),
CheckKind::MisplacedComparisonConstant(comparison) => {
Some(format!("Replace with {comparison}"))
}
CheckKind::MissingReturnTypeSpecialMethod(..) => {
Some("Add `None` return type".to_string())
}
CheckKind::NativeLiterals(literal_type) => {
Some(format!("Replace with `{literal_type}`"))
}
CheckKind::OpenAlias => Some("Replace with builtin `open`".to_string()),
CheckKind::NewLineAfterLastParagraph => {
Some("Move closing quotes to new line".to_string())
}
CheckKind::ReplaceUniversalNewlines => {
Some("Replace with `text` keyword argument".to_string())
}
CheckKind::ReplaceStdoutStderr => {
Some("Replace with `capture_output` keyword argument".to_string())
}
CheckKind::RewriteCElementTree => Some("Replace with `ElementTree`".to_string()),
CheckKind::RewriteUnicodeLiteral => Some("Remove unicode prefix".to_string()),
CheckKind::NewLineAfterSectionName(name) => {
Some(format!("Add newline after \"{name}\""))
}
CheckKind::NoBlankLineBeforeFunction(..) => {
Some("Remove blank line(s) before function docstring".to_string())
}
CheckKind::NoBlankLineAfterFunction(..) => {
Some("Remove blank line(s) after function docstring".to_string())
}
CheckKind::NoBlankLineBeforeClass(..) => {
Some("Remove blank line(s) before class docstring".to_string())
}
CheckKind::OneBlankLineBeforeClass(..) => {
Some("Insert 1 blank line before class docstring".to_string())
}
CheckKind::OneBlankLineAfterClass(..) => {
Some("Insert 1 blank line after class docstring".to_string())
}
CheckKind::NoBlankLinesBetweenHeaderAndContent(..) => {
Some("Remove blank line(s)".to_string())
}
CheckKind::NoNewLineAtEndOfFile => Some("Add trailing newline".to_string()),
CheckKind::NoOverIndentation => Some("Remove over-indentation".to_string()),
CheckKind::NoSurroundingWhitespace => Some("Trim surrounding whitespace".to_string()),
CheckKind::NoUnderIndentation => Some("Increase indentation".to_string()),
CheckKind::NoneComparison(op) => Some(match op {
EqCmpop::Eq => "Replace with `cond is None`".to_string(),
EqCmpop::NotEq => "Replace with `cond is not None`".to_string(),
}),
CheckKind::NotInTest => Some("Convert to `not in`".to_string()),
CheckKind::NotIsTest => Some("Convert to `is not`".to_string()),
CheckKind::PEP3120UnnecessaryCodingComment => {
Some("Remove unnecessary coding comment".to_string())
}
CheckKind::PPrintFound => Some("Remove `pprint`".to_string()),
CheckKind::PercentFormatExtraNamedArguments(missing)
| CheckKind::StringDotFormatExtraNamedArguments(missing) => {
let message = missing.join(", ");
Some(format!("Remove extra named arguments: {message}"))
}
CheckKind::PrintFound => Some("Remove `print`".to_string()),
CheckKind::RaiseNotImplemented => Some("Use `raise NotImplementedError`".to_string()),
CheckKind::RedundantOpenModes(replacement) => Some(match replacement {
None => "Remove open mode parameters".to_string(),
Some(replacement) => {
format!("Replace with \"{replacement}\"")
}
}),
CheckKind::RedundantTupleInExceptionHandler(name) => {
Some(format!("Replace with `except {name}`"))
}
CheckKind::RemoveSixCompat => Some("Remove `six` usage".to_string()),
CheckKind::SectionNameEndsInColon(name) => Some(format!("Add colon to \"{name}\"")),
CheckKind::SectionNotOverIndented(name) => {
Some(format!("Remove over-indentation from \"{name}\""))
}
CheckKind::SectionUnderlineAfterName(name) => {
Some(format!("Add underline to \"{name}\""))
}
CheckKind::SectionUnderlineMatchesSectionLength(name) => {
Some(format!("Adjust underline length to match \"{name}\""))
}
CheckKind::SectionUnderlineNotOverIndented(name) => {
Some(format!("Remove over-indentation from \"{name}\" underline"))
}
CheckKind::SetAttrWithConstant => Some("Replace `setattr` with assignment".to_string()),
CheckKind::SuperCallWithParameters => Some("Remove `__super__` parameters".to_string()),
CheckKind::TrueFalseComparison(true, EqCmpop::Eq) => {
Some("Replace with `cond is True`".to_string())
}
CheckKind::TrueFalseComparison(true, EqCmpop::NotEq) => {
Some("Replace with `cond is not True`".to_string())
}
CheckKind::TrueFalseComparison(false, EqCmpop::Eq) => {
Some("Replace with `cond is False`".to_string())
}
CheckKind::TrueFalseComparison(false, EqCmpop::NotEq) => {
Some("Replace with `cond is not False`".to_string())
}
CheckKind::TypeOfPrimitive(primitive) => Some(format!(
"Replace `type(...)` with `{}`",
primitive.builtin()
)),
CheckKind::TypingTextStrAlias => Some("Replace with `str`".to_string()),
CheckKind::UnnecessaryCallAroundSorted(func) => {
Some(format!("Remove unnecessary `{func}` call"))
}
CheckKind::UnnecessaryCollectionCall(..) => Some("Rewrite as a literal".to_string()),
CheckKind::UnnecessaryComprehension(obj_type) => {
Some(format!("Rewrite using `{obj_type}()`"))
}
CheckKind::UnnecessaryEncodeUTF8 => Some("Remove unnecessary `encode`".to_string()),
CheckKind::UnnecessaryFutureImport(..) => {
Some("Remove unnecessary `__future__` import".to_string())
}
CheckKind::UnnecessaryGeneratorDict => {
Some("Rewrite as a `dict` comprehension".to_string())
}
CheckKind::UnnecessaryGeneratorList => {
Some("Rewrite as a `list` comprehension".to_string())
}
CheckKind::UnnecessaryGeneratorSet => {
Some("Rewrite as a `set` comprehension".to_string())
}
CheckKind::UnnecessaryLRUCacheParams => {
Some("Remove unnecessary parameters".to_string())
}
CheckKind::UnnecessaryListCall => Some("Remove outer `list` call".to_string()),
CheckKind::UnnecessaryListComprehensionDict => {
Some("Rewrite as a `dict` comprehension".to_string())
}
CheckKind::UnnecessaryListComprehensionSet => {
Some("Rewrite as a `set` comprehension".to_string())
}
CheckKind::UnnecessaryLiteralDict(..) => {
Some("Rewrite as a `dict` literal".to_string())
}
CheckKind::UnnecessaryLiteralSet(..) => Some("Rewrite as a `set` literal".to_string()),
CheckKind::UnnecessaryLiteralWithinTupleCall(literal) => Some({
if literal == "list" {
"Rewrite as a `tuple` literal".to_string()
} else {
"Remove outer `tuple` call".to_string()
}
}),
CheckKind::UnnecessaryLiteralWithinListCall(literal) => Some({
if literal == "list" {
"Remove outer `list` call".to_string()
} else {
"Rewrite as a `list` literal".to_string()
}
}),
CheckKind::UnnecessaryReturnNone => Some("Remove explicit `return None`".to_string()),
CheckKind::UnsortedImports => Some("Organize imports".to_string()),
CheckKind::UnusedImport(name, false, multiple) => {
if *multiple {
Some("Remove unused import".to_string())
} else {
Some(format!("Remove unused import: `{name}`"))
}
}
CheckKind::UnusedLoopControlVariable(name) => {
Some(format!("Rename unused `{name}` to `_{name}`"))
}
CheckKind::UnusedNOQA(..) => Some("Remove unused `noqa` directive".to_string()),
CheckKind::UsePEP585Annotation(name) => {
Some(format!("Replace `{name}` with `{}`", name.to_lowercase(),))
}
CheckKind::UsePEP604Annotation => Some("Convert to `X | Y`".to_string()),
CheckKind::UseSysExit(name) => Some(format!("Replace `{name}` with `sys.exit()`")),
CheckKind::UselessImportAlias => Some("Remove import alias".to_string()),
CheckKind::UselessMetaclassType => Some("Remove `__metaclass__ = type`".to_string()),
CheckKind::UselessObjectInheritance(..) => {
Some("Remove `object` inheritance".to_string())
}
_ => None,
}
}
} }
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
@ -3361,4 +3641,17 @@ mod tests {
); );
} }
} }
#[test]
fn fixable_codes() {
for check_code in CheckCode::iter() {
let kind = check_code.kind();
if kind.fixable() {
assert!(
kind.commit().is_some(),
"{check_code:?} is fixable but has no commit message."
);
}
}
}
} }

View File

@ -2,10 +2,9 @@ use std::path::Path;
use rustpython_ast::Location; use rustpython_ast::Location;
use rustpython_parser::lexer::LexResult; use rustpython_parser::lexer::LexResult;
use serde::{Deserialize, Serialize}; use serde::Serialize;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use crate::autofix::Fix;
use crate::checks::CheckCode; use crate::checks::CheckCode;
use crate::checks_gen::CheckCodePrefix; use crate::checks_gen::CheckCodePrefix;
use crate::linter::check_path; use crate::linter::check_path;
@ -39,6 +38,7 @@ export interface Check {
}; };
fix: { fix: {
content: string; content: string;
message: string | null;
location: { location: {
row: number; row: number;
column: number; column: number;
@ -51,13 +51,21 @@ export interface Check {
}; };
"#; "#;
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Serialize)]
struct Message { struct ExpandedMessage {
code: CheckCode, code: CheckCode,
message: String, message: String,
location: Location, location: Location,
end_location: Location, end_location: Location,
fix: Option<Fix>, fix: Option<ExpandedFix>,
}
#[derive(Serialize)]
struct ExpandedFix {
content: String,
message: Option<String>,
location: Location,
end_location: Location,
} }
#[wasm_bindgen(start)] #[wasm_bindgen(start)]
@ -161,14 +169,19 @@ pub fn check(contents: &str, options: JsValue) -> Result<JsValue, JsValue> {
) )
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
let messages: Vec<Message> = checks let messages: Vec<ExpandedMessage> = checks
.into_iter() .into_iter()
.map(|check| Message { .map(|check| ExpandedMessage {
code: check.kind.code().clone(), code: check.kind.code().clone(),
message: check.kind.body(), message: check.kind.body(),
location: check.location, location: check.location,
end_location: check.end_location, end_location: check.end_location,
fix: check.fix, fix: check.fix.map(|fix| ExpandedFix {
content: fix.content,
message: check.kind.commit(),
location: fix.location,
end_location: fix.end_location,
}),
}) })
.collect(); .collect();
@ -200,7 +213,7 @@ mod test {
check!( check!(
"if (1, 2): pass", "if (1, 2): pass",
r#"{}"#, r#"{}"#,
[Message { [ExpandedMessage {
code: CheckCode::F634, code: CheckCode::F634,
message: "If test is a tuple, which is always `True`".to_string(), message: "If test is a tuple, which is always `True`".to_string(),
location: Location::new(1, 0), location: Location::new(1, 0),

View File

@ -10,7 +10,7 @@ use rustpython_parser::ast::Location;
use serde::Serialize; use serde::Serialize;
use serde_json::json; use serde_json::json;
use crate::autofix::{fixer, Fix}; use crate::autofix::fixer;
use crate::checks::CheckCode; use crate::checks::CheckCode;
use crate::fs::relativize_path; use crate::fs::relativize_path;
use crate::linter::Diagnostics; use crate::linter::Diagnostics;
@ -25,11 +25,19 @@ pub enum Violations {
Hide, Hide,
} }
#[derive(Serialize)]
struct ExpandedFix<'a> {
content: &'a str,
message: Option<String>,
location: &'a Location,
end_location: &'a Location,
}
#[derive(Serialize)] #[derive(Serialize)]
struct ExpandedMessage<'a> { struct ExpandedMessage<'a> {
code: &'a CheckCode, code: &'a CheckCode,
message: String, message: String,
fix: Option<&'a Fix>, fix: Option<ExpandedFix<'a>>,
location: Location, location: Location,
end_location: Location, end_location: Location,
filename: &'a str, filename: &'a str,
@ -127,7 +135,12 @@ impl<'a> Printer<'a> {
.map(|message| ExpandedMessage { .map(|message| ExpandedMessage {
code: message.kind.code(), code: message.kind.code(),
message: message.kind.body(), message: message.kind.body(),
fix: message.fix.as_ref(), fix: message.fix.as_ref().map(|fix| ExpandedFix {
content: &fix.content,
location: &fix.location,
end_location: &fix.end_location,
message: message.kind.commit(),
}),
location: message.location, location: message.location,
end_location: message.end_location, end_location: message.end_location,
filename: &message.filename, filename: &message.filename,

View File

@ -11,7 +11,7 @@ use crate::ast::types::Range;
use crate::ast::whitespace::leading_space; use crate::ast::whitespace::leading_space;
use crate::autofix::Fix; use crate::autofix::Fix;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckKind, RejectedCmpop}; use crate::checks::{Check, CheckKind};
use crate::source_code_generator::SourceCodeGenerator; use crate::source_code_generator::SourceCodeGenerator;
use crate::source_code_style::SourceCodeStyleDetector; use crate::source_code_style::SourceCodeStyleDetector;
@ -68,7 +68,7 @@ pub fn literal_comparisons(
{ {
if matches!(op, Cmpop::Eq) { if matches!(op, Cmpop::Eq) {
let check = Check::new( let check = Check::new(
CheckKind::NoneComparison(RejectedCmpop::Eq), CheckKind::NoneComparison(op.into()),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch(check.kind.code()) && !helpers::is_constant_non_singleton(next) { if checker.patch(check.kind.code()) && !helpers::is_constant_non_singleton(next) {
@ -78,7 +78,7 @@ pub fn literal_comparisons(
} }
if matches!(op, Cmpop::NotEq) { if matches!(op, Cmpop::NotEq) {
let check = Check::new( let check = Check::new(
CheckKind::NoneComparison(RejectedCmpop::NotEq), CheckKind::NoneComparison(op.into()),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch(check.kind.code()) && !helpers::is_constant_non_singleton(next) { if checker.patch(check.kind.code()) && !helpers::is_constant_non_singleton(next) {
@ -96,7 +96,7 @@ pub fn literal_comparisons(
{ {
if matches!(op, Cmpop::Eq) { if matches!(op, Cmpop::Eq) {
let check = Check::new( let check = Check::new(
CheckKind::TrueFalseComparison(value, RejectedCmpop::Eq), CheckKind::TrueFalseComparison(value, op.into()),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch(check.kind.code()) && !helpers::is_constant_non_singleton(next) { if checker.patch(check.kind.code()) && !helpers::is_constant_non_singleton(next) {
@ -106,7 +106,7 @@ pub fn literal_comparisons(
} }
if matches!(op, Cmpop::NotEq) { if matches!(op, Cmpop::NotEq) {
let check = Check::new( let check = Check::new(
CheckKind::TrueFalseComparison(value, RejectedCmpop::NotEq), CheckKind::TrueFalseComparison(value, op.into()),
Range::from_located(comparator), Range::from_located(comparator),
); );
if checker.patch(check.kind.code()) && !helpers::is_constant_non_singleton(next) { if checker.patch(check.kind.code()) && !helpers::is_constant_non_singleton(next) {
@ -130,7 +130,7 @@ pub fn literal_comparisons(
{ {
if matches!(op, Cmpop::Eq) { if matches!(op, Cmpop::Eq) {
let check = Check::new( let check = Check::new(
CheckKind::NoneComparison(RejectedCmpop::Eq), CheckKind::NoneComparison(op.into()),
Range::from_located(next), Range::from_located(next),
); );
if checker.patch(check.kind.code()) if checker.patch(check.kind.code())
@ -142,7 +142,7 @@ pub fn literal_comparisons(
} }
if matches!(op, Cmpop::NotEq) { if matches!(op, Cmpop::NotEq) {
let check = Check::new( let check = Check::new(
CheckKind::NoneComparison(RejectedCmpop::NotEq), CheckKind::NoneComparison(op.into()),
Range::from_located(next), Range::from_located(next),
); );
if checker.patch(check.kind.code()) if checker.patch(check.kind.code())
@ -162,7 +162,7 @@ pub fn literal_comparisons(
{ {
if matches!(op, Cmpop::Eq) { if matches!(op, Cmpop::Eq) {
let check = Check::new( let check = Check::new(
CheckKind::TrueFalseComparison(value, RejectedCmpop::Eq), CheckKind::TrueFalseComparison(value, op.into()),
Range::from_located(next), Range::from_located(next),
); );
if checker.patch(check.kind.code()) if checker.patch(check.kind.code())
@ -174,7 +174,7 @@ pub fn literal_comparisons(
} }
if matches!(op, Cmpop::NotEq) { if matches!(op, Cmpop::NotEq) {
let check = Check::new( let check = Check::new(
CheckKind::TrueFalseComparison(value, RejectedCmpop::NotEq), CheckKind::TrueFalseComparison(value, op.into()),
Range::from_located(next), Range::from_located(next),
); );
if checker.patch(check.kind.code()) if checker.patch(check.kind.code())
@ -311,7 +311,10 @@ fn function(
pub fn do_not_assign_lambda(checker: &mut Checker, target: &Expr, value: &Expr, stmt: &Stmt) { pub fn do_not_assign_lambda(checker: &mut Checker, target: &Expr, value: &Expr, stmt: &Stmt) {
if let ExprKind::Name { id, .. } = &target.node { if let ExprKind::Name { id, .. } = &target.node {
if let ExprKind::Lambda { args, body } = &value.node { if let ExprKind::Lambda { args, body } = &value.node {
let mut check = Check::new(CheckKind::DoNotAssignLambda, Range::from_located(stmt)); let mut check = Check::new(
CheckKind::DoNotAssignLambda(id.to_string()),
Range::from_located(stmt),
);
if checker.patch(check.kind.code()) { if checker.patch(check.kind.code()) {
if !match_leading_content(stmt, checker.locator) if !match_leading_content(stmt, checker.locator)
&& !match_trailing_content(stmt, checker.locator) && !match_trailing_content(stmt, checker.locator)

View File

@ -2,7 +2,8 @@
source: src/pycodestyle/mod.rs source: src/pycodestyle/mod.rs
expression: checks expression: checks
--- ---
- kind: DoNotAssignLambda - kind:
DoNotAssignLambda: f
location: location:
row: 2 row: 2
column: 0 column: 0
@ -18,7 +19,8 @@ expression: checks
row: 2 row: 2
column: 19 column: 19
parent: ~ parent: ~
- kind: DoNotAssignLambda - kind:
DoNotAssignLambda: f
location: location:
row: 4 row: 4
column: 0 column: 0
@ -34,7 +36,8 @@ expression: checks
row: 4 row: 4
column: 19 column: 19
parent: ~ parent: ~
- kind: DoNotAssignLambda - kind:
DoNotAssignLambda: this
location: location:
row: 7 row: 7
column: 4 column: 4

View File

@ -2,7 +2,8 @@
source: src/pycodestyle/mod.rs source: src/pycodestyle/mod.rs
expression: checks expression: checks
--- ---
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 4 row: 4
column: 3 column: 3
@ -18,7 +19,8 @@ expression: checks
row: 4 row: 4
column: 11 column: 11
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 6 row: 6
column: 3 column: 3
@ -34,7 +36,8 @@ expression: checks
row: 6 row: 6
column: 11 column: 11
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 8 row: 8
column: 3 column: 3
@ -50,7 +53,8 @@ expression: checks
row: 8 row: 8
column: 10 column: 10
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 10 row: 10
column: 3 column: 3
@ -66,7 +70,8 @@ expression: checks
row: 10 row: 10
column: 11 column: 11
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 12 row: 12
column: 3 column: 3

View File

@ -24,7 +24,7 @@ pub fn invalid_literal_comparison(
&& (helpers::is_constant_non_singleton(left) && (helpers::is_constant_non_singleton(left)
|| helpers::is_constant_non_singleton(right)) || helpers::is_constant_non_singleton(right))
{ {
let mut check = Check::new(CheckKind::IsLiteral, location); let mut check = Check::new(CheckKind::IsLiteral(op.into()), location);
if checker.patch(check.kind.code()) { if checker.patch(check.kind.code()) {
if let Some(located_op) = &located.get(index) { if let Some(located_op) = &located.get(index) {
assert_eq!(&located_op.node, op); assert_eq!(&located_op.node, op);

View File

@ -6,6 +6,7 @@ expression: checks
UnusedImport: UnusedImport:
- functools - functools
- false - false
- false
location: location:
row: 2 row: 2
column: 7 column: 7
@ -25,6 +26,7 @@ expression: checks
UnusedImport: UnusedImport:
- collections.OrderedDict - collections.OrderedDict
- false - false
- false
location: location:
row: 6 row: 6
column: 4 column: 4
@ -46,6 +48,7 @@ expression: checks
UnusedImport: UnusedImport:
- logging.handlers - logging.handlers
- false - false
- false
location: location:
row: 12 row: 12
column: 7 column: 7
@ -65,6 +68,7 @@ expression: checks
UnusedImport: UnusedImport:
- shelve - shelve
- false - false
- false
location: location:
row: 32 row: 32
column: 11 column: 11
@ -84,6 +88,7 @@ expression: checks
UnusedImport: UnusedImport:
- importlib - importlib
- false - false
- false
location: location:
row: 33 row: 33
column: 11 column: 11
@ -103,6 +108,7 @@ expression: checks
UnusedImport: UnusedImport:
- pathlib - pathlib
- false - false
- false
location: location:
row: 37 row: 37
column: 11 column: 11
@ -122,6 +128,7 @@ expression: checks
UnusedImport: UnusedImport:
- pickle - pickle
- false - false
- false
location: location:
row: 52 row: 52
column: 15 column: 15

View File

@ -6,6 +6,7 @@ expression: checks
UnusedImport: UnusedImport:
- a.b.c - a.b.c
- false - false
- false
location: location:
row: 2 row: 2
column: 16 column: 16
@ -25,6 +26,7 @@ expression: checks
UnusedImport: UnusedImport:
- d.e.f - d.e.f
- false - false
- false
location: location:
row: 3 row: 3
column: 16 column: 16
@ -44,6 +46,7 @@ expression: checks
UnusedImport: UnusedImport:
- h.i - h.i
- false - false
- false
location: location:
row: 4 row: 4
column: 7 column: 7
@ -63,6 +66,7 @@ expression: checks
UnusedImport: UnusedImport:
- j.k - j.k
- false - false
- false
location: location:
row: 5 row: 5
column: 7 column: 7

View File

@ -6,6 +6,7 @@ expression: checks
UnusedImport: UnusedImport:
- background.BackgroundTasks - background.BackgroundTasks
- false - false
- false
location: location:
row: 7 row: 7
column: 24 column: 24
@ -25,6 +26,7 @@ expression: checks
UnusedImport: UnusedImport:
- datastructures.UploadFile - datastructures.UploadFile
- false - false
- false
location: location:
row: 10 row: 10
column: 28 column: 28
@ -44,6 +46,7 @@ expression: checks
UnusedImport: UnusedImport:
- background - background
- false - false
- false
location: location:
row: 17 row: 17
column: 7 column: 7
@ -63,6 +66,7 @@ expression: checks
UnusedImport: UnusedImport:
- datastructures - datastructures
- false - false
- false
location: location:
row: 20 row: 20
column: 7 column: 7

View File

@ -6,6 +6,7 @@ expression: checks
UnusedImport: UnusedImport:
- typing.Union - typing.Union
- false - false
- false
location: location:
row: 30 row: 30
column: 4 column: 4
@ -27,6 +28,7 @@ expression: checks
UnusedImport: UnusedImport:
- typing.Awaitable - typing.Awaitable
- false - false
- true
location: location:
row: 66 row: 66
column: 19 column: 19
@ -46,6 +48,7 @@ expression: checks
UnusedImport: UnusedImport:
- typing.AwaitableGenerator - typing.AwaitableGenerator
- false - false
- true
location: location:
row: 66 row: 66
column: 30 column: 30

View File

@ -2,7 +2,8 @@
source: src/pyflakes/mod.rs source: src/pyflakes/mod.rs
expression: checks expression: checks
--- ---
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 1 row: 1
column: 3 column: 3
@ -18,7 +19,8 @@ expression: checks
row: 1 row: 1
column: 7 column: 7
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: IsNot
location: location:
row: 4 row: 4
column: 3 column: 3
@ -34,7 +36,8 @@ expression: checks
row: 4 row: 4
column: 13 column: 13
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: IsNot
location: location:
row: 7 row: 7
column: 3 column: 3
@ -50,7 +53,8 @@ expression: checks
row: 8 row: 8
column: 11 column: 11
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 11 row: 11
column: 3 column: 3
@ -66,7 +70,8 @@ expression: checks
row: 11 row: 11
column: 11 column: 11
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 14 row: 14
column: 3 column: 3
@ -82,7 +87,8 @@ expression: checks
row: 14 row: 14
column: 16 column: 16
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 17 row: 17
column: 3 column: 3
@ -98,7 +104,8 @@ expression: checks
row: 17 row: 17
column: 18 column: 18
parent: ~ parent: ~
- kind: IsLiteral - kind:
IsLiteral: Is
location: location:
row: 20 row: 20
column: 13 column: 13

View File

@ -6,6 +6,7 @@ expression: checks
UnusedImport: UnusedImport:
- models.Nut - models.Nut
- false - false
- false
location: location:
row: 8 row: 8
column: 4 column: 4

View File

@ -6,6 +6,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 3 row: 3
column: 11 column: 11
@ -25,6 +26,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 4 row: 4
column: 11 column: 11
@ -44,6 +46,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 7 row: 7
column: 11 column: 11
@ -63,6 +66,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 11 row: 11
column: 11 column: 11
@ -82,6 +86,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 16 row: 16
column: 18 column: 18
@ -101,6 +106,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 21 row: 21
column: 16 column: 16
@ -120,6 +126,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 26 row: 26
column: 17 column: 17
@ -139,6 +146,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 30 row: 30
column: 18 column: 18
@ -158,6 +166,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 31 row: 31
column: 22 column: 22
@ -177,6 +186,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 35 row: 35
column: 15 column: 15
@ -196,6 +206,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 40 row: 40
column: 16 column: 16
@ -215,6 +226,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 46 row: 46
column: 7 column: 7
@ -234,6 +246,7 @@ expression: checks
UnusedImport: UnusedImport:
- foo - foo
- false - false
- false
location: location:
row: 51 row: 51
column: 7 column: 7

View File

@ -5,7 +5,7 @@ use rustpython_parser::lexer::Tok;
use crate::ast::types::Range; use crate::ast::types::Range;
use crate::autofix::Fix; use crate::autofix::Fix;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckCode, CheckKind}; use crate::checks::{Check, CheckCode, CheckKind, LiteralType};
/// UP018 /// UP018
pub fn native_literals( pub fn native_literals(
@ -23,7 +23,12 @@ pub fn native_literals(
&& checker.is_builtin(id) && checker.is_builtin(id)
{ {
let Some(arg) = args.get(0) else { let Some(arg) = args.get(0) else {
let mut check = Check::new(CheckKind::NativeLiterals, Range::from_located(expr)); let literal_type = if id == "str" {
LiteralType::Str
} else {
LiteralType::Bytes
};
let mut check = Check::new(CheckKind::NativeLiterals(literal_type), Range::from_located(expr));
if checker.patch(&CheckCode::UP018) { if checker.patch(&CheckCode::UP018) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
format!("{}\"\"", if id == "bytes" { "b" } else { "" }), format!("{}\"\"", if id == "bytes" { "b" } else { "" }),
@ -35,15 +40,14 @@ pub fn native_literals(
return; return;
}; };
if !matches!( let ExprKind::Constant { value, ..} = &arg.node else {
&arg.node,
ExprKind::Constant {
value: Constant::Str(_) | Constant::Bytes(_),
..
}
) {
return; return;
} };
let literal_type = match value {
Constant::Str { .. } => LiteralType::Str,
Constant::Bytes { .. } => LiteralType::Bytes,
_ => return,
};
// rust-python merges adjacent string/bytes literals into one node, but we can't // rust-python merges adjacent string/bytes literals into one node, but we can't
// safely remove the outer call in this situation. We're following pyupgrade // safely remove the outer call in this situation. We're following pyupgrade
@ -60,7 +64,10 @@ pub fn native_literals(
return; return;
} }
let mut check = Check::new(CheckKind::NativeLiterals, Range::from_located(expr)); let mut check = Check::new(
CheckKind::NativeLiterals(literal_type),
Range::from_located(expr),
);
if checker.patch(&CheckCode::UP018) { if checker.patch(&CheckCode::UP018) {
check.amend(Fix::replacement( check.amend(Fix::replacement(
arg_code.to_string(), arg_code.to_string(),

View File

@ -2,10 +2,11 @@ use std::str::FromStr;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use log::error; use log::error;
use rustpython_ast::{Constant, Expr, ExprKind, Keyword, KeywordData, Location}; use rustpython_ast::{Constant, Expr, ExprKind, Keyword, Location};
use rustpython_parser::lexer; use rustpython_parser::lexer;
use rustpython_parser::token::Tok; use rustpython_parser::token::Tok;
use crate::ast::helpers::find_keyword;
use crate::ast::types::Range; use crate::ast::types::Range;
use crate::autofix::Fix; use crate::autofix::Fix;
use crate::checkers::ast::Checker; use crate::checkers::ast::Checker;
@ -78,7 +79,10 @@ fn create_check(
locator: &SourceCodeLocator, locator: &SourceCodeLocator,
patch: bool, patch: bool,
) -> Check { ) -> Check {
let mut check = Check::new(CheckKind::RedundantOpenModes, Range::from_located(expr)); let mut check = Check::new(
CheckKind::RedundantOpenModes(replacement_value.clone()),
Range::from_located(expr),
);
if patch { if patch {
if let Some(content) = replacement_value { if let Some(content) = replacement_value {
check.amend(Fix::replacement( check.amend(Fix::replacement(
@ -153,27 +157,16 @@ pub fn redundant_open_modes(checker: &mut Checker, expr: &Expr) {
} }
let (mode_param, keywords): (Option<&Expr>, Vec<Keyword>) = match_open(expr); let (mode_param, keywords): (Option<&Expr>, Vec<Keyword>) = match_open(expr);
if mode_param.is_none() && !keywords.is_empty() { if mode_param.is_none() && !keywords.is_empty() {
if let Some(value) = keywords.iter().find_map(|keyword| { if let Some(keyword) = find_keyword(&keywords, MODE_KEYWORD_ARGUMENT) {
let KeywordData { arg, value } = &keyword.node;
if arg
.as_ref()
.map(|arg| arg == MODE_KEYWORD_ARGUMENT)
.unwrap_or_default()
{
Some(value)
} else {
None
}
}) {
if let ExprKind::Constant { if let ExprKind::Constant {
value: Constant::Str(mode_param_value), value: Constant::Str(mode_param_value),
.. ..
} = &value.node } = &keyword.node.value.node
{ {
if let Ok(mode) = OpenMode::from_str(mode_param_value.as_str()) { if let Ok(mode) = OpenMode::from_str(mode_param_value.as_str()) {
checker.add_check(create_check( checker.add_check(create_check(
expr, expr,
value, &keyword.node.value,
mode.replacement_value(), mode.replacement_value(),
checker.locator, checker.locator,
checker.patch(&CheckCode::UP015), checker.patch(&CheckCode::UP015),

View File

@ -2,7 +2,8 @@
source: src/pyupgrade/mod.rs source: src/pyupgrade/mod.rs
expression: checks expression: checks
--- ---
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 1 row: 1
column: 0 column: 0
@ -18,7 +19,8 @@ expression: checks
row: 1 row: 1
column: 15 column: 15
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 2 row: 2
column: 0 column: 0
@ -34,7 +36,8 @@ expression: checks
row: 2 row: 2
column: 16 column: 16
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 3 row: 3
column: 0 column: 0
@ -50,7 +53,8 @@ expression: checks
row: 3 row: 3
column: 16 column: 16
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 4 row: 4
column: 0 column: 0
@ -66,7 +70,8 @@ expression: checks
row: 4 row: 4
column: 17 column: 17
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 5 row: 5
column: 0 column: 0
@ -82,7 +87,8 @@ expression: checks
row: 5 row: 5
column: 15 column: 15
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 6 row: 6
column: 0 column: 0
@ -98,7 +104,8 @@ expression: checks
row: 6 row: 6
column: 16 column: 16
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 7 row: 7
column: 0 column: 0
@ -114,7 +121,8 @@ expression: checks
row: 7 row: 7
column: 13 column: 13
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"w\""
location: location:
row: 8 row: 8
column: 0 column: 0
@ -130,7 +138,8 @@ expression: checks
row: 8 row: 8
column: 14 column: 14
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 10 row: 10
column: 5 column: 5
@ -146,7 +155,8 @@ expression: checks
row: 10 row: 10
column: 20 column: 20
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 12 row: 12
column: 5 column: 5
@ -162,7 +172,8 @@ expression: checks
row: 12 row: 12
column: 21 column: 21
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 14 row: 14
column: 5 column: 5
@ -178,7 +189,8 @@ expression: checks
row: 14 row: 14
column: 21 column: 21
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 16 row: 16
column: 5 column: 5
@ -194,7 +206,8 @@ expression: checks
row: 16 row: 16
column: 22 column: 22
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 18 row: 18
column: 5 column: 5
@ -210,7 +223,8 @@ expression: checks
row: 18 row: 18
column: 20 column: 20
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 20 row: 20
column: 5 column: 5
@ -226,7 +240,8 @@ expression: checks
row: 20 row: 20
column: 21 column: 21
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 22 row: 22
column: 5 column: 5
@ -242,7 +257,8 @@ expression: checks
row: 22 row: 22
column: 20 column: 20
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"w\""
location: location:
row: 24 row: 24
column: 5 column: 5
@ -258,7 +274,8 @@ expression: checks
row: 24 row: 24
column: 21 column: 21
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 27 row: 27
column: 0 column: 0
@ -274,7 +291,8 @@ expression: checks
row: 27 row: 27
column: 26 column: 26
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 28 row: 28
column: 0 column: 0
@ -290,7 +308,8 @@ expression: checks
row: 28 row: 28
column: 27 column: 27
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 30 row: 30
column: 5 column: 5
@ -306,7 +325,8 @@ expression: checks
row: 30 row: 30
column: 31 column: 31
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 32 row: 32
column: 5 column: 5
@ -322,7 +342,8 @@ expression: checks
row: 32 row: 32
column: 32 column: 32
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 35 row: 35
column: 5 column: 5
@ -338,7 +359,8 @@ expression: checks
row: 35 row: 35
column: 20 column: 20
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 35 row: 35
column: 29 column: 29
@ -354,7 +376,8 @@ expression: checks
row: 35 row: 35
column: 44 column: 44
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 37 row: 37
column: 5 column: 5
@ -370,7 +393,8 @@ expression: checks
row: 37 row: 37
column: 21 column: 21
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 37 row: 37
column: 30 column: 30
@ -386,7 +410,8 @@ expression: checks
row: 37 row: 37
column: 46 column: 46
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 40 row: 40
column: 0 column: 0
@ -402,7 +427,8 @@ expression: checks
row: 40 row: 40
column: 20 column: 20
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 41 row: 41
column: 0 column: 0
@ -418,7 +444,8 @@ expression: checks
row: 41 row: 41
column: 25 column: 25
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 42 row: 42
column: 0 column: 0
@ -434,7 +461,8 @@ expression: checks
row: 42 row: 42
column: 15 column: 15
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 44 row: 44
column: 5 column: 5
@ -450,7 +478,8 @@ expression: checks
row: 44 row: 44
column: 25 column: 25
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 46 row: 46
column: 5 column: 5
@ -466,7 +495,8 @@ expression: checks
row: 46 row: 46
column: 30 column: 30
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 48 row: 48
column: 5 column: 5
@ -482,7 +512,8 @@ expression: checks
row: 48 row: 48
column: 20 column: 20
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 51 row: 51
column: 0 column: 0
@ -498,7 +529,8 @@ expression: checks
row: 51 row: 51
column: 21 column: 21
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 52 row: 52
column: 0 column: 0
@ -514,7 +546,8 @@ expression: checks
row: 52 row: 52
column: 26 column: 26
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 53 row: 53
column: 0 column: 0
@ -530,7 +563,8 @@ expression: checks
row: 53 row: 53
column: 14 column: 14
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 55 row: 55
column: 5 column: 5
@ -546,7 +580,8 @@ expression: checks
row: 55 row: 55
column: 26 column: 26
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 57 row: 57
column: 5 column: 5
@ -562,7 +597,8 @@ expression: checks
row: 57 row: 57
column: 31 column: 31
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 59 row: 59
column: 5 column: 5
@ -578,7 +614,8 @@ expression: checks
row: 59 row: 59
column: 19 column: 19
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 62 row: 62
column: 0 column: 0
@ -594,7 +631,8 @@ expression: checks
row: 62 row: 62
column: 25 column: 25
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 63 row: 63
column: 0 column: 0
@ -610,7 +648,8 @@ expression: checks
row: 63 row: 63
column: 109 column: 109
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 64 row: 64
column: 0 column: 0
@ -626,7 +665,8 @@ expression: checks
row: 64 row: 64
column: 68 column: 68
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: ~
location: location:
row: 65 row: 65
column: 0 column: 0
@ -642,7 +682,8 @@ expression: checks
row: 65 row: 65
column: 15 column: 15
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 67 row: 67
column: 0 column: 0
@ -658,7 +699,8 @@ expression: checks
row: 67 row: 67
column: 26 column: 26
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 68 row: 68
column: 0 column: 0
@ -674,7 +716,8 @@ expression: checks
row: 68 row: 68
column: 110 column: 110
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 69 row: 69
column: 0 column: 0
@ -690,7 +733,8 @@ expression: checks
row: 69 row: 69
column: 69 column: 69
parent: ~ parent: ~
- kind: RedundantOpenModes - kind:
RedundantOpenModes: "\"rb\""
location: location:
row: 70 row: 70
column: 0 column: 0

View File

@ -2,7 +2,8 @@
source: src/pyupgrade/mod.rs source: src/pyupgrade/mod.rs
expression: checks expression: checks
--- ---
- kind: NativeLiterals - kind:
NativeLiterals: Str
location: location:
row: 18 row: 18
column: 0 column: 0
@ -18,7 +19,8 @@ expression: checks
row: 18 row: 18
column: 5 column: 5
parent: ~ parent: ~
- kind: NativeLiterals - kind:
NativeLiterals: Str
location: location:
row: 19 row: 19
column: 0 column: 0
@ -34,7 +36,8 @@ expression: checks
row: 19 row: 19
column: 10 column: 10
parent: ~ parent: ~
- kind: NativeLiterals - kind:
NativeLiterals: Str
location: location:
row: 20 row: 20
column: 0 column: 0
@ -50,7 +53,8 @@ expression: checks
row: 21 row: 21
column: 7 column: 7
parent: ~ parent: ~
- kind: NativeLiterals - kind:
NativeLiterals: Bytes
location: location:
row: 22 row: 22
column: 0 column: 0
@ -66,7 +70,8 @@ expression: checks
row: 22 row: 22
column: 7 column: 7
parent: ~ parent: ~
- kind: NativeLiterals - kind:
NativeLiterals: Bytes
location: location:
row: 23 row: 23
column: 0 column: 0
@ -82,7 +87,8 @@ expression: checks
row: 23 row: 23
column: 13 column: 13
parent: ~ parent: ~
- kind: NativeLiterals - kind:
NativeLiterals: Bytes
location: location:
row: 24 row: 24
column: 0 column: 0

View File

@ -222,6 +222,7 @@ expression: checks
UnusedImport: UnusedImport:
- shelve - shelve
- false - false
- false
location: location:
row: 85 row: 85
column: 7 column: 7

View File

@ -6,6 +6,7 @@ expression: checks
UnusedImport: UnusedImport:
- typing.Union - typing.Union
- false - false
- false
location: location:
row: 28 row: 28
column: 4 column: 4
@ -111,6 +112,7 @@ expression: checks
UnusedImport: UnusedImport:
- typing.Awaitable - typing.Awaitable
- false - false
- true
location: location:
row: 64 row: 64
column: 19 column: 19
@ -130,6 +132,7 @@ expression: checks
UnusedImport: UnusedImport:
- typing.AwaitableGenerator - typing.AwaitableGenerator
- false - false
- true
location: location:
row: 64 row: 64
column: 30 column: 30

View File

@ -63,6 +63,7 @@ fn test_stdin_json() -> Result<()> {
"message": "`os` imported but unused", "message": "`os` imported but unused",
"fix": { "fix": {
"content": "", "content": "",
"message": "Remove unused import: `os`",
"location": { "location": {
"row": 1, "row": 1,
"column": 0 "column": 0