Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e8c237167 | ||
|
|
960c5e2006 | ||
|
|
9ba17fbf92 | ||
|
|
bfdf972a5d |
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.204
|
||||
rev: v0.0.205
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -750,7 +750,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.204-dev.0"
|
||||
version = "0.0.205-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.32",
|
||||
@@ -1878,7 +1878,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.204"
|
||||
version = "0.0.205"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1946,7 +1946,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.204"
|
||||
version = "0.0.205"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.32",
|
||||
@@ -1967,7 +1967,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.204"
|
||||
version = "0.0.205"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.204"
|
||||
version = "0.0.205"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
@@ -51,7 +51,7 @@ path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix
|
||||
quick-junit = { version = "0.3.2" }
|
||||
regex = { version = "1.6.0" }
|
||||
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
|
||||
ruff_macros = { version = "0.0.204", path = "ruff_macros" }
|
||||
ruff_macros = { version = "0.0.205", path = "ruff_macros" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "8cb2b8292062adf13bde1b863a9b02c9f0bda3dd" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "8cb2b8292062adf13bde1b863a9b02c9f0bda3dd" }
|
||||
|
||||
@@ -169,7 +169,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.204'
|
||||
rev: 'v0.0.205'
|
||||
hooks:
|
||||
- id: ruff
|
||||
# Respect `exclude` and `extend-exclude` settings.
|
||||
|
||||
4
flake8_to_ruff/Cargo.lock
generated
4
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.204"
|
||||
version = "0.0.205"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.204"
|
||||
version = "0.0.205"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.204-dev.0"
|
||||
version = "0.0.205-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function SourceEditor({
|
||||
.filter((check) => check.fix)
|
||||
.map((check) => ({
|
||||
title: check.fix
|
||||
? check.fix.message ?? `Fix ${check.code}`
|
||||
? `${check.code}: ${check.fix.message}` ?? `Fix ${check.code}`
|
||||
: "Autofix",
|
||||
id: `fix-${check.code}`,
|
||||
kind: "quickfix",
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "ruff"
|
||||
version = "0.0.204"
|
||||
version = "0.0.205"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
authors = [
|
||||
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
|
||||
|
||||
14
resources/test/fixtures/pyflakes/F541.py
vendored
14
resources/test/fixtures/pyflakes/F541.py
vendored
@@ -1,6 +1,8 @@
|
||||
# OK
|
||||
a = "abc"
|
||||
b = f"ghi{'jkl'}"
|
||||
|
||||
# Errors
|
||||
c = f"def"
|
||||
d = f"def" + "ghi"
|
||||
e = (
|
||||
@@ -8,5 +10,17 @@ e = (
|
||||
"ghi"
|
||||
)
|
||||
|
||||
# OK
|
||||
g = f"ghi{123:{45}}"
|
||||
|
||||
# Error
|
||||
h = "x" "y" f"z"
|
||||
|
||||
v = 23.234234
|
||||
|
||||
# OK
|
||||
f"{v:0.2f}"
|
||||
|
||||
# OK (false negatives)
|
||||
f"{v:{f'0.2f'}}"
|
||||
f"{f''}"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.204"
|
||||
version = "0.0.205"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.204"
|
||||
version = "0.0.205"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -5,7 +5,7 @@ use regex::Regex;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_ast::{
|
||||
Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprKind, Keyword, KeywordData,
|
||||
Location, Stmt, StmtKind,
|
||||
Located, Location, Stmt, StmtKind,
|
||||
};
|
||||
use rustpython_parser::lexer;
|
||||
use rustpython_parser::lexer::Tok;
|
||||
@@ -395,6 +395,19 @@ pub fn identifier_range(stmt: &Stmt, locator: &SourceCodeLocator) -> Range {
|
||||
Range::from_located(stmt)
|
||||
}
|
||||
|
||||
// Return the ranges of `Name` tokens within a specified node.
|
||||
pub fn find_names<T>(located: &Located<T>, locator: &SourceCodeLocator) -> Vec<Range> {
|
||||
let contents = locator.slice_source_code_range(&Range::from_located(located));
|
||||
lexer::make_tokenizer_located(&contents, located.location)
|
||||
.flatten()
|
||||
.filter(|(_, tok, _)| matches!(tok, Tok::Name { .. }))
|
||||
.map(|(start, _, end)| Range {
|
||||
location: start,
|
||||
end_location: end,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Return the `Range` of `name` in `Excepthandler`.
|
||||
pub fn excepthandler_name_range(
|
||||
handler: &Excepthandler,
|
||||
|
||||
@@ -91,6 +91,7 @@ pub struct Checker<'a> {
|
||||
in_type_definition: bool,
|
||||
in_deferred_string_type_definition: bool,
|
||||
in_deferred_type_definition: bool,
|
||||
in_f_string: bool,
|
||||
in_literal: bool,
|
||||
in_subscript: bool,
|
||||
seen_import_boundary: bool,
|
||||
@@ -147,6 +148,7 @@ impl<'a> Checker<'a> {
|
||||
in_type_definition: false,
|
||||
in_deferred_string_type_definition: false,
|
||||
in_deferred_type_definition: false,
|
||||
in_f_string: false,
|
||||
in_literal: false,
|
||||
in_subscript: false,
|
||||
seen_import_boundary: false,
|
||||
@@ -264,16 +266,17 @@ where
|
||||
match &stmt.node {
|
||||
StmtKind::Global { names } => {
|
||||
let scope_index = *self.scope_stack.last().expect("No current scope found");
|
||||
let ranges = helpers::find_names(stmt, self.locator);
|
||||
if scope_index != GLOBAL_SCOPE_INDEX {
|
||||
// Add the binding to the current scope.
|
||||
let scope = &mut self.scopes[scope_index];
|
||||
let usage = Some((scope.id, Range::from_located(stmt)));
|
||||
for name in names {
|
||||
for (name, range) in names.iter().zip(ranges.iter()) {
|
||||
let index = self.bindings.len();
|
||||
self.bindings.push(Binding {
|
||||
kind: BindingKind::Global,
|
||||
used: usage,
|
||||
range: Range::from_located(stmt),
|
||||
range: *range,
|
||||
source: Some(RefEquality(stmt)),
|
||||
});
|
||||
scope.values.insert(name, index);
|
||||
@@ -284,8 +287,9 @@ where
|
||||
self.add_checks(
|
||||
names
|
||||
.iter()
|
||||
.filter_map(|name| {
|
||||
pycodestyle::checks::ambiguous_variable_name(name, stmt)
|
||||
.zip(ranges.iter())
|
||||
.filter_map(|(name, range)| {
|
||||
pycodestyle::checks::ambiguous_variable_name(name, *range)
|
||||
})
|
||||
.into_iter(),
|
||||
);
|
||||
@@ -293,16 +297,17 @@ where
|
||||
}
|
||||
StmtKind::Nonlocal { names } => {
|
||||
let scope_index = *self.scope_stack.last().expect("No current scope found");
|
||||
let ranges = helpers::find_names(stmt, self.locator);
|
||||
if scope_index != GLOBAL_SCOPE_INDEX {
|
||||
let scope = &mut self.scopes[scope_index];
|
||||
let usage = Some((scope.id, Range::from_located(stmt)));
|
||||
for name in names {
|
||||
for (name, range) in names.iter().zip(ranges.iter()) {
|
||||
// Add a binding to the current scope.
|
||||
let index = self.bindings.len();
|
||||
self.bindings.push(Binding {
|
||||
kind: BindingKind::Nonlocal,
|
||||
used: usage,
|
||||
range: Range::from_located(stmt),
|
||||
range: *range,
|
||||
source: Some(RefEquality(stmt)),
|
||||
});
|
||||
scope.values.insert(name, index);
|
||||
@@ -310,7 +315,7 @@ where
|
||||
|
||||
// Mark the binding in the defining scopes as used too. (Skip the global scope
|
||||
// and the current scope.)
|
||||
for name in names {
|
||||
for (name, range) in names.iter().zip(ranges.iter()) {
|
||||
let mut exists = false;
|
||||
for index in self.scope_stack.iter().skip(1).rev().skip(1) {
|
||||
if let Some(index) = self.scopes[*index].values.get(&name.as_str()) {
|
||||
@@ -324,7 +329,7 @@ where
|
||||
if self.settings.enabled.contains(&CheckCode::PLE0117) {
|
||||
self.add_check(Check::new(
|
||||
CheckKind::NonlocalWithoutBinding(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
*range,
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -335,8 +340,9 @@ where
|
||||
self.add_checks(
|
||||
names
|
||||
.iter()
|
||||
.filter_map(|name| {
|
||||
pycodestyle::checks::ambiguous_variable_name(name, stmt)
|
||||
.zip(ranges.iter())
|
||||
.filter_map(|(name, range)| {
|
||||
pycodestyle::checks::ambiguous_variable_name(name, *range)
|
||||
})
|
||||
.into_iter(),
|
||||
);
|
||||
@@ -1466,6 +1472,7 @@ where
|
||||
|
||||
self.push_expr(expr);
|
||||
|
||||
let prev_in_f_string = self.in_f_string;
|
||||
let prev_in_literal = self.in_literal;
|
||||
let prev_in_type_definition = self.in_type_definition;
|
||||
|
||||
@@ -1540,9 +1547,10 @@ where
|
||||
}
|
||||
ExprContext::Store => {
|
||||
if self.settings.enabled.contains(&CheckCode::E741) {
|
||||
if let Some(check) =
|
||||
pycodestyle::checks::ambiguous_variable_name(id, expr)
|
||||
{
|
||||
if let Some(check) = pycodestyle::checks::ambiguous_variable_name(
|
||||
id,
|
||||
Range::from_located(expr),
|
||||
) {
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
@@ -2151,7 +2159,9 @@ where
|
||||
}
|
||||
}
|
||||
ExprKind::JoinedStr { values } => {
|
||||
if self.settings.enabled.contains(&CheckCode::F541) {
|
||||
// Conversion flags are parsed as f-strings without placeholders, so skip
|
||||
// nested f-strings, which would lead to false positives.
|
||||
if !self.in_f_string && self.settings.enabled.contains(&CheckCode::F541) {
|
||||
if !values
|
||||
.iter()
|
||||
.any(|value| matches!(value.node, ExprKind::FormattedValue { .. }))
|
||||
@@ -2654,6 +2664,11 @@ where
|
||||
}
|
||||
self.in_subscript = prev_in_subscript;
|
||||
}
|
||||
ExprKind::JoinedStr { .. } => {
|
||||
self.in_f_string = true;
|
||||
visitor::walk_expr(self, expr);
|
||||
self.in_f_string = prev_in_f_string;
|
||||
}
|
||||
_ => visitor::walk_expr(self, expr),
|
||||
}
|
||||
|
||||
@@ -2671,6 +2686,7 @@ where
|
||||
|
||||
self.in_type_definition = prev_in_type_definition;
|
||||
self.in_literal = prev_in_literal;
|
||||
self.in_f_string = prev_in_f_string;
|
||||
|
||||
self.pop_expr();
|
||||
}
|
||||
@@ -2704,9 +2720,11 @@ where
|
||||
match name {
|
||||
Some(name) => {
|
||||
if self.settings.enabled.contains(&CheckCode::E741) {
|
||||
if let Some(check) =
|
||||
pycodestyle::checks::ambiguous_variable_name(name, excepthandler)
|
||||
{
|
||||
if let Some(check) = pycodestyle::checks::ambiguous_variable_name(
|
||||
name,
|
||||
helpers::excepthandler_name_range(excepthandler, self.locator)
|
||||
.expect("Failed to find `name` range"),
|
||||
) {
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
@@ -2823,7 +2841,10 @@ where
|
||||
);
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::E741) {
|
||||
if let Some(check) = pycodestyle::checks::ambiguous_variable_name(&arg.node.arg, arg) {
|
||||
if let Some(check) = pycodestyle::checks::ambiguous_variable_name(
|
||||
&arg.node.arg,
|
||||
Range::from_located(arg),
|
||||
) {
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use itertools::izip;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_ast::{Constant, Excepthandler, Located, Location, Stmt, StmtKind};
|
||||
use rustpython_ast::{Constant, Excepthandler, Location, Stmt, StmtKind};
|
||||
use rustpython_parser::ast::{Cmpop, Expr, ExprKind};
|
||||
|
||||
use crate::ast::helpers::except_range;
|
||||
@@ -111,11 +111,11 @@ fn is_ambiguous_name(name: &str) -> bool {
|
||||
}
|
||||
|
||||
/// E741
|
||||
pub fn ambiguous_variable_name<T>(name: &str, located: &Located<T>) -> Option<Check> {
|
||||
pub fn ambiguous_variable_name(name: &str, range: Range) -> Option<Check> {
|
||||
if is_ambiguous_name(name) {
|
||||
Some(Check::new(
|
||||
CheckKind::AmbiguousVariableName(name.to_string()),
|
||||
Range::from_located(located),
|
||||
range,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -106,7 +106,7 @@ expression: checks
|
||||
AmbiguousVariableName: l
|
||||
location:
|
||||
row: 25
|
||||
column: 4
|
||||
column: 11
|
||||
end_location:
|
||||
row: 25
|
||||
column: 12
|
||||
@@ -136,7 +136,7 @@ expression: checks
|
||||
AmbiguousVariableName: l
|
||||
location:
|
||||
row: 33
|
||||
column: 8
|
||||
column: 17
|
||||
end_location:
|
||||
row: 33
|
||||
column: 18
|
||||
@@ -236,10 +236,10 @@ expression: checks
|
||||
AmbiguousVariableName: l
|
||||
location:
|
||||
row: 71
|
||||
column: 0
|
||||
column: 21
|
||||
end_location:
|
||||
row: 72
|
||||
column: 8
|
||||
row: 71
|
||||
column: 22
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
|
||||
@@ -4,19 +4,10 @@ expression: checks
|
||||
---
|
||||
- kind: FStringMissingPlaceholders
|
||||
location:
|
||||
row: 4
|
||||
row: 6
|
||||
column: 4
|
||||
end_location:
|
||||
row: 4
|
||||
column: 10
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind: FStringMissingPlaceholders
|
||||
location:
|
||||
row: 5
|
||||
column: 4
|
||||
end_location:
|
||||
row: 5
|
||||
row: 6
|
||||
column: 10
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -31,10 +22,19 @@ expression: checks
|
||||
parent: ~
|
||||
- kind: FStringMissingPlaceholders
|
||||
location:
|
||||
row: 12
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 12
|
||||
row: 9
|
||||
column: 10
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind: FStringMissingPlaceholders
|
||||
location:
|
||||
row: 17
|
||||
column: 4
|
||||
end_location:
|
||||
row: 17
|
||||
column: 16
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -6,7 +6,7 @@ expression: checks
|
||||
NonlocalWithoutBinding: x
|
||||
location:
|
||||
row: 5
|
||||
column: 4
|
||||
column: 13
|
||||
end_location:
|
||||
row: 5
|
||||
column: 14
|
||||
@@ -16,7 +16,7 @@ expression: checks
|
||||
NonlocalWithoutBinding: y
|
||||
location:
|
||||
row: 9
|
||||
column: 4
|
||||
column: 13
|
||||
end_location:
|
||||
row: 9
|
||||
column: 14
|
||||
@@ -26,7 +26,7 @@ expression: checks
|
||||
NonlocalWithoutBinding: y
|
||||
location:
|
||||
row: 19
|
||||
column: 8
|
||||
column: 17
|
||||
end_location:
|
||||
row: 19
|
||||
column: 18
|
||||
|
||||
@@ -6,7 +6,7 @@ expression: checks
|
||||
GlobalVariableNotAssigned: x
|
||||
location:
|
||||
row: 5
|
||||
column: 4
|
||||
column: 11
|
||||
end_location:
|
||||
row: 5
|
||||
column: 12
|
||||
@@ -16,7 +16,7 @@ expression: checks
|
||||
GlobalVariableNotAssigned: x
|
||||
location:
|
||||
row: 9
|
||||
column: 4
|
||||
column: 11
|
||||
end_location:
|
||||
row: 9
|
||||
column: 12
|
||||
|
||||
Reference in New Issue
Block a user