mirror of
https://github.com/astral-sh/ruff.git
synced 2025-12-23 09:19:58 +00:00
Remove some additional manual iterator matches (#5482)
## Summary I've done a few of these PRs, I thought I'd caught them all, but missed this pattern.
This commit is contained in:
parent
dadad0e9ed
commit
00fbbe4223
6 changed files with 75 additions and 69 deletions
|
|
@ -644,10 +644,7 @@ where
|
|||
},
|
||||
) => {
|
||||
if self.enabled(Rule::DjangoNullableModelStringField) {
|
||||
self.diagnostics
|
||||
.extend(flake8_django::rules::nullable_model_string_field(
|
||||
self, body,
|
||||
));
|
||||
flake8_django::rules::nullable_model_string_field(self, body);
|
||||
}
|
||||
if self.enabled(Rule::DjangoExcludeWithModelForm) {
|
||||
if let Some(diagnostic) =
|
||||
|
|
|
|||
|
|
@ -21,21 +21,6 @@ impl Violation for RequestWithNoCertValidation {
|
|||
}
|
||||
}
|
||||
|
||||
const REQUESTS_HTTP_VERBS: [&str; 7] = ["get", "options", "head", "post", "put", "patch", "delete"];
|
||||
const HTTPX_METHODS: [&str; 11] = [
|
||||
"get",
|
||||
"options",
|
||||
"head",
|
||||
"post",
|
||||
"put",
|
||||
"patch",
|
||||
"delete",
|
||||
"request",
|
||||
"stream",
|
||||
"Client",
|
||||
"AsyncClient",
|
||||
];
|
||||
|
||||
/// S501
|
||||
pub(crate) fn request_with_no_cert_validation(
|
||||
checker: &mut Checker,
|
||||
|
|
@ -46,16 +31,13 @@ pub(crate) fn request_with_no_cert_validation(
|
|||
if let Some(target) = checker
|
||||
.semantic()
|
||||
.resolve_call_path(func)
|
||||
.and_then(|call_path| {
|
||||
if call_path.len() == 2 {
|
||||
if call_path[0] == "requests" && REQUESTS_HTTP_VERBS.contains(&call_path[1]) {
|
||||
return Some("requests");
|
||||
}
|
||||
if call_path[0] == "httpx" && HTTPX_METHODS.contains(&call_path[1]) {
|
||||
return Some("httpx");
|
||||
}
|
||||
.and_then(|call_path| match call_path.as_slice() {
|
||||
["requests", "get" | "options" | "head" | "post" | "put" | "patch" | "delete"] => {
|
||||
Some("requests")
|
||||
}
|
||||
None
|
||||
["httpx", "get" | "options" | "head" | "post" | "put" | "patch" | "delete" | "request"
|
||||
| "stream" | "Client" | "AsyncClient"] => Some("httpx"),
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
|
|
|
|||
|
|
@ -51,24 +51,14 @@ impl Violation for DjangoNullableModelStringField {
|
|||
}
|
||||
}
|
||||
|
||||
const NOT_NULL_TRUE_FIELDS: [&str; 6] = [
|
||||
"CharField",
|
||||
"TextField",
|
||||
"SlugField",
|
||||
"EmailField",
|
||||
"FilePathField",
|
||||
"URLField",
|
||||
];
|
||||
|
||||
/// DJ001
|
||||
pub(crate) fn nullable_model_string_field(checker: &Checker, body: &[Stmt]) -> Vec<Diagnostic> {
|
||||
let mut errors = Vec::new();
|
||||
pub(crate) fn nullable_model_string_field(checker: &mut Checker, body: &[Stmt]) {
|
||||
for statement in body.iter() {
|
||||
let Stmt::Assign(ast::StmtAssign { value, .. }) = statement else {
|
||||
continue;
|
||||
};
|
||||
if let Some(field_name) = is_nullable_field(checker, value) {
|
||||
errors.push(Diagnostic::new(
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
DjangoNullableModelStringField {
|
||||
field_name: field_name.to_string(),
|
||||
},
|
||||
|
|
@ -76,7 +66,6 @@ pub(crate) fn nullable_model_string_field(checker: &Checker, body: &[Stmt]) -> V
|
|||
));
|
||||
}
|
||||
}
|
||||
errors
|
||||
}
|
||||
|
||||
fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a str> {
|
||||
|
|
@ -88,7 +77,10 @@ fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a st
|
|||
return None;
|
||||
};
|
||||
|
||||
if !NOT_NULL_TRUE_FIELDS.contains(&valid_field_name) {
|
||||
if !matches!(
|
||||
valid_field_name,
|
||||
"CharField" | "TextField" | "SlugField" | "EmailField" | "FilePathField" | "URLField"
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,7 @@ use ruff_python_ast::helpers::map_callable;
|
|||
use crate::model::SemanticModel;
|
||||
use crate::scope::{Scope, ScopeKind};
|
||||
|
||||
const CLASS_METHODS: [&str; 3] = ["__new__", "__init_subclass__", "__class_getitem__"];
|
||||
const METACLASS_BASES: [(&str, &str); 2] = [("", "type"), ("abc", "ABCMeta")];
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum FunctionType {
|
||||
Function,
|
||||
Method,
|
||||
|
|
@ -44,24 +41,28 @@ pub fn classify(
|
|||
})
|
||||
}) {
|
||||
FunctionType::StaticMethod
|
||||
} else if CLASS_METHODS.contains(&name)
|
||||
// Special-case class method, like `__new__`.
|
||||
} else if matches!(name, "__new__" | "__init_subclass__" | "__class_getitem__")
|
||||
// Special-case class method, like `__new__`.
|
||||
|| scope.bases.iter().any(|expr| {
|
||||
// The class itself extends a known metaclass, so all methods are class methods.
|
||||
semantic.resolve_call_path(map_callable(expr)).map_or(false, |call_path| {
|
||||
METACLASS_BASES
|
||||
.iter()
|
||||
.any(|(module, member)| call_path.as_slice() == [*module, *member])
|
||||
})
|
||||
semantic
|
||||
.resolve_call_path(map_callable(expr))
|
||||
.map_or(false, |call_path| {
|
||||
matches!(call_path.as_slice(), ["", "type"] | ["abc", "ABCMeta"])
|
||||
})
|
||||
})
|
||||
|| decorator_list.iter().any(|decorator| {
|
||||
// The method is decorated with a class method decorator (like `@classmethod`).
|
||||
semantic.resolve_call_path(map_callable(&decorator.expression)).map_or(false, |call_path| {
|
||||
matches!(call_path.as_slice(), ["", "classmethod"] | ["abc", "abstractclassmethod"]) ||
|
||||
classmethod_decorators
|
||||
.iter()
|
||||
.any(|decorator| call_path == from_qualified_name(decorator))
|
||||
})
|
||||
semantic
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
matches!(
|
||||
call_path.as_slice(),
|
||||
["", "classmethod"] | ["abc", "abstractclassmethod"]
|
||||
) || classmethod_decorators
|
||||
.iter()
|
||||
.any(|decorator| call_path == from_qualified_name(decorator))
|
||||
})
|
||||
})
|
||||
{
|
||||
FunctionType::ClassMethod
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::keyword::KWLIST;
|
||||
use crate::keyword::is_keyword;
|
||||
|
||||
/// Returns `true` if a string is a valid Python identifier (e.g., variable
|
||||
/// name).
|
||||
|
|
@ -18,7 +18,7 @@ pub fn is_identifier(name: &str) -> bool {
|
|||
}
|
||||
|
||||
// Is the identifier a keyword?
|
||||
if KWLIST.contains(&name) {
|
||||
if is_keyword(name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ pub fn is_module_name(name: &str) -> bool {
|
|||
}
|
||||
|
||||
// Is the identifier a keyword?
|
||||
if KWLIST.contains(&name) {
|
||||
if is_keyword(name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ pub fn is_migration_name(name: &str) -> bool {
|
|||
}
|
||||
|
||||
// Is the identifier a keyword?
|
||||
if KWLIST.contains(&name) {
|
||||
if is_keyword(name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,41 @@
|
|||
// See: https://github.com/python/cpython/blob/9d692841691590c25e6cf5b2250a594d3bf54825/Lib/keyword.py#L18
|
||||
pub(crate) const KWLIST: [&str; 35] = [
|
||||
"False", "None", "True", "and", "as", "assert", "async", "await", "break", "class", "continue",
|
||||
"def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import",
|
||||
"in", "is", "lambda", "nonlocal", "not", "or", "pass", "raise", "return", "try", "while",
|
||||
"with", "yield",
|
||||
];
|
||||
pub(crate) fn is_keyword(name: &str) -> bool {
|
||||
matches!(
|
||||
name,
|
||||
"False"
|
||||
| "None"
|
||||
| "True"
|
||||
| "and"
|
||||
| "as"
|
||||
| "assert"
|
||||
| "async"
|
||||
| "await"
|
||||
| "break"
|
||||
| "class"
|
||||
| "continue"
|
||||
| "def"
|
||||
| "del"
|
||||
| "elif"
|
||||
| "else"
|
||||
| "except"
|
||||
| "finally"
|
||||
| "for"
|
||||
| "from"
|
||||
| "global"
|
||||
| "if"
|
||||
| "import"
|
||||
| "in"
|
||||
| "is"
|
||||
| "lambda"
|
||||
| "nonlocal"
|
||||
| "not"
|
||||
| "or"
|
||||
| "pass"
|
||||
| "raise"
|
||||
| "return"
|
||||
| "try"
|
||||
| "while"
|
||||
| "with"
|
||||
| "yield",
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue