Implement F722

This commit is contained in:
Charlie Marsh 2022-09-12 21:34:12 -04:00
parent dfba1416b2
commit 00f82b11a9
9 changed files with 56 additions and 3 deletions

View File

@ -124,13 +124,13 @@ 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 60 rules, give or take. At time of writing, ruff
implements 37 rules. (Note that these 37 rules likely cover a disproportionate share of errors:
implements 38 rules. (Note that these 38 rules likely cover a disproportionate share of errors:
unused imports, undefined variables, etc.)
The 23 unimplemented rules are tracked in #170, and include:
The unimplemented rules are tracked in #170, and include:
- 14 rules related to string `.format` calls.
- 3 rules related to parsing and syntax errors.
- 1 rule related to parsing and syntax.
- 6 logical rules.
Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis Flake8:
@ -172,6 +172,7 @@ Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis F
| F704 | YieldOutsideFunction | a `yield` or `yield from` statement outside of a function/method |
| F706 | ReturnOutsideFunction | a `return` statement outside of a function/method |
| F707 | DefaultExceptNotLast | an `except:` block as not the last exception handler |
| F722 | ForwardAnnotationSyntaxError | syntax error in forward annotation '...' |
| F821 | UndefinedName | Undefined name `...` |
| F822 | UndefinedExport | Undefined name `...` in `__all__` |
| F823 | UndefinedLocal | Local variable `...` referenced before assignment |

View File

@ -13,6 +13,7 @@ fn main() {
CheckKind::DoNotAssignLambda,
CheckKind::DoNotUseBareExcept,
CheckKind::DuplicateArgumentName,
CheckKind::ForwardAnnotationSyntaxError("...".to_string()),
CheckKind::FStringMissingPlaceholders,
CheckKind::FutureFeatureNotDefined("...".to_string()),
CheckKind::IOError("...".to_string()),

10
resources/test/fixtures/F722.py vendored Normal file
View File

@ -0,0 +1,10 @@
class A:
pass
def f() -> "A":
pass
def g() -> "///":
pass

View File

@ -31,6 +31,7 @@ select = [
"F704",
"F706",
"F707",
"F722",
"F821",
"F822",
"F823",

View File

@ -1181,6 +1181,11 @@ impl<'a> Checker<'a> {
if let Ok(mut expr) = parser::parse_expression(expression, path) {
relocate_expr(&mut expr, location);
allocator.push(expr);
} else if self.settings.select.contains(&CheckCode::F722) {
self.checks.push(Check::new(
CheckKind::ForwardAnnotationSyntaxError(expression.to_string()),
location,
));
}
}
for expr in allocator {

View File

@ -37,6 +37,7 @@ pub enum CheckCode {
F704,
F706,
F707,
F722,
F821,
F822,
F823,
@ -126,6 +127,7 @@ impl CheckCode {
CheckCode::F704 => "F704",
CheckCode::F706 => "F706",
CheckCode::F707 => "F707",
CheckCode::F722 => "F722",
CheckCode::F821 => "F821",
CheckCode::F822 => "F822",
CheckCode::F823 => "F823",
@ -172,6 +174,7 @@ pub enum CheckKind {
DoNotAssignLambda,
DoNotUseBareExcept,
DuplicateArgumentName,
ForwardAnnotationSyntaxError(String),
FStringMissingPlaceholders,
FutureFeatureNotDefined(String),
IOError(String),
@ -215,6 +218,7 @@ impl CheckKind {
CheckKind::DoNotAssignLambda => "DoNotAssignLambda",
CheckKind::DoNotUseBareExcept => "DoNotUseBareExcept",
CheckKind::DuplicateArgumentName => "DuplicateArgumentName",
CheckKind::ForwardAnnotationSyntaxError(_) => "ForwardAnnotationSyntaxError",
CheckKind::FStringMissingPlaceholders => "FStringMissingPlaceholders",
CheckKind::FutureFeatureNotDefined(_) => "FutureFeatureNotDefined",
CheckKind::IOError(_) => "IOError",
@ -260,6 +264,7 @@ impl CheckKind {
CheckKind::DoNotAssignLambda => &CheckCode::E731,
CheckKind::DoNotUseBareExcept => &CheckCode::E722,
CheckKind::DuplicateArgumentName => &CheckCode::F831,
CheckKind::ForwardAnnotationSyntaxError(_) => &CheckCode::F722,
CheckKind::FStringMissingPlaceholders => &CheckCode::F541,
CheckKind::FutureFeatureNotDefined(_) => &CheckCode::F407,
CheckKind::IOError(_) => &CheckCode::E902,
@ -317,6 +322,9 @@ impl CheckKind {
CheckKind::DuplicateArgumentName => {
"Duplicate argument name in function definition".to_string()
}
CheckKind::ForwardAnnotationSyntaxError(body) => {
format!("syntax error in forward annotation '{body}'")
}
CheckKind::FStringMissingPlaceholders => {
"f-string without any placeholders".to_string()
}

View File

@ -1073,6 +1073,31 @@ mod tests {
Ok(())
}
#[test]
fn f722() -> Result<()> {
let mut actual = check_path(
Path::new("./resources/test/fixtures/F722.py"),
&settings::Settings {
line_length: 88,
exclude: vec![],
select: BTreeSet::from([CheckCode::F722]),
},
&fixer::Mode::Generate,
)?;
actual.sort_by_key(|check| check.location);
let expected = vec![Check {
kind: CheckKind::ForwardAnnotationSyntaxError("///".to_string()),
location: Location::new(9, 13),
fix: None,
}];
assert_eq!(actual.len(), expected.len());
for i in 0..actual.len() {
assert_eq!(actual[i], expected[i]);
}
Ok(())
}
#[test]
fn f821() -> Result<()> {
let mut actual = check_path(

View File

@ -288,6 +288,7 @@ other-attribute = 1
CheckCode::F704,
CheckCode::F706,
CheckCode::F707,
CheckCode::F722,
CheckCode::F821,
CheckCode::F822,
CheckCode::F823,

View File

@ -72,6 +72,7 @@ impl Settings {
CheckCode::F704,
CheckCode::F706,
CheckCode::F707,
CheckCode::F722,
CheckCode::F821,
CheckCode::F822,
CheckCode::F823,