Implement F632 (#190)

This commit is contained in:
Charlie Marsh
2022-09-14 18:22:35 -04:00
committed by GitHub
parent b03a8728b5
commit 2e1eb84cbf
10 changed files with 108 additions and 6 deletions

View File

@@ -432,6 +432,50 @@ pub fn check_literal_comparisons(
checks
}
fn is_constant(expr: &Expr) -> bool {
match &expr.node {
ExprKind::Constant { .. } => true,
ExprKind::Tuple { elts, .. } => elts.iter().all(is_constant),
_ => false,
}
}
fn is_singleton(expr: &Expr) -> bool {
matches!(
expr.node,
ExprKind::Constant {
value: Constant::None | Constant::Bool(_) | Constant::Ellipsis,
..
}
)
}
fn is_constant_non_singleton(expr: &Expr) -> bool {
is_constant(expr) && !is_singleton(expr)
}
/// Check IsLiteral compliance.
pub fn check_is_literal(
left: &Expr,
ops: &Vec<Cmpop>,
comparators: &Vec<Expr>,
location: Location,
) -> Vec<Check> {
let mut checks: Vec<Check> = vec![];
let mut left = left;
for (op, right) in izip!(ops, comparators) {
if matches!(op, Cmpop::Is | Cmpop::IsNot)
&& (is_constant_non_singleton(left) || is_constant_non_singleton(right))
{
checks.push(Check::new(CheckKind::IsLiteral, location));
}
left = right;
}
checks
}
/// Check TwoStarredExpressions and TooManyExpressionsInStarredAssignment compliance.
pub fn check_starred_expressions(
elts: &[Expr],

View File

@@ -737,6 +737,15 @@ where
check_true_false_comparisons,
));
}
if self.settings.select.contains(&CheckCode::F632) {
self.checks.extend(checks::check_is_literal(
left,
ops,
comparators,
expr.location,
));
}
}
ExprKind::Constant {
value: Constant::Str(value),

View File

@@ -31,6 +31,7 @@ pub enum CheckCode {
F621,
F622,
F631,
F632,
F633,
F634,
F701,
@@ -77,6 +78,7 @@ impl FromStr for CheckCode {
"F621" => Ok(CheckCode::F621),
"F622" => Ok(CheckCode::F622),
"F631" => Ok(CheckCode::F631),
"F632" => Ok(CheckCode::F632),
"F633" => Ok(CheckCode::F633),
"F634" => Ok(CheckCode::F634),
"F701" => Ok(CheckCode::F701),
@@ -123,6 +125,7 @@ impl CheckCode {
CheckCode::F621 => "F621",
CheckCode::F622 => "F622",
CheckCode::F631 => "F631",
CheckCode::F632 => "F632",
CheckCode::F633 => "F633",
CheckCode::F634 => "F634",
CheckCode::F701 => "F701",
@@ -182,9 +185,10 @@ pub enum CheckKind {
FutureFeatureNotDefined(String),
IOError(String),
IfTuple,
InvalidPrintSyntax,
ImportStarNotPermitted(String),
ImportStarUsage(String),
InvalidPrintSyntax,
IsLiteral,
LateFutureImport,
LineTooLong(usize, usize),
ModuleImportNotAtTopOfFile,
@@ -222,14 +226,15 @@ impl CheckKind {
CheckKind::DoNotAssignLambda => "DoNotAssignLambda",
CheckKind::DoNotUseBareExcept => "DoNotUseBareExcept",
CheckKind::DuplicateArgumentName => "DuplicateArgumentName",
CheckKind::ForwardAnnotationSyntaxError(_) => "ForwardAnnotationSyntaxError",
CheckKind::FStringMissingPlaceholders => "FStringMissingPlaceholders",
CheckKind::ForwardAnnotationSyntaxError(_) => "ForwardAnnotationSyntaxError",
CheckKind::FutureFeatureNotDefined(_) => "FutureFeatureNotDefined",
CheckKind::IOError(_) => "IOError",
CheckKind::IfTuple => "IfTuple",
CheckKind::InvalidPrintSyntax => "InvalidPrintSyntax",
CheckKind::ImportStarNotPermitted(_) => "ImportStarNotPermitted",
CheckKind::ImportStarUsage(_) => "ImportStarUsage",
CheckKind::InvalidPrintSyntax => "InvalidPrintSyntax",
CheckKind::IsLiteral => "IsLiteral",
CheckKind::LateFutureImport => "LateFutureImport",
CheckKind::LineTooLong(_, _) => "LineTooLong",
CheckKind::ModuleImportNotAtTopOfFile => "ModuleImportNotAtTopOfFile",
@@ -269,14 +274,15 @@ impl CheckKind {
CheckKind::DoNotAssignLambda => &CheckCode::E731,
CheckKind::DoNotUseBareExcept => &CheckCode::E722,
CheckKind::DuplicateArgumentName => &CheckCode::F831,
CheckKind::ForwardAnnotationSyntaxError(_) => &CheckCode::F722,
CheckKind::FStringMissingPlaceholders => &CheckCode::F541,
CheckKind::ForwardAnnotationSyntaxError(_) => &CheckCode::F722,
CheckKind::FutureFeatureNotDefined(_) => &CheckCode::F407,
CheckKind::IOError(_) => &CheckCode::E902,
CheckKind::IfTuple => &CheckCode::F634,
CheckKind::InvalidPrintSyntax => &CheckCode::F633,
CheckKind::ImportStarNotPermitted(_) => &CheckCode::F406,
CheckKind::ImportStarUsage(_) => &CheckCode::F403,
CheckKind::InvalidPrintSyntax => &CheckCode::F633,
CheckKind::IsLiteral => &CheckCode::F632,
CheckKind::LateFutureImport => &CheckCode::F404,
CheckKind::LineTooLong(_, _) => &CheckCode::E501,
CheckKind::ModuleImportNotAtTopOfFile => &CheckCode::E402,
@@ -348,6 +354,7 @@ impl CheckKind {
CheckKind::ImportStarUsage(name) => {
format!("`from {name} import *` used; unable to detect undefined names")
}
CheckKind::IsLiteral => "use ==/!= to compare constant literals".to_string(),
CheckKind::LateFutureImport => {
"from __future__ imports must occur at the beginning of the file".to_string()
}

View File

@@ -851,6 +851,38 @@ mod tests {
Ok(())
}
#[test]
fn f632() -> Result<()> {
let mut actual = check_path(
Path::new("./resources/test/fixtures/F632.py"),
&settings::Settings {
line_length: 88,
exclude: vec![],
select: BTreeSet::from([CheckCode::F632]),
},
&fixer::Mode::Generate,
)?;
actual.sort_by_key(|check| check.location);
let expected = vec![
Check {
kind: CheckKind::IsLiteral,
location: Location::new(1, 6),
fix: None,
},
Check {
kind: CheckKind::IsLiteral,
location: Location::new(4, 8),
fix: None,
},
];
assert_eq!(actual.len(), expected.len());
for i in 0..actual.len() {
assert_eq!(actual[i], expected[i]);
}
Ok(())
}
#[test]
fn f633() -> Result<()> {
let mut actual = check_path(

View File

@@ -283,6 +283,7 @@ other-attribute = 1
CheckCode::F621,
CheckCode::F622,
CheckCode::F631,
CheckCode::F632,
CheckCode::F633,
CheckCode::F634,
CheckCode::F701,

View File

@@ -65,6 +65,7 @@ impl Settings {
CheckCode::F621,
CheckCode::F622,
CheckCode::F631,
CheckCode::F632,
CheckCode::F633,
CheckCode::F634,
CheckCode::F701,