mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 02:13:08 +00:00
Upgrade RustPython (#4900)
This commit is contained in:
parent
4b78141f6b
commit
39a1f3980f
51 changed files with 416 additions and 320 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -2030,7 +2030,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruff_text_size"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=0dc8fdf52d146698c5bcf0b842fddc9e398ad8db#0dc8fdf52d146698c5bcf0b842fddc9e398ad8db"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
|
@ -2108,7 +2108,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=0dc8fdf52d146698c5bcf0b842fddc9e398ad8db#0dc8fdf52d146698c5bcf0b842fddc9e398ad8db"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"num-bigint",
|
||||
|
@ -2119,7 +2119,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-format"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=0dc8fdf52d146698c5bcf0b842fddc9e398ad8db#0dc8fdf52d146698c5bcf0b842fddc9e398ad8db"
|
||||
dependencies = [
|
||||
"bitflags 2.3.1",
|
||||
"itertools",
|
||||
|
@ -2131,7 +2131,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-literal"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=0dc8fdf52d146698c5bcf0b842fddc9e398ad8db#0dc8fdf52d146698c5bcf0b842fddc9e398ad8db"
|
||||
dependencies = [
|
||||
"hexf-parse",
|
||||
"is-macro",
|
||||
|
@ -2143,7 +2143,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=0dc8fdf52d146698c5bcf0b842fddc9e398ad8db#0dc8fdf52d146698c5bcf0b842fddc9e398ad8db"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"is-macro",
|
||||
|
@ -2166,7 +2166,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-parser-core"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd#7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd"
|
||||
source = "git+https://github.com/astral-sh/RustPython-Parser.git?rev=0dc8fdf52d146698c5bcf0b842fddc9e398ad8db#0dc8fdf52d146698c5bcf0b842fddc9e398ad8db"
|
||||
dependencies = [
|
||||
"is-macro",
|
||||
"ruff_text_size",
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -1,5 +1,6 @@
|
|||
[workspace]
|
||||
members = ["crates/*"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
|
@ -34,11 +35,11 @@ proc-macro2 = { version = "1.0.51" }
|
|||
quote = { version = "1.0.23" }
|
||||
regex = { version = "1.7.1" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd" }
|
||||
rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd", default-features = false, features = ["all-nodes-with-ranges"]}
|
||||
rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd" }
|
||||
rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd" }
|
||||
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "7a3eedbf6fb4ea7068a1bf7fe0e97e963ea95ffd", default-features = false, features = ["full-lexer", "all-nodes-with-ranges"] }
|
||||
ruff_text_size = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "0dc8fdf52d146698c5bcf0b842fddc9e398ad8db" }
|
||||
rustpython-ast = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "0dc8fdf52d146698c5bcf0b842fddc9e398ad8db", default-features = false, features = ["all-nodes-with-ranges"]}
|
||||
rustpython-format = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "0dc8fdf52d146698c5bcf0b842fddc9e398ad8db" }
|
||||
rustpython-literal = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "0dc8fdf52d146698c5bcf0b842fddc9e398ad8db" }
|
||||
rustpython-parser = { git = "https://github.com/astral-sh/RustPython-Parser.git", rev = "0dc8fdf52d146698c5bcf0b842fddc9e398ad8db", default-features = false, features = ["full-lexer", "all-nodes-with-ranges"] }
|
||||
schemars = { version = "0.8.12" }
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = { version = "1.0.93", features = ["preserve_order"] }
|
||||
|
|
|
@ -1833,8 +1833,8 @@ where
|
|||
}) => {
|
||||
// Visit the decorators and arguments, but avoid the body, which will be
|
||||
// deferred.
|
||||
for expr in decorator_list {
|
||||
self.visit_expr(expr);
|
||||
for decorator in decorator_list {
|
||||
self.visit_decorator(decorator);
|
||||
}
|
||||
|
||||
// Function annotations are always evaluated at runtime, unless future annotations
|
||||
|
@ -1943,8 +1943,8 @@ where
|
|||
for keyword in keywords {
|
||||
self.visit_keyword(keyword);
|
||||
}
|
||||
for expr in decorator_list {
|
||||
self.visit_expr(expr);
|
||||
for decorator in decorator_list {
|
||||
self.visit_decorator(decorator);
|
||||
}
|
||||
|
||||
let definition = docstrings::extraction::extract_definition(
|
||||
|
|
|
@ -7,7 +7,7 @@ use ruff_python_semantic::model::SemanticModel;
|
|||
|
||||
pub(super) fn match_function_def(
|
||||
stmt: &Stmt,
|
||||
) -> (&str, &Arguments, Option<&Expr>, &[Stmt], &[Expr]) {
|
||||
) -> (&str, &Arguments, Option<&Expr>, &[Stmt], &[ast::Decorator]) {
|
||||
match stmt {
|
||||
Stmt::FunctionDef(ast::StmtFunctionDef {
|
||||
name,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Arguments, Expr};
|
||||
use rustpython_parser::ast::{Arguments, Decorator};
|
||||
|
||||
use ruff_diagnostics::Violation;
|
||||
|
||||
|
@ -61,15 +61,16 @@ impl Violation for BooleanDefaultValueInFunctionDefinition {
|
|||
pub(crate) fn check_boolean_default_value_in_function_definition(
|
||||
checker: &mut Checker,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
arguments: &Arguments,
|
||||
) {
|
||||
if FUNC_DEF_NAME_ALLOWLIST.contains(&name) {
|
||||
return;
|
||||
}
|
||||
|
||||
if decorator_list.iter().any(|expr| {
|
||||
collect_call_path(expr).map_or(false, |call_path| call_path.as_slice() == [name, "setter"])
|
||||
if decorator_list.iter().any(|decorator| {
|
||||
collect_call_path(&decorator.expression)
|
||||
.map_or(false, |call_path| call_path.as_slice() == [name, "setter"])
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Arguments, Constant, Expr, Ranged};
|
||||
use rustpython_parser::ast::{self, Arguments, Constant, Decorator, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Violation;
|
||||
|
@ -79,15 +79,16 @@ impl Violation for BooleanPositionalArgInFunctionDefinition {
|
|||
pub(crate) fn check_positional_boolean_in_def(
|
||||
checker: &mut Checker,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
arguments: &Arguments,
|
||||
) {
|
||||
if FUNC_DEF_NAME_ALLOWLIST.contains(&name) {
|
||||
return;
|
||||
}
|
||||
|
||||
if decorator_list.iter().any(|expr| {
|
||||
collect_call_path(expr).map_or(false, |call_path| call_path.as_slice() == [name, "setter"])
|
||||
if decorator_list.iter().any(|decorator| {
|
||||
collect_call_path(&decorator.expression)
|
||||
.map_or(false, |call_path| call_path.as_slice() == [name, "setter"])
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
use rustpython_parser::ast::{self, Decorator, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -26,14 +26,14 @@ fn is_cache_func(model: &SemanticModel, expr: &Expr) -> bool {
|
|||
}
|
||||
|
||||
/// B019
|
||||
pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Expr]) {
|
||||
pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Decorator]) {
|
||||
if !checker.semantic_model().scope().kind.is_class() {
|
||||
return;
|
||||
}
|
||||
for decorator in decorator_list {
|
||||
// TODO(charlie): This should take into account `classmethod-decorators` and
|
||||
// `staticmethod-decorators`.
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = decorator {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = &decorator.expression {
|
||||
if id == "classmethod" || id == "staticmethod" {
|
||||
return;
|
||||
}
|
||||
|
@ -42,9 +42,9 @@ pub(crate) fn cached_instance_method(checker: &mut Checker, decorator_list: &[Ex
|
|||
for decorator in decorator_list {
|
||||
if is_cache_func(
|
||||
checker.semantic_model(),
|
||||
match decorator {
|
||||
match &decorator.expression {
|
||||
Expr::Call(ast::ExprCall { func, .. }) => func,
|
||||
_ => decorator,
|
||||
_ => &decorator.expression,
|
||||
},
|
||||
) {
|
||||
checker
|
||||
|
|
|
@ -1,81 +1,81 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
|
||||
---
|
||||
B019.py:78:6: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
B019.py:78:5: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
|
|
||||
78 | # Remaining methods should emit B019
|
||||
79 | @functools.cache
|
||||
| ^^^^^^^^^^^^^^^ B019
|
||||
| ^^^^^^^^^^^^^^^^ B019
|
||||
80 | def cached_instance_method(self, y):
|
||||
81 | ...
|
||||
|
|
||||
|
||||
B019.py:82:6: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
B019.py:82:5: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
|
|
||||
82 | ...
|
||||
83 |
|
||||
84 | @cache
|
||||
| ^^^^^ B019
|
||||
| ^^^^^^ B019
|
||||
85 | def another_cached_instance_method(self, y):
|
||||
86 | ...
|
||||
|
|
||||
|
||||
B019.py:86:6: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
B019.py:86:5: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
|
|
||||
86 | ...
|
||||
87 |
|
||||
88 | @functools.cache()
|
||||
| ^^^^^^^^^^^^^^^^^ B019
|
||||
| ^^^^^^^^^^^^^^^^^^ B019
|
||||
89 | def called_cached_instance_method(self, y):
|
||||
90 | ...
|
||||
|
|
||||
|
||||
B019.py:90:6: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
B019.py:90:5: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
|
|
||||
90 | ...
|
||||
91 |
|
||||
92 | @cache()
|
||||
| ^^^^^^^ B019
|
||||
| ^^^^^^^^ B019
|
||||
93 | def another_called_cached_instance_method(self, y):
|
||||
94 | ...
|
||||
|
|
||||
|
||||
B019.py:94:6: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
B019.py:94:5: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
|
|
||||
94 | ...
|
||||
95 |
|
||||
96 | @functools.lru_cache
|
||||
| ^^^^^^^^^^^^^^^^^^^ B019
|
||||
| ^^^^^^^^^^^^^^^^^^^^ B019
|
||||
97 | def lru_cached_instance_method(self, y):
|
||||
98 | ...
|
||||
|
|
||||
|
||||
B019.py:98:6: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
B019.py:98:5: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
|
|
||||
98 | ...
|
||||
99 |
|
||||
100 | @lru_cache
|
||||
| ^^^^^^^^^ B019
|
||||
| ^^^^^^^^^^ B019
|
||||
101 | def another_lru_cached_instance_method(self, y):
|
||||
102 | ...
|
||||
|
|
||||
|
||||
B019.py:102:6: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
B019.py:102:5: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
|
|
||||
102 | ...
|
||||
103 |
|
||||
104 | @functools.lru_cache()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ B019
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ B019
|
||||
105 | def called_lru_cached_instance_method(self, y):
|
||||
106 | ...
|
||||
|
|
||||
|
||||
B019.py:106:6: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
B019.py:106:5: B019 Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks
|
||||
|
|
||||
106 | ...
|
||||
107 |
|
||||
108 | @lru_cache()
|
||||
| ^^^^^^^^^^^ B019
|
||||
| ^^^^^^^^^^^^ B019
|
||||
109 | def another_called_lru_cached_instance_method(self, y):
|
||||
110 | ...
|
||||
|
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
use rustpython_parser::ast::{self, Decorator, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -49,7 +49,7 @@ impl Violation for DjangoNonLeadingReceiverDecorator {
|
|||
|
||||
/// DJ013
|
||||
pub(crate) fn non_leading_receiver_decorator<'a, F>(
|
||||
decorator_list: &'a [Expr],
|
||||
decorator_list: &'a [Decorator],
|
||||
resolve_call_path: F,
|
||||
) -> Vec<Diagnostic>
|
||||
where
|
||||
|
@ -58,7 +58,7 @@ where
|
|||
let mut diagnostics = vec![];
|
||||
let mut seen_receiver = false;
|
||||
for (i, decorator) in decorator_list.iter().enumerate() {
|
||||
let is_receiver = match decorator {
|
||||
let is_receiver = match &decorator.expression {
|
||||
Expr::Call(ast::ExprCall { func, .. }) => resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "dispatch", "receiver"]
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_django/mod.rs
|
||||
---
|
||||
DJ013.py:15:2: DJ013 `@receiver` decorator must be on top of all the other decorators
|
||||
DJ013.py:15:1: DJ013 `@receiver` decorator must be on top of all the other decorators
|
||||
|
|
||||
15 | @test_decorator
|
||||
16 | @receiver(pre_save, sender=MyModel)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DJ013
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DJ013
|
||||
17 | def incorrect_pre_save_handler():
|
||||
18 | pass
|
||||
|
|
||||
|
||||
DJ013.py:35:2: DJ013 `@receiver` decorator must be on top of all the other decorators
|
||||
DJ013.py:35:1: DJ013 `@receiver` decorator must be on top of all the other decorators
|
||||
|
|
||||
35 | @receiver(pre_save, sender=MyModel)
|
||||
36 | @test_decorator
|
||||
37 | @receiver(pre_save, sender=MyModel)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DJ013
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ DJ013
|
||||
38 | def incorrect_multiple():
|
||||
39 | pass
|
||||
|
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Arguments, Expr, Stmt};
|
||||
use rustpython_parser::ast::{self, Arguments, Decorator, Expr, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -114,7 +114,7 @@ pub(crate) fn non_self_return_type(
|
|||
checker: &mut Checker,
|
||||
stmt: &Stmt,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
returns: Option<&Expr>,
|
||||
args: &Arguments,
|
||||
async_: bool,
|
||||
|
|
|
@ -9,6 +9,7 @@ use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
|||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::collect_call_path;
|
||||
use ruff_python_ast::helpers::collect_arg_names;
|
||||
use ruff_python_ast::prelude::Decorator;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::visitor::Visitor;
|
||||
use ruff_python_ast::{helpers, visitor};
|
||||
|
@ -243,7 +244,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn get_fixture_decorator<'a>(model: &SemanticModel, decorators: &'a [Expr]) -> Option<&'a Expr> {
|
||||
fn get_fixture_decorator<'a>(
|
||||
model: &SemanticModel,
|
||||
decorators: &'a [Decorator],
|
||||
) -> Option<&'a Decorator> {
|
||||
decorators.iter().find(|decorator| {
|
||||
is_pytest_fixture(model, decorator) || is_pytest_yield_fixture(model, decorator)
|
||||
})
|
||||
|
@ -251,7 +255,7 @@ fn get_fixture_decorator<'a>(model: &SemanticModel, decorators: &'a [Expr]) -> O
|
|||
|
||||
fn pytest_fixture_parentheses(
|
||||
checker: &mut Checker,
|
||||
decorator: &Expr,
|
||||
decorator: &Decorator,
|
||||
fix: Fix,
|
||||
expected: Parentheses,
|
||||
actual: Parentheses,
|
||||
|
@ -277,8 +281,8 @@ pub(crate) fn fix_extraneous_scope_function(
|
|||
}
|
||||
|
||||
/// PT001, PT002, PT003
|
||||
fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &Expr) {
|
||||
match decorator {
|
||||
fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &Decorator) {
|
||||
match &decorator.expression {
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
|
@ -431,7 +435,7 @@ fn check_test_function_args(checker: &mut Checker, args: &Arguments) {
|
|||
}
|
||||
|
||||
/// PT020
|
||||
fn check_fixture_decorator_name(checker: &mut Checker, decorator: &Expr) {
|
||||
fn check_fixture_decorator_name(checker: &mut Checker, decorator: &Decorator) {
|
||||
if is_pytest_yield_fixture(checker.semantic_model(), decorator) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PytestDeprecatedYieldFixture,
|
||||
|
@ -461,7 +465,7 @@ fn check_fixture_addfinalizer(checker: &mut Checker, args: &Arguments, body: &[S
|
|||
}
|
||||
|
||||
/// PT024, PT025
|
||||
fn check_fixture_marks(checker: &mut Checker, decorators: &[Expr]) {
|
||||
fn check_fixture_marks(checker: &mut Checker, decorators: &[Decorator]) {
|
||||
for (expr, call_path) in get_mark_decorators(decorators) {
|
||||
let name = call_path.last().expect("Expected a mark name");
|
||||
if checker.enabled(Rule::PytestUnnecessaryAsyncioMarkOnFixture) {
|
||||
|
@ -497,7 +501,7 @@ pub(crate) fn fixture(
|
|||
stmt: &Stmt,
|
||||
name: &str,
|
||||
args: &Arguments,
|
||||
decorators: &[Expr],
|
||||
decorators: &[Decorator],
|
||||
body: &[Stmt],
|
||||
) {
|
||||
let decorator = get_fixture_decorator(checker.semantic_model(), decorators);
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
use rustpython_parser::ast::{self, Constant, Expr, Keyword};
|
||||
use rustpython_parser::ast::{self, Constant, Decorator, Expr, Keyword};
|
||||
|
||||
use ruff_python_ast::call_path::{collect_call_path, CallPath};
|
||||
use ruff_python_ast::helpers::map_callable;
|
||||
use ruff_python_semantic::model::SemanticModel;
|
||||
|
||||
pub(super) fn get_mark_decorators(decorators: &[Expr]) -> impl Iterator<Item = (&Expr, CallPath)> {
|
||||
pub(super) fn get_mark_decorators(
|
||||
decorators: &[Decorator],
|
||||
) -> impl Iterator<Item = (&Decorator, CallPath)> {
|
||||
decorators.iter().filter_map(|decorator| {
|
||||
let Some(call_path) = collect_call_path(map_callable(decorator)) else {
|
||||
let Some(call_path) = collect_call_path(map_callable(&decorator.expression)) else {
|
||||
return None;
|
||||
};
|
||||
if call_path.len() > 2 && call_path.as_slice()[..2] == ["pytest", "mark"] {
|
||||
|
@ -23,25 +25,25 @@ pub(super) fn is_pytest_fail(model: &SemanticModel, call: &Expr) -> bool {
|
|||
})
|
||||
}
|
||||
|
||||
pub(super) fn is_pytest_fixture(model: &SemanticModel, decorator: &Expr) -> bool {
|
||||
pub(super) fn is_pytest_fixture(model: &SemanticModel, decorator: &Decorator) -> bool {
|
||||
model
|
||||
.resolve_call_path(map_callable(decorator))
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pytest", "fixture"]
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn is_pytest_yield_fixture(model: &SemanticModel, decorator: &Expr) -> bool {
|
||||
pub(super) fn is_pytest_yield_fixture(model: &SemanticModel, decorator: &Decorator) -> bool {
|
||||
model
|
||||
.resolve_call_path(map_callable(decorator))
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pytest", "yield_fixture"]
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn is_pytest_parametrize(model: &SemanticModel, decorator: &Expr) -> bool {
|
||||
pub(super) fn is_pytest_parametrize(model: &SemanticModel, decorator: &Decorator) -> bool {
|
||||
model
|
||||
.resolve_call_path(map_callable(decorator))
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pytest", "mark", "parametrize"]
|
||||
})
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use ruff_text_size::TextSize;
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
use rustpython_parser::ast::{self, Decorator, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -52,7 +51,7 @@ impl AlwaysAutofixableViolation for PytestUseFixturesWithoutParameters {
|
|||
|
||||
fn pytest_mark_parentheses(
|
||||
checker: &mut Checker,
|
||||
decorator: &Expr,
|
||||
decorator: &Decorator,
|
||||
call_path: &CallPath,
|
||||
fix: Fix,
|
||||
preferred: &str,
|
||||
|
@ -72,8 +71,8 @@ fn pytest_mark_parentheses(
|
|||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
fn check_mark_parentheses(checker: &mut Checker, decorator: &Expr, call_path: &CallPath) {
|
||||
match decorator {
|
||||
fn check_mark_parentheses(checker: &mut Checker, decorator: &Decorator, call_path: &CallPath) {
|
||||
match &decorator.expression {
|
||||
Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
|
@ -99,14 +98,14 @@ fn check_mark_parentheses(checker: &mut Checker, decorator: &Expr, call_path: &C
|
|||
}
|
||||
}
|
||||
|
||||
fn check_useless_usefixtures(checker: &mut Checker, decorator: &Expr, call_path: &CallPath) {
|
||||
fn check_useless_usefixtures(checker: &mut Checker, decorator: &Decorator, call_path: &CallPath) {
|
||||
if *call_path.last().unwrap() != "usefixtures" {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut has_parameters = false;
|
||||
|
||||
if let Expr::Call(ast::ExprCall { args, keywords, .. }) = decorator {
|
||||
if let Expr::Call(ast::ExprCall { args, keywords, .. }) = &decorator.expression {
|
||||
if !args.is_empty() || !keywords.is_empty() {
|
||||
has_parameters = true;
|
||||
}
|
||||
|
@ -116,24 +115,22 @@ fn check_useless_usefixtures(checker: &mut Checker, decorator: &Expr, call_path:
|
|||
let mut diagnostic = Diagnostic::new(PytestUseFixturesWithoutParameters, decorator.range());
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
#[allow(deprecated)]
|
||||
diagnostic.set_fix(Fix::unspecified(Edit::range_deletion(
|
||||
decorator.range().sub_start(TextSize::from(1)),
|
||||
)));
|
||||
diagnostic.set_fix(Fix::unspecified(Edit::range_deletion(decorator.range())));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn marks(checker: &mut Checker, decorators: &[Expr]) {
|
||||
pub(crate) fn marks(checker: &mut Checker, decorators: &[Decorator]) {
|
||||
let enforce_parentheses = checker.enabled(Rule::PytestIncorrectMarkParenthesesStyle);
|
||||
let enforce_useless_usefixtures = checker.enabled(Rule::PytestUseFixturesWithoutParameters);
|
||||
|
||||
for (expr, call_path) in get_mark_decorators(decorators) {
|
||||
for (decorator, call_path) in get_mark_decorators(decorators) {
|
||||
if enforce_parentheses {
|
||||
check_mark_parentheses(checker, expr, &call_path);
|
||||
check_mark_parentheses(checker, decorator, &call_path);
|
||||
}
|
||||
if enforce_useless_usefixtures {
|
||||
check_useless_usefixtures(checker, expr, &call_path);
|
||||
check_useless_usefixtures(checker, decorator, &call_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, ExprContext, Ranged};
|
||||
use rustpython_parser::ast::{self, Constant, Decorator, Expr, ExprContext, Ranged};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
|
||||
|
@ -94,7 +94,7 @@ fn elts_to_csv(elts: &[Expr], generator: Generator) -> Option<String> {
|
|||
/// ```
|
||||
///
|
||||
/// This method assumes that the first argument is a string.
|
||||
fn get_parametrize_name_range(decorator: &Expr, expr: &Expr, locator: &Locator) -> TextRange {
|
||||
fn get_parametrize_name_range(decorator: &Decorator, expr: &Expr, locator: &Locator) -> TextRange {
|
||||
let mut locations = Vec::new();
|
||||
let mut implicit_concat = None;
|
||||
|
||||
|
@ -128,7 +128,7 @@ fn get_parametrize_name_range(decorator: &Expr, expr: &Expr, locator: &Locator)
|
|||
}
|
||||
|
||||
/// PT006
|
||||
fn check_names(checker: &mut Checker, decorator: &Expr, expr: &Expr) {
|
||||
fn check_names(checker: &mut Checker, decorator: &Decorator, expr: &Expr) {
|
||||
let names_type = checker.settings.flake8_pytest_style.parametrize_names_type;
|
||||
|
||||
match expr {
|
||||
|
@ -417,10 +417,10 @@ fn handle_value_rows(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Expr]) {
|
||||
pub(crate) fn parametrize(checker: &mut Checker, decorators: &[Decorator]) {
|
||||
for decorator in decorators {
|
||||
if is_pytest_parametrize(checker.semantic_model(), decorator) {
|
||||
if let Expr::Call(ast::ExprCall { args, .. }) = decorator {
|
||||
if let Expr::Call(ast::ExprCall { args, .. }) = &decorator.expression {
|
||||
if checker.enabled(Rule::PytestParametrizeNamesWrongType) {
|
||||
if let Some(names) = args.get(0) {
|
||||
check_names(checker, decorator, names);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT001.py:9:2: PT001 [*] Use `@pytest.fixture()` over `@pytest.fixture`
|
||||
PT001.py:9:1: PT001 [*] Use `@pytest.fixture()` over `@pytest.fixture`
|
||||
|
|
||||
9 | @pytest.fixture
|
||||
| ^^^^^^^^^^^^^^ PT001
|
||||
| ^^^^^^^^^^^^^^^ PT001
|
||||
10 | def no_parentheses():
|
||||
11 | return 42
|
||||
|
|
||||
|
@ -20,10 +20,10 @@ PT001.py:9:2: PT001 [*] Use `@pytest.fixture()` over `@pytest.fixture`
|
|||
11 11 | return 42
|
||||
12 12 |
|
||||
|
||||
PT001.py:34:2: PT001 [*] Use `@pytest.fixture()` over `@pytest.fixture`
|
||||
PT001.py:34:1: PT001 [*] Use `@pytest.fixture()` over `@pytest.fixture`
|
||||
|
|
||||
34 | @fixture
|
||||
| ^^^^^^^ PT001
|
||||
| ^^^^^^^^ PT001
|
||||
35 | def imported_from_no_parentheses():
|
||||
36 | return 42
|
||||
|
|
||||
|
@ -39,10 +39,10 @@ PT001.py:34:2: PT001 [*] Use `@pytest.fixture()` over `@pytest.fixture`
|
|||
36 36 | return 42
|
||||
37 37 |
|
||||
|
||||
PT001.py:59:2: PT001 [*] Use `@pytest.fixture()` over `@pytest.fixture`
|
||||
PT001.py:59:1: PT001 [*] Use `@pytest.fixture()` over `@pytest.fixture`
|
||||
|
|
||||
59 | @aliased
|
||||
| ^^^^^^^ PT001
|
||||
| ^^^^^^^^ PT001
|
||||
60 | def aliased_no_parentheses():
|
||||
61 | return 42
|
||||
|
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT001.py:14:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
PT001.py:14:1: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
|
|
||||
14 | @pytest.fixture()
|
||||
| ^^^^^^^^^^^^^^^^ PT001
|
||||
| ^^^^^^^^^^^^^^^^^ PT001
|
||||
15 | def parentheses_no_params():
|
||||
16 | return 42
|
||||
|
|
||||
|
@ -20,10 +20,9 @@ PT001.py:14:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
|||
16 16 | return 42
|
||||
17 17 |
|
||||
|
||||
PT001.py:24:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
PT001.py:24:1: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
|
|
||||
24 | @pytest.fixture(
|
||||
| __^
|
||||
24 | / @pytest.fixture(
|
||||
25 | |
|
||||
26 | | )
|
||||
| |_^ PT001
|
||||
|
@ -44,10 +43,10 @@ PT001.py:24:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
|||
28 26 | return 42
|
||||
29 27 |
|
||||
|
||||
PT001.py:39:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
PT001.py:39:1: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
|
|
||||
39 | @fixture()
|
||||
| ^^^^^^^^^ PT001
|
||||
| ^^^^^^^^^^ PT001
|
||||
40 | def imported_from_parentheses_no_params():
|
||||
41 | return 42
|
||||
|
|
||||
|
@ -63,10 +62,9 @@ PT001.py:39:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
|||
41 41 | return 42
|
||||
42 42 |
|
||||
|
||||
PT001.py:49:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
PT001.py:49:1: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
|
|
||||
49 | @fixture(
|
||||
| __^
|
||||
49 | / @fixture(
|
||||
50 | |
|
||||
51 | | )
|
||||
| |_^ PT001
|
||||
|
@ -87,10 +85,10 @@ PT001.py:49:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
|||
53 51 | return 42
|
||||
54 52 |
|
||||
|
||||
PT001.py:64:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
PT001.py:64:1: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
|
|
||||
64 | @aliased()
|
||||
| ^^^^^^^^^ PT001
|
||||
| ^^^^^^^^^^ PT001
|
||||
65 | def aliased_parentheses_no_params():
|
||||
66 | return 42
|
||||
|
|
||||
|
@ -106,10 +104,9 @@ PT001.py:64:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
|||
66 66 | return 42
|
||||
67 67 |
|
||||
|
||||
PT001.py:74:2: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
PT001.py:74:1: PT001 [*] Use `@pytest.fixture` over `@pytest.fixture()`
|
||||
|
|
||||
74 | @aliased(
|
||||
| __^
|
||||
74 | / @aliased(
|
||||
75 | |
|
||||
76 | | )
|
||||
| |_^ PT001
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT002.py:14:2: PT002 Configuration for fixture `my_fixture` specified via positional args, use kwargs
|
||||
PT002.py:14:1: PT002 Configuration for fixture `my_fixture` specified via positional args, use kwargs
|
||||
|
|
||||
14 | @pytest.fixture("module")
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ PT002
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PT002
|
||||
15 | def my_fixture(): # Error only args
|
||||
16 | return 0
|
||||
|
|
||||
|
||||
PT002.py:19:2: PT002 Configuration for fixture `my_fixture` specified via positional args, use kwargs
|
||||
PT002.py:19:1: PT002 Configuration for fixture `my_fixture` specified via positional args, use kwargs
|
||||
|
|
||||
19 | @pytest.fixture("module", autouse=True)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PT002
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PT002
|
||||
20 | def my_fixture(): # Error mixed
|
||||
21 | return 0
|
||||
|
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT020.py:14:2: PT020 `@pytest.yield_fixture` is deprecated, use `@pytest.fixture`
|
||||
PT020.py:14:1: PT020 `@pytest.yield_fixture` is deprecated, use `@pytest.fixture`
|
||||
|
|
||||
14 | @pytest.yield_fixture()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ PT020
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ PT020
|
||||
15 | def error_without_parens():
|
||||
16 | return 0
|
||||
|
|
||||
|
||||
PT020.py:19:2: PT020 `@pytest.yield_fixture` is deprecated, use `@pytest.fixture`
|
||||
PT020.py:19:1: PT020 `@pytest.yield_fixture` is deprecated, use `@pytest.fixture`
|
||||
|
|
||||
19 | @pytest.yield_fixture
|
||||
| ^^^^^^^^^^^^^^^^^^^^ PT020
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ PT020
|
||||
20 | def error_with_parens():
|
||||
21 | return 0
|
||||
|
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT023.py:12:2: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
PT023.py:12:1: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
12 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
13 | def test_something():
|
||||
14 | pass
|
||||
|
|
||||
|
@ -20,10 +20,10 @@ PT023.py:12:2: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
|||
14 14 | pass
|
||||
15 15 |
|
||||
|
||||
PT023.py:17:2: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
PT023.py:17:1: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
17 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
18 | class TestClass:
|
||||
19 | def test_something():
|
||||
|
|
||||
|
@ -39,11 +39,11 @@ PT023.py:17:2: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
|||
19 19 | def test_something():
|
||||
20 20 | pass
|
||||
|
||||
PT023.py:24:6: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
PT023.py:24:5: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
24 | class TestClass:
|
||||
25 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
26 | def test_something():
|
||||
27 | pass
|
||||
|
|
||||
|
@ -59,11 +59,11 @@ PT023.py:24:6: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
|||
26 26 | pass
|
||||
27 27 |
|
||||
|
||||
PT023.py:30:6: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
PT023.py:30:5: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
30 | class TestClass:
|
||||
31 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
32 | class TestNestedClass:
|
||||
33 | def test_something():
|
||||
|
|
||||
|
@ -79,12 +79,12 @@ PT023.py:30:6: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
|||
32 32 | def test_something():
|
||||
33 33 | pass
|
||||
|
||||
PT023.py:38:10: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
PT023.py:38:9: PT023 [*] Use `@pytest.mark.foo()` over `@pytest.mark.foo`
|
||||
|
|
||||
38 | class TestClass:
|
||||
39 | class TestNestedClass:
|
||||
40 | @pytest.mark.foo
|
||||
| ^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^ PT023
|
||||
41 | def test_something():
|
||||
42 | pass
|
||||
|
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT023.py:46:2: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
PT023.py:46:1: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
46 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
47 | def test_something():
|
||||
48 | pass
|
||||
|
|
||||
|
@ -20,10 +20,10 @@ PT023.py:46:2: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
|||
48 48 | pass
|
||||
49 49 |
|
||||
|
||||
PT023.py:51:2: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
PT023.py:51:1: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
51 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
52 | class TestClass:
|
||||
53 | def test_something():
|
||||
|
|
||||
|
@ -39,11 +39,11 @@ PT023.py:51:2: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
|||
53 53 | def test_something():
|
||||
54 54 | pass
|
||||
|
||||
PT023.py:58:6: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
PT023.py:58:5: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
58 | class TestClass:
|
||||
59 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
60 | def test_something():
|
||||
61 | pass
|
||||
|
|
||||
|
@ -59,11 +59,11 @@ PT023.py:58:6: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
|||
60 60 | pass
|
||||
61 61 |
|
||||
|
||||
PT023.py:64:6: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
PT023.py:64:5: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
64 | class TestClass:
|
||||
65 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
66 | class TestNestedClass:
|
||||
67 | def test_something():
|
||||
|
|
||||
|
@ -79,12 +79,12 @@ PT023.py:64:6: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
|||
66 66 | def test_something():
|
||||
67 67 | pass
|
||||
|
||||
PT023.py:72:10: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
PT023.py:72:9: PT023 [*] Use `@pytest.mark.foo` over `@pytest.mark.foo()`
|
||||
|
|
||||
72 | class TestClass:
|
||||
73 | class TestNestedClass:
|
||||
74 | @pytest.mark.foo()
|
||||
| ^^^^^^^^^^^^^^^^^ PT023
|
||||
| ^^^^^^^^^^^^^^^^^^ PT023
|
||||
75 | def test_something():
|
||||
76 | pass
|
||||
|
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT024.py:14:2: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
||||
PT024.py:14:1: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
||||
|
|
||||
14 | @pytest.mark.asyncio()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ PT024
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ PT024
|
||||
15 | @pytest.fixture()
|
||||
16 | async def my_fixture(): # Error before
|
||||
|
|
||||
|
@ -19,10 +19,10 @@ PT024.py:14:2: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
|||
16 15 | async def my_fixture(): # Error before
|
||||
17 16 | return 0
|
||||
|
||||
PT024.py:20:2: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
||||
PT024.py:20:1: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
||||
|
|
||||
20 | @pytest.mark.asyncio
|
||||
| ^^^^^^^^^^^^^^^^^^^ PT024
|
||||
| ^^^^^^^^^^^^^^^^^^^^ PT024
|
||||
21 | @pytest.fixture()
|
||||
22 | async def my_fixture(): # Error before no parens
|
||||
|
|
||||
|
@ -37,11 +37,11 @@ PT024.py:20:2: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
|||
22 21 | async def my_fixture(): # Error before no parens
|
||||
23 22 | return 0
|
||||
|
||||
PT024.py:27:2: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
||||
PT024.py:27:1: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
||||
|
|
||||
27 | @pytest.fixture()
|
||||
28 | @pytest.mark.asyncio()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ PT024
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ PT024
|
||||
29 | async def my_fixture(): # Error after
|
||||
30 | return 0
|
||||
|
|
||||
|
@ -56,11 +56,11 @@ PT024.py:27:2: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
|||
29 28 | return 0
|
||||
30 29 |
|
||||
|
||||
PT024.py:33:2: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
||||
PT024.py:33:1: PT024 [*] `pytest.mark.asyncio` is unnecessary for fixtures
|
||||
|
|
||||
33 | @pytest.fixture()
|
||||
34 | @pytest.mark.asyncio
|
||||
| ^^^^^^^^^^^^^^^^^^^ PT024
|
||||
| ^^^^^^^^^^^^^^^^^^^^ PT024
|
||||
35 | async def my_fixture(): # Error after no parens
|
||||
36 | return 0
|
||||
|
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT025.py:9:2: PT025 [*] `pytest.mark.usefixtures` has no effect on fixtures
|
||||
PT025.py:9:1: PT025 [*] `pytest.mark.usefixtures` has no effect on fixtures
|
||||
|
|
||||
9 | @pytest.mark.usefixtures("a")
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PT025
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PT025
|
||||
10 | @pytest.fixture()
|
||||
11 | def my_fixture(): # Error before
|
||||
|
|
||||
|
@ -19,11 +19,11 @@ PT025.py:9:2: PT025 [*] `pytest.mark.usefixtures` has no effect on fixtures
|
|||
11 10 | def my_fixture(): # Error before
|
||||
12 11 | return 0
|
||||
|
||||
PT025.py:16:2: PT025 [*] `pytest.mark.usefixtures` has no effect on fixtures
|
||||
PT025.py:16:1: PT025 [*] `pytest.mark.usefixtures` has no effect on fixtures
|
||||
|
|
||||
16 | @pytest.fixture()
|
||||
17 | @pytest.mark.usefixtures("a")
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PT025
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PT025
|
||||
18 | def my_fixture(): # Error after
|
||||
19 | return 0
|
||||
|
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pytest_style/mod.rs
|
||||
---
|
||||
PT026.py:19:2: PT026 [*] Useless `pytest.mark.usefixtures` without parameters
|
||||
PT026.py:19:1: PT026 [*] Useless `pytest.mark.usefixtures` without parameters
|
||||
|
|
||||
19 | @pytest.mark.usefixtures()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PT026
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ PT026
|
||||
20 | def test_error_with_parens():
|
||||
21 | pass
|
||||
|
|
||||
|
@ -20,10 +20,10 @@ PT026.py:19:2: PT026 [*] Useless `pytest.mark.usefixtures` without parameters
|
|||
21 21 | pass
|
||||
22 22 |
|
||||
|
||||
PT026.py:24:2: PT026 [*] Useless `pytest.mark.usefixtures` without parameters
|
||||
PT026.py:24:1: PT026 [*] Useless `pytest.mark.usefixtures` without parameters
|
||||
|
|
||||
24 | @pytest.mark.usefixtures
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ PT026
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ PT026
|
||||
25 | def test_error_no_parens():
|
||||
26 | pass
|
||||
|
|
||||
|
|
|
@ -87,8 +87,8 @@ impl<'a> Visitor<'a> for ReturnVisitor<'a> {
|
|||
.push(stmt.start());
|
||||
|
||||
// Don't recurse into the body, but visit the decorators, etc.
|
||||
for expr in decorator_list {
|
||||
visitor::walk_expr(self, expr);
|
||||
for decorator in decorator_list {
|
||||
visitor::walk_decorator(self, decorator);
|
||||
}
|
||||
}
|
||||
Stmt::FunctionDef(ast::StmtFunctionDef {
|
||||
|
@ -113,8 +113,8 @@ impl<'a> Visitor<'a> for ReturnVisitor<'a> {
|
|||
.push(stmt.start());
|
||||
|
||||
// Don't recurse into the body, but visit the decorators, etc.
|
||||
for expr in decorator_list {
|
||||
visitor::walk_expr(self, expr);
|
||||
for decorator in decorator_list {
|
||||
visitor::walk_decorator(self, decorator);
|
||||
}
|
||||
if let Some(returns) = returns {
|
||||
visitor::walk_expr(self, returns);
|
||||
|
|
|
@ -63,7 +63,9 @@ fn runtime_evaluated_decorators(semantic_model: &SemanticModel, decorators: &[St
|
|||
if let ScopeKind::Class(ast::StmtClassDef { decorator_list, .. }) = &semantic_model.scope().kind
|
||||
{
|
||||
for decorator in decorator_list.iter() {
|
||||
if let Some(call_path) = semantic_model.resolve_call_path(map_callable(decorator)) {
|
||||
if let Some(call_path) =
|
||||
semantic_model.resolve_call_path(map_callable(&decorator.expression))
|
||||
{
|
||||
if decorators
|
||||
.iter()
|
||||
.any(|decorator| from_qualified_name(decorator) == call_path)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Arguments, Expr, Ranged};
|
||||
use rustpython_parser::ast::{Arguments, Decorator, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -59,7 +59,7 @@ pub(crate) fn invalid_first_argument_name_for_class_method(
|
|||
checker: &Checker,
|
||||
scope: &Scope,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
args: &Arguments,
|
||||
) -> Option<Diagnostic> {
|
||||
if !matches!(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Arguments, Expr, Ranged};
|
||||
use rustpython_parser::ast::{Arguments, Decorator, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -56,7 +56,7 @@ pub(crate) fn invalid_first_argument_name_for_method(
|
|||
checker: &Checker,
|
||||
scope: &Scope,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
args: &Arguments,
|
||||
) -> Option<Diagnostic> {
|
||||
if !matches!(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{Expr, Stmt};
|
||||
use rustpython_parser::ast::{Decorator, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -51,7 +51,7 @@ impl Violation for InvalidFunctionName {
|
|||
pub(crate) fn invalid_function_name(
|
||||
stmt: &Stmt,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
ignore_names: &[String],
|
||||
model: &SemanticModel,
|
||||
locator: &Locator,
|
||||
|
|
|
@ -51,7 +51,7 @@ pub(crate) fn should_ignore_definition(
|
|||
}) = definition
|
||||
{
|
||||
for decorator in cast::decorator_list(stmt) {
|
||||
if let Some(call_path) = model.resolve_call_path(map_callable(decorator)) {
|
||||
if let Some(call_path) = model.resolve_call_path(map_callable(&decorator.expression)) {
|
||||
if ignore_decorators
|
||||
.iter()
|
||||
.any(|decorator| from_qualified_name(decorator) == call_path)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Arguments, Expr, Stmt};
|
||||
use rustpython_parser::ast::{self, Arguments, Decorator, Expr, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -50,12 +50,12 @@ impl Violation for PropertyWithParameters {
|
|||
pub(crate) fn property_with_parameters(
|
||||
checker: &mut Checker,
|
||||
stmt: &Stmt,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
args: &Arguments,
|
||||
) {
|
||||
if !decorator_list
|
||||
.iter()
|
||||
.any(|d| matches!(&d, Expr::Name(ast::ExprName { id, .. }) if id == "property"))
|
||||
.any(|d| matches!(&d.expression, Expr::Name(ast::ExprName { id, .. }) if id == "property"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::cmp::Ordering;
|
||||
|
||||
use rustpython_parser::ast::{Arguments, Expr, Stmt};
|
||||
use rustpython_parser::ast::{Arguments, Decorator, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -141,7 +141,7 @@ pub(crate) fn unexpected_special_method_signature(
|
|||
checker: &mut Checker,
|
||||
stmt: &Stmt,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
args: &Arguments,
|
||||
locator: &Locator,
|
||||
) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Constant, Expr, Keyword, Ranged};
|
||||
use rustpython_parser::ast::{self, Constant, Decorator, Expr, Keyword, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -23,14 +23,14 @@ impl AlwaysAutofixableViolation for LRUCacheWithMaxsizeNone {
|
|||
}
|
||||
|
||||
/// UP033
|
||||
pub(crate) fn lru_cache_with_maxsize_none(checker: &mut Checker, decorator_list: &[Expr]) {
|
||||
for expr in decorator_list.iter() {
|
||||
pub(crate) fn lru_cache_with_maxsize_none(checker: &mut Checker, decorator_list: &[Decorator]) {
|
||||
for decorator in decorator_list.iter() {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
}) = expr else {
|
||||
}) = &decorator.expression else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
@ -61,16 +61,17 @@ pub(crate) fn lru_cache_with_maxsize_none(checker: &mut Checker, decorator_list:
|
|||
{
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
LRUCacheWithMaxsizeNone,
|
||||
TextRange::new(func.end(), expr.end()),
|
||||
TextRange::new(func.end(), decorator.end()),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
diagnostic.try_set_fix(|| {
|
||||
let (import_edit, binding) = checker.importer.get_or_import_symbol(
|
||||
&ImportRequest::import("functools", "cache"),
|
||||
expr.start(),
|
||||
decorator.start(),
|
||||
checker.semantic_model(),
|
||||
)?;
|
||||
let reference_edit = Edit::range_replacement(binding, expr.range());
|
||||
let reference_edit =
|
||||
Edit::range_replacement(binding, decorator.expression.range());
|
||||
#[allow(deprecated)]
|
||||
Ok(Fix::unspecified_edits(import_edit, [reference_edit]))
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use rustpython_parser::ast::{self, Expr, Ranged};
|
||||
use rustpython_parser::ast::{self, Decorator, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -22,14 +22,14 @@ impl AlwaysAutofixableViolation for LRUCacheWithoutParameters {
|
|||
}
|
||||
|
||||
/// UP011
|
||||
pub(crate) fn lru_cache_without_parameters(checker: &mut Checker, decorator_list: &[Expr]) {
|
||||
for expr in decorator_list.iter() {
|
||||
pub(crate) fn lru_cache_without_parameters(checker: &mut Checker, decorator_list: &[Decorator]) {
|
||||
for decorator in decorator_list.iter() {
|
||||
let Expr::Call(ast::ExprCall {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
range: _,
|
||||
}) = expr else {
|
||||
}) = &decorator.expression else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
@ -45,13 +45,13 @@ pub(crate) fn lru_cache_without_parameters(checker: &mut Checker, decorator_list
|
|||
{
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
LRUCacheWithoutParameters,
|
||||
TextRange::new(func.end(), expr.end()),
|
||||
TextRange::new(func.end(), decorator.end()),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
#[allow(deprecated)]
|
||||
diagnostic.set_fix(Fix::unspecified(Edit::range_replacement(
|
||||
checker.generator().expr(func),
|
||||
expr.range(),
|
||||
decorator.expression.range(),
|
||||
)));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, Ranged, Stmt};
|
||||
use rustpython_parser::ast::{self, Decorator, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
|
@ -244,10 +244,10 @@ pub(crate) fn mutable_dataclass_default(checker: &mut Checker, body: &[Stmt]) {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_dataclass(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
||||
pub(crate) fn is_dataclass(model: &SemanticModel, decorator_list: &[Decorator]) -> bool {
|
||||
decorator_list.iter().any(|decorator| {
|
||||
model
|
||||
.resolve_call_path(map_callable(decorator))
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["dataclasses", "dataclass"]
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::{self, Expr, Stmt};
|
||||
use rustpython_parser::ast::{self, Decorator, Stmt};
|
||||
|
||||
pub fn name(stmt: &Stmt) -> &str {
|
||||
match stmt {
|
||||
|
@ -8,7 +8,7 @@ pub fn name(stmt: &Stmt) -> &str {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn decorator_list(stmt: &Stmt) -> &[Expr] {
|
||||
pub fn decorator_list(stmt: &Stmt) -> &[Decorator] {
|
||||
match stmt {
|
||||
Stmt::FunctionDef(ast::StmtFunctionDef { decorator_list, .. })
|
||||
| Stmt::AsyncFunctionDef(ast::StmtAsyncFunctionDef { decorator_list, .. }) => {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
//! ability to compare expressions for equality (via [`Eq`] and [`Hash`]).
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use rustpython_ast::Decorator;
|
||||
use rustpython_parser::ast::{
|
||||
self, Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, ConversionFlag,
|
||||
Excepthandler, Expr, ExprContext, Identifier, Int, Keyword, MatchCase, Operator, Pattern, Stmt,
|
||||
|
@ -267,6 +268,19 @@ impl<'a> From<&'a MatchCase> for ComparableMatchCase<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ComparableDecorator<'a> {
|
||||
pub expression: ComparableExpr<'a>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Decorator> for ComparableDecorator<'a> {
|
||||
fn from(decorator: &'a Decorator) -> Self {
|
||||
Self {
|
||||
expression: (&decorator.expression).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ComparableConstant<'a> {
|
||||
None,
|
||||
|
@ -777,7 +791,7 @@ pub enum ComparableStmt<'a> {
|
|||
name: &'a str,
|
||||
args: ComparableArguments<'a>,
|
||||
body: Vec<ComparableStmt<'a>>,
|
||||
decorator_list: Vec<ComparableExpr<'a>>,
|
||||
decorator_list: Vec<ComparableDecorator<'a>>,
|
||||
returns: Option<ComparableExpr<'a>>,
|
||||
type_comment: Option<&'a str>,
|
||||
},
|
||||
|
@ -785,7 +799,7 @@ pub enum ComparableStmt<'a> {
|
|||
name: &'a str,
|
||||
args: ComparableArguments<'a>,
|
||||
body: Vec<ComparableStmt<'a>>,
|
||||
decorator_list: Vec<ComparableExpr<'a>>,
|
||||
decorator_list: Vec<ComparableDecorator<'a>>,
|
||||
returns: Option<ComparableExpr<'a>>,
|
||||
type_comment: Option<&'a str>,
|
||||
},
|
||||
|
@ -794,7 +808,7 @@ pub enum ComparableStmt<'a> {
|
|||
bases: Vec<ComparableExpr<'a>>,
|
||||
keywords: Vec<ComparableKeyword<'a>>,
|
||||
body: Vec<ComparableStmt<'a>>,
|
||||
decorator_list: Vec<ComparableExpr<'a>>,
|
||||
decorator_list: Vec<ComparableDecorator<'a>>,
|
||||
},
|
||||
Return {
|
||||
value: Option<ComparableExpr<'a>>,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::node::AnyNodeRef;
|
||||
use ruff_text_size::TextRange;
|
||||
use rustpython_ast::{
|
||||
Arguments, Expr, Identifier, Ranged, StmtAsyncFunctionDef, StmtFunctionDef, Suite,
|
||||
Arguments, Decorator, Expr, Identifier, Ranged, StmtAsyncFunctionDef, StmtFunctionDef, Suite,
|
||||
};
|
||||
|
||||
/// Enum that represents any python function definition.
|
||||
|
@ -65,7 +65,7 @@ impl<'a> AnyFunctionDefinition<'a> {
|
|||
}
|
||||
|
||||
/// Returns the decorators attributing the function.
|
||||
pub fn decorators(self) -> &'a [Expr] {
|
||||
pub fn decorators(self) -> &'a [Decorator] {
|
||||
match self {
|
||||
Self::FunctionDefinition(definition) => &definition.decorator_list,
|
||||
Self::AsyncFunctionDefinition(definition) => &definition.decorator_list,
|
||||
|
|
|
@ -363,7 +363,9 @@ where
|
|||
.map_or(false, |expr| any_over_expr(expr, func))
|
||||
})
|
||||
|| body.iter().any(|stmt| any_over_stmt(stmt, func))
|
||||
|| decorator_list.iter().any(|expr| any_over_expr(expr, func))
|
||||
|| decorator_list
|
||||
.iter()
|
||||
.any(|decorator| any_over_expr(&decorator.expression, func))
|
||||
|| returns
|
||||
.as_ref()
|
||||
.map_or(false, |value| any_over_expr(value, func))
|
||||
|
@ -380,7 +382,9 @@ where
|
|||
.iter()
|
||||
.any(|keyword| any_over_expr(&keyword.value, func))
|
||||
|| body.iter().any(|stmt| any_over_stmt(stmt, func))
|
||||
|| decorator_list.iter().any(|expr| any_over_expr(expr, func))
|
||||
|| decorator_list
|
||||
.iter()
|
||||
.any(|decorator| any_over_expr(&decorator.expression, func))
|
||||
}
|
||||
Stmt::Return(ast::StmtReturn {
|
||||
value,
|
||||
|
|
|
@ -92,6 +92,7 @@ pub enum AnyNode {
|
|||
Alias(Alias<TextRange>),
|
||||
Withitem(Withitem<TextRange>),
|
||||
MatchCase(MatchCase<TextRange>),
|
||||
Decorator(Decorator<TextRange>),
|
||||
}
|
||||
|
||||
impl AnyNode {
|
||||
|
@ -172,7 +173,8 @@ impl AnyNode {
|
|||
| AnyNode::Keyword(_)
|
||||
| AnyNode::Alias(_)
|
||||
| AnyNode::Withitem(_)
|
||||
| AnyNode::MatchCase(_) => None,
|
||||
| AnyNode::MatchCase(_)
|
||||
| AnyNode::Decorator(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +255,8 @@ impl AnyNode {
|
|||
| AnyNode::Keyword(_)
|
||||
| AnyNode::Alias(_)
|
||||
| AnyNode::Withitem(_)
|
||||
| AnyNode::MatchCase(_) => None,
|
||||
| AnyNode::MatchCase(_)
|
||||
| AnyNode::Decorator(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,7 +337,8 @@ impl AnyNode {
|
|||
| AnyNode::Keyword(_)
|
||||
| AnyNode::Alias(_)
|
||||
| AnyNode::Withitem(_)
|
||||
| AnyNode::MatchCase(_) => None,
|
||||
| AnyNode::MatchCase(_)
|
||||
| AnyNode::Decorator(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -415,7 +419,8 @@ impl AnyNode {
|
|||
| AnyNode::Keyword(_)
|
||||
| AnyNode::Alias(_)
|
||||
| AnyNode::Withitem(_)
|
||||
| AnyNode::MatchCase(_) => None,
|
||||
| AnyNode::MatchCase(_)
|
||||
| AnyNode::Decorator(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -496,7 +501,8 @@ impl AnyNode {
|
|||
| AnyNode::Keyword(_)
|
||||
| AnyNode::Alias(_)
|
||||
| AnyNode::Withitem(_)
|
||||
| AnyNode::MatchCase(_) => None,
|
||||
| AnyNode::MatchCase(_)
|
||||
| AnyNode::Decorator(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -577,7 +583,8 @@ impl AnyNode {
|
|||
| AnyNode::Keyword(_)
|
||||
| AnyNode::Alias(_)
|
||||
| AnyNode::Withitem(_)
|
||||
| AnyNode::MatchCase(_) => None,
|
||||
| AnyNode::MatchCase(_)
|
||||
| AnyNode::Decorator(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -682,6 +689,7 @@ impl AnyNode {
|
|||
Self::Alias(node) => AnyNodeRef::Alias(node),
|
||||
Self::Withitem(node) => AnyNodeRef::Withitem(node),
|
||||
Self::MatchCase(node) => AnyNodeRef::MatchCase(node),
|
||||
Self::Decorator(node) => AnyNodeRef::Decorator(node),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2793,6 +2801,35 @@ impl AstNode for MatchCase<TextRange> {
|
|||
}
|
||||
}
|
||||
|
||||
impl AstNode for Decorator<TextRange> {
|
||||
fn cast(kind: AnyNode) -> Option<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
if let AnyNode::Decorator(node) = kind {
|
||||
Some(node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn cast_ref(kind: AnyNodeRef) -> Option<&Self> {
|
||||
if let AnyNodeRef::Decorator(node) = kind {
|
||||
Some(node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn as_any_node_ref(&self) -> AnyNodeRef {
|
||||
AnyNodeRef::from(self)
|
||||
}
|
||||
|
||||
fn into_any_node(self) -> AnyNode {
|
||||
AnyNode::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Stmt> for AnyNode {
|
||||
fn from(stmt: Stmt) -> Self {
|
||||
match stmt {
|
||||
|
@ -3346,6 +3383,11 @@ impl From<MatchCase> for AnyNode {
|
|||
AnyNode::MatchCase(node)
|
||||
}
|
||||
}
|
||||
impl From<Decorator> for AnyNode {
|
||||
fn from(node: Decorator) -> Self {
|
||||
AnyNode::Decorator(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for AnyNode {
|
||||
fn range(&self) -> TextRange {
|
||||
|
@ -3425,6 +3467,7 @@ impl Ranged for AnyNode {
|
|||
AnyNode::Alias(node) => node.range(),
|
||||
AnyNode::Withitem(node) => node.range(),
|
||||
AnyNode::MatchCase(node) => node.range(),
|
||||
AnyNode::Decorator(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3506,6 +3549,7 @@ pub enum AnyNodeRef<'a> {
|
|||
Alias(&'a Alias<TextRange>),
|
||||
Withitem(&'a Withitem<TextRange>),
|
||||
MatchCase(&'a MatchCase<TextRange>),
|
||||
Decorator(&'a Decorator<TextRange>),
|
||||
}
|
||||
|
||||
impl AnyNodeRef<'_> {
|
||||
|
@ -3586,6 +3630,7 @@ impl AnyNodeRef<'_> {
|
|||
AnyNodeRef::Alias(node) => NonNull::from(*node).cast(),
|
||||
AnyNodeRef::Withitem(node) => NonNull::from(*node).cast(),
|
||||
AnyNodeRef::MatchCase(node) => NonNull::from(*node).cast(),
|
||||
AnyNodeRef::Decorator(node) => NonNull::from(*node).cast(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3672,6 +3717,7 @@ impl AnyNodeRef<'_> {
|
|||
AnyNodeRef::Alias(_) => NodeKind::Alias,
|
||||
AnyNodeRef::Withitem(_) => NodeKind::Withitem,
|
||||
AnyNodeRef::MatchCase(_) => NodeKind::MatchCase,
|
||||
AnyNodeRef::Decorator(_) => NodeKind::Decorator,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3752,7 +3798,8 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::Keyword(_)
|
||||
| AnyNodeRef::Alias(_)
|
||||
| AnyNodeRef::Withitem(_)
|
||||
| AnyNodeRef::MatchCase(_) => false,
|
||||
| AnyNodeRef::MatchCase(_)
|
||||
| AnyNodeRef::Decorator(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3833,7 +3880,8 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::Keyword(_)
|
||||
| AnyNodeRef::Alias(_)
|
||||
| AnyNodeRef::Withitem(_)
|
||||
| AnyNodeRef::MatchCase(_) => false,
|
||||
| AnyNodeRef::MatchCase(_)
|
||||
| AnyNodeRef::Decorator(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3914,7 +3962,8 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::Keyword(_)
|
||||
| AnyNodeRef::Alias(_)
|
||||
| AnyNodeRef::Withitem(_)
|
||||
| AnyNodeRef::MatchCase(_) => false,
|
||||
| AnyNodeRef::MatchCase(_)
|
||||
| AnyNodeRef::Decorator(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3995,7 +4044,8 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::Keyword(_)
|
||||
| AnyNodeRef::Alias(_)
|
||||
| AnyNodeRef::Withitem(_)
|
||||
| AnyNodeRef::MatchCase(_) => false,
|
||||
| AnyNodeRef::MatchCase(_)
|
||||
| AnyNodeRef::Decorator(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4076,7 +4126,8 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::Keyword(_)
|
||||
| AnyNodeRef::Alias(_)
|
||||
| AnyNodeRef::Withitem(_)
|
||||
| AnyNodeRef::MatchCase(_) => false,
|
||||
| AnyNodeRef::MatchCase(_)
|
||||
| AnyNodeRef::Decorator(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4157,7 +4208,8 @@ impl AnyNodeRef<'_> {
|
|||
| AnyNodeRef::Keyword(_)
|
||||
| AnyNodeRef::Alias(_)
|
||||
| AnyNodeRef::Withitem(_)
|
||||
| AnyNodeRef::MatchCase(_) => false,
|
||||
| AnyNodeRef::MatchCase(_)
|
||||
| AnyNodeRef::Decorator(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4570,6 +4622,12 @@ impl<'a> From<&'a TypeIgnoreTypeIgnore> for AnyNodeRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Decorator> for AnyNodeRef<'a> {
|
||||
fn from(node: &'a Decorator) -> Self {
|
||||
AnyNodeRef::Decorator(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Stmt> for AnyNodeRef<'a> {
|
||||
fn from(stmt: &'a Stmt) -> Self {
|
||||
match stmt {
|
||||
|
@ -4796,6 +4854,7 @@ impl Ranged for AnyNodeRef<'_> {
|
|||
AnyNodeRef::Alias(node) => node.range(),
|
||||
AnyNodeRef::Withitem(node) => node.range(),
|
||||
AnyNodeRef::MatchCase(node) => node.range(),
|
||||
AnyNodeRef::Decorator(node) => node.range(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4877,4 +4936,5 @@ pub enum NodeKind {
|
|||
Alias,
|
||||
Withitem,
|
||||
MatchCase,
|
||||
Decorator,
|
||||
}
|
||||
|
|
|
@ -212,7 +212,7 @@ impl<'a> Generator<'a> {
|
|||
for decorator in decorator_list {
|
||||
statement!({
|
||||
self.p("@");
|
||||
self.unparse_expr(decorator, precedence::MAX);
|
||||
self.unparse_expr(&decorator.expression, precedence::MAX);
|
||||
});
|
||||
}
|
||||
statement!({
|
||||
|
@ -244,7 +244,7 @@ impl<'a> Generator<'a> {
|
|||
for decorator in decorator_list {
|
||||
statement!({
|
||||
self.p("@");
|
||||
self.unparse_expr(decorator, precedence::MAX);
|
||||
self.unparse_expr(&decorator.expression, precedence::MAX);
|
||||
});
|
||||
}
|
||||
statement!({
|
||||
|
@ -276,7 +276,7 @@ impl<'a> Generator<'a> {
|
|||
for decorator in decorator_list {
|
||||
statement!({
|
||||
self.p("@");
|
||||
self.unparse_expr(decorator, precedence::MAX);
|
||||
self.unparse_expr(&decorator.expression, precedence::MAX);
|
||||
});
|
||||
}
|
||||
statement!({
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
pub mod preorder;
|
||||
|
||||
use rustpython_ast::Decorator;
|
||||
use rustpython_parser::ast::{
|
||||
self, Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, Excepthandler, Expr,
|
||||
ExprContext, Keyword, MatchCase, Operator, Pattern, Stmt, Unaryop, Withitem,
|
||||
|
@ -21,6 +22,9 @@ pub trait Visitor<'a> {
|
|||
fn visit_annotation(&mut self, expr: &'a Expr) {
|
||||
walk_expr(self, expr);
|
||||
}
|
||||
fn visit_decorator(&mut self, decorator: &'a Decorator) {
|
||||
walk_decorator(self, decorator);
|
||||
}
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
walk_expr(self, expr);
|
||||
}
|
||||
|
@ -93,8 +97,8 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
|||
..
|
||||
}) => {
|
||||
visitor.visit_arguments(args);
|
||||
for expr in decorator_list {
|
||||
visitor.visit_expr(expr);
|
||||
for decorator in decorator_list {
|
||||
visitor.visit_decorator(decorator);
|
||||
}
|
||||
for expr in returns {
|
||||
visitor.visit_annotation(expr);
|
||||
|
@ -109,8 +113,8 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
|||
..
|
||||
}) => {
|
||||
visitor.visit_arguments(args);
|
||||
for expr in decorator_list {
|
||||
visitor.visit_expr(expr);
|
||||
for decorator in decorator_list {
|
||||
visitor.visit_decorator(decorator);
|
||||
}
|
||||
for expr in returns {
|
||||
visitor.visit_annotation(expr);
|
||||
|
@ -130,8 +134,8 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
|||
for keyword in keywords {
|
||||
visitor.visit_keyword(keyword);
|
||||
}
|
||||
for expr in decorator_list {
|
||||
visitor.visit_expr(expr);
|
||||
for decorator in decorator_list {
|
||||
visitor.visit_decorator(decorator);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
|
@ -318,6 +322,10 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn walk_decorator<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, decorator: &'a Decorator) {
|
||||
visitor.visit_expr(&decorator.expression);
|
||||
}
|
||||
|
||||
pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
|
||||
match expr {
|
||||
Expr::BoolOp(ast::ExprBoolOp {
|
||||
|
|
|
@ -18,6 +18,10 @@ pub trait PreorderVisitor<'a> {
|
|||
walk_expr(self, expr);
|
||||
}
|
||||
|
||||
fn visit_decorator(&mut self, decorator: &'a Decorator) {
|
||||
walk_decorator(self, decorator);
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self, constant: &'a Constant) {
|
||||
walk_constant(self, constant);
|
||||
}
|
||||
|
@ -151,8 +155,8 @@ where
|
|||
returns,
|
||||
..
|
||||
}) => {
|
||||
for expr in decorator_list {
|
||||
visitor.visit_expr(expr);
|
||||
for decorator in decorator_list {
|
||||
visitor.visit_decorator(decorator);
|
||||
}
|
||||
|
||||
visitor.visit_arguments(args);
|
||||
|
@ -171,8 +175,8 @@ where
|
|||
decorator_list,
|
||||
..
|
||||
}) => {
|
||||
for expr in decorator_list {
|
||||
visitor.visit_expr(expr);
|
||||
for decorator in decorator_list {
|
||||
visitor.visit_decorator(decorator);
|
||||
}
|
||||
|
||||
for expr in bases {
|
||||
|
@ -387,6 +391,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn walk_decorator<'a, V>(visitor: &mut V, decorator: &'a Decorator)
|
||||
where
|
||||
V: PreorderVisitor<'a> + ?Sized,
|
||||
{
|
||||
visitor.visit_expr(&decorator.expression);
|
||||
}
|
||||
|
||||
pub fn walk_expr<'a, V>(visitor: &mut V, expr: &'a Expr)
|
||||
where
|
||||
V: PreorderVisitor<'a> + ?Sized,
|
||||
|
|
|
@ -745,9 +745,13 @@ fn find_pos_only_slash_offset(
|
|||
),
|
||||
locator.contents(),
|
||||
)
|
||||
.map(|(offset, c)| {
|
||||
debug_assert_eq!(c, '/');
|
||||
offset
|
||||
.and_then(|(offset, c)| {
|
||||
if c == '/' {
|
||||
Some(offset)
|
||||
} else {
|
||||
debug_assert_eq!(c, ')');
|
||||
None
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
|
|
|
@ -5,8 +5,8 @@ expression: comments.debug(test_case.source_code)
|
|||
{
|
||||
Node {
|
||||
kind: Arguments,
|
||||
range: 10..94,
|
||||
source: `a=10,/, # trailing position...t comment.⏎`,
|
||||
range: 9..96,
|
||||
source: `(a=10,/, # trailing positio...t comment.⏎`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [
|
||||
|
|
|
@ -5,8 +5,8 @@ expression: comments.debug(test_case.source_code)
|
|||
{
|
||||
Node {
|
||||
kind: Arguments,
|
||||
range: 15..177,
|
||||
source: `a=10 # trailing positional comment⏎`,
|
||||
range: 9..179,
|
||||
source: `(⏎`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [
|
||||
|
|
|
@ -3,25 +3,10 @@ source: crates/ruff_python_formatter/src/comments/mod.rs
|
|||
expression: comments.debug(test_case.source_code)
|
||||
---
|
||||
{
|
||||
Node {
|
||||
kind: Arg,
|
||||
range: 15..16,
|
||||
source: `a`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [],
|
||||
"trailing": [
|
||||
SourceComment {
|
||||
text: "# trailing positional comment",
|
||||
position: EndOfLine,
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
Node {
|
||||
kind: Arguments,
|
||||
range: 15..168,
|
||||
source: `a, # trailing positional comment⏎`,
|
||||
range: 9..170,
|
||||
source: `(⏎`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [
|
||||
|
@ -38,6 +23,21 @@ expression: comments.debug(test_case.source_code)
|
|||
],
|
||||
"trailing": [],
|
||||
},
|
||||
Node {
|
||||
kind: Arg,
|
||||
range: 15..16,
|
||||
source: `a`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [],
|
||||
"trailing": [
|
||||
SourceComment {
|
||||
text: "# trailing positional comment",
|
||||
position: EndOfLine,
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
Node {
|
||||
kind: Arg,
|
||||
range: 166..167,
|
||||
|
|
|
@ -3,6 +3,26 @@ source: crates/ruff_python_formatter/src/comments/mod.rs
|
|||
expression: comments.debug(test_case.source_code)
|
||||
---
|
||||
{
|
||||
Node {
|
||||
kind: Arguments,
|
||||
range: 9..166,
|
||||
source: `(⏎`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [
|
||||
SourceComment {
|
||||
text: "# Positional arguments only after here",
|
||||
position: OwnLine,
|
||||
formatted: false,
|
||||
},
|
||||
SourceComment {
|
||||
text: "# trailing positional argument comment.",
|
||||
position: EndOfLine,
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
"trailing": [],
|
||||
},
|
||||
Node {
|
||||
kind: Arg,
|
||||
range: 15..16,
|
||||
|
@ -16,42 +36,11 @@ expression: comments.debug(test_case.source_code)
|
|||
position: EndOfLine,
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
Node {
|
||||
kind: Arguments,
|
||||
range: 15..97,
|
||||
source: `a, # trailing positional comment⏎`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [
|
||||
SourceComment {
|
||||
text: "# Positional arguments only after here",
|
||||
position: OwnLine,
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
"trailing": [
|
||||
SourceComment {
|
||||
text: "# trailing positional argument comment.",
|
||||
position: EndOfLine,
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
Node {
|
||||
kind: StmtPass,
|
||||
range: 168..172,
|
||||
source: `pass`,
|
||||
}: {
|
||||
"leading": [
|
||||
SourceComment {
|
||||
text: "# Trailing on new line",
|
||||
position: OwnLine,
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
"dangling": [],
|
||||
"trailing": [],
|
||||
},
|
||||
}
|
||||
|
|
|
@ -3,25 +3,10 @@ source: crates/ruff_python_formatter/src/comments/mod.rs
|
|||
expression: comments.debug(test_case.source_code)
|
||||
---
|
||||
{
|
||||
Node {
|
||||
kind: Arg,
|
||||
range: 15..16,
|
||||
source: `a`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [],
|
||||
"trailing": [
|
||||
SourceComment {
|
||||
text: "# trailing positional comment",
|
||||
position: EndOfLine,
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
Node {
|
||||
kind: Arguments,
|
||||
range: 15..168,
|
||||
source: `a # trailing positional comment⏎`,
|
||||
range: 9..170,
|
||||
source: `(⏎`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [
|
||||
|
@ -38,6 +23,21 @@ expression: comments.debug(test_case.source_code)
|
|||
],
|
||||
"trailing": [],
|
||||
},
|
||||
Node {
|
||||
kind: Arg,
|
||||
range: 15..16,
|
||||
source: `a`,
|
||||
}: {
|
||||
"leading": [],
|
||||
"dangling": [],
|
||||
"trailing": [
|
||||
SourceComment {
|
||||
text: "# trailing positional comment",
|
||||
position: EndOfLine,
|
||||
formatted: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
Node {
|
||||
kind: Arg,
|
||||
range: 166..167,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustpython_parser::ast::Expr;
|
||||
use rustpython_parser::ast::Decorator;
|
||||
|
||||
use ruff_python_ast::call_path::from_qualified_name;
|
||||
use ruff_python_ast::helpers::map_callable;
|
||||
|
@ -22,18 +22,18 @@ pub fn classify(
|
|||
model: &SemanticModel,
|
||||
scope: &Scope,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
classmethod_decorators: &[String],
|
||||
staticmethod_decorators: &[String],
|
||||
) -> FunctionType {
|
||||
let ScopeKind::Class(scope) = &scope.kind else {
|
||||
return FunctionType::Function;
|
||||
};
|
||||
if decorator_list.iter().any(|expr| {
|
||||
if decorator_list.iter().any(|decorator| {
|
||||
// The method is decorated with a static method decorator (like
|
||||
// `@staticmethod`).
|
||||
model
|
||||
.resolve_call_path(map_callable(expr))
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "staticmethod"]
|
||||
|| staticmethod_decorators
|
||||
|
@ -52,9 +52,9 @@ pub fn classify(
|
|||
.any(|(module, member)| call_path.as_slice() == [*module, *member])
|
||||
})
|
||||
})
|
||||
|| decorator_list.iter().any(|expr| {
|
||||
|| decorator_list.iter().any(|decorator| {
|
||||
// The method is decorated with a class method decorator (like `@classmethod`).
|
||||
model.resolve_call_path(map_callable(expr)).map_or(false, |call_path| {
|
||||
model.resolve_call_path(map_callable(&decorator.expression)).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "classmethod"] ||
|
||||
classmethod_decorators
|
||||
.iter()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::path::Path;
|
||||
|
||||
use rustpython_parser::ast::{self, Expr, Stmt};
|
||||
use rustpython_parser::ast::{self, Decorator, Stmt};
|
||||
|
||||
use ruff_python_ast::call_path::{collect_call_path, CallPath};
|
||||
use ruff_python_ast::helpers::map_callable;
|
||||
|
@ -14,10 +14,10 @@ pub enum Visibility {
|
|||
}
|
||||
|
||||
/// Returns `true` if a function is a "static method".
|
||||
pub fn is_staticmethod(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
||||
decorator_list.iter().any(|expr| {
|
||||
pub fn is_staticmethod(model: &SemanticModel, decorator_list: &[Decorator]) -> bool {
|
||||
decorator_list.iter().any(|decorator| {
|
||||
model
|
||||
.resolve_call_path(map_callable(expr))
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "staticmethod"]
|
||||
})
|
||||
|
@ -25,10 +25,10 @@ pub fn is_staticmethod(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
|||
}
|
||||
|
||||
/// Returns `true` if a function is a "class method".
|
||||
pub fn is_classmethod(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
||||
decorator_list.iter().any(|expr| {
|
||||
pub fn is_classmethod(model: &SemanticModel, decorator_list: &[Decorator]) -> bool {
|
||||
decorator_list.iter().any(|decorator| {
|
||||
model
|
||||
.resolve_call_path(map_callable(expr))
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "classmethod"]
|
||||
})
|
||||
|
@ -36,24 +36,24 @@ pub fn is_classmethod(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
|||
}
|
||||
|
||||
/// Returns `true` if a function definition is an `@overload`.
|
||||
pub fn is_overload(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
||||
pub fn is_overload(model: &SemanticModel, decorator_list: &[Decorator]) -> bool {
|
||||
decorator_list
|
||||
.iter()
|
||||
.any(|expr| model.match_typing_expr(map_callable(expr), "overload"))
|
||||
.any(|decorator| model.match_typing_expr(map_callable(&decorator.expression), "overload"))
|
||||
}
|
||||
|
||||
/// Returns `true` if a function definition is an `@override` (PEP 698).
|
||||
pub fn is_override(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
||||
pub fn is_override(model: &SemanticModel, decorator_list: &[Decorator]) -> bool {
|
||||
decorator_list
|
||||
.iter()
|
||||
.any(|expr| model.match_typing_expr(map_callable(expr), "override"))
|
||||
.any(|decorator| model.match_typing_expr(map_callable(&decorator.expression), "override"))
|
||||
}
|
||||
|
||||
/// Returns `true` if a function definition is an abstract method based on its decorators.
|
||||
pub fn is_abstract(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
||||
decorator_list.iter().any(|expr| {
|
||||
pub fn is_abstract(model: &SemanticModel, decorator_list: &[Decorator]) -> bool {
|
||||
decorator_list.iter().any(|decorator| {
|
||||
model
|
||||
.resolve_call_path(map_callable(expr))
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
matches!(
|
||||
call_path.as_slice(),
|
||||
|
@ -74,12 +74,12 @@ pub fn is_abstract(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
|||
/// `@property`-like decorators.
|
||||
pub fn is_property(
|
||||
model: &SemanticModel,
|
||||
decorator_list: &[Expr],
|
||||
decorator_list: &[Decorator],
|
||||
extra_properties: &[CallPath],
|
||||
) -> bool {
|
||||
decorator_list.iter().any(|expr| {
|
||||
decorator_list.iter().any(|decorator| {
|
||||
model
|
||||
.resolve_call_path(map_callable(expr))
|
||||
.resolve_call_path(map_callable(&decorator.expression))
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "property"]
|
||||
|| call_path.as_slice() == ["functools", "cached_property"]
|
||||
|
@ -91,10 +91,10 @@ pub fn is_property(
|
|||
}
|
||||
|
||||
/// Returns `true` if a class is an `final`.
|
||||
pub fn is_final(model: &SemanticModel, decorator_list: &[Expr]) -> bool {
|
||||
pub fn is_final(model: &SemanticModel, decorator_list: &[Decorator]) -> bool {
|
||||
decorator_list
|
||||
.iter()
|
||||
.any(|expr| model.match_typing_expr(map_callable(expr), "final"))
|
||||
.any(|decorator| model.match_typing_expr(map_callable(&decorator.expression), "final"))
|
||||
}
|
||||
|
||||
/// Returns `true` if a function is a "magic method".
|
||||
|
@ -206,8 +206,8 @@ pub(crate) fn method_visibility(stmt: &Stmt) -> Visibility {
|
|||
..
|
||||
}) => {
|
||||
// Is this a setter or deleter?
|
||||
if decorator_list.iter().any(|expr| {
|
||||
collect_call_path(expr).map_or(false, |call_path| {
|
||||
if decorator_list.iter().any(|decorator| {
|
||||
collect_call_path(&decorator.expression).map_or(false, |call_path| {
|
||||
call_path.as_slice() == [name, "setter"]
|
||||
|| call_path.as_slice() == [name, "deleter"]
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue