mirror of https://github.com/astral-sh/ruff
Implement F407
This commit is contained in:
parent
549732b1da
commit
27ba8900eb
|
|
@ -124,7 +124,7 @@ ruff's goal is to achieve feature-parity with Flake8 when used (1) without any p
|
|||
stylistic checks; limiting to Python 3 obviates the need for certain compatibility checks.)
|
||||
|
||||
Under those conditions, Flake8 implements about 58 rules, give or take. At time of writing, ruff
|
||||
implements 30 rules. (Note that these 30 rules likely cover a disproportionate share of errors:
|
||||
implements 31 rules. (Note that these 31 rules likely cover a disproportionate share of errors:
|
||||
unused imports, undefined variables, etc.)
|
||||
|
||||
Of the unimplemented rules, ruff is missing:
|
||||
|
|
@ -158,6 +158,7 @@ Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis F
|
|||
| F401 | UnusedImport | `...` imported but unused |
|
||||
| F403 | ImportStarUsage | Unable to detect undefined names |
|
||||
| F404 | LateFutureImport | from __future__ imports must occur at the beginning of the file |
|
||||
| F407 | FutureFeatureNotDefined | future feature '...' is not defined |
|
||||
| F541 | FStringMissingPlaceholders | f-string without any placeholders |
|
||||
| F601 | MultiValueRepeatedKeyLiteral | Dictionary key literal repeated |
|
||||
| F602 | MultiValueRepeatedKeyVariable | Dictionary key `...` repeated |
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ fn main() {
|
|||
CheckKind::DoNotAssignLambda,
|
||||
CheckKind::DuplicateArgumentName,
|
||||
CheckKind::FStringMissingPlaceholders,
|
||||
CheckKind::FutureFeatureNotDefined("...".to_string()),
|
||||
CheckKind::IOError("...".to_string()),
|
||||
CheckKind::IfTuple,
|
||||
CheckKind::ImportStarUsage,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
from __future__ import print_function
|
||||
from __future__ import non_existent_feature
|
||||
|
|
@ -14,6 +14,7 @@ select = [
|
|||
"F401",
|
||||
"F403",
|
||||
"F404",
|
||||
"F407",
|
||||
"F541",
|
||||
"F601",
|
||||
"F602",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::ops::Deref;
|
||||
use std::path::Path;
|
||||
|
||||
use rustpython_parser::ast::{
|
||||
|
|
@ -14,6 +15,7 @@ use crate::ast::{checks, operations, visitor};
|
|||
use crate::autofix::fixer;
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
use crate::python::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||
use crate::python::future::ALL_FEATURE_NAMES;
|
||||
use crate::python::typing;
|
||||
use crate::settings::Settings;
|
||||
|
||||
|
|
@ -391,7 +393,16 @@ where
|
|||
},
|
||||
);
|
||||
|
||||
if !self.futures_allowed && self.settings.select.contains(&CheckCode::F404)
|
||||
if self.settings.select.contains(&CheckCode::F407)
|
||||
&& !ALL_FEATURE_NAMES.contains(&alias.node.name.deref())
|
||||
{
|
||||
self.checks.push(Check::new(
|
||||
CheckKind::FutureFeatureNotDefined(alias.node.name.to_string()),
|
||||
stmt.location,
|
||||
));
|
||||
}
|
||||
|
||||
if self.settings.select.contains(&CheckCode::F404) && !self.futures_allowed
|
||||
{
|
||||
self.checks
|
||||
.push(Check::new(CheckKind::LateFutureImport, stmt.location));
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ pub enum CheckCode {
|
|||
F401,
|
||||
F403,
|
||||
F404,
|
||||
F407,
|
||||
F541,
|
||||
F601,
|
||||
F602,
|
||||
|
|
@ -57,6 +58,7 @@ impl FromStr for CheckCode {
|
|||
"F401" => Ok(CheckCode::F401),
|
||||
"F403" => Ok(CheckCode::F403),
|
||||
"F404" => Ok(CheckCode::F404),
|
||||
"F407" => Ok(CheckCode::F407),
|
||||
"F541" => Ok(CheckCode::F541),
|
||||
"F601" => Ok(CheckCode::F601),
|
||||
"F602" => Ok(CheckCode::F602),
|
||||
|
|
@ -95,6 +97,7 @@ impl CheckCode {
|
|||
CheckCode::F401 => "F401",
|
||||
CheckCode::F403 => "F403",
|
||||
CheckCode::F404 => "F404",
|
||||
CheckCode::F407 => "F407",
|
||||
CheckCode::F541 => "F541",
|
||||
CheckCode::F601 => "F601",
|
||||
CheckCode::F602 => "F602",
|
||||
|
|
@ -131,6 +134,7 @@ impl CheckCode {
|
|||
CheckCode::F401 => &LintSource::AST,
|
||||
CheckCode::F403 => &LintSource::AST,
|
||||
CheckCode::F404 => &LintSource::AST,
|
||||
CheckCode::F407 => &LintSource::AST,
|
||||
CheckCode::F541 => &LintSource::AST,
|
||||
CheckCode::F601 => &LintSource::AST,
|
||||
CheckCode::F602 => &LintSource::AST,
|
||||
|
|
@ -174,6 +178,7 @@ pub enum CheckKind {
|
|||
DoNotAssignLambda,
|
||||
DuplicateArgumentName,
|
||||
FStringMissingPlaceholders,
|
||||
FutureFeatureNotDefined(String),
|
||||
IOError(String),
|
||||
IfTuple,
|
||||
ImportStarUsage,
|
||||
|
|
@ -209,6 +214,7 @@ impl CheckKind {
|
|||
CheckKind::DefaultExceptNotLast => "DefaultExceptNotLast",
|
||||
CheckKind::DuplicateArgumentName => "DuplicateArgumentName",
|
||||
CheckKind::FStringMissingPlaceholders => "FStringMissingPlaceholders",
|
||||
CheckKind::FutureFeatureNotDefined(_) => "FutureFeatureNotDefined",
|
||||
CheckKind::IOError(_) => "IOError",
|
||||
CheckKind::IfTuple => "IfTuple",
|
||||
CheckKind::ImportStarUsage => "ImportStarUsage",
|
||||
|
|
@ -246,6 +252,7 @@ impl CheckKind {
|
|||
CheckKind::DefaultExceptNotLast => &CheckCode::F707,
|
||||
CheckKind::DuplicateArgumentName => &CheckCode::F831,
|
||||
CheckKind::FStringMissingPlaceholders => &CheckCode::F541,
|
||||
CheckKind::FutureFeatureNotDefined(_) => &CheckCode::F407,
|
||||
CheckKind::IOError(_) => &CheckCode::E902,
|
||||
CheckKind::IfTuple => &CheckCode::F634,
|
||||
CheckKind::ImportStarUsage => &CheckCode::F403,
|
||||
|
|
@ -290,6 +297,9 @@ impl CheckKind {
|
|||
CheckKind::FStringMissingPlaceholders => {
|
||||
"f-string without any placeholders".to_string()
|
||||
}
|
||||
CheckKind::FutureFeatureNotDefined(name) => {
|
||||
format!("future feature '{name}' is not defined")
|
||||
}
|
||||
CheckKind::IOError(name) => {
|
||||
format!("No such file or directory: `{name}`")
|
||||
}
|
||||
|
|
@ -384,6 +394,7 @@ impl CheckKind {
|
|||
CheckKind::DoNotAssignLambda => false,
|
||||
CheckKind::DuplicateArgumentName => false,
|
||||
CheckKind::FStringMissingPlaceholders => false,
|
||||
CheckKind::FutureFeatureNotDefined(_) => false,
|
||||
CheckKind::IOError(_) => false,
|
||||
CheckKind::IfTuple => false,
|
||||
CheckKind::ImportStarUsage => false,
|
||||
|
|
|
|||
|
|
@ -535,6 +535,31 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f407() -> Result<()> {
|
||||
let mut actual = check_path(
|
||||
Path::new("./resources/test/fixtures/F407.py"),
|
||||
&settings::Settings {
|
||||
line_length: 88,
|
||||
exclude: vec![],
|
||||
select: BTreeSet::from([CheckCode::F407]),
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
actual.sort_by_key(|check| check.location);
|
||||
let expected = vec![Check {
|
||||
kind: CheckKind::FutureFeatureNotDefined("non_existent_feature".to_string()),
|
||||
location: Location::new(2, 1),
|
||||
fix: None,
|
||||
}];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
for i in 0..actual.len() {
|
||||
assert_eq!(actual[i], expected[i]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f541() -> Result<()> {
|
||||
let mut actual = check_path(
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ other-attribute = 1
|
|||
CheckCode::F401,
|
||||
CheckCode::F403,
|
||||
CheckCode::F404,
|
||||
CheckCode::F407,
|
||||
CheckCode::F541,
|
||||
CheckCode::F601,
|
||||
CheckCode::F602,
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
pub mod builtins;
|
||||
pub mod future;
|
||||
pub mod typing;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
/// A copy of `__future__.all_feature_names`.
|
||||
pub const ALL_FEATURE_NAMES: &[&str] = &[
|
||||
"nested_scopes",
|
||||
"generators",
|
||||
"division",
|
||||
"absolute_import",
|
||||
"with_statement",
|
||||
"print_function",
|
||||
"unicode_literals",
|
||||
"barry_as_FLUFL",
|
||||
"generator_stop",
|
||||
"annotations",
|
||||
];
|
||||
|
|
@ -55,6 +55,7 @@ impl Settings {
|
|||
CheckCode::E902,
|
||||
CheckCode::F401,
|
||||
CheckCode::F403,
|
||||
CheckCode::F407,
|
||||
CheckCode::F541,
|
||||
CheckCode::F601,
|
||||
CheckCode::F602,
|
||||
|
|
|
|||
Loading…
Reference in New Issue