mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 01:50:38 +00:00
[ruff] Implement falsy-dict-get-fallback (RUF056) (#15160)
Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
parent
68d2466832
commit
3c9021ffcb
51 changed files with 897 additions and 88 deletions
171
crates/ruff_linter/resources/test/fixtures/ruff/RUF056.py
vendored
Normal file
171
crates/ruff_linter/resources/test/fixtures/ruff/RUF056.py
vendored
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
# Correct
|
||||||
|
|
||||||
|
my_dict = {"key": "value", "other_key": "other_value"}
|
||||||
|
|
||||||
|
# Using dict.get without a fallback
|
||||||
|
value = my_dict.get("key")
|
||||||
|
|
||||||
|
# Using dict.get with a truthy fallback
|
||||||
|
value = my_dict.get("key", "default")
|
||||||
|
value = my_dict.get("key", 42)
|
||||||
|
value = my_dict.get("key", [1, 2, 3])
|
||||||
|
value = my_dict.get("key", {"nested": "dict"})
|
||||||
|
value = my_dict.get("key", set([1, 2]))
|
||||||
|
value = my_dict.get("key", True)
|
||||||
|
value = my_dict.get("key", "Non-empty string")
|
||||||
|
value = my_dict.get("key", 3.14)
|
||||||
|
value = my_dict.get("key", (1, 2)) # Tuples are truthy
|
||||||
|
|
||||||
|
# Chained get calls with truthy fallbacks
|
||||||
|
value1 = my_dict.get("key1", {'k': 'v'}).get("subkey")
|
||||||
|
value2 = my_dict.get("key2", [1, 2, 3]).append(4)
|
||||||
|
|
||||||
|
# Valid
|
||||||
|
|
||||||
|
# Using dict.get with a falsy fallback: False
|
||||||
|
value = my_dict.get("key", False)
|
||||||
|
|
||||||
|
# Using dict.get with a falsy fallback: empty string
|
||||||
|
value = my_dict.get("key", "")
|
||||||
|
|
||||||
|
# Using dict.get with a falsy fallback: empty list
|
||||||
|
value = my_dict.get("key", [])
|
||||||
|
|
||||||
|
# Using dict.get with a falsy fallback: empty dict
|
||||||
|
value = my_dict.get("key", {})
|
||||||
|
|
||||||
|
# Using dict.get with a falsy fallback: empty set
|
||||||
|
value = my_dict.get("key", set())
|
||||||
|
|
||||||
|
# Using dict.get with a falsy fallback: zero integer
|
||||||
|
value = my_dict.get("key", 0)
|
||||||
|
|
||||||
|
# Using dict.get with a falsy fallback: zero float
|
||||||
|
value = my_dict.get("key", 0.0)
|
||||||
|
|
||||||
|
# Using dict.get with a falsy fallback: None
|
||||||
|
value = my_dict.get("key", None)
|
||||||
|
|
||||||
|
# Using dict.get with a falsy fallback via function call
|
||||||
|
value = my_dict.get("key", list())
|
||||||
|
value = my_dict.get("key", dict())
|
||||||
|
value = my_dict.get("key", set())
|
||||||
|
|
||||||
|
# Reassigning with falsy fallback
|
||||||
|
def get_value(d):
|
||||||
|
return d.get("key", False)
|
||||||
|
|
||||||
|
# Multiple dict.get calls with mixed fallbacks
|
||||||
|
value1 = my_dict.get("key1", "default")
|
||||||
|
value2 = my_dict.get("key2", 0)
|
||||||
|
value3 = my_dict.get("key3", "another default")
|
||||||
|
|
||||||
|
# Using dict.get in a class with falsy fallback
|
||||||
|
class MyClass:
|
||||||
|
def method(self):
|
||||||
|
return self.data.get("key", {})
|
||||||
|
|
||||||
|
# Using dict.get in a nested function with falsy fallback
|
||||||
|
def outer():
|
||||||
|
def inner():
|
||||||
|
return my_dict.get("key", "")
|
||||||
|
return inner()
|
||||||
|
|
||||||
|
# Using dict.get with variable fallback that is falsy
|
||||||
|
falsy_value = None
|
||||||
|
value = my_dict.get("key", falsy_value)
|
||||||
|
|
||||||
|
# Using dict.get with variable fallback that is truthy
|
||||||
|
truthy_value = "exists"
|
||||||
|
value = my_dict.get("key", truthy_value)
|
||||||
|
|
||||||
|
# Using dict.get with complex expressions as fallback
|
||||||
|
value = my_dict.get("key", 0 or "default")
|
||||||
|
value = my_dict.get("key", [] if condition else {})
|
||||||
|
|
||||||
|
# testing dict.get call using kwargs
|
||||||
|
value = my_dict.get(key="key", default=False)
|
||||||
|
value = my_dict.get(default=[], key="key")
|
||||||
|
|
||||||
|
|
||||||
|
# Edge Cases
|
||||||
|
|
||||||
|
dicts = [my_dict, my_dict, my_dict]
|
||||||
|
|
||||||
|
# Falsy fallback in a lambda
|
||||||
|
get_fallback = lambda d: d.get("key", False)
|
||||||
|
|
||||||
|
# Falsy fallback in a list comprehension
|
||||||
|
results = [d.get("key", "") for d in dicts]
|
||||||
|
|
||||||
|
# Falsy fallback in a generator expression
|
||||||
|
results = (d.get("key", None) for d in dicts)
|
||||||
|
|
||||||
|
# Falsy fallback in a ternary expression
|
||||||
|
value = my_dict.get("key", 0) if True else "default"
|
||||||
|
|
||||||
|
|
||||||
|
# Falsy fallback with inline comment
|
||||||
|
value = my_dict.get("key", # comment1
|
||||||
|
[] # comment2
|
||||||
|
) # comment3
|
||||||
|
|
||||||
|
# Invalid
|
||||||
|
# Invalid falsy fallbacks are when the call to dict.get is used in a boolean context
|
||||||
|
|
||||||
|
# dict.get in ternary expression
|
||||||
|
value = "not found" if my_dict.get("key", False) else "default" # [RUF056]
|
||||||
|
|
||||||
|
# dict.get in an if statement
|
||||||
|
if my_dict.get("key", False): # [RUF056]
|
||||||
|
pass
|
||||||
|
|
||||||
|
# dict.get in compound if statement
|
||||||
|
if True and my_dict.get("key", False): # [RUF056]
|
||||||
|
pass
|
||||||
|
|
||||||
|
if my_dict.get("key", False) or True: # [RUF056]
|
||||||
|
pass
|
||||||
|
|
||||||
|
# dict.get in an assert statement
|
||||||
|
assert my_dict.get("key", False) # [RUF056]
|
||||||
|
|
||||||
|
# dict.get in a while statement
|
||||||
|
while my_dict.get("key", False): # [RUF056]
|
||||||
|
pass
|
||||||
|
|
||||||
|
# dict.get in unary not expression
|
||||||
|
value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
|
||||||
|
# testing all falsy fallbacks
|
||||||
|
value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
value = not my_dict.get("key", "") # [RUF056]
|
||||||
|
|
||||||
|
# testing dict.get call using kwargs
|
||||||
|
value = not my_dict.get(key="key", default=False) # [RUF056]
|
||||||
|
value = not my_dict.get(default=[], key="key") # [RUF056]
|
||||||
|
|
||||||
|
# testing invalid dict.get call with inline comment
|
||||||
|
value = not my_dict.get("key", # comment1
|
||||||
|
[] # comment2
|
||||||
|
) # [RUF056]
|
||||||
|
|
||||||
|
# testing invalid dict.get call with kwargs and inline comment
|
||||||
|
value = not my_dict.get(key="key", # comment1
|
||||||
|
default=False # comment2
|
||||||
|
) # [RUF056]
|
||||||
|
value = not my_dict.get(default=[], # comment1
|
||||||
|
key="key" # comment2
|
||||||
|
) # [RUF056]
|
||||||
|
|
||||||
|
# testing invalid dict.get calls
|
||||||
|
value = not my_dict.get(key="key", other="something", default=False)
|
||||||
|
value = not my_dict.get(default=False, other="something", key="test")
|
|
@ -1111,6 +1111,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
||||||
if checker.enabled(Rule::PytestRaisesAmbiguousPattern) {
|
if checker.enabled(Rule::PytestRaisesAmbiguousPattern) {
|
||||||
ruff::rules::pytest_raises_ambiguous_pattern(checker, call);
|
ruff::rules::pytest_raises_ambiguous_pattern(checker, call);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::FalsyDictGetFallback) {
|
||||||
|
ruff::rules::falsy_dict_get_fallback(checker, expr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::Dict(dict) => {
|
Expr::Dict(dict) => {
|
||||||
if checker.any_enabled(&[
|
if checker.any_enabled(&[
|
||||||
|
|
|
@ -991,6 +991,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||||
(Ruff, "051") => (RuleGroup::Preview, rules::ruff::rules::IfKeyInDictDel),
|
(Ruff, "051") => (RuleGroup::Preview, rules::ruff::rules::IfKeyInDictDel),
|
||||||
(Ruff, "052") => (RuleGroup::Preview, rules::ruff::rules::UsedDummyVariable),
|
(Ruff, "052") => (RuleGroup::Preview, rules::ruff::rules::UsedDummyVariable),
|
||||||
(Ruff, "055") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRegularExpression),
|
(Ruff, "055") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRegularExpression),
|
||||||
|
(Ruff, "056") => (RuleGroup::Preview, rules::ruff::rules::FalsyDictGetFallback),
|
||||||
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
|
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
|
||||||
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
|
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
|
||||||
|
|
||||||
|
|
|
@ -293,10 +293,10 @@ impl Renamer {
|
||||||
let qualified_name = semantic.resolve_qualified_name(func)?;
|
let qualified_name = semantic.resolve_qualified_name(func)?;
|
||||||
|
|
||||||
let name_argument = match qualified_name.segments() {
|
let name_argument = match qualified_name.segments() {
|
||||||
["collections", "namedtuple"] => arguments.find_argument("typename", 0),
|
["collections", "namedtuple"] => arguments.find_argument_value("typename", 0),
|
||||||
|
|
||||||
["typing" | "typing_extensions", "TypeVar" | "ParamSpec" | "TypeVarTuple" | "NewType" | "TypeAliasType"] => {
|
["typing" | "typing_extensions", "TypeVar" | "ParamSpec" | "TypeVarTuple" | "NewType" | "TypeAliasType"] => {
|
||||||
arguments.find_argument("name", 0)
|
arguments.find_argument_value("name", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
["enum", "Enum" | "IntEnum" | "StrEnum" | "ReprEnum" | "Flag" | "IntFlag"]
|
["enum", "Enum" | "IntEnum" | "StrEnum" | "ReprEnum" | "Flag" | "IntFlag"]
|
||||||
|
|
|
@ -62,7 +62,7 @@ pub(crate) fn async_zero_sleep(checker: &mut Checker, call: &ExprCall) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(arg) = call.arguments.find_argument("seconds", 0) else {
|
let Some(arg) = call.arguments.find_argument_value("seconds", 0) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ pub(crate) fn blocking_process_invocation(checker: &mut Checker, call: &ast::Exp
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_p_wait(call: &ast::ExprCall, semantic: &SemanticModel) -> bool {
|
fn is_p_wait(call: &ast::ExprCall, semantic: &SemanticModel) -> bool {
|
||||||
let Some(arg) = call.arguments.find_argument("mode", 0) else {
|
let Some(arg) = call.arguments.find_argument_value("mode", 0) else {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ pub(crate) fn long_sleep_not_forever(checker: &mut Checker, call: &ExprCall) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(arg) = call.arguments.find_argument("seconds", 0) else {
|
let Some(arg) = call.arguments.find_argument_value("seconds", 0) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ pub(crate) fn bad_file_permissions(checker: &mut Checker, call: &ast::ExprCall)
|
||||||
.resolve_qualified_name(&call.func)
|
.resolve_qualified_name(&call.func)
|
||||||
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["os", "chmod"]))
|
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["os", "chmod"]))
|
||||||
{
|
{
|
||||||
if let Some(mode_arg) = call.arguments.find_argument("mode", 1) {
|
if let Some(mode_arg) = call.arguments.find_argument_value("mode", 1) {
|
||||||
match parse_mask(mode_arg, checker.semantic()) {
|
match parse_mask(mode_arg, checker.semantic()) {
|
||||||
// The mask couldn't be determined (e.g., it's dynamic).
|
// The mask couldn't be determined (e.g., it's dynamic).
|
||||||
Ok(None) => {}
|
Ok(None) => {}
|
||||||
|
|
|
@ -62,7 +62,7 @@ pub(crate) fn django_extra(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
|
|
||||||
fn is_call_insecure(call: &ast::ExprCall) -> bool {
|
fn is_call_insecure(call: &ast::ExprCall) -> bool {
|
||||||
for (argument_name, position) in [("select", 0), ("where", 1), ("tables", 3)] {
|
for (argument_name, position) in [("select", 0), ("where", 1), ("tables", 3)] {
|
||||||
if let Some(argument) = call.arguments.find_argument(argument_name, position) {
|
if let Some(argument) = call.arguments.find_argument_value(argument_name, position) {
|
||||||
match argument_name {
|
match argument_name {
|
||||||
"select" => match argument {
|
"select" => match argument {
|
||||||
Expr::Dict(dict) => {
|
Expr::Dict(dict) => {
|
||||||
|
|
|
@ -52,7 +52,7 @@ pub(crate) fn django_raw_sql(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
{
|
{
|
||||||
if !call
|
if !call
|
||||||
.arguments
|
.arguments
|
||||||
.find_argument("sql", 0)
|
.find_argument_value("sql", 0)
|
||||||
.is_some_and(Expr::is_string_literal_expr)
|
.is_some_and(Expr::is_string_literal_expr)
|
||||||
{
|
{
|
||||||
checker
|
checker
|
||||||
|
|
|
@ -115,7 +115,7 @@ fn detect_insecure_hashlib_calls(
|
||||||
|
|
||||||
match hashlib_call {
|
match hashlib_call {
|
||||||
HashlibCall::New => {
|
HashlibCall::New => {
|
||||||
let Some(name_arg) = call.arguments.find_argument("name", 0) else {
|
let Some(name_arg) = call.arguments.find_argument_value("name", 0) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(hash_func_name) = string_literal(name_arg) else {
|
let Some(hash_func_name) = string_literal(name_arg) else {
|
||||||
|
@ -159,7 +159,7 @@ fn detect_insecure_crypt_calls(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.and_then(|(argument_name, position)| {
|
.and_then(|(argument_name, position)| {
|
||||||
call.arguments.find_argument(argument_name, position)
|
call.arguments.find_argument_value(argument_name, position)
|
||||||
})
|
})
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -53,7 +53,7 @@ pub(crate) fn ssh_no_host_key_verification(checker: &mut Checker, call: &ExprCal
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(policy_argument) = call.arguments.find_argument("policy", 0) else {
|
let Some(policy_argument) = call.arguments.find_argument_value("policy", 0) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -906,7 +906,7 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
|
||||||
["six", "moves", "urllib", "request", "Request"] => {
|
["six", "moves", "urllib", "request", "Request"] => {
|
||||||
// If the `url` argument is a string literal or an f-string, allow `http` and `https` schemes.
|
// If the `url` argument is a string literal or an f-string, allow `http` and `https` schemes.
|
||||||
if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) {
|
if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) {
|
||||||
if call.arguments.find_argument("url", 0).and_then(leading_chars).is_some_and(has_http_prefix) {
|
if call.arguments.find_argument_value("url", 0).and_then(leading_chars).is_some_and(has_http_prefix) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -916,11 +916,11 @@ pub(crate) fn suspicious_function_call(checker: &mut Checker, call: &ExprCall) {
|
||||||
["urllib", "request", "urlopen" | "urlretrieve" ] |
|
["urllib", "request", "urlopen" | "urlretrieve" ] |
|
||||||
["six", "moves", "urllib", "request", "urlopen" | "urlretrieve" ] => {
|
["six", "moves", "urllib", "request", "urlopen" | "urlretrieve" ] => {
|
||||||
if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) {
|
if call.arguments.args.iter().all(|arg| !arg.is_starred_expr()) && call.arguments.keywords.iter().all(|keyword| keyword.arg.is_some()) {
|
||||||
match call.arguments.find_argument("url", 0) {
|
match call.arguments.find_argument_value("url", 0) {
|
||||||
// If the `url` argument is a `urllib.request.Request` object, allow `http` and `https` schemes.
|
// If the `url` argument is a `urllib.request.Request` object, allow `http` and `https` schemes.
|
||||||
Some(Expr::Call(ExprCall { func, arguments, .. })) => {
|
Some(Expr::Call(ExprCall { func, arguments, .. })) => {
|
||||||
if checker.semantic().resolve_qualified_name(func.as_ref()).is_some_and(|name| name.segments() == ["urllib", "request", "Request"]) {
|
if checker.semantic().resolve_qualified_name(func.as_ref()).is_some_and(|name| name.segments() == ["urllib", "request", "Request"]) {
|
||||||
if arguments.find_argument("url", 0).and_then(leading_chars).is_some_and(has_http_prefix) {
|
if arguments.find_argument_value("url", 0).and_then(leading_chars).is_some_and(has_http_prefix) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ pub(crate) fn unsafe_yaml_load(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
.resolve_qualified_name(&call.func)
|
.resolve_qualified_name(&call.func)
|
||||||
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["yaml", "load"]))
|
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["yaml", "load"]))
|
||||||
{
|
{
|
||||||
if let Some(loader_arg) = call.arguments.find_argument("Loader", 1) {
|
if let Some(loader_arg) = call.arguments.find_argument_value("Loader", 1) {
|
||||||
if !checker
|
if !checker
|
||||||
.semantic()
|
.semantic()
|
||||||
.resolve_qualified_name(loader_arg)
|
.resolve_qualified_name(loader_arg)
|
||||||
|
|
|
@ -114,7 +114,7 @@ fn extract_cryptographic_key(
|
||||||
Some((CryptographicKey::Rsa { key_size }, range))
|
Some((CryptographicKey::Rsa { key_size }, range))
|
||||||
}
|
}
|
||||||
"ec" => {
|
"ec" => {
|
||||||
let argument = call.arguments.find_argument("curve", 0)?;
|
let argument = call.arguments.find_argument_value("curve", 0)?;
|
||||||
let ExprAttribute { attr, value, .. } = argument.as_attribute_expr()?;
|
let ExprAttribute { attr, value, .. } = argument.as_attribute_expr()?;
|
||||||
let qualified_name = checker.semantic().resolve_qualified_name(value)?;
|
let qualified_name = checker.semantic().resolve_qualified_name(value)?;
|
||||||
if matches!(
|
if matches!(
|
||||||
|
@ -150,7 +150,7 @@ fn extract_cryptographic_key(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_int_argument(call: &ExprCall, name: &str, position: usize) -> Option<(u16, TextRange)> {
|
fn extract_int_argument(call: &ExprCall, name: &str, position: usize) -> Option<(u16, TextRange)> {
|
||||||
let argument = call.arguments.find_argument(name, position)?;
|
let argument = call.arguments.find_argument_value(name, position)?;
|
||||||
let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||||
value: ast::Number::Int(i),
|
value: ast::Number::Int(i),
|
||||||
..
|
..
|
||||||
|
|
|
@ -60,7 +60,10 @@ pub(crate) fn no_explicit_stacklevel(checker: &mut Checker, call: &ast::ExprCall
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if call.arguments.find_argument("stacklevel", 2).is_some()
|
if call
|
||||||
|
.arguments
|
||||||
|
.find_argument_value("stacklevel", 2)
|
||||||
|
.is_some()
|
||||||
|| call
|
|| call
|
||||||
.arguments
|
.arguments
|
||||||
.args
|
.args
|
||||||
|
|
|
@ -91,7 +91,7 @@ pub(crate) fn call_datetime_fromtimestamp(checker: &mut Checker, call: &ast::Exp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let antipattern = match call.arguments.find_argument("tz", 1) {
|
let antipattern = match call.arguments.find_argument_value("tz", 1) {
|
||||||
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
|
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
|
||||||
Some(_) => return,
|
Some(_) => return,
|
||||||
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
|
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
|
||||||
|
|
|
@ -86,7 +86,7 @@ pub(crate) fn call_datetime_now_without_tzinfo(checker: &mut Checker, call: &ast
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let antipattern = match call.arguments.find_argument("tz", 0) {
|
let antipattern = match call.arguments.find_argument_value("tz", 0) {
|
||||||
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
|
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
|
||||||
Some(_) => return,
|
Some(_) => return,
|
||||||
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
|
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
|
||||||
|
|
|
@ -80,7 +80,7 @@ pub(crate) fn call_datetime_without_tzinfo(checker: &mut Checker, call: &ast::Ex
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let antipattern = match call.arguments.find_argument("tzinfo", 7) {
|
let antipattern = match call.arguments.find_argument_value("tzinfo", 7) {
|
||||||
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
|
Some(ast::Expr::NoneLiteral(_)) => DatetimeModuleAntipattern::NonePassedToTzArgument,
|
||||||
Some(_) => return,
|
Some(_) => return,
|
||||||
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
|
None => DatetimeModuleAntipattern::NoTzArgumentPassed,
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub(crate) fn locals_in_render_function(checker: &mut Checker, call: &ast::ExprC
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(argument) = call.arguments.find_argument("context", 2) {
|
if let Some(argument) = call.arguments.find_argument_value("context", 2) {
|
||||||
if is_locals_call(argument, checker.semantic()) {
|
if is_locals_call(argument, checker.semantic()) {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
DjangoLocalsInRenderFunction,
|
DjangoLocalsInRenderFunction,
|
||||||
|
|
|
@ -62,7 +62,8 @@ pub(crate) fn invalid_get_logger_argument(checker: &mut Checker, call: &ast::Exp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(Expr::Name(expr @ ast::ExprName { id, .. })) = call.arguments.find_argument("name", 0)
|
let Some(Expr::Name(expr @ ast::ExprName { id, .. })) =
|
||||||
|
call.arguments.find_argument_value("name", 0)
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
@ -181,7 +181,7 @@ pub(crate) fn logging_call(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
|
|
||||||
// G001 - G004
|
// G001 - G004
|
||||||
let msg_pos = usize::from(matches!(logging_call_type, LoggingCallType::LogCall));
|
let msg_pos = usize::from(matches!(logging_call_type, LoggingCallType::LogCall));
|
||||||
if let Some(format_arg) = call.arguments.find_argument("msg", msg_pos) {
|
if let Some(format_arg) = call.arguments.find_argument_value("msg", msg_pos) {
|
||||||
check_msg(checker, format_arg);
|
check_msg(checker, format_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,8 @@ pub(crate) fn fail_call(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
// `pytest.fail(msg="...")` (deprecated in pytest 7.0)
|
// `pytest.fail(msg="...")` (deprecated in pytest 7.0)
|
||||||
if call
|
if call
|
||||||
.arguments
|
.arguments
|
||||||
.find_argument("reason", 0)
|
.find_argument_value("reason", 0)
|
||||||
.or_else(|| call.arguments.find_argument("msg", 0))
|
.or_else(|| call.arguments.find_argument_value("msg", 0))
|
||||||
.map_or(true, is_empty_or_null_string)
|
.map_or(true, is_empty_or_null_string)
|
||||||
{
|
{
|
||||||
checker
|
checker
|
||||||
|
|
|
@ -864,12 +864,12 @@ pub(crate) fn parametrize(checker: &mut Checker, call: &ExprCall) {
|
||||||
|
|
||||||
if checker.enabled(Rule::PytestParametrizeNamesWrongType) {
|
if checker.enabled(Rule::PytestParametrizeNamesWrongType) {
|
||||||
let names = if checker.settings.preview.is_enabled() {
|
let names = if checker.settings.preview.is_enabled() {
|
||||||
call.arguments.find_argument("argnames", 0)
|
call.arguments.find_argument_value("argnames", 0)
|
||||||
} else {
|
} else {
|
||||||
call.arguments.find_positional(0)
|
call.arguments.find_positional(0)
|
||||||
};
|
};
|
||||||
let values = if checker.settings.preview.is_enabled() {
|
let values = if checker.settings.preview.is_enabled() {
|
||||||
call.arguments.find_argument("argvalues", 1)
|
call.arguments.find_argument_value("argvalues", 1)
|
||||||
} else {
|
} else {
|
||||||
call.arguments.find_positional(1)
|
call.arguments.find_positional(1)
|
||||||
};
|
};
|
||||||
|
@ -879,12 +879,12 @@ pub(crate) fn parametrize(checker: &mut Checker, call: &ExprCall) {
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::PytestParametrizeValuesWrongType) {
|
if checker.enabled(Rule::PytestParametrizeValuesWrongType) {
|
||||||
let names = if checker.settings.preview.is_enabled() {
|
let names = if checker.settings.preview.is_enabled() {
|
||||||
call.arguments.find_argument("argnames", 0)
|
call.arguments.find_argument_value("argnames", 0)
|
||||||
} else {
|
} else {
|
||||||
call.arguments.find_positional(0)
|
call.arguments.find_positional(0)
|
||||||
};
|
};
|
||||||
let values = if checker.settings.preview.is_enabled() {
|
let values = if checker.settings.preview.is_enabled() {
|
||||||
call.arguments.find_argument("argvalues", 1)
|
call.arguments.find_argument_value("argvalues", 1)
|
||||||
} else {
|
} else {
|
||||||
call.arguments.find_positional(1)
|
call.arguments.find_positional(1)
|
||||||
};
|
};
|
||||||
|
@ -894,7 +894,7 @@ pub(crate) fn parametrize(checker: &mut Checker, call: &ExprCall) {
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::PytestDuplicateParametrizeTestCases) {
|
if checker.enabled(Rule::PytestDuplicateParametrizeTestCases) {
|
||||||
if let Some(values) = if checker.settings.preview.is_enabled() {
|
if let Some(values) = if checker.settings.preview.is_enabled() {
|
||||||
call.arguments.find_argument("argvalues", 1)
|
call.arguments.find_argument_value("argvalues", 1)
|
||||||
} else {
|
} else {
|
||||||
call.arguments.find_positional(1)
|
call.arguments.find_positional(1)
|
||||||
} {
|
} {
|
||||||
|
|
|
@ -84,7 +84,7 @@ fn check_patch_call(call: &ast::ExprCall, index: usize) -> Option<Diagnostic> {
|
||||||
range: _,
|
range: _,
|
||||||
} = call
|
} = call
|
||||||
.arguments
|
.arguments
|
||||||
.find_argument("new", index)?
|
.find_argument_value("new", index)?
|
||||||
.as_lambda_expr()?;
|
.as_lambda_expr()?;
|
||||||
|
|
||||||
// Walk the lambda body. If the lambda uses the arguments, then it's valid.
|
// Walk the lambda body. If the lambda uses the arguments, then it's valid.
|
||||||
|
|
|
@ -177,7 +177,7 @@ pub(crate) fn raises_call(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if checker.enabled(Rule::PytestRaisesTooBroad) {
|
if checker.enabled(Rule::PytestRaisesTooBroad) {
|
||||||
if let Some(exception) = call.arguments.find_argument("expected_exception", 0) {
|
if let Some(exception) = call.arguments.find_argument_value("expected_exception", 0) {
|
||||||
if call
|
if call
|
||||||
.arguments
|
.arguments
|
||||||
.find_keyword("match")
|
.find_keyword("match")
|
||||||
|
|
|
@ -67,7 +67,7 @@ pub(crate) fn split_static_string(
|
||||||
) {
|
) {
|
||||||
let ExprCall { arguments, .. } = call;
|
let ExprCall { arguments, .. } = call;
|
||||||
|
|
||||||
let maxsplit_arg = arguments.find_argument("maxsplit", 1);
|
let maxsplit_arg = arguments.find_argument_value("maxsplit", 1);
|
||||||
let Some(maxsplit_value) = get_maxsplit_value(maxsplit_arg) else {
|
let Some(maxsplit_value) = get_maxsplit_value(maxsplit_arg) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -79,7 +79,7 @@ pub(crate) fn split_static_string(
|
||||||
Direction::Right
|
Direction::Right
|
||||||
};
|
};
|
||||||
|
|
||||||
let sep_arg = arguments.find_argument("sep", 0);
|
let sep_arg = arguments.find_argument_value("sep", 0);
|
||||||
let split_replacement = if let Some(sep) = sep_arg {
|
let split_replacement = if let Some(sep) = sep_arg {
|
||||||
match sep {
|
match sep {
|
||||||
Expr::NoneLiteral(_) => split_default(str_value, maxsplit_value),
|
Expr::NoneLiteral(_) => split_default(str_value, maxsplit_value),
|
||||||
|
|
|
@ -89,7 +89,7 @@ pub(crate) fn invalid_pathlib_with_suffix(checker: &mut Checker, call: &ast::Exp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(ast::Expr::StringLiteral(string)) = arguments.find_argument("suffix", 0) else {
|
let Some(ast::Expr::StringLiteral(string)) = arguments.find_argument_value("suffix", 0) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ pub(crate) fn os_sep_split(checker: &mut Checker, call: &ast::ExprCall) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(sep) = call.arguments.find_argument("sep", 0) else {
|
let Some(sep) = call.arguments.find_argument_value("sep", 0) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ pub(crate) fn replaceable_by_pathlib(checker: &mut Checker, call: &ExprCall) {
|
||||||
// ```
|
// ```
|
||||||
if call
|
if call
|
||||||
.arguments
|
.arguments
|
||||||
.find_argument("closefd", 6)
|
.find_argument_value("closefd", 6)
|
||||||
.is_some_and(|expr| {
|
.is_some_and(|expr| {
|
||||||
!matches!(
|
!matches!(
|
||||||
expr,
|
expr,
|
||||||
|
@ -124,7 +124,7 @@ pub(crate) fn replaceable_by_pathlib(checker: &mut Checker, call: &ExprCall) {
|
||||||
})
|
})
|
||||||
|| call
|
|| call
|
||||||
.arguments
|
.arguments
|
||||||
.find_argument("opener", 7)
|
.find_argument_value("opener", 7)
|
||||||
.is_some_and(|expr| !expr.is_none_literal_expr())
|
.is_some_and(|expr| !expr.is_none_literal_expr())
|
||||||
|| call
|
|| call
|
||||||
.arguments
|
.arguments
|
||||||
|
|
|
@ -121,8 +121,8 @@ pub(super) fn is_django_model_import(name: &str, stmt: &Stmt, semantic: &Semanti
|
||||||
// Match against, e.g., `apps.get_model("zerver", "Attachment")`.
|
// Match against, e.g., `apps.get_model("zerver", "Attachment")`.
|
||||||
if let Some(unqualified_name) = UnqualifiedName::from_expr(func.as_ref()) {
|
if let Some(unqualified_name) = UnqualifiedName::from_expr(func.as_ref()) {
|
||||||
if matches!(unqualified_name.segments(), [.., "get_model"]) {
|
if matches!(unqualified_name.segments(), [.., "get_model"]) {
|
||||||
if let Some(argument) =
|
if let Some(argument) = arguments
|
||||||
arguments.find_argument("model_name", arguments.args.len().saturating_sub(1))
|
.find_argument_value("model_name", arguments.args.len().saturating_sub(1))
|
||||||
{
|
{
|
||||||
if let Some(string_literal) = argument.as_string_literal_expr() {
|
if let Some(string_literal) = argument.as_string_literal_expr() {
|
||||||
if string_literal.value.to_str() == name {
|
if string_literal.value.to_str() == name {
|
||||||
|
@ -141,7 +141,7 @@ pub(super) fn is_django_model_import(name: &str, stmt: &Stmt, semantic: &Semanti
|
||||||
qualified_name.segments(),
|
qualified_name.segments(),
|
||||||
["django", "utils", "module_loading", "import_string"]
|
["django", "utils", "module_loading", "import_string"]
|
||||||
) {
|
) {
|
||||||
if let Some(argument) = arguments.find_argument("dotted_path", 0) {
|
if let Some(argument) = arguments.find_argument_value("dotted_path", 0) {
|
||||||
if let Some(string_literal) = argument.as_string_literal_expr() {
|
if let Some(string_literal) = argument.as_string_literal_expr() {
|
||||||
if let Some((.., model)) = string_literal.value.to_str().rsplit_once('.') {
|
if let Some((.., model)) = string_literal.value.to_str().rsplit_once('.') {
|
||||||
if model == name {
|
if model == name {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::settings::LinterSettings;
|
||||||
/// Returns the value of the `name` parameter to, e.g., a `TypeVar` constructor.
|
/// Returns the value of the `name` parameter to, e.g., a `TypeVar` constructor.
|
||||||
pub(super) fn type_param_name(arguments: &Arguments) -> Option<&str> {
|
pub(super) fn type_param_name(arguments: &Arguments) -> Option<&str> {
|
||||||
// Handle both `TypeVar("T")` and `TypeVar(name="T")`.
|
// Handle both `TypeVar("T")` and `TypeVar(name="T")`.
|
||||||
let name_param = arguments.find_argument("name", 0)?;
|
let name_param = arguments.find_argument_value("name", 0)?;
|
||||||
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &name_param {
|
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &name_param {
|
||||||
Some(value.to_str())
|
Some(value.to_str())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -107,7 +107,7 @@ fn is_open(func: &Expr, semantic: &SemanticModel) -> Option<Kind> {
|
||||||
/// Returns the mode argument, if present.
|
/// Returns the mode argument, if present.
|
||||||
fn extract_mode(call: &ast::ExprCall, kind: Kind) -> Option<&Expr> {
|
fn extract_mode(call: &ast::ExprCall, kind: Kind) -> Option<&Expr> {
|
||||||
match kind {
|
match kind {
|
||||||
Kind::Builtin => call.arguments.find_argument("mode", 1),
|
Kind::Builtin => call.arguments.find_argument_value("mode", 1),
|
||||||
Kind::Pathlib => call.arguments.find_argument("mode", 0),
|
Kind::Pathlib => call.arguments.find_argument_value("mode", 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ pub(crate) fn invalid_envvar_default(checker: &mut Checker, call: &ast::ExprCall
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
// Find the `default` argument, if it exists.
|
// Find the `default` argument, if it exists.
|
||||||
let Some(expr) = call.arguments.find_argument("default", 1) else {
|
let Some(expr) = call.arguments.find_argument_value("default", 1) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ pub(crate) fn invalid_envvar_value(checker: &mut Checker, call: &ast::ExprCall)
|
||||||
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["os", "getenv"]))
|
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["os", "getenv"]))
|
||||||
{
|
{
|
||||||
// Find the `key` argument, if it exists.
|
// Find the `key` argument, if it exists.
|
||||||
let Some(expr) = call.arguments.find_argument("key", 0) else {
|
let Some(expr) = call.arguments.find_argument_value("key", 0) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,9 @@ fn enumerate_items<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the `enumerate` call has a non-zero `start`, don't omit.
|
// If the `enumerate` call has a non-zero `start`, don't omit.
|
||||||
if !arguments.find_argument("start", 1).map_or(true, |expr| {
|
if !arguments
|
||||||
|
.find_argument_value("start", 1)
|
||||||
|
.map_or(true, |expr| {
|
||||||
matches!(
|
matches!(
|
||||||
expr,
|
expr,
|
||||||
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||||
|
@ -160,7 +162,8 @@ fn enumerate_items<'a>(
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}) {
|
})
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,19 +203,19 @@ fn is_violation(call: &ast::ExprCall, qualified_name: &Callee) -> bool {
|
||||||
match qualified_name {
|
match qualified_name {
|
||||||
Callee::Qualified(qualified_name) => match qualified_name.segments() {
|
Callee::Qualified(qualified_name) => match qualified_name.segments() {
|
||||||
["" | "codecs" | "_io", "open"] => {
|
["" | "codecs" | "_io", "open"] => {
|
||||||
if let Some(mode_arg) = call.arguments.find_argument("mode", 1) {
|
if let Some(mode_arg) = call.arguments.find_argument_value("mode", 1) {
|
||||||
if is_binary_mode(mode_arg).unwrap_or(true) {
|
if is_binary_mode(mode_arg).unwrap_or(true) {
|
||||||
// binary mode or unknown mode is no violation
|
// binary mode or unknown mode is no violation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else mode not specified, defaults to text mode
|
// else mode not specified, defaults to text mode
|
||||||
call.arguments.find_argument("encoding", 3).is_none()
|
call.arguments.find_argument_value("encoding", 3).is_none()
|
||||||
}
|
}
|
||||||
["tempfile", tempfile_class @ ("TemporaryFile" | "NamedTemporaryFile" | "SpooledTemporaryFile")] =>
|
["tempfile", tempfile_class @ ("TemporaryFile" | "NamedTemporaryFile" | "SpooledTemporaryFile")] =>
|
||||||
{
|
{
|
||||||
let mode_pos = usize::from(*tempfile_class == "SpooledTemporaryFile");
|
let mode_pos = usize::from(*tempfile_class == "SpooledTemporaryFile");
|
||||||
if let Some(mode_arg) = call.arguments.find_argument("mode", mode_pos) {
|
if let Some(mode_arg) = call.arguments.find_argument_value("mode", mode_pos) {
|
||||||
if is_binary_mode(mode_arg).unwrap_or(true) {
|
if is_binary_mode(mode_arg).unwrap_or(true) {
|
||||||
// binary mode or unknown mode is no violation
|
// binary mode or unknown mode is no violation
|
||||||
return false;
|
return false;
|
||||||
|
@ -225,27 +225,27 @@ fn is_violation(call: &ast::ExprCall, qualified_name: &Callee) -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
call.arguments
|
call.arguments
|
||||||
.find_argument("encoding", mode_pos + 2)
|
.find_argument_value("encoding", mode_pos + 2)
|
||||||
.is_none()
|
.is_none()
|
||||||
}
|
}
|
||||||
["io" | "_io", "TextIOWrapper"] => {
|
["io" | "_io", "TextIOWrapper"] => {
|
||||||
call.arguments.find_argument("encoding", 1).is_none()
|
call.arguments.find_argument_value("encoding", 1).is_none()
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
Callee::Pathlib(attr) => match *attr {
|
Callee::Pathlib(attr) => match *attr {
|
||||||
"open" => {
|
"open" => {
|
||||||
if let Some(mode_arg) = call.arguments.find_argument("mode", 0) {
|
if let Some(mode_arg) = call.arguments.find_argument_value("mode", 0) {
|
||||||
if is_binary_mode(mode_arg).unwrap_or(true) {
|
if is_binary_mode(mode_arg).unwrap_or(true) {
|
||||||
// binary mode or unknown mode is no violation
|
// binary mode or unknown mode is no violation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else mode not specified, defaults to text mode
|
// else mode not specified, defaults to text mode
|
||||||
call.arguments.find_argument("encoding", 2).is_none()
|
call.arguments.find_argument_value("encoding", 2).is_none()
|
||||||
}
|
}
|
||||||
"read_text" => call.arguments.find_argument("encoding", 0).is_none(),
|
"read_text" => call.arguments.find_argument_value("encoding", 0).is_none(),
|
||||||
"write_text" => call.arguments.find_argument("encoding", 1).is_none(),
|
"write_text" => call.arguments.find_argument_value("encoding", 1).is_none(),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ pub(crate) fn redundant_open_modes(checker: &mut Checker, call: &ast::ExprCall)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(mode_param) = call.arguments.find_argument("mode", 1) else {
|
let Some(mode_param) = call.arguments.find_argument_value("mode", 1) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &mode_param else {
|
let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = &mode_param else {
|
||||||
|
|
|
@ -178,7 +178,7 @@ pub(crate) fn unnecessary_enumerate(checker: &mut Checker, stmt_for: &ast::StmtF
|
||||||
{
|
{
|
||||||
// If the `start` argument is set to something other than the `range` default,
|
// If the `start` argument is set to something other than the `range` default,
|
||||||
// there's no clear fix.
|
// there's no clear fix.
|
||||||
let start = arguments.find_argument("start", 1);
|
let start = arguments.find_argument_value("start", 1);
|
||||||
if start.map_or(true, |start| {
|
if start.map_or(true, |start| {
|
||||||
matches!(
|
matches!(
|
||||||
start,
|
start,
|
||||||
|
|
|
@ -115,8 +115,8 @@ pub(crate) fn unnecessary_from_float(checker: &mut Checker, call: &ExprCall) {
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(value) = (match method_name {
|
let Some(value) = (match method_name {
|
||||||
MethodName::FromFloat => call.arguments.find_argument("f", 0),
|
MethodName::FromFloat => call.arguments.find_argument_value("f", 0),
|
||||||
MethodName::FromDecimal => call.arguments.find_argument("dec", 0),
|
MethodName::FromDecimal => call.arguments.find_argument_value("dec", 0),
|
||||||
}) else {
|
}) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
@ -67,7 +67,7 @@ pub(crate) fn verbose_decimal_constructor(checker: &mut Checker, call: &ast::Exp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decimal accepts arguments of the form: `Decimal(value='0', context=None)`
|
// Decimal accepts arguments of the form: `Decimal(value='0', context=None)`
|
||||||
let Some(value) = call.arguments.find_argument("value", 0) else {
|
let Some(value) = call.arguments.find_argument_value("value", 0) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ mod tests {
|
||||||
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.py"))]
|
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.py"))]
|
||||||
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.pyi"))]
|
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.pyi"))]
|
||||||
#[test_case(Rule::IfKeyInDictDel, Path::new("RUF051.py"))]
|
#[test_case(Rule::IfKeyInDictDel, Path::new("RUF051.py"))]
|
||||||
|
#[test_case(Rule::FalsyDictGetFallback, Path::new("RUF056.py"))]
|
||||||
#[test_case(Rule::UsedDummyVariable, Path::new("RUF052.py"))]
|
#[test_case(Rule::UsedDummyVariable, Path::new("RUF052.py"))]
|
||||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::fix::edits::{remove_argument, Parentheses};
|
||||||
|
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Fix};
|
||||||
|
use ruff_macros::{derive_message_formats, ViolationMetadata};
|
||||||
|
use ruff_python_ast::{helpers::Truthiness, Expr, ExprAttribute, ExprName};
|
||||||
|
use ruff_python_semantic::analyze::typing;
|
||||||
|
use ruff_python_semantic::SemanticModel;
|
||||||
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for `dict.get(key, falsy_value)` calls in boolean test positions.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// The default fallback `None` is already falsy.
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// if dict.get(key, False):
|
||||||
|
/// ...
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
///
|
||||||
|
/// ```python
|
||||||
|
/// if dict.get(key):
|
||||||
|
/// ...
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Fix safety
|
||||||
|
/// This rule's fix is marked as safe, unless the `dict.get()` call contains comments between arguments.
|
||||||
|
#[derive(ViolationMetadata)]
|
||||||
|
pub(crate) struct FalsyDictGetFallback;
|
||||||
|
|
||||||
|
impl AlwaysFixableViolation for FalsyDictGetFallback {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
"Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fix_title(&self) -> String {
|
||||||
|
"Remove falsy fallback from `dict.get()`".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn falsy_dict_get_fallback(checker: &mut Checker, expr: &Expr) {
|
||||||
|
let semantic = checker.semantic();
|
||||||
|
|
||||||
|
// Check if we are in a boolean test
|
||||||
|
if !semantic.in_boolean_test() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the expression is a call
|
||||||
|
let Expr::Call(call) = expr else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the function being called is an attribute (e.g. `dict.get`)
|
||||||
|
let Expr::Attribute(ExprAttribute { value, attr, .. }) = &*call.func else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ensure the method called is `get`
|
||||||
|
if attr != "get" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the object is a dictionary using the semantic model
|
||||||
|
if !value
|
||||||
|
.as_name_expr()
|
||||||
|
.is_some_and(|name| is_known_to_be_of_type_dict(semantic, name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the fallback argument
|
||||||
|
let Some(fallback_arg) = call.arguments.find_argument("default", 1) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the fallback is a falsy value
|
||||||
|
if Truthiness::from_expr(fallback_arg.value(), |id| semantic.has_builtin_binding(id))
|
||||||
|
.into_bool()
|
||||||
|
!= Some(false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut diagnostic = Diagnostic::new(FalsyDictGetFallback, fallback_arg.range());
|
||||||
|
|
||||||
|
let comment_ranges = checker.comment_ranges();
|
||||||
|
|
||||||
|
// Determine applicability based on the presence of comments
|
||||||
|
let applicability = if comment_ranges.intersects(call.arguments.range()) {
|
||||||
|
Applicability::Unsafe
|
||||||
|
} else {
|
||||||
|
Applicability::Safe
|
||||||
|
};
|
||||||
|
|
||||||
|
diagnostic.try_set_fix(|| {
|
||||||
|
remove_argument(
|
||||||
|
&fallback_arg,
|
||||||
|
&call.arguments,
|
||||||
|
Parentheses::Preserve,
|
||||||
|
checker.locator().contents(),
|
||||||
|
)
|
||||||
|
.map(|edit| Fix::applicable_edit(edit, applicability))
|
||||||
|
});
|
||||||
|
|
||||||
|
checker.diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_known_to_be_of_type_dict(semantic: &SemanticModel, expr: &ExprName) -> bool {
|
||||||
|
let Some(binding) = semantic.only_binding(expr).map(|id| semantic.binding(id)) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
typing::is_dict(binding, semantic)
|
||||||
|
}
|
|
@ -103,7 +103,7 @@ fn is_dunder_version_split_dot(expr: &ast::Expr) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(ast::Expr::StringLiteral(ast::ExprStringLiteral { value, range: _ })) =
|
let Some(ast::Expr::StringLiteral(ast::ExprStringLiteral { value, range: _ })) =
|
||||||
arguments.find_argument("sep", 0)
|
arguments.find_argument_value("sep", 0)
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub(crate) use collection_literal_concatenation::*;
|
||||||
pub(crate) use decimal_from_float_literal::*;
|
pub(crate) use decimal_from_float_literal::*;
|
||||||
pub(crate) use default_factory_kwarg::*;
|
pub(crate) use default_factory_kwarg::*;
|
||||||
pub(crate) use explicit_f_string_type_conversion::*;
|
pub(crate) use explicit_f_string_type_conversion::*;
|
||||||
|
pub(crate) use falsy_dict_get_fallback::*;
|
||||||
pub(crate) use function_call_in_dataclass_default::*;
|
pub(crate) use function_call_in_dataclass_default::*;
|
||||||
pub(crate) use if_key_in_dict_del::*;
|
pub(crate) use if_key_in_dict_del::*;
|
||||||
pub(crate) use implicit_optional::*;
|
pub(crate) use implicit_optional::*;
|
||||||
|
@ -54,6 +55,7 @@ mod confusables;
|
||||||
mod decimal_from_float_literal;
|
mod decimal_from_float_literal;
|
||||||
mod default_factory_kwarg;
|
mod default_factory_kwarg;
|
||||||
mod explicit_f_string_type_conversion;
|
mod explicit_f_string_type_conversion;
|
||||||
|
mod falsy_dict_get_fallback;
|
||||||
mod function_call_in_dataclass_default;
|
mod function_call_in_dataclass_default;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
mod if_key_in_dict_del;
|
mod if_key_in_dict_del;
|
||||||
|
|
|
@ -128,7 +128,7 @@ fn convert_to_reduce(iterable: &Expr, call: &ast::ExprCall, checker: &Checker) -
|
||||||
|
|
||||||
/// Returns `true` if the `start` argument to a `sum()` call is an empty list.
|
/// Returns `true` if the `start` argument to a `sum()` call is an empty list.
|
||||||
fn start_is_empty_list(arguments: &Arguments, semantic: &SemanticModel) -> bool {
|
fn start_is_empty_list(arguments: &Arguments, semantic: &SemanticModel) -> bool {
|
||||||
let Some(start_arg) = arguments.find_argument("start", 1) else {
|
let Some(start_arg) = arguments.find_argument_value("start", 1) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -175,8 +175,8 @@ fn round_applicability(checker: &Checker, arguments: &Arguments) -> Option<Appli
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let number = arguments.find_argument("number", 0)?;
|
let number = arguments.find_argument_value("number", 0)?;
|
||||||
let ndigits = arguments.find_argument("ndigits", 1);
|
let ndigits = arguments.find_argument_value("ndigits", 1);
|
||||||
|
|
||||||
let number_kind = match number {
|
let number_kind = match number {
|
||||||
Expr::Name(name) => {
|
Expr::Name(name) => {
|
||||||
|
|
|
@ -173,14 +173,14 @@ impl<'a> ReFunc<'a> {
|
||||||
// have already been filtered out from the `pattern`
|
// have already been filtered out from the `pattern`
|
||||||
("split", 2) => Some(ReFunc {
|
("split", 2) => Some(ReFunc {
|
||||||
kind: ReFuncKind::Split,
|
kind: ReFuncKind::Split,
|
||||||
pattern: call.arguments.find_argument("pattern", 0)?,
|
pattern: call.arguments.find_argument_value("pattern", 0)?,
|
||||||
string: call.arguments.find_argument("string", 1)?,
|
string: call.arguments.find_argument_value("string", 1)?,
|
||||||
}),
|
}),
|
||||||
// `sub` is only safe to fix if `repl` is a string. `re.sub` also
|
// `sub` is only safe to fix if `repl` is a string. `re.sub` also
|
||||||
// allows it to be a function, which will *not* work in the str
|
// allows it to be a function, which will *not* work in the str
|
||||||
// version
|
// version
|
||||||
("sub", 3) => {
|
("sub", 3) => {
|
||||||
let repl = call.arguments.find_argument("repl", 1)?;
|
let repl = call.arguments.find_argument_value("repl", 1)?;
|
||||||
let lit = resolve_string_literal(repl, semantic)?;
|
let lit = resolve_string_literal(repl, semantic)?;
|
||||||
let mut fixable = true;
|
let mut fixable = true;
|
||||||
for (c, next) in lit.value.chars().tuple_windows() {
|
for (c, next) in lit.value.chars().tuple_windows() {
|
||||||
|
@ -207,24 +207,24 @@ impl<'a> ReFunc<'a> {
|
||||||
kind: ReFuncKind::Sub {
|
kind: ReFuncKind::Sub {
|
||||||
repl: fixable.then_some(repl),
|
repl: fixable.then_some(repl),
|
||||||
},
|
},
|
||||||
pattern: call.arguments.find_argument("pattern", 0)?,
|
pattern: call.arguments.find_argument_value("pattern", 0)?,
|
||||||
string: call.arguments.find_argument("string", 2)?,
|
string: call.arguments.find_argument_value("string", 2)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
("match", 2) if in_if_context => Some(ReFunc {
|
("match", 2) if in_if_context => Some(ReFunc {
|
||||||
kind: ReFuncKind::Match,
|
kind: ReFuncKind::Match,
|
||||||
pattern: call.arguments.find_argument("pattern", 0)?,
|
pattern: call.arguments.find_argument_value("pattern", 0)?,
|
||||||
string: call.arguments.find_argument("string", 1)?,
|
string: call.arguments.find_argument_value("string", 1)?,
|
||||||
}),
|
}),
|
||||||
("search", 2) if in_if_context => Some(ReFunc {
|
("search", 2) if in_if_context => Some(ReFunc {
|
||||||
kind: ReFuncKind::Search,
|
kind: ReFuncKind::Search,
|
||||||
pattern: call.arguments.find_argument("pattern", 0)?,
|
pattern: call.arguments.find_argument_value("pattern", 0)?,
|
||||||
string: call.arguments.find_argument("string", 1)?,
|
string: call.arguments.find_argument_value("string", 1)?,
|
||||||
}),
|
}),
|
||||||
("fullmatch", 2) if in_if_context => Some(ReFunc {
|
("fullmatch", 2) if in_if_context => Some(ReFunc {
|
||||||
kind: ReFuncKind::Fullmatch,
|
kind: ReFuncKind::Fullmatch,
|
||||||
pattern: call.arguments.find_argument("pattern", 0)?,
|
pattern: call.arguments.find_argument_value("pattern", 0)?,
|
||||||
string: call.arguments.find_argument("string", 1)?,
|
string: call.arguments.find_argument_value("string", 1)?,
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,485 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_linter/src/rules/ruff/mod.rs
|
||||||
|
snapshot_kind: text
|
||||||
|
---
|
||||||
|
RUF056.py:117:43: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
116 | # dict.get in ternary expression
|
||||||
|
117 | value = "not found" if my_dict.get("key", False) else "default" # [RUF056]
|
||||||
|
| ^^^^^ RUF056
|
||||||
|
118 |
|
||||||
|
119 | # dict.get in an if statement
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
114 114 | # Invalid falsy fallbacks are when the call to dict.get is used in a boolean context
|
||||||
|
115 115 |
|
||||||
|
116 116 | # dict.get in ternary expression
|
||||||
|
117 |-value = "not found" if my_dict.get("key", False) else "default" # [RUF056]
|
||||||
|
117 |+value = "not found" if my_dict.get("key") else "default" # [RUF056]
|
||||||
|
118 118 |
|
||||||
|
119 119 | # dict.get in an if statement
|
||||||
|
120 120 | if my_dict.get("key", False): # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:120:23: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
119 | # dict.get in an if statement
|
||||||
|
120 | if my_dict.get("key", False): # [RUF056]
|
||||||
|
| ^^^^^ RUF056
|
||||||
|
121 | pass
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
117 117 | value = "not found" if my_dict.get("key", False) else "default" # [RUF056]
|
||||||
|
118 118 |
|
||||||
|
119 119 | # dict.get in an if statement
|
||||||
|
120 |-if my_dict.get("key", False): # [RUF056]
|
||||||
|
120 |+if my_dict.get("key"): # [RUF056]
|
||||||
|
121 121 | pass
|
||||||
|
122 122 |
|
||||||
|
123 123 | # dict.get in compound if statement
|
||||||
|
|
||||||
|
RUF056.py:124:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
123 | # dict.get in compound if statement
|
||||||
|
124 | if True and my_dict.get("key", False): # [RUF056]
|
||||||
|
| ^^^^^ RUF056
|
||||||
|
125 | pass
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
121 121 | pass
|
||||||
|
122 122 |
|
||||||
|
123 123 | # dict.get in compound if statement
|
||||||
|
124 |-if True and my_dict.get("key", False): # [RUF056]
|
||||||
|
124 |+if True and my_dict.get("key"): # [RUF056]
|
||||||
|
125 125 | pass
|
||||||
|
126 126 |
|
||||||
|
127 127 | if my_dict.get("key", False) or True: # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:127:23: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
125 | pass
|
||||||
|
126 |
|
||||||
|
127 | if my_dict.get("key", False) or True: # [RUF056]
|
||||||
|
| ^^^^^ RUF056
|
||||||
|
128 | pass
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
124 124 | if True and my_dict.get("key", False): # [RUF056]
|
||||||
|
125 125 | pass
|
||||||
|
126 126 |
|
||||||
|
127 |-if my_dict.get("key", False) or True: # [RUF056]
|
||||||
|
127 |+if my_dict.get("key") or True: # [RUF056]
|
||||||
|
128 128 | pass
|
||||||
|
129 129 |
|
||||||
|
130 130 | # dict.get in an assert statement
|
||||||
|
|
||||||
|
RUF056.py:131:27: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
130 | # dict.get in an assert statement
|
||||||
|
131 | assert my_dict.get("key", False) # [RUF056]
|
||||||
|
| ^^^^^ RUF056
|
||||||
|
132 |
|
||||||
|
133 | # dict.get in a while statement
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
128 128 | pass
|
||||||
|
129 129 |
|
||||||
|
130 130 | # dict.get in an assert statement
|
||||||
|
131 |-assert my_dict.get("key", False) # [RUF056]
|
||||||
|
131 |+assert my_dict.get("key") # [RUF056]
|
||||||
|
132 132 |
|
||||||
|
133 133 | # dict.get in a while statement
|
||||||
|
134 134 | while my_dict.get("key", False): # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:134:26: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
133 | # dict.get in a while statement
|
||||||
|
134 | while my_dict.get("key", False): # [RUF056]
|
||||||
|
| ^^^^^ RUF056
|
||||||
|
135 | pass
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
131 131 | assert my_dict.get("key", False) # [RUF056]
|
||||||
|
132 132 |
|
||||||
|
133 133 | # dict.get in a while statement
|
||||||
|
134 |-while my_dict.get("key", False): # [RUF056]
|
||||||
|
134 |+while my_dict.get("key"): # [RUF056]
|
||||||
|
135 135 | pass
|
||||||
|
136 136 |
|
||||||
|
137 137 | # dict.get in unary not expression
|
||||||
|
|
||||||
|
RUF056.py:138:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
137 | # dict.get in unary not expression
|
||||||
|
138 | value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
| ^^^^^ RUF056
|
||||||
|
139 |
|
||||||
|
140 | # testing all falsy fallbacks
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
135 135 | pass
|
||||||
|
136 136 |
|
||||||
|
137 137 | # dict.get in unary not expression
|
||||||
|
138 |-value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
138 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
139 139 |
|
||||||
|
140 140 | # testing all falsy fallbacks
|
||||||
|
141 141 | value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:141:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
140 | # testing all falsy fallbacks
|
||||||
|
141 | value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
| ^^^^^ RUF056
|
||||||
|
142 | value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
138 138 | value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
139 139 |
|
||||||
|
140 140 | # testing all falsy fallbacks
|
||||||
|
141 |-value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
141 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
142 142 | value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
143 143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
144 144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:142:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
140 | # testing all falsy fallbacks
|
||||||
|
141 | value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
142 | value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
| ^^ RUF056
|
||||||
|
143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
139 139 |
|
||||||
|
140 140 | # testing all falsy fallbacks
|
||||||
|
141 141 | value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
142 |-value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
142 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
143 143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
144 144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
145 145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:143:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
141 | value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
142 | value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
| ^^^^^^ RUF056
|
||||||
|
144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
140 140 | # testing all falsy fallbacks
|
||||||
|
141 141 | value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
142 142 | value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
143 |-value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
143 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
144 144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
145 145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
146 146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:144:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
142 | value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
| ^^ RUF056
|
||||||
|
145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
141 141 | value = not my_dict.get("key", False) # [RUF056]
|
||||||
|
142 142 | value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
143 143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
144 |-value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
144 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
145 145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
146 146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
147 147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:145:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
| ^^^^^^ RUF056
|
||||||
|
146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
142 142 | value = not my_dict.get("key", []) # [RUF056]
|
||||||
|
143 143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
144 144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
145 |-value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
145 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
146 146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
147 147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
148 148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:146:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
| ^^^^^ RUF056
|
||||||
|
147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
143 143 | value = not my_dict.get("key", list()) # [RUF056]
|
||||||
|
144 144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
145 145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
146 |-value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
146 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
147 147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
148 148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
149 149 | value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:147:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
| ^^^^ RUF056
|
||||||
|
148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
149 | value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
144 144 | value = not my_dict.get("key", {}) # [RUF056]
|
||||||
|
145 145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
146 146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
147 |-value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
147 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
148 148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
149 149 | value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
150 150 | value = not my_dict.get("key", "") # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:148:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
| ^ RUF056
|
||||||
|
149 | value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
150 | value = not my_dict.get("key", "") # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
145 145 | value = not my_dict.get("key", dict()) # [RUF056]
|
||||||
|
146 146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
147 147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
148 |-value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
148 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
149 149 | value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
150 150 | value = not my_dict.get("key", "") # [RUF056]
|
||||||
|
151 151 |
|
||||||
|
|
||||||
|
RUF056.py:149:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
149 | value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
| ^^^ RUF056
|
||||||
|
150 | value = not my_dict.get("key", "") # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
146 146 | value = not my_dict.get("key", set()) # [RUF056]
|
||||||
|
147 147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
148 148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
149 |-value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
149 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
150 150 | value = not my_dict.get("key", "") # [RUF056]
|
||||||
|
151 151 |
|
||||||
|
152 152 | # testing dict.get call using kwargs
|
||||||
|
|
||||||
|
RUF056.py:150:32: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
149 | value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
150 | value = not my_dict.get("key", "") # [RUF056]
|
||||||
|
| ^^ RUF056
|
||||||
|
151 |
|
||||||
|
152 | # testing dict.get call using kwargs
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
147 147 | value = not my_dict.get("key", None) # [RUF056]
|
||||||
|
148 148 | value = not my_dict.get("key", 0) # [RUF056]
|
||||||
|
149 149 | value = not my_dict.get("key", 0.0) # [RUF056]
|
||||||
|
150 |-value = not my_dict.get("key", "") # [RUF056]
|
||||||
|
150 |+value = not my_dict.get("key") # [RUF056]
|
||||||
|
151 151 |
|
||||||
|
152 152 | # testing dict.get call using kwargs
|
||||||
|
153 153 | value = not my_dict.get(key="key", default=False) # [RUF056]
|
||||||
|
|
||||||
|
RUF056.py:153:36: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
152 | # testing dict.get call using kwargs
|
||||||
|
153 | value = not my_dict.get(key="key", default=False) # [RUF056]
|
||||||
|
| ^^^^^^^^^^^^^ RUF056
|
||||||
|
154 | value = not my_dict.get(default=[], key="key") # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
150 150 | value = not my_dict.get("key", "") # [RUF056]
|
||||||
|
151 151 |
|
||||||
|
152 152 | # testing dict.get call using kwargs
|
||||||
|
153 |-value = not my_dict.get(key="key", default=False) # [RUF056]
|
||||||
|
153 |+value = not my_dict.get(key="key") # [RUF056]
|
||||||
|
154 154 | value = not my_dict.get(default=[], key="key") # [RUF056]
|
||||||
|
155 155 |
|
||||||
|
156 156 | # testing invalid dict.get call with inline comment
|
||||||
|
|
||||||
|
RUF056.py:154:25: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
152 | # testing dict.get call using kwargs
|
||||||
|
153 | value = not my_dict.get(key="key", default=False) # [RUF056]
|
||||||
|
154 | value = not my_dict.get(default=[], key="key") # [RUF056]
|
||||||
|
| ^^^^^^^^^^ RUF056
|
||||||
|
155 |
|
||||||
|
156 | # testing invalid dict.get call with inline comment
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
151 151 |
|
||||||
|
152 152 | # testing dict.get call using kwargs
|
||||||
|
153 153 | value = not my_dict.get(key="key", default=False) # [RUF056]
|
||||||
|
154 |-value = not my_dict.get(default=[], key="key") # [RUF056]
|
||||||
|
154 |+value = not my_dict.get(key="key") # [RUF056]
|
||||||
|
155 155 |
|
||||||
|
156 156 | # testing invalid dict.get call with inline comment
|
||||||
|
157 157 | value = not my_dict.get("key", # comment1
|
||||||
|
|
||||||
|
RUF056.py:158:22: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
156 | # testing invalid dict.get call with inline comment
|
||||||
|
157 | value = not my_dict.get("key", # comment1
|
||||||
|
158 | [] # comment2
|
||||||
|
| ^^ RUF056
|
||||||
|
159 | ) # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
154 154 | value = not my_dict.get(default=[], key="key") # [RUF056]
|
||||||
|
155 155 |
|
||||||
|
156 156 | # testing invalid dict.get call with inline comment
|
||||||
|
157 |-value = not my_dict.get("key", # comment1
|
||||||
|
158 |- [] # comment2
|
||||||
|
157 |+value = not my_dict.get("key" # comment2
|
||||||
|
159 158 | ) # [RUF056]
|
||||||
|
160 159 |
|
||||||
|
161 160 | # testing invalid dict.get call with kwargs and inline comment
|
||||||
|
|
||||||
|
RUF056.py:163:25: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
161 | # testing invalid dict.get call with kwargs and inline comment
|
||||||
|
162 | value = not my_dict.get(key="key", # comment1
|
||||||
|
163 | default=False # comment2
|
||||||
|
| ^^^^^^^^^^^^^ RUF056
|
||||||
|
164 | ) # [RUF056]
|
||||||
|
165 | value = not my_dict.get(default=[], # comment1
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
159 159 | ) # [RUF056]
|
||||||
|
160 160 |
|
||||||
|
161 161 | # testing invalid dict.get call with kwargs and inline comment
|
||||||
|
162 |-value = not my_dict.get(key="key", # comment1
|
||||||
|
163 |- default=False # comment2
|
||||||
|
162 |+value = not my_dict.get(key="key" # comment2
|
||||||
|
164 163 | ) # [RUF056]
|
||||||
|
165 164 | value = not my_dict.get(default=[], # comment1
|
||||||
|
166 165 | key="key" # comment2
|
||||||
|
|
||||||
|
RUF056.py:165:25: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
163 | default=False # comment2
|
||||||
|
164 | ) # [RUF056]
|
||||||
|
165 | value = not my_dict.get(default=[], # comment1
|
||||||
|
| ^^^^^^^^^^ RUF056
|
||||||
|
166 | key="key" # comment2
|
||||||
|
167 | ) # [RUF056]
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
162 162 | value = not my_dict.get(key="key", # comment1
|
||||||
|
163 163 | default=False # comment2
|
||||||
|
164 164 | ) # [RUF056]
|
||||||
|
165 |-value = not my_dict.get(default=[], # comment1
|
||||||
|
165 |+value = not my_dict.get(# comment1
|
||||||
|
166 166 | key="key" # comment2
|
||||||
|
167 167 | ) # [RUF056]
|
||||||
|
168 168 |
|
||||||
|
|
||||||
|
RUF056.py:170:55: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
169 | # testing invalid dict.get calls
|
||||||
|
170 | value = not my_dict.get(key="key", other="something", default=False)
|
||||||
|
| ^^^^^^^^^^^^^ RUF056
|
||||||
|
171 | value = not my_dict.get(default=False, other="something", key="test")
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
167 167 | ) # [RUF056]
|
||||||
|
168 168 |
|
||||||
|
169 169 | # testing invalid dict.get calls
|
||||||
|
170 |-value = not my_dict.get(key="key", other="something", default=False)
|
||||||
|
170 |+value = not my_dict.get(key="key", other="something")
|
||||||
|
171 171 | value = not my_dict.get(default=False, other="something", key="test")
|
||||||
|
|
||||||
|
RUF056.py:171:25: RUF056 [*] Avoid providing a falsy fallback to `dict.get()` in boolean test positions. The default fallback `None` is already falsy.
|
||||||
|
|
|
||||||
|
169 | # testing invalid dict.get calls
|
||||||
|
170 | value = not my_dict.get(key="key", other="something", default=False)
|
||||||
|
171 | value = not my_dict.get(default=False, other="something", key="test")
|
||||||
|
| ^^^^^^^^^^^^^ RUF056
|
||||||
|
|
|
||||||
|
= help: Remove falsy fallback from `dict.get()`
|
||||||
|
|
||||||
|
ℹ Safe fix
|
||||||
|
168 168 |
|
||||||
|
169 169 | # testing invalid dict.get calls
|
||||||
|
170 170 | value = not my_dict.get(key="key", other="something", default=False)
|
||||||
|
171 |-value = not my_dict.get(default=False, other="something", key="test")
|
||||||
|
171 |+value = not my_dict.get(other="something", key="test")
|
|
@ -3780,6 +3780,15 @@ pub enum ArgOrKeyword<'a> {
|
||||||
Keyword(&'a Keyword),
|
Keyword(&'a Keyword),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ArgOrKeyword<'a> {
|
||||||
|
pub const fn value(&self) -> &'a Expr {
|
||||||
|
match self {
|
||||||
|
ArgOrKeyword::Arg(argument) => argument,
|
||||||
|
ArgOrKeyword::Keyword(keyword) => &keyword.value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a Expr> for ArgOrKeyword<'a> {
|
impl<'a> From<&'a Expr> for ArgOrKeyword<'a> {
|
||||||
fn from(arg: &'a Expr) -> Self {
|
fn from(arg: &'a Expr) -> Self {
|
||||||
Self::Arg(arg)
|
Self::Arg(arg)
|
||||||
|
@ -3828,15 +3837,24 @@ impl Arguments {
|
||||||
.nth(position)
|
.nth(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the argument with the given name or at the given position, or `None` if no such
|
/// Return the value for the argument with the given name or at the given position, or `None` if no such
|
||||||
/// argument exists. Used to retrieve arguments that can be provided _either_ as keyword or
|
/// argument exists. Used to retrieve argument values that can be provided _either_ as keyword or
|
||||||
/// positional arguments.
|
/// positional arguments.
|
||||||
pub fn find_argument(&self, name: &str, position: usize) -> Option<&Expr> {
|
pub fn find_argument_value(&self, name: &str, position: usize) -> Option<&Expr> {
|
||||||
self.find_keyword(name)
|
self.find_keyword(name)
|
||||||
.map(|keyword| &keyword.value)
|
.map(|keyword| &keyword.value)
|
||||||
.or_else(|| self.find_positional(position))
|
.or_else(|| self.find_positional(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the the argument with the given name or at the given position, or `None` if no such
|
||||||
|
/// argument exists. Used to retrieve arguments that can be provided _either_ as keyword or
|
||||||
|
/// positional arguments.
|
||||||
|
pub fn find_argument(&self, name: &str, position: usize) -> Option<ArgOrKeyword> {
|
||||||
|
self.find_keyword(name)
|
||||||
|
.map(ArgOrKeyword::from)
|
||||||
|
.or_else(|| self.find_positional(position).map(ArgOrKeyword::from))
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the positional and keyword arguments in the order of declaration.
|
/// Return the positional and keyword arguments in the order of declaration.
|
||||||
///
|
///
|
||||||
/// Positional arguments are generally before keyword arguments, but star arguments are an
|
/// Positional arguments are generally before keyword arguments, but star arguments are an
|
||||||
|
|
1
ruff.schema.json
generated
1
ruff.schema.json
generated
|
@ -3865,6 +3865,7 @@
|
||||||
"RUF051",
|
"RUF051",
|
||||||
"RUF052",
|
"RUF052",
|
||||||
"RUF055",
|
"RUF055",
|
||||||
|
"RUF056",
|
||||||
"RUF1",
|
"RUF1",
|
||||||
"RUF10",
|
"RUF10",
|
||||||
"RUF100",
|
"RUF100",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue