mirror of https://github.com/astral-sh/ruff
parent
edab268d50
commit
9384a081f9
|
|
@ -980,6 +980,7 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/
|
||||||
| SIM109 | CompareWithTuple | Use `value in (..., ...)` instead of `value == ... or value == ...` | 🛠 |
|
| SIM109 | CompareWithTuple | Use `value in (..., ...)` instead of `value == ... or value == ...` | 🛠 |
|
||||||
| SIM110 | ConvertLoopToAny | Use `return any(x for x in y)` instead of `for` loop | 🛠 |
|
| SIM110 | ConvertLoopToAny | Use `return any(x for x in y)` instead of `for` loop | 🛠 |
|
||||||
| SIM111 | ConvertLoopToAll | Use `return all(x for x in y)` instead of `for` loop | 🛠 |
|
| SIM111 | ConvertLoopToAll | Use `return all(x for x in y)` instead of `for` loop | 🛠 |
|
||||||
|
| SIM112 | UseCapitalEnvironmentVariables | Use capitalized environment variable `...` instead of `...` | 🛠 |
|
||||||
| SIM117 | MultipleWithStatements | Use a single `with` statement with multiple contexts instead of nested `with` statements | |
|
| SIM117 | MultipleWithStatements | Use a single `with` statement with multiple contexts instead of nested `with` statements | |
|
||||||
| SIM118 | KeyInDict | Use `key in dict` instead of `key in dict.keys()` | 🛠 |
|
| SIM118 | KeyInDict | Use `key in dict` instead of `key in dict.keys()` | 🛠 |
|
||||||
| SIM201 | NegateEqualOp | Use `left != right` instead of `not left == right` | 🛠 |
|
| SIM201 | NegateEqualOp | Use `left != right` instead of `not left == right` | 🛠 |
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Bad
|
||||||
|
os.environ['foo']
|
||||||
|
|
||||||
|
os.environ.get('foo')
|
||||||
|
|
||||||
|
os.environ.get('foo', 'bar')
|
||||||
|
|
||||||
|
os.getenv('foo')
|
||||||
|
|
||||||
|
# Good
|
||||||
|
os.environ['FOO']
|
||||||
|
|
||||||
|
os.environ.get('FOO')
|
||||||
|
|
||||||
|
os.environ.get('FOO', 'bar')
|
||||||
|
|
||||||
|
os.getenv('FOO')
|
||||||
|
|
@ -1506,6 +1506,7 @@
|
||||||
"SIM11",
|
"SIM11",
|
||||||
"SIM110",
|
"SIM110",
|
||||||
"SIM111",
|
"SIM111",
|
||||||
|
"SIM112",
|
||||||
"SIM117",
|
"SIM117",
|
||||||
"SIM118",
|
"SIM118",
|
||||||
"SIM2",
|
"SIM2",
|
||||||
|
|
|
||||||
|
|
@ -1405,6 +1405,9 @@ where
|
||||||
if self.settings.enabled.contains(&RuleCode::B015) {
|
if self.settings.enabled.contains(&RuleCode::B015) {
|
||||||
flake8_bugbear::rules::useless_comparison(self, value);
|
flake8_bugbear::rules::useless_comparison(self, value);
|
||||||
}
|
}
|
||||||
|
if self.settings.enabled.contains(&RuleCode::SIM112) {
|
||||||
|
flake8_simplify::rules::use_capital_environment_variables(self, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ mod tests {
|
||||||
#[test_case(RuleCode::SIM109, Path::new("SIM109.py"); "SIM109")]
|
#[test_case(RuleCode::SIM109, Path::new("SIM109.py"); "SIM109")]
|
||||||
#[test_case(RuleCode::SIM110, Path::new("SIM110.py"); "SIM110")]
|
#[test_case(RuleCode::SIM110, Path::new("SIM110.py"); "SIM110")]
|
||||||
#[test_case(RuleCode::SIM111, Path::new("SIM111.py"); "SIM111")]
|
#[test_case(RuleCode::SIM111, Path::new("SIM111.py"); "SIM111")]
|
||||||
|
#[test_case(RuleCode::SIM112, Path::new("SIM112.py"); "SIM112")]
|
||||||
#[test_case(RuleCode::SIM117, Path::new("SIM117.py"); "SIM117")]
|
#[test_case(RuleCode::SIM117, Path::new("SIM117.py"); "SIM117")]
|
||||||
#[test_case(RuleCode::SIM201, Path::new("SIM201.py"); "SIM201")]
|
#[test_case(RuleCode::SIM201, Path::new("SIM201.py"); "SIM201")]
|
||||||
#[test_case(RuleCode::SIM202, Path::new("SIM202.py"); "SIM202")]
|
#[test_case(RuleCode::SIM202, Path::new("SIM202.py"); "SIM202")]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
use rustpython_ast::{Constant, Expr, ExprKind};
|
||||||
|
|
||||||
|
use crate::ast::helpers::{create_expr, match_module_member, unparse_expr};
|
||||||
|
use crate::ast::types::Range;
|
||||||
|
use crate::autofix::Fix;
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::registry::{Diagnostic, RuleCode};
|
||||||
|
use crate::violations;
|
||||||
|
|
||||||
|
/// SIM112
|
||||||
|
pub fn use_capital_environment_variables(checker: &mut Checker, expr: &Expr) {
|
||||||
|
// check `os.environ['foo']`
|
||||||
|
if let ExprKind::Subscript { .. } = &expr.node {
|
||||||
|
check_os_environ_subscript(checker, expr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check `os.environ.get('foo')` and `os.getenv('foo')``
|
||||||
|
let is_os_environ_get = match_module_member(
|
||||||
|
expr,
|
||||||
|
"os.environ",
|
||||||
|
"get",
|
||||||
|
&checker.from_imports,
|
||||||
|
&checker.import_aliases,
|
||||||
|
);
|
||||||
|
let is_os_getenv = match_module_member(
|
||||||
|
expr,
|
||||||
|
"os",
|
||||||
|
"getenv",
|
||||||
|
&checker.from_imports,
|
||||||
|
&checker.import_aliases,
|
||||||
|
);
|
||||||
|
if !(is_os_environ_get || is_os_getenv) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ExprKind::Call { args, .. } = &expr.node else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(arg) = args.get(0) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let ExprKind::Constant { value: Constant::Str(env_var), kind } = &arg.node else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let capital_env_var = env_var.to_ascii_uppercase();
|
||||||
|
if &capital_env_var == env_var {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
violations::UseCapitalEnvironmentVariables(capital_env_var.clone(), env_var.clone()),
|
||||||
|
Range::from_located(arg),
|
||||||
|
);
|
||||||
|
if checker.patch(&RuleCode::SIM112) {
|
||||||
|
let new_env_var = create_expr(ExprKind::Constant {
|
||||||
|
value: capital_env_var.into(),
|
||||||
|
kind: kind.clone(),
|
||||||
|
});
|
||||||
|
diagnostic.amend(Fix::replacement(
|
||||||
|
unparse_expr(&new_env_var, checker.style),
|
||||||
|
arg.location,
|
||||||
|
arg.end_location.unwrap(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
checker.diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
|
||||||
|
let ExprKind::Subscript { value, slice, .. } = &expr.node else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let ExprKind::Attribute { value: attr_value, attr, .. } = &value.node else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let ExprKind::Name { id, .. } = &attr_value.node else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if id != "os" || attr != "environ" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ExprKind::Constant { value: Constant::Str(env_var), kind } = &slice.node else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let capital_env_var = env_var.to_ascii_uppercase();
|
||||||
|
if &capital_env_var == env_var {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
violations::UseCapitalEnvironmentVariables(capital_env_var.clone(), env_var.clone()),
|
||||||
|
Range::from_located(slice),
|
||||||
|
);
|
||||||
|
if checker.patch(&RuleCode::SIM112) {
|
||||||
|
let new_env_var = create_expr(ExprKind::Constant {
|
||||||
|
value: capital_env_var.into(),
|
||||||
|
kind: kind.clone(),
|
||||||
|
});
|
||||||
|
diagnostic.amend(Fix::replacement(
|
||||||
|
unparse_expr(&new_env_var, checker.style),
|
||||||
|
slice.location,
|
||||||
|
slice.end_location.unwrap(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
checker.diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
pub use ast_bool_op::{
|
pub use ast_bool_op::{
|
||||||
a_and_not_a, a_or_not_a, and_false, compare_with_tuple, duplicate_isinstance_call, or_true,
|
a_and_not_a, a_or_not_a, and_false, compare_with_tuple, duplicate_isinstance_call, or_true,
|
||||||
};
|
};
|
||||||
|
pub use ast_expr::use_capital_environment_variables;
|
||||||
pub use ast_for::convert_loop_to_any_all;
|
pub use ast_for::convert_loop_to_any_all;
|
||||||
pub use ast_if::{nested_if_statements, return_bool_condition_directly, use_ternary_operator};
|
pub use ast_if::{nested_if_statements, return_bool_condition_directly, use_ternary_operator};
|
||||||
pub use ast_ifexp::{
|
pub use ast_ifexp::{
|
||||||
|
|
@ -14,6 +15,7 @@ pub use use_contextlib_suppress::use_contextlib_suppress;
|
||||||
pub use yoda_conditions::yoda_conditions;
|
pub use yoda_conditions::yoda_conditions;
|
||||||
|
|
||||||
mod ast_bool_op;
|
mod ast_bool_op;
|
||||||
|
mod ast_expr;
|
||||||
mod ast_for;
|
mod ast_for;
|
||||||
mod ast_if;
|
mod ast_if;
|
||||||
mod ast_ifexp;
|
mod ast_ifexp;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
---
|
||||||
|
source: src/flake8_simplify/mod.rs
|
||||||
|
expression: diagnostics
|
||||||
|
---
|
||||||
|
- kind:
|
||||||
|
UseCapitalEnvironmentVariables:
|
||||||
|
- FOO
|
||||||
|
- foo
|
||||||
|
location:
|
||||||
|
row: 4
|
||||||
|
column: 11
|
||||||
|
end_location:
|
||||||
|
row: 4
|
||||||
|
column: 16
|
||||||
|
fix:
|
||||||
|
content: "'FOO'"
|
||||||
|
location:
|
||||||
|
row: 4
|
||||||
|
column: 11
|
||||||
|
end_location:
|
||||||
|
row: 4
|
||||||
|
column: 16
|
||||||
|
parent: ~
|
||||||
|
- kind:
|
||||||
|
UseCapitalEnvironmentVariables:
|
||||||
|
- FOO
|
||||||
|
- foo
|
||||||
|
location:
|
||||||
|
row: 6
|
||||||
|
column: 15
|
||||||
|
end_location:
|
||||||
|
row: 6
|
||||||
|
column: 20
|
||||||
|
fix:
|
||||||
|
content: "'FOO'"
|
||||||
|
location:
|
||||||
|
row: 6
|
||||||
|
column: 15
|
||||||
|
end_location:
|
||||||
|
row: 6
|
||||||
|
column: 20
|
||||||
|
parent: ~
|
||||||
|
- kind:
|
||||||
|
UseCapitalEnvironmentVariables:
|
||||||
|
- FOO
|
||||||
|
- foo
|
||||||
|
location:
|
||||||
|
row: 8
|
||||||
|
column: 15
|
||||||
|
end_location:
|
||||||
|
row: 8
|
||||||
|
column: 20
|
||||||
|
fix:
|
||||||
|
content: "'FOO'"
|
||||||
|
location:
|
||||||
|
row: 8
|
||||||
|
column: 15
|
||||||
|
end_location:
|
||||||
|
row: 8
|
||||||
|
column: 20
|
||||||
|
parent: ~
|
||||||
|
- kind:
|
||||||
|
UseCapitalEnvironmentVariables:
|
||||||
|
- FOO
|
||||||
|
- foo
|
||||||
|
location:
|
||||||
|
row: 10
|
||||||
|
column: 10
|
||||||
|
end_location:
|
||||||
|
row: 10
|
||||||
|
column: 15
|
||||||
|
fix:
|
||||||
|
content: "'FOO'"
|
||||||
|
location:
|
||||||
|
row: 10
|
||||||
|
column: 10
|
||||||
|
end_location:
|
||||||
|
row: 10
|
||||||
|
column: 15
|
||||||
|
parent: ~
|
||||||
|
|
||||||
|
|
@ -295,6 +295,7 @@ define_rule_mapping!(
|
||||||
SIM109 => violations::CompareWithTuple,
|
SIM109 => violations::CompareWithTuple,
|
||||||
SIM110 => violations::ConvertLoopToAny,
|
SIM110 => violations::ConvertLoopToAny,
|
||||||
SIM111 => violations::ConvertLoopToAll,
|
SIM111 => violations::ConvertLoopToAll,
|
||||||
|
SIM112 => violations::UseCapitalEnvironmentVariables,
|
||||||
SIM117 => violations::MultipleWithStatements,
|
SIM117 => violations::MultipleWithStatements,
|
||||||
SIM118 => violations::KeyInDict,
|
SIM118 => violations::KeyInDict,
|
||||||
SIM201 => violations::NegateEqualOp,
|
SIM201 => violations::NegateEqualOp,
|
||||||
|
|
@ -1110,6 +1111,7 @@ impl RuleCode {
|
||||||
RuleCode::SIM109 => RuleOrigin::Flake8Simplify,
|
RuleCode::SIM109 => RuleOrigin::Flake8Simplify,
|
||||||
RuleCode::SIM110 => RuleOrigin::Flake8Simplify,
|
RuleCode::SIM110 => RuleOrigin::Flake8Simplify,
|
||||||
RuleCode::SIM111 => RuleOrigin::Flake8Simplify,
|
RuleCode::SIM111 => RuleOrigin::Flake8Simplify,
|
||||||
|
RuleCode::SIM112 => RuleOrigin::Flake8Simplify,
|
||||||
RuleCode::SIM117 => RuleOrigin::Flake8Simplify,
|
RuleCode::SIM117 => RuleOrigin::Flake8Simplify,
|
||||||
RuleCode::SIM118 => RuleOrigin::Flake8Simplify,
|
RuleCode::SIM118 => RuleOrigin::Flake8Simplify,
|
||||||
RuleCode::SIM201 => RuleOrigin::Flake8Simplify,
|
RuleCode::SIM201 => RuleOrigin::Flake8Simplify,
|
||||||
|
|
|
||||||
|
|
@ -2677,6 +2677,24 @@ impl Violation for SysVersionSlice1Referenced {
|
||||||
}
|
}
|
||||||
|
|
||||||
// flake8-simplify
|
// flake8-simplify
|
||||||
|
define_violation!(
|
||||||
|
pub struct UseCapitalEnvironmentVariables(pub String, pub String);
|
||||||
|
);
|
||||||
|
impl AlwaysAutofixableViolation for UseCapitalEnvironmentVariables {
|
||||||
|
fn message(&self) -> String {
|
||||||
|
let UseCapitalEnvironmentVariables(expected, original) = self;
|
||||||
|
format!("Use capitalized environment variable `{expected}` instead of `{original}`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn autofix_title(&self) -> String {
|
||||||
|
let UseCapitalEnvironmentVariables(expected, original) = self;
|
||||||
|
format!("Replace `{original}` with `{expected}`")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn placeholder() -> Self {
|
||||||
|
UseCapitalEnvironmentVariables("...".to_string(), "...".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
define_violation!(
|
define_violation!(
|
||||||
pub struct DuplicateIsinstanceCall(pub String);
|
pub struct DuplicateIsinstanceCall(pub String);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue