mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 20:10:09 +00:00
Add check for W292 (#339)
This commit is contained in:
parent
95dfc61315
commit
473675fffb
9 changed files with 130 additions and 9 deletions
|
@ -246,6 +246,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
|||
| E743 | AmbiguousFunctionName | Ambiguous function name: `...` | ✅ | |
|
||||
| E902 | IOError | IOError: `...` | ✅ | |
|
||||
| E999 | SyntaxError | SyntaxError: `...` | ✅ | |
|
||||
| W292 | NoNewLineAtEndOfFile | No newline at end of file | ✅ | |
|
||||
| F401 | UnusedImport | `...` imported but unused | ✅ | 🛠 |
|
||||
| F402 | ImportShadowedByLoopVar | Import `...` from line 1 shadowed by loop variable | ✅ | |
|
||||
| F403 | ImportStarUsed | `from ... import *` used; unable to detect undefined names | ✅ | |
|
||||
|
@ -291,6 +292,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
|||
| U005 | NoAssertEquals | `assertEquals` is deprecated, use `assertEqual` instead | | 🛠 |
|
||||
| M001 | UnusedNOQA | Unused `noqa` directive | | 🛠 |
|
||||
|
||||
|
||||
## Integrations
|
||||
|
||||
### PyCharm
|
||||
|
|
2
resources/test/fixtures/W292_0.py
vendored
Normal file
2
resources/test/fixtures/W292_0.py
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
def fn() -> None:
|
||||
pass
|
2
resources/test/fixtures/W292_1.py
vendored
Normal file
2
resources/test/fixtures/W292_1.py
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
def fn() -> None:
|
||||
pass # noqa: W292
|
|
@ -113,6 +113,46 @@ pub fn check_lines(
|
|||
}
|
||||
}
|
||||
|
||||
// Enforce newlines at end of files.
|
||||
if settings.enabled.contains(&CheckCode::W292) {
|
||||
// If the file terminates with a newline, the last line should be an empty string slice.
|
||||
if let Some(line) = lines.last() {
|
||||
if !line.is_empty() {
|
||||
let lineno = lines.len() - 1;
|
||||
let noqa_lineno = noqa_line_for
|
||||
.get(lineno)
|
||||
.map(|lineno| lineno - 1)
|
||||
.unwrap_or(lineno);
|
||||
|
||||
let noqa = noqa_directives
|
||||
.entry(noqa_lineno)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[noqa_lineno]), vec![]));
|
||||
|
||||
let check = Check::new(
|
||||
CheckKind::NoNewLineAtEndOfFile,
|
||||
Range {
|
||||
location: Location::new(lines.len(), line.len() + 1),
|
||||
end_location: Location::new(lines.len(), line.len() + 1),
|
||||
},
|
||||
);
|
||||
|
||||
match noqa {
|
||||
(Directive::All(_, _), matches) => {
|
||||
matches.push(check.kind.code().as_str());
|
||||
}
|
||||
(Directive::Codes(_, _, codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_str()) {
|
||||
matches.push(check.kind.code().as_str());
|
||||
} else {
|
||||
line_checks.push(check);
|
||||
}
|
||||
}
|
||||
(Directive::None, _) => line_checks.push(check),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce that the noqa directive was actually used.
|
||||
if enforce_noqa {
|
||||
for (row, (directive, matches)) in noqa_directives {
|
||||
|
|
|
@ -8,8 +8,8 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::ast::types::Range;
|
||||
|
||||
pub const DEFAULT_CHECK_CODES: [CheckCode; 42] = [
|
||||
// pycodestyle
|
||||
pub const DEFAULT_CHECK_CODES: [CheckCode; 43] = [
|
||||
// pycodestyle errors
|
||||
CheckCode::E402,
|
||||
CheckCode::E501,
|
||||
CheckCode::E711,
|
||||
|
@ -24,6 +24,8 @@ pub const DEFAULT_CHECK_CODES: [CheckCode; 42] = [
|
|||
CheckCode::E743,
|
||||
CheckCode::E902,
|
||||
CheckCode::E999,
|
||||
// pycodestyle warnings
|
||||
CheckCode::W292,
|
||||
// pyflakes
|
||||
CheckCode::F401,
|
||||
CheckCode::F402,
|
||||
|
@ -55,8 +57,8 @@ pub const DEFAULT_CHECK_CODES: [CheckCode; 42] = [
|
|||
CheckCode::F901,
|
||||
];
|
||||
|
||||
pub const ALL_CHECK_CODES: [CheckCode; 58] = [
|
||||
// pycodestyle
|
||||
pub const ALL_CHECK_CODES: [CheckCode; 59] = [
|
||||
// pycodestyle errors
|
||||
CheckCode::E402,
|
||||
CheckCode::E501,
|
||||
CheckCode::E711,
|
||||
|
@ -71,6 +73,8 @@ pub const ALL_CHECK_CODES: [CheckCode; 58] = [
|
|||
CheckCode::E743,
|
||||
CheckCode::E902,
|
||||
CheckCode::E999,
|
||||
// pycodestyle warnings
|
||||
CheckCode::W292,
|
||||
// pyflakes
|
||||
CheckCode::F401,
|
||||
CheckCode::F402,
|
||||
|
@ -126,7 +130,7 @@ pub const ALL_CHECK_CODES: [CheckCode; 58] = [
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Hash, PartialOrd, Ord)]
|
||||
pub enum CheckCode {
|
||||
// pycodestyle
|
||||
// pycodestyle errors
|
||||
E402,
|
||||
E501,
|
||||
E711,
|
||||
|
@ -141,6 +145,8 @@ pub enum CheckCode {
|
|||
E743,
|
||||
E902,
|
||||
E999,
|
||||
// pycodestyle warnings
|
||||
W292,
|
||||
// pyflakes
|
||||
F401,
|
||||
F402,
|
||||
|
@ -199,7 +205,7 @@ impl FromStr for CheckCode {
|
|||
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
match s {
|
||||
// pycodestyle
|
||||
// pycodestyle errors
|
||||
"E402" => Ok(CheckCode::E402),
|
||||
"E501" => Ok(CheckCode::E501),
|
||||
"E711" => Ok(CheckCode::E711),
|
||||
|
@ -214,6 +220,8 @@ impl FromStr for CheckCode {
|
|||
"E743" => Ok(CheckCode::E743),
|
||||
"E902" => Ok(CheckCode::E902),
|
||||
"E999" => Ok(CheckCode::E999),
|
||||
// pycodestyle warnings
|
||||
"W292" => Ok(CheckCode::W292),
|
||||
// pyflakes
|
||||
"F401" => Ok(CheckCode::F401),
|
||||
"F402" => Ok(CheckCode::F402),
|
||||
|
@ -271,7 +279,7 @@ impl FromStr for CheckCode {
|
|||
impl CheckCode {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
// pycodestyle
|
||||
// pycodestyle errors
|
||||
CheckCode::E402 => "E402",
|
||||
CheckCode::E501 => "E501",
|
||||
CheckCode::E711 => "E711",
|
||||
|
@ -286,6 +294,8 @@ impl CheckCode {
|
|||
CheckCode::E743 => "E743",
|
||||
CheckCode::E902 => "E902",
|
||||
CheckCode::E999 => "E999",
|
||||
// pycodestyle warnings
|
||||
CheckCode::W292 => "W292",
|
||||
// pyflakes
|
||||
CheckCode::F401 => "F401",
|
||||
CheckCode::F402 => "F402",
|
||||
|
@ -352,7 +362,7 @@ impl CheckCode {
|
|||
/// A placeholder representation of the CheckKind for the check.
|
||||
pub fn kind(&self) -> CheckKind {
|
||||
match self {
|
||||
// pycodestyle
|
||||
// pycodestyle errors
|
||||
CheckCode::E402 => CheckKind::ModuleImportNotAtTopOfFile,
|
||||
CheckCode::E501 => CheckKind::LineTooLong(89, 88),
|
||||
CheckCode::E711 => CheckKind::NoneComparison(RejectedCmpop::Eq),
|
||||
|
@ -367,6 +377,8 @@ impl CheckCode {
|
|||
CheckCode::E743 => CheckKind::AmbiguousFunctionName("...".to_string()),
|
||||
CheckCode::E902 => CheckKind::IOError("IOError: `...`".to_string()),
|
||||
CheckCode::E999 => CheckKind::SyntaxError("`...`".to_string()),
|
||||
// pycodestyle warnings
|
||||
CheckCode::W292 => CheckKind::NoNewLineAtEndOfFile,
|
||||
// pyflakes
|
||||
CheckCode::F401 => CheckKind::UnusedImport(vec!["...".to_string()]),
|
||||
CheckCode::F402 => CheckKind::ImportShadowedByLoopVar("...".to_string(), 1),
|
||||
|
@ -481,6 +493,8 @@ pub enum CheckKind {
|
|||
UnusedImport(Vec<String>),
|
||||
UnusedVariable(String),
|
||||
YieldOutsideFunction,
|
||||
// More style
|
||||
NoNewLineAtEndOfFile,
|
||||
// flake8-builtin
|
||||
BuiltinVariableShadowing(String),
|
||||
BuiltinArgumentShadowing(String),
|
||||
|
@ -551,6 +565,8 @@ impl CheckKind {
|
|||
CheckKind::UnusedImport(_) => "UnusedImport",
|
||||
CheckKind::UnusedVariable(_) => "UnusedVariable",
|
||||
CheckKind::YieldOutsideFunction => "YieldOutsideFunction",
|
||||
// More style
|
||||
CheckKind::NoNewLineAtEndOfFile => "NoNewLineAtEndOfFile",
|
||||
// flake8-builtins
|
||||
CheckKind::BuiltinVariableShadowing(_) => "BuiltinVariableShadowing",
|
||||
CheckKind::BuiltinArgumentShadowing(_) => "BuiltinArgumentShadowing",
|
||||
|
@ -621,6 +637,8 @@ impl CheckKind {
|
|||
CheckKind::UnusedImport(_) => &CheckCode::F401,
|
||||
CheckKind::UnusedVariable(_) => &CheckCode::F841,
|
||||
CheckKind::YieldOutsideFunction => &CheckCode::F704,
|
||||
// More style
|
||||
CheckKind::NoNewLineAtEndOfFile => &CheckCode::W292,
|
||||
// flake8-builtins
|
||||
CheckKind::BuiltinVariableShadowing(_) => &CheckCode::A001,
|
||||
CheckKind::BuiltinArgumentShadowing(_) => &CheckCode::A002,
|
||||
|
@ -776,7 +794,8 @@ impl CheckKind {
|
|||
CheckKind::YieldOutsideFunction => {
|
||||
"`yield` or `yield from` statement outside of a function/method".to_string()
|
||||
}
|
||||
|
||||
// More style
|
||||
CheckKind::NoNewLineAtEndOfFile => "No newline at end of file".to_string(),
|
||||
// flake8-builtins
|
||||
CheckKind::BuiltinVariableShadowing(name) => {
|
||||
format!("Variable `{name}` is shadowing a python builtin")
|
||||
|
|
|
@ -339,6 +339,30 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn w292_0() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
Path::new("./resources/test/fixtures/W292_0.py"),
|
||||
&settings::Settings::for_rule(CheckCode::W292),
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn w292_1() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
Path::new("./resources/test/fixtures/W292_1.py"),
|
||||
&settings::Settings::for_rule(CheckCode::W292),
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f401() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
|
|
13
src/snapshots/ruff__linter__tests__w292.snap
Normal file
13
src/snapshots/ruff__linter__tests__w292.snap
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: NoNewLineAtEndOfFile
|
||||
location:
|
||||
row: 2
|
||||
column: 9
|
||||
end_location:
|
||||
row: 2
|
||||
column: 9
|
||||
fix: ~
|
||||
|
13
src/snapshots/ruff__linter__tests__w292_0.snap
Normal file
13
src/snapshots/ruff__linter__tests__w292_0.snap
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: NoNewLineAtEndOfFile
|
||||
location:
|
||||
row: 2
|
||||
column: 9
|
||||
end_location:
|
||||
row: 2
|
||||
column: 9
|
||||
fix: ~
|
||||
|
6
src/snapshots/ruff__linter__tests__w292_1.snap
Normal file
6
src/snapshots/ruff__linter__tests__w292_1.snap
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
[]
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue