Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4319bd1755 | ||
|
|
6bb6cb1783 | ||
|
|
e9412c9452 | ||
|
|
94faa7f301 | ||
|
|
5041f6530c | ||
|
|
3c7716ef27 |
@@ -1,5 +1,5 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff
|
||||
rev: v0.0.24
|
||||
rev: v0.0.25
|
||||
hooks:
|
||||
- id: lint
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1641,7 +1641,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.24"
|
||||
version = "0.0.25"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.24"
|
||||
version = "0.0.25"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
23
README.md
23
README.md
@@ -56,7 +56,7 @@ ruff also works with [Pre-Commit](https://pre-commit.com) (requires Cargo on sys
|
||||
```yaml
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff
|
||||
rev: v0.0.24
|
||||
rev: v0.0.25
|
||||
hooks:
|
||||
- id: lint
|
||||
```
|
||||
@@ -106,6 +106,25 @@ OPTIONS:
|
||||
-w, --watch Run in watch mode by re-running whenever files change
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
| Code | Name | Message |
|
||||
| ---- | ----- | ------- |
|
||||
| E501 | LineTooLong | Line too long |
|
||||
| F401 | UnusedImport | `...` imported but unused |
|
||||
| F403 | ImportStarUsage | Unable to detect undefined names |
|
||||
| F541 | FStringMissingPlaceholders | f-string without any placeholders |
|
||||
| F634 | IfTuple | If test is a tuple, which is always `True` |
|
||||
| F704 | YieldOutsideFunction | a `yield` or `yield from` statement outside of a function/method |
|
||||
| F706 | ReturnOutsideFunction | a `return` statement outside of a function/method |
|
||||
| F821 | UndefinedName | Undefined name `...` |
|
||||
| F822 | UndefinedExport | Undefined name `...` in __all__ |
|
||||
| F823 | UndefinedLocal | Local variable `...` referenced before assignment |
|
||||
| F831 | DuplicateArgumentName | Duplicate argument name in function definition |
|
||||
| F841 | UnusedVariable | Local variable `...` is assigned to but never used |
|
||||
| F901 | RaiseNotImplemented | 'raise NotImplemented' should be 'raise NotImplementedError |
|
||||
| R0205 | UselessObjectInheritance | Class ... inherits from object |
|
||||
|
||||
## Development
|
||||
|
||||
ruff is written in Rust (1.63.0). You'll need to install the [Rust toolchain](https://www.rust-lang.org/tools/install)
|
||||
@@ -114,7 +133,7 @@ for development.
|
||||
Assuming you have `cargo` installed, you can run:
|
||||
|
||||
```shell
|
||||
cargo run resources/test/src
|
||||
cargo run resources/test/fixtures
|
||||
cargo fmt
|
||||
cargo clippy
|
||||
cargo test
|
||||
|
||||
33
examples/generate_rules_table.rs
Normal file
33
examples/generate_rules_table.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
/// Generate a Markdown-compatible table of supported lint rules.
|
||||
use ruff::checks::CheckKind;
|
||||
|
||||
fn main() {
|
||||
let mut check_kinds: Vec<CheckKind> = vec![
|
||||
CheckKind::DuplicateArgumentName,
|
||||
CheckKind::FStringMissingPlaceholders,
|
||||
CheckKind::IfTuple,
|
||||
CheckKind::ImportStarUsage,
|
||||
CheckKind::LineTooLong,
|
||||
CheckKind::RaiseNotImplemented,
|
||||
CheckKind::ReturnOutsideFunction,
|
||||
CheckKind::UndefinedLocal("...".to_string()),
|
||||
CheckKind::UndefinedName("...".to_string()),
|
||||
CheckKind::UndefinedExport("...".to_string()),
|
||||
CheckKind::UnusedImport("...".to_string()),
|
||||
CheckKind::UnusedVariable("...".to_string()),
|
||||
CheckKind::UselessObjectInheritance("...".to_string()),
|
||||
CheckKind::YieldOutsideFunction,
|
||||
];
|
||||
check_kinds.sort_by_key(|check_kind| check_kind.code());
|
||||
|
||||
println!("| Code | Name | Message |");
|
||||
println!("| ---- | ----- | ------- |");
|
||||
for check_kind in check_kinds {
|
||||
println!(
|
||||
"| {} | {} | {} |",
|
||||
check_kind.code().as_str(),
|
||||
check_kind.name(),
|
||||
check_kind.body()
|
||||
);
|
||||
}
|
||||
}
|
||||
3
resources/test/fixtures/F822.py
vendored
Normal file
3
resources/test/fixtures/F822.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
a = 1
|
||||
|
||||
__all__ = ["a", "b"]
|
||||
22
resources/test/fixtures/R0205.py
vendored
Normal file
22
resources/test/fixtures/R0205.py
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
class A:
|
||||
...
|
||||
|
||||
|
||||
class B(object):
|
||||
...
|
||||
|
||||
|
||||
class C(B, object):
|
||||
...
|
||||
|
||||
|
||||
def f():
|
||||
class D(object):
|
||||
...
|
||||
|
||||
|
||||
object = A
|
||||
|
||||
|
||||
class E(object):
|
||||
...
|
||||
@@ -10,8 +10,10 @@ select = [
|
||||
"F704",
|
||||
"F706",
|
||||
"F821",
|
||||
"F822",
|
||||
"F823",
|
||||
"F831",
|
||||
"F841",
|
||||
"F901",
|
||||
"R0205",
|
||||
]
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::Path;
|
||||
|
||||
use rustpython_parser::ast::{
|
||||
Arg, Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprContext, ExprKind, Stmt,
|
||||
@@ -15,6 +16,7 @@ use crate::visitor::{walk_excepthandler, Visitor};
|
||||
|
||||
struct Checker<'a> {
|
||||
settings: &'a Settings,
|
||||
path: &'a str,
|
||||
checks: Vec<Check>,
|
||||
scopes: Vec<Scope>,
|
||||
dead_scopes: Vec<Scope>,
|
||||
@@ -24,9 +26,10 @@ struct Checker<'a> {
|
||||
}
|
||||
|
||||
impl Checker<'_> {
|
||||
pub fn new(settings: &Settings) -> Checker {
|
||||
pub fn new<'a>(settings: &'a Settings, path: &'a str) -> Checker<'a> {
|
||||
Checker {
|
||||
settings,
|
||||
path,
|
||||
checks: vec![],
|
||||
scopes: vec![],
|
||||
dead_scopes: vec![],
|
||||
@@ -108,11 +111,37 @@ impl Visitor for Checker<'_> {
|
||||
}
|
||||
}
|
||||
StmtKind::ClassDef {
|
||||
name,
|
||||
bases,
|
||||
keywords,
|
||||
decorator_list,
|
||||
..
|
||||
} => {
|
||||
if self.settings.select.contains(&CheckCode::R0205) {
|
||||
for expr in bases {
|
||||
if let ExprKind::Name { id, .. } = &expr.node {
|
||||
if id == "object" {
|
||||
let scope = self.scopes.last().expect("No current scope found.");
|
||||
match scope.values.get(id) {
|
||||
None
|
||||
| Some(Binding {
|
||||
kind: BindingKind::Builtin,
|
||||
..
|
||||
}) => {
|
||||
self.checks.push(Check {
|
||||
kind: CheckKind::UselessObjectInheritance(
|
||||
name.to_string(),
|
||||
),
|
||||
location: stmt.location,
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for expr in bases {
|
||||
self.visit_expr(expr, Some(stmt))
|
||||
}
|
||||
@@ -647,19 +676,40 @@ impl Checker<'_> {
|
||||
}
|
||||
|
||||
fn check_dead_scopes(&mut self) {
|
||||
if self.settings.select.contains(&CheckCode::F401) {
|
||||
for scope in &self.dead_scopes {
|
||||
let all_binding = match scope.values.get("__all__") {
|
||||
Some(binding) => match &binding.kind {
|
||||
BindingKind::Export(names) => Some(names),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
if !self.settings.select.contains(&CheckCode::F822)
|
||||
&& !self.settings.select.contains(&CheckCode::F401)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for scope in &self.dead_scopes {
|
||||
let all_binding = scope.values.get("__all__");
|
||||
let all_names = all_binding.and_then(|binding| match &binding.kind {
|
||||
BindingKind::Export(names) => Some(names),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
if self.settings.select.contains(&CheckCode::F822)
|
||||
&& !Path::new(self.path).ends_with("__init__.py")
|
||||
{
|
||||
if let Some(binding) = all_binding {
|
||||
if let Some(names) = all_names {
|
||||
for name in names {
|
||||
if !scope.values.contains_key(name) {
|
||||
self.checks.push(Check {
|
||||
kind: CheckKind::UndefinedExport(name.to_string()),
|
||||
location: binding.location,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.settings.select.contains(&CheckCode::F401) {
|
||||
for (name, binding) in scope.values.iter().rev() {
|
||||
let used = binding.used.is_some()
|
||||
|| all_binding
|
||||
|| all_names
|
||||
.map(|names| names.contains(name))
|
||||
.unwrap_or_default();
|
||||
|
||||
@@ -682,7 +732,7 @@ impl Checker<'_> {
|
||||
}
|
||||
|
||||
pub fn check_ast(python_ast: &Suite, settings: &Settings, path: &str) -> Vec<Check> {
|
||||
let mut checker = Checker::new(settings);
|
||||
let mut checker = Checker::new(settings, path);
|
||||
checker.push_scope(Scope::new(ScopeKind::Module));
|
||||
checker.bind_builtins();
|
||||
|
||||
|
||||
@@ -16,10 +16,12 @@ pub enum CheckCode {
|
||||
F704,
|
||||
F706,
|
||||
F821,
|
||||
F822,
|
||||
F823,
|
||||
F831,
|
||||
F841,
|
||||
F901,
|
||||
R0205,
|
||||
}
|
||||
|
||||
impl FromStr for CheckCode {
|
||||
@@ -35,10 +37,12 @@ impl FromStr for CheckCode {
|
||||
"F704" => Ok(CheckCode::F704),
|
||||
"F706" => Ok(CheckCode::F706),
|
||||
"F821" => Ok(CheckCode::F821),
|
||||
"F822" => Ok(CheckCode::F822),
|
||||
"F823" => Ok(CheckCode::F823),
|
||||
"F831" => Ok(CheckCode::F831),
|
||||
"F841" => Ok(CheckCode::F841),
|
||||
"F901" => Ok(CheckCode::F901),
|
||||
"R0205" => Ok(CheckCode::R0205),
|
||||
_ => Err(anyhow::anyhow!("Unknown check code: {s}")),
|
||||
}
|
||||
}
|
||||
@@ -56,9 +60,11 @@ impl CheckCode {
|
||||
CheckCode::F706 => "F706",
|
||||
CheckCode::F821 => "F821",
|
||||
CheckCode::F823 => "F823",
|
||||
CheckCode::F822 => "F822",
|
||||
CheckCode::F831 => "F831",
|
||||
CheckCode::F841 => "F841",
|
||||
CheckCode::F901 => "F901",
|
||||
CheckCode::R0205 => "R0205",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,10 +79,12 @@ impl CheckCode {
|
||||
CheckCode::F704 => &LintSource::AST,
|
||||
CheckCode::F706 => &LintSource::AST,
|
||||
CheckCode::F821 => &LintSource::AST,
|
||||
CheckCode::F822 => &LintSource::AST,
|
||||
CheckCode::F823 => &LintSource::AST,
|
||||
CheckCode::F831 => &LintSource::AST,
|
||||
CheckCode::F841 => &LintSource::AST,
|
||||
CheckCode::F901 => &LintSource::AST,
|
||||
CheckCode::R0205 => &LintSource::AST,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,13 +105,35 @@ pub enum CheckKind {
|
||||
RaiseNotImplemented,
|
||||
ReturnOutsideFunction,
|
||||
UndefinedLocal(String),
|
||||
UndefinedExport(String),
|
||||
UndefinedName(String),
|
||||
UnusedImport(String),
|
||||
UnusedVariable(String),
|
||||
UselessObjectInheritance(String),
|
||||
YieldOutsideFunction,
|
||||
}
|
||||
|
||||
impl CheckKind {
|
||||
/// The name of the check.
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
CheckKind::DuplicateArgumentName => "DuplicateArgumentName",
|
||||
CheckKind::FStringMissingPlaceholders => "FStringMissingPlaceholders",
|
||||
CheckKind::IfTuple => "IfTuple",
|
||||
CheckKind::ImportStarUsage => "ImportStarUsage",
|
||||
CheckKind::LineTooLong => "LineTooLong",
|
||||
CheckKind::RaiseNotImplemented => "RaiseNotImplemented",
|
||||
CheckKind::ReturnOutsideFunction => "ReturnOutsideFunction",
|
||||
CheckKind::UndefinedLocal(_) => "UndefinedLocal",
|
||||
CheckKind::UndefinedExport(_) => "UndefinedExport",
|
||||
CheckKind::UndefinedName(_) => "UndefinedName",
|
||||
CheckKind::UnusedImport(_) => "UnusedImport",
|
||||
CheckKind::UnusedVariable(_) => "UnusedVariable",
|
||||
CheckKind::UselessObjectInheritance(_) => "UselessObjectInheritance",
|
||||
CheckKind::YieldOutsideFunction => "YieldOutsideFunction",
|
||||
}
|
||||
}
|
||||
|
||||
/// A four-letter shorthand code for the check.
|
||||
pub fn code(&self) -> &'static CheckCode {
|
||||
match self {
|
||||
@@ -114,10 +144,12 @@ impl CheckKind {
|
||||
CheckKind::LineTooLong => &CheckCode::E501,
|
||||
CheckKind::RaiseNotImplemented => &CheckCode::F901,
|
||||
CheckKind::ReturnOutsideFunction => &CheckCode::F706,
|
||||
CheckKind::UndefinedExport(_) => &CheckCode::F822,
|
||||
CheckKind::UndefinedLocal(_) => &CheckCode::F823,
|
||||
CheckKind::UndefinedName(_) => &CheckCode::F821,
|
||||
CheckKind::UnusedImport(_) => &CheckCode::F401,
|
||||
CheckKind::UnusedVariable(_) => &CheckCode::F841,
|
||||
CheckKind::UselessObjectInheritance(_) => &CheckCode::R0205,
|
||||
CheckKind::YieldOutsideFunction => &CheckCode::F704,
|
||||
}
|
||||
}
|
||||
@@ -140,6 +172,9 @@ impl CheckKind {
|
||||
CheckKind::ReturnOutsideFunction => {
|
||||
"a `return` statement outside of a function/method".to_string()
|
||||
}
|
||||
CheckKind::UndefinedExport(name) => {
|
||||
format!("Undefined name `{name}` in __all__")
|
||||
}
|
||||
CheckKind::UndefinedName(name) => {
|
||||
format!("Undefined name `{name}`")
|
||||
}
|
||||
@@ -150,6 +185,9 @@ impl CheckKind {
|
||||
CheckKind::UnusedVariable(name) => {
|
||||
format!("Local variable `{name}` is assigned to but never used")
|
||||
}
|
||||
CheckKind::UselessObjectInheritance(name) => {
|
||||
format!("Class {name} inherits from object")
|
||||
}
|
||||
CheckKind::YieldOutsideFunction => {
|
||||
"a `yield` or `yield from` statement outside of a function/method".to_string()
|
||||
}
|
||||
|
||||
172
src/linter.rs
172
src/linter.rs
@@ -68,7 +68,7 @@ mod tests {
|
||||
#[test]
|
||||
fn e501() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/E501.py"),
|
||||
Path::new("./resources/test/fixtures/E501.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -79,7 +79,7 @@ mod tests {
|
||||
let expected = vec![Message {
|
||||
kind: CheckKind::LineTooLong,
|
||||
location: Location::new(5, 89),
|
||||
filename: "./resources/test/src/E501.py".to_string(),
|
||||
filename: "./resources/test/fixtures/E501.py".to_string(),
|
||||
}];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
for i in 0..actual.len() {
|
||||
@@ -92,7 +92,7 @@ mod tests {
|
||||
#[test]
|
||||
fn f401() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F401.py"),
|
||||
Path::new("./resources/test/fixtures/F401.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -104,17 +104,17 @@ mod tests {
|
||||
Message {
|
||||
kind: CheckKind::UnusedImport("logging.handlers".to_string()),
|
||||
location: Location::new(12, 1),
|
||||
filename: "./resources/test/src/F401.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F401.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::UnusedImport("functools".to_string()),
|
||||
location: Location::new(3, 1),
|
||||
filename: "./resources/test/src/F401.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F401.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::UnusedImport("collections.OrderedDict".to_string()),
|
||||
location: Location::new(4, 1),
|
||||
filename: "./resources/test/src/F401.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F401.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
@@ -128,7 +128,7 @@ mod tests {
|
||||
#[test]
|
||||
fn f403() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F403.py"),
|
||||
Path::new("./resources/test/fixtures/F403.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -140,12 +140,12 @@ mod tests {
|
||||
Message {
|
||||
kind: CheckKind::ImportStarUsage,
|
||||
location: Location::new(1, 1),
|
||||
filename: "./resources/test/src/F403.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F403.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::ImportStarUsage,
|
||||
location: Location::new(2, 1),
|
||||
filename: "./resources/test/src/F403.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F403.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
@@ -158,7 +158,7 @@ mod tests {
|
||||
#[test]
|
||||
fn f541() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F541.py"),
|
||||
Path::new("./resources/test/fixtures/F541.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -170,17 +170,17 @@ mod tests {
|
||||
Message {
|
||||
kind: CheckKind::FStringMissingPlaceholders,
|
||||
location: Location::new(4, 7),
|
||||
filename: "./resources/test/src/F541.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F541.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::FStringMissingPlaceholders,
|
||||
location: Location::new(5, 7),
|
||||
filename: "./resources/test/src/F541.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F541.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::FStringMissingPlaceholders,
|
||||
location: Location::new(7, 7),
|
||||
filename: "./resources/test/src/F541.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F541.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
@@ -194,7 +194,7 @@ mod tests {
|
||||
#[test]
|
||||
fn f634() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F634.py"),
|
||||
Path::new("./resources/test/fixtures/F634.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -206,12 +206,12 @@ mod tests {
|
||||
Message {
|
||||
kind: CheckKind::IfTuple,
|
||||
location: Location::new(1, 1),
|
||||
filename: "./resources/test/src/F634.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F634.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::IfTuple,
|
||||
location: Location::new(7, 5),
|
||||
filename: "./resources/test/src/F634.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F634.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
@@ -225,7 +225,7 @@ mod tests {
|
||||
#[test]
|
||||
fn f704() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F704.py"),
|
||||
Path::new("./resources/test/fixtures/F704.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -237,17 +237,17 @@ mod tests {
|
||||
Message {
|
||||
kind: CheckKind::YieldOutsideFunction,
|
||||
location: Location::new(6, 5),
|
||||
filename: "./resources/test/src/F704.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F704.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::YieldOutsideFunction,
|
||||
location: Location::new(9, 1),
|
||||
filename: "./resources/test/src/F704.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F704.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::YieldOutsideFunction,
|
||||
location: Location::new(10, 1),
|
||||
filename: "./resources/test/src/F704.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F704.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
@@ -261,7 +261,7 @@ mod tests {
|
||||
#[test]
|
||||
fn f706() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F706.py"),
|
||||
Path::new("./resources/test/fixtures/F706.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -273,12 +273,12 @@ mod tests {
|
||||
Message {
|
||||
kind: CheckKind::ReturnOutsideFunction,
|
||||
location: Location::new(6, 5),
|
||||
filename: "./resources/test/src/F706.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F706.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::ReturnOutsideFunction,
|
||||
location: Location::new(9, 1),
|
||||
filename: "./resources/test/src/F706.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F706.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
@@ -292,7 +292,7 @@ mod tests {
|
||||
#[test]
|
||||
fn f821() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F821.py"),
|
||||
Path::new("./resources/test/fixtures/F821.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -304,22 +304,22 @@ mod tests {
|
||||
Message {
|
||||
kind: CheckKind::UndefinedName("self".to_string()),
|
||||
location: Location::new(2, 12),
|
||||
filename: "./resources/test/src/F821.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F821.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::UndefinedName("self".to_string()),
|
||||
location: Location::new(6, 13),
|
||||
filename: "./resources/test/src/F821.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F821.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::UndefinedName("self".to_string()),
|
||||
location: Location::new(10, 9),
|
||||
filename: "./resources/test/src/F821.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F821.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::UndefinedName("numeric_string".to_string()),
|
||||
location: Location::new(21, 12),
|
||||
filename: "./resources/test/src/F821.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F821.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
@@ -331,33 +331,21 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f831() -> Result<()> {
|
||||
fn f822() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F831.py"),
|
||||
Path::new("./resources/test/fixtures/F822.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
select: BTreeSet::from([CheckCode::F831]),
|
||||
select: BTreeSet::from([CheckCode::F822]),
|
||||
},
|
||||
&cache::Mode::None,
|
||||
)?;
|
||||
let expected = vec![
|
||||
Message {
|
||||
kind: CheckKind::DuplicateArgumentName,
|
||||
location: Location::new(1, 25),
|
||||
filename: "./resources/test/src/F831.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::DuplicateArgumentName,
|
||||
location: Location::new(5, 28),
|
||||
filename: "./resources/test/src/F831.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::DuplicateArgumentName,
|
||||
location: Location::new(9, 27),
|
||||
filename: "./resources/test/src/F831.py".to_string(),
|
||||
},
|
||||
];
|
||||
let expected = vec![Message {
|
||||
kind: CheckKind::UndefinedExport("b".to_string()),
|
||||
location: Location::new(3, 1),
|
||||
filename: "./resources/test/fixtures/F822.py".to_string(),
|
||||
}];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
for i in 0..actual.len() {
|
||||
assert_eq!(actual[i], expected[i]);
|
||||
@@ -369,7 +357,7 @@ mod tests {
|
||||
#[test]
|
||||
fn f823() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F823.py"),
|
||||
Path::new("./resources/test/fixtures/F823.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -380,7 +368,7 @@ mod tests {
|
||||
let expected = vec![Message {
|
||||
kind: CheckKind::UndefinedLocal("my_var".to_string()),
|
||||
location: Location::new(6, 5),
|
||||
filename: "./resources/test/src/F823.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F823.py".to_string(),
|
||||
}];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
for i in 0..actual.len() {
|
||||
@@ -390,10 +378,46 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f831() -> Result<()> {
|
||||
let actual = check_path(
|
||||
Path::new("./resources/test/fixtures/F831.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
select: BTreeSet::from([CheckCode::F831]),
|
||||
},
|
||||
&cache::Mode::None,
|
||||
)?;
|
||||
let expected = vec![
|
||||
Message {
|
||||
kind: CheckKind::DuplicateArgumentName,
|
||||
location: Location::new(1, 25),
|
||||
filename: "./resources/test/fixtures/F831.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::DuplicateArgumentName,
|
||||
location: Location::new(5, 28),
|
||||
filename: "./resources/test/fixtures/F831.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::DuplicateArgumentName,
|
||||
location: Location::new(9, 27),
|
||||
filename: "./resources/test/fixtures/F831.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
for i in 0..actual.len() {
|
||||
assert_eq!(actual[i], expected[i]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f841() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F841.py"),
|
||||
Path::new("./resources/test/fixtures/F841.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -405,12 +429,12 @@ mod tests {
|
||||
Message {
|
||||
kind: CheckKind::UnusedVariable("e".to_string()),
|
||||
location: Location::new(3, 1),
|
||||
filename: "./resources/test/src/F841.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F841.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::UnusedVariable("z".to_string()),
|
||||
location: Location::new(16, 5),
|
||||
filename: "./resources/test/src/F841.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F841.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
@@ -424,7 +448,7 @@ mod tests {
|
||||
#[test]
|
||||
fn f901() -> Result<()> {
|
||||
let actual = check_path(
|
||||
&Path::new("./resources/test/src/F901.py"),
|
||||
Path::new("./resources/test/fixtures/F901.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
@@ -436,12 +460,48 @@ mod tests {
|
||||
Message {
|
||||
kind: CheckKind::RaiseNotImplemented,
|
||||
location: Location::new(2, 5),
|
||||
filename: "./resources/test/src/F901.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F901.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::RaiseNotImplemented,
|
||||
location: Location::new(6, 5),
|
||||
filename: "./resources/test/src/F901.py".to_string(),
|
||||
filename: "./resources/test/fixtures/F901.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
for i in 0..actual.len() {
|
||||
assert_eq!(actual[i], expected[i]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn r0205() -> Result<()> {
|
||||
let actual = check_path(
|
||||
Path::new("./resources/test/fixtures/R0205.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
select: BTreeSet::from([CheckCode::R0205]),
|
||||
},
|
||||
&cache::Mode::None,
|
||||
)?;
|
||||
let expected = vec![
|
||||
Message {
|
||||
kind: CheckKind::UselessObjectInheritance("B".to_string()),
|
||||
location: Location::new(5, 1),
|
||||
filename: "./resources/test/fixtures/R0205.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::UselessObjectInheritance("C".to_string()),
|
||||
location: Location::new(9, 1),
|
||||
filename: "./resources/test/fixtures/R0205.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: CheckKind::UselessObjectInheritance("D".to_string()),
|
||||
location: Location::new(14, 5),
|
||||
filename: "./resources/test/fixtures/R0205.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
|
||||
@@ -216,18 +216,17 @@ other-attribute = 1
|
||||
|
||||
#[test]
|
||||
fn find_and_parse_pyproject_toml() -> Result<()> {
|
||||
let project_root = find_project_root([Path::new("resources/test/src/__init__.py")])
|
||||
let project_root = find_project_root([Path::new("resources/test/fixtures/__init__.py")])
|
||||
.expect("Unable to find project root.");
|
||||
assert_eq!(project_root, Path::new("resources/test/src"));
|
||||
assert_eq!(project_root, Path::new("resources/test/fixtures"));
|
||||
|
||||
let path = find_pyproject_toml(&project_root).expect("Unable to find pyproject.toml.");
|
||||
assert_eq!(path, Path::new("resources/test/src/pyproject.toml"));
|
||||
assert_eq!(path, Path::new("resources/test/fixtures/pyproject.toml"));
|
||||
|
||||
let pyproject = parse_pyproject_toml(&path)?;
|
||||
let config = pyproject
|
||||
.tool
|
||||
.map(|tool| tool.ruff)
|
||||
.flatten()
|
||||
.and_then(|tool| tool.ruff)
|
||||
.expect("Unable to find tool.ruff.");
|
||||
assert_eq!(
|
||||
config,
|
||||
@@ -246,10 +245,12 @@ other-attribute = 1
|
||||
CheckCode::F704,
|
||||
CheckCode::F706,
|
||||
CheckCode::F821,
|
||||
CheckCode::F822,
|
||||
CheckCode::F823,
|
||||
CheckCode::F831,
|
||||
CheckCode::F841,
|
||||
CheckCode::F901,
|
||||
CheckCode::R0205,
|
||||
])),
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user