Compare commits

..

2 Commits

Author SHA1 Message Date
Charlie Marsh
2446cd49fa Make CallPath its own struct 2023-04-01 12:06:01 -04:00
Charlie Marsh
5f5e71e81d Make collect_call_path return an Option 2023-04-01 12:05:52 -04:00
138 changed files with 760 additions and 1772 deletions

26
Cargo.lock generated
View File

@@ -774,7 +774,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.0.261"
version = "0.0.260"
dependencies = [
"anyhow",
"clap 4.1.8",
@@ -1977,7 +1977,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.261"
version = "0.0.260"
dependencies = [
"anyhow",
"bitflags",
@@ -2010,7 +2010,6 @@ dependencies = [
"ruff_diagnostics",
"ruff_macros",
"ruff_python_ast",
"ruff_python_semantic",
"ruff_python_stdlib",
"ruff_rustpython",
"rustc-hash",
@@ -2060,7 +2059,7 @@ dependencies = [
[[package]]
name = "ruff_cli"
version = "0.0.261"
version = "0.0.260"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -2088,7 +2087,6 @@ dependencies = [
"ruff",
"ruff_cache",
"ruff_diagnostics",
"ruff_python_ast",
"ruff_python_stdlib",
"rustc-hash",
"serde",
@@ -2171,15 +2169,16 @@ dependencies = [
"is-macro",
"itertools",
"log",
"nohash-hasher",
"num-bigint",
"num-traits",
"once_cell",
"regex",
"ruff_python_stdlib",
"ruff_rustpython",
"rustc-hash",
"rustpython-common",
"rustpython-parser",
"serde",
"smallvec",
]
@@ -2195,6 +2194,7 @@ dependencies = [
"once_cell",
"ruff_formatter",
"ruff_python_ast",
"ruff_python_stdlib",
"ruff_rustpython",
"ruff_testing_macros",
"ruff_text_size",
@@ -2205,20 +2205,6 @@ dependencies = [
"test-case",
]
[[package]]
name = "ruff_python_semantic"
version = "0.0.0"
dependencies = [
"bitflags",
"is-macro",
"nohash-hasher",
"ruff_python_ast",
"ruff_python_stdlib",
"rustc-hash",
"rustpython-parser",
"smallvec",
]
[[package]]
name = "ruff_python_stdlib"
version = "0.0.0"

View File

@@ -24,7 +24,6 @@ is-macro = { version = "0.2.2" }
itertools = { version = "0.10.5" }
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "80e4c1399f95e5beb532fdd1e209ad2dbb470438" }
log = { version = "0.4.17" }
nohash-hasher = { version = "0.2.0" }
once_cell = { version = "1.17.1" }
path-absolutize = { version = "3.0.14" }
proc-macro2 = { version = "1.0.51" }
@@ -41,7 +40,6 @@ serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.93", features = ["preserve_order"] }
shellexpand = { version = "3.0.0" }
similar = { version = "2.2.1" }
smallvec = { version = "1.10.0" }
strum = { version = "0.24.1", features = ["strum_macros"] }
strum_macros = { version = "0.24.3" }
syn = { version = "1.0.109" }

View File

@@ -137,7 +137,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
```yaml
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.261'
rev: 'v0.0.260'
hooks:
- id: ruff
```
@@ -145,20 +145,6 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
Ruff can also be used as a [VS Code extension](https://github.com/charliermarsh/ruff-vscode) or
alongside any other editor through the [Ruff LSP](https://github.com/charliermarsh/ruff-lsp).
Ruff can also be used as a [GitHub Action](https://github.com/features/actions) via
[`ruff-action`](https://github.com/chartboost/ruff-action):
```yaml
name: Ruff
on: [ push, pull_request ]
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: chartboost/ruff-action@v1
```
### Configuration
Ruff can be configured through a `pyproject.toml`, `ruff.toml`, or `.ruff.toml` file (see:
@@ -378,9 +364,6 @@ Ruff is used in a number of major open-source projects, including:
- [Neon](https://github.com/neondatabase/neon)
- [The Algorithms](https://github.com/TheAlgorithms/Python)
- [Openverse](https://github.com/WordPress/openverse)
- [MegaLinter](https://github.com/oxsecurity/megalinter)
- [LangChain](https://github.com/hwchase17/langchain)
- [LlamaIndex](https://github.com/jerryjliu/llama_index)
## License

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.0.261"
version = "0.0.260"
edition = { workspace = true }
rust-version = { workspace = true }

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff"
version = "0.0.261"
version = "0.0.260"
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
@@ -18,7 +18,6 @@ ruff_cache = { path = "../ruff_cache" }
ruff_diagnostics = { path = "../ruff_diagnostics", features = ["serde"] }
ruff_macros = { path = "../ruff_macros" }
ruff_python_ast = { path = "../ruff_python_ast" }
ruff_python_semantic = { path = "../ruff_python_semantic" }
ruff_python_stdlib = { path = "../ruff_python_stdlib" }
ruff_rustpython = { path = "../ruff_rustpython" }
@@ -38,7 +37,7 @@ itertools = { workspace = true }
libcst = { workspace = true }
log = { workspace = true }
natord = { version = "1.0.9" }
nohash-hasher = { workspace = true }
nohash-hasher = { version = "0.2.0" }
num-bigint = { version = "0.4.3" }
num-traits = { version = "0.2.15" }
once_cell = { workspace = true }
@@ -58,7 +57,7 @@ semver = { version = "1.0.16" }
serde = { workspace = true }
serde_json = { workspace = true }
shellexpand = { workspace = true }
smallvec = { workspace = true }
smallvec = { version = "1.10.0" }
strum = { workspace = true }
strum_macros = { workspace = true }
textwrap = { workspace = true }

View File

@@ -28,11 +28,6 @@ except (ValueError, *(RuntimeError, (KeyError, TypeError))): # error
pass
try:
pass
except (*a, *(RuntimeError, (KeyError, TypeError))): # error
pass
try:
pass
except (ValueError, *(RuntimeError, TypeError)): # ok
@@ -43,36 +38,10 @@ try:
except (ValueError, *[RuntimeError, *(TypeError,)]): # ok
pass
try:
pass
except (*a, *b): # ok
pass
try:
pass
except (*a, *(RuntimeError, TypeError)): # ok
pass
try:
pass
except (*a, *(b, c)): # ok
pass
try:
pass
except (*a, *(*b, *c)): # ok
pass
def what_to_catch():
return ...
try:
pass
except what_to_catch(): # ok
pass
pass

View File

@@ -78,56 +78,6 @@ for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
for shopper in shoppers:
collect_shop_items(shopper, section_items) # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
if _section == "greens":
collect_shop_items(shopper, section_items)
else:
collect_shop_items(shopper, section_items)
collect_shop_items(shopper, section_items) # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# Mutually exclusive branches shouldn't trigger the warning
if _section == "greens":
collect_shop_items(shopper, section_items)
if _section == "greens":
collect_shop_items(shopper, section_items) # B031
elif _section == "frozen items":
collect_shop_items(shopper, section_items) # B031
else:
collect_shop_items(shopper, section_items) # B031
collect_shop_items(shopper, section_items) # B031
elif _section == "frozen items":
# Mix `match` and `if` statements
match shopper:
case "Jane":
collect_shop_items(shopper, section_items)
if _section == "fourth":
collect_shop_items(shopper, section_items) # B031
case _:
collect_shop_items(shopper, section_items)
else:
collect_shop_items(shopper, section_items)
# Now, it should detect
collect_shop_items(shopper, section_items) # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# Mutually exclusive branches shouldn't trigger the warning
match _section:
case "greens":
collect_shop_items(shopper, section_items)
match shopper:
case "Jane":
collect_shop_items(shopper, section_items) # B031
case _:
collect_shop_items(shopper, section_items) # B031
case "frozen items":
collect_shop_items(shopper, section_items)
collect_shop_items(shopper, section_items) # B031
case _:
collect_shop_items(shopper, section_items)
# Now, it should detect
collect_shop_items(shopper, section_items) # B031
for group in groupby(items, key=lambda p: p[1]):
# This is bad, but not detected currently
collect_shop_items("Jane", group[1])

View File

@@ -1,5 +1,3 @@
import logging
from distutils import log
logging.warn("Hello World!")
log.warn("Hello world!") # This shouldn't be considered as a logger candidate

View File

@@ -1,6 +1,6 @@
import builtins
import typing
from typing import TypeAlias, Final, NewType, TypeVar, TypeVarTuple, ParamSpec
from typing import TypeAlias, Final
# We shouldn't emit Y015 for simple default values
field1: int
@@ -26,10 +26,6 @@ field9 = None # Y026 Use typing_extensions.TypeAlias for type aliases, e.g. "fi
Field95: TypeAlias = None
Field96: TypeAlias = int | None
Field97: TypeAlias = None | typing.SupportsInt | builtins.str | float | bool
Field98 = NewType('MyInt', int)
Field99 = TypeVar('Field99')
Field100 = TypeVarTuple('Field100')
Field101 = ParamSpec('Field101')
field19 = [1, 2, 3] # Y052 Need type annotation for "field19"
field191: list[int] = [1, 2, 3]
field20 = (1, 2, 3) # Y052 Need type annotation for "field20"

View File

@@ -9,17 +9,6 @@ os.environ.get('foo', 'bar')
os.getenv('foo')
env = os.environ.get('foo')
env = os.environ['foo']
if env := os.environ.get('foo'):
pass
if env := os.environ['foo']:
pass
# Good
os.environ['FOO']
@@ -28,13 +17,3 @@ os.environ.get('FOO')
os.environ.get('FOO', 'bar')
os.getenv('FOO')
env = os.getenv('FOO')
if env := os.getenv('FOO'):
pass
env = os.environ['FOO']
if env := os.environ['FOO']:
pass

View File

@@ -1,27 +0,0 @@
# SIM910
{}.get(key, None)
# SIM910
{}.get("key", None)
# OK
{}.get(key)
# OK
{}.get("key")
# OK
{}.get(key, False)
# OK
{}.get("key", False)
# SIM910
if a := {}.get(key, None):
pass
# SIM910
a = {}.get(key, None)
# SIM910
({}).get(key, None)

View File

@@ -1,4 +1,3 @@
//! Interface for generating autofix edits from higher-level actions (e.g., "remove an argument").
use anyhow::{bail, Result};
use itertools::Itertools;
use libcst_native::{
@@ -8,12 +7,12 @@ use rustpython_parser::ast::{ExcepthandlerKind, Expr, Keyword, Location, Stmt, S
use rustpython_parser::{lexer, Mode, Tok};
use ruff_diagnostics::Edit;
use ruff_python_ast::context::Context;
use ruff_python_ast::helpers;
use ruff_python_ast::helpers::to_absolute;
use ruff_python_ast::imports::{AnyImport, Import};
use ruff_python_ast::newlines::NewlineWithTrailingNewline;
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
use ruff_python_semantic::context::Context;
use crate::cst::helpers::compose_module_path;
use crate::cst::matchers::match_module;
@@ -532,7 +531,7 @@ mod tests {
use ruff_python_ast::source_code::Locator;
use crate::autofix::actions::{next_stmt_break, trailing_semicolon};
use crate::autofix::helpers::{next_stmt_break, trailing_semicolon};
#[test]
fn find_semicolon() -> Result<()> {

View File

@@ -11,7 +11,7 @@ use ruff_python_ast::types::Range;
use crate::linter::FixTable;
use crate::registry::{AsRule, Rule};
pub mod actions;
pub mod helpers;
/// Auto-fix errors in a file, and write the fixed source code to disk.
pub fn fix_file(diagnostics: &[Diagnostic], locator: &Locator) -> Option<(String, FixTable)> {

View File

@@ -1,9 +1,9 @@
use ruff_python_semantic::scope::ScopeStack;
use ruff_python_ast::scope::ScopeStack;
use rustpython_parser::ast::{Expr, Stmt};
use ruff_python_ast::types::Range;
use ruff_python_ast::types::RefEquality;
use ruff_python_semantic::analyze::visibility::{Visibility, VisibleScope};
use ruff_python_ast::visibility::{Visibility, VisibleScope};
use crate::checkers::ast::AnnotationContext;
use crate::docstrings::definition::Definition;

View File

@@ -14,22 +14,22 @@ use rustpython_parser::ast::{
use ruff_diagnostics::Diagnostic;
use ruff_python_ast::all::{extract_all_names, AllNamesFlags};
use ruff_python_ast::helpers::{extract_handled_exceptions, to_module_path};
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
use ruff_python_ast::types::{Node, Range, RefEquality};
use ruff_python_ast::typing::parse_type_annotation;
use ruff_python_ast::visitor::{walk_excepthandler, walk_pattern, Visitor};
use ruff_python_ast::{branch_detection, cast, helpers, str, visitor};
use ruff_python_semantic::analyze;
use ruff_python_semantic::analyze::typing::{Callable, SubscriptKind};
use ruff_python_semantic::binding::{
use ruff_python_ast::binding::{
Binding, BindingId, BindingKind, Exceptions, ExecutionContext, Export, FromImportation,
Importation, StarImportation, SubmoduleImportation,
};
use ruff_python_semantic::context::Context;
use ruff_python_semantic::scope::{
use ruff_python_ast::context::Context;
use ruff_python_ast::helpers::{extract_handled_exceptions, to_module_path};
use ruff_python_ast::scope::{
ClassDef, FunctionDef, Lambda, Scope, ScopeId, ScopeKind, ScopeStack,
};
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
use ruff_python_ast::types::{Node, Range, RefEquality};
use ruff_python_ast::typing::{
match_annotated_subscript, parse_type_annotation, Callable, SubscriptKind,
};
use ruff_python_ast::visitor::{walk_excepthandler, walk_pattern, Visitor};
use ruff_python_ast::{branch_detection, cast, helpers, str, typing, visibility, visitor};
use ruff_python_stdlib::builtins::{BUILTINS, MAGIC_GLOBALS};
use ruff_python_stdlib::path::is_python_stub_file;
@@ -1847,6 +1847,13 @@ where
if self.settings.rules.enabled(Rule::UselessExpression) {
flake8_bugbear::rules::useless_expression(self, value);
}
if self
.settings
.rules
.enabled(Rule::UncapitalizedEnvironmentVariables)
{
flake8_simplify::rules::use_capital_environment_variables(self, value);
}
if self.settings.rules.enabled(Rule::AsyncioDanglingTask) {
if let Some(diagnostic) = ruff::rules::asyncio_dangling_task(value, |expr| {
self.ctx.resolve_call_path(expr)
@@ -2203,14 +2210,6 @@ where
]) {
flake8_2020::rules::subscript(self, value, slice);
}
if self
.settings
.rules
.enabled(Rule::UncapitalizedEnvironmentVariables)
{
flake8_simplify::rules::use_capital_environment_variables(self, expr);
}
}
ExprKind::Tuple { elts, ctx } | ExprKind::List { elts, ctx } => {
if matches!(ctx, ExprContext::Store) {
@@ -2249,7 +2248,7 @@ where
|| (self.settings.target_version >= PythonVersion::Py37
&& self.ctx.annotations_future_enabled
&& self.ctx.in_annotation))
&& analyze::typing::is_pep585_builtin(expr, &self.ctx)
&& typing::is_pep585_builtin(expr, &self.ctx)
{
pyupgrade::rules::use_pep585_annotation(self, expr);
}
@@ -2292,7 +2291,7 @@ where
|| (self.settings.target_version >= PythonVersion::Py37
&& self.ctx.annotations_future_enabled
&& self.ctx.in_annotation))
&& analyze::typing::is_pep585_builtin(expr, &self.ctx)
&& typing::is_pep585_builtin(expr, &self.ctx)
{
pyupgrade::rules::use_pep585_annotation(self, expr);
}
@@ -2911,14 +2910,6 @@ where
}
// flake8-simplify
if self
.settings
.rules
.enabled(Rule::UncapitalizedEnvironmentVariables)
{
flake8_simplify::rules::use_capital_environment_variables(self, expr);
}
if self
.settings
.rules
@@ -2927,10 +2918,6 @@ where
flake8_simplify::rules::open_file_with_context_handler(self, func);
}
if self.settings.rules.enabled(Rule::DictGetWithNoneDefault) {
flake8_simplify::rules::dict_get_with_none_default(self, expr);
}
// flake8-use-pathlib
if self.settings.rules.any_enabled(&[
Rule::OsPathAbspath,
@@ -3641,7 +3628,7 @@ where
self.ctx.in_subscript = true;
visitor::walk_expr(self, expr);
} else {
match analyze::typing::match_annotated_subscript(
match match_annotated_subscript(
value,
&self.ctx,
self.settings.typing_modules.iter().map(String::as_str),
@@ -4060,7 +4047,7 @@ impl<'a> Checker<'a> {
&& binding.redefines(existing)
&& (!self.settings.dummy_variable_rgx.is_match(name) || existing_is_import)
&& !(existing.kind.is_function_definition()
&& analyze::visibility::is_overload(
&& visibility::is_overload(
&self.ctx,
cast::decorator_list(existing.source.as_ref().unwrap()),
))
@@ -4094,7 +4081,7 @@ impl<'a> Checker<'a> {
}
} else if existing_is_import && binding.redefines(existing) {
self.ctx
.shadowed_bindings
.redefinitions
.entry(existing_binding_index)
.or_insert_with(Vec::new)
.push(binding_id);
@@ -4136,7 +4123,13 @@ impl<'a> Checker<'a> {
// in scope.
let scope = self.ctx.scope_mut();
if !(binding.kind.is_annotation() && scope.defines(name)) {
scope.add(name, binding_id);
if let Some(rebound_index) = scope.add(name, binding_id) {
scope
.rebounds
.entry(name)
.or_insert_with(Vec::new)
.push(rebound_index);
}
}
self.ctx.bindings.push(binding);
@@ -4459,23 +4452,7 @@ impl<'a> Checker<'a> {
}
_ => false,
} {
let (all_names, all_names_flags) = {
let (mut names, flags) =
extract_all_names(parent, |name| self.ctx.is_builtin(name));
// Grab the existing bound __all__ values.
if let StmtKind::AugAssign { .. } = &parent.node {
if let Some(index) = current.get("__all__") {
if let BindingKind::Export(Export { names: existing }) =
&self.ctx.bindings[*index].kind
{
names.extend_from_slice(existing);
}
}
}
(names, flags)
};
let (all_names, all_names_flags) = extract_all_names(&self.ctx, parent, current);
if self.settings.rules.enabled(Rule::InvalidAllFormat) {
if matches!(all_names_flags, AllNamesFlags::INVALID_FORMAT) {
@@ -4772,7 +4749,7 @@ impl<'a> Checker<'a> {
// Mark anything referenced in `__all__` as used.
let all_bindings: Option<(Vec<BindingId>, Range)> = {
let global_scope = self.ctx.global_scope();
let all_names: Option<(&Vec<&str>, Range)> = global_scope
let all_names: Option<(&Vec<String>, Range)> = global_scope
.get("__all__")
.map(|index| &self.ctx.bindings[*index])
.and_then(|binding| match &binding.kind {
@@ -4784,7 +4761,7 @@ impl<'a> Checker<'a> {
(
names
.iter()
.filter_map(|name| global_scope.get(name).copied())
.filter_map(|name| global_scope.get(name.as_str()).copied())
.collect(),
range,
)
@@ -4802,13 +4779,15 @@ impl<'a> Checker<'a> {
}
// Extract `__all__` names from the global scope.
let all_names: Option<(&[&str], Range)> = self
let all_names: Option<(Vec<&str>, Range)> = self
.ctx
.global_scope()
.get("__all__")
.map(|index| &self.ctx.bindings[*index])
.and_then(|binding| match &binding.kind {
BindingKind::Export(Export { names }) => Some((names.as_slice(), binding.range)),
BindingKind::Export(Export { names }) => {
Some((names.iter().map(String::as_str).collect(), binding.range))
}
_ => None,
});
@@ -4868,7 +4847,7 @@ impl<'a> Checker<'a> {
.dedup()
.collect();
if !sources.is_empty() {
for &name in names.iter() {
for &name in names {
if !scope.defines(name) {
diagnostics.push(Diagnostic::new(
pyflakes::rules::UndefinedLocalWithImportStarUsage {
@@ -4926,7 +4905,7 @@ impl<'a> Checker<'a> {
continue;
}
if let Some(indices) = self.ctx.shadowed_bindings.get(index) {
if let Some(indices) = self.ctx.redefinitions.get(index) {
for index in indices {
let rebound = &self.ctx.bindings[*index];
let mut diagnostic = Diagnostic::new(
@@ -5073,7 +5052,7 @@ impl<'a> Checker<'a> {
let fix = if !in_init && !in_except_handler && self.patch(Rule::UnusedImport) {
let deleted: Vec<&Stmt> = self.deletions.iter().map(Into::into).collect();
match autofix::actions::remove_unused_imports(
match autofix::helpers::remove_unused_imports(
unused_imports.iter().map(|(full_name, _)| *full_name),
child,
parent,

View File

@@ -1,12 +1,10 @@
//! Lint rules based on import analysis.
use std::borrow::Cow;
use std::path::Path;
use rustpython_parser::ast::{StmtKind, Suite};
use rustpython_parser::ast::Suite;
use ruff_diagnostics::Diagnostic;
use ruff_python_ast::helpers::to_module_path;
use ruff_python_ast::imports::{ImportMap, ModuleImport};
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
use ruff_python_ast::visitor::Visitor;
@@ -16,66 +14,6 @@ use crate::rules::isort;
use crate::rules::isort::track::{Block, ImportTracker};
use crate::settings::{flags, Settings};
fn extract_import_map(path: &Path, package: Option<&Path>, blocks: &[&Block]) -> Option<ImportMap> {
let Some(package) = package else {
return None;
};
let Some(module_path) = to_module_path(package, path) else {
return None;
};
let num_imports = blocks.iter().map(|block| block.imports.len()).sum();
let mut module_imports = Vec::with_capacity(num_imports);
for stmt in blocks.iter().flat_map(|block| &block.imports) {
match &stmt.node {
StmtKind::Import { names } => {
module_imports.extend(names.iter().map(|name| {
ModuleImport::new(
name.node.name.clone(),
stmt.location,
stmt.end_location.unwrap(),
)
}));
}
StmtKind::ImportFrom {
module,
names,
level,
} => {
let level = level.unwrap_or(0);
let module = if let Some(module) = module {
if level == 0 {
Cow::Borrowed(module)
} else {
if module_path.len() <= level {
continue;
}
let prefix = module_path[..module_path.len() - level].join(".");
Cow::Owned(format!("{prefix}.{module}"))
}
} else {
if module_path.len() <= level {
continue;
}
Cow::Owned(module_path[..module_path.len() - level].join("."))
};
module_imports.extend(names.iter().map(|name| {
ModuleImport::new(
format!("{}.{}", module, name.node.name),
name.location,
name.end_location.unwrap(),
)
}));
}
_ => panic!("Expected StmtKind::Import | StmtKind::ImportFrom"),
}
}
let mut import_map = ImportMap::default();
import_map.insert(module_path.join("."), module_imports);
Some(import_map)
}
#[allow(clippy::too_many_arguments)]
pub fn check_imports(
python_ast: &Suite,
@@ -87,7 +25,7 @@ pub fn check_imports(
autofix: flags::Autofix,
path: &Path,
package: Option<&Path>,
) -> (Vec<Diagnostic>, Option<ImportMap>) {
) -> Vec<Diagnostic> {
// Extract all imports from the AST.
let tracker = {
let mut tracker = ImportTracker::new(locator, directives, path);
@@ -114,9 +52,5 @@ pub fn check_imports(
&blocks, python_ast, locator, stylist, settings, autofix,
));
}
// Extract import map.
let imports = extract_import_map(path, package, &blocks);
(diagnostics, imports)
diagnostics
}

View File

@@ -356,7 +356,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
(Flake8Simplify, "223") => Rule::ExprAndFalse,
(Flake8Simplify, "300") => Rule::YodaConditions,
(Flake8Simplify, "401") => Rule::IfElseBlockInsteadOfDictGet,
(Flake8Simplify, "910") => Rule::DictGetWithNoneDefault,
// pyupgrade
(Pyupgrade, "001") => Rule::UselessMetaclassType,

View File

@@ -1,8 +1,7 @@
use rustpython_parser::ast::{Expr, Stmt};
use ruff_python_semantic::analyze::visibility::{
use ruff_python_ast::visibility::{
class_visibility, function_visibility, method_visibility, Modifier, Visibility, VisibleScope,
};
use rustpython_parser::ast::{Expr, Stmt};
#[derive(Debug, Clone)]
pub enum DefinitionKind<'a> {

View File

@@ -2,7 +2,7 @@
use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
use ruff_python_semantic::analyze::visibility;
use ruff_python_ast::visibility::{Modifier, VisibleScope};
use crate::docstrings::definition::{Definition, DefinitionKind, Documentable};
@@ -28,7 +28,7 @@ pub fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
/// Extract a `Definition` from the AST node defined by a `Stmt`.
pub fn extract<'a>(
scope: visibility::VisibleScope,
scope: VisibleScope,
stmt: &'a Stmt,
body: &'a [Stmt],
kind: Documentable,
@@ -36,22 +36,22 @@ pub fn extract<'a>(
let expr = docstring_from(body);
match kind {
Documentable::Function => match scope {
visibility::VisibleScope {
modifier: visibility::Modifier::Module,
VisibleScope {
modifier: Modifier::Module,
..
} => Definition {
kind: DefinitionKind::Function(stmt),
docstring: expr,
},
visibility::VisibleScope {
modifier: visibility::Modifier::Class,
VisibleScope {
modifier: Modifier::Class,
..
} => Definition {
kind: DefinitionKind::Method(stmt),
docstring: expr,
},
visibility::VisibleScope {
modifier: visibility::Modifier::Function,
VisibleScope {
modifier: Modifier::Function,
..
} => Definition {
kind: DefinitionKind::NestedFunction(stmt),
@@ -59,22 +59,22 @@ pub fn extract<'a>(
},
},
Documentable::Class => match scope {
visibility::VisibleScope {
modifier: visibility::Modifier::Module,
VisibleScope {
modifier: Modifier::Module,
..
} => Definition {
kind: DefinitionKind::Class(stmt),
docstring: expr,
},
visibility::VisibleScope {
modifier: visibility::Modifier::Class,
VisibleScope {
modifier: Modifier::Class,
..
} => Definition {
kind: DefinitionKind::NestedClass(stmt),
docstring: expr,
},
visibility::VisibleScope {
modifier: visibility::Modifier::Function,
VisibleScope {
modifier: Modifier::Function,
..
} => Definition {
kind: DefinitionKind::NestedClass(stmt),

View File

@@ -9,7 +9,6 @@ use rustpython_parser::lexer::LexResult;
use rustpython_parser::ParseError;
use ruff_diagnostics::Diagnostic;
use ruff_python_ast::imports::ImportMap;
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
use ruff_python_stdlib::path::is_python_stub_file;
@@ -52,15 +51,6 @@ impl<T> LinterResult<T> {
pub type FixTable = FxHashMap<Rule, usize>;
pub struct FixerResult<'a> {
/// The result returned by the linter, after applying any fixes.
pub result: LinterResult<(Vec<Message>, Option<ImportMap>)>,
/// The resulting source code, after applying any fixes.
pub transformed: Cow<'a, str>,
/// The number of fixes applied for each [`Rule`].
pub fixed: FixTable,
}
/// Generate `Diagnostic`s from the source code contents at the
/// given `Path`.
#[allow(clippy::too_many_arguments)]
@@ -76,10 +66,9 @@ pub fn check_path(
settings: &Settings,
noqa: flags::Noqa,
autofix: flags::Autofix,
) -> LinterResult<(Vec<Diagnostic>, Option<ImportMap>)> {
) -> LinterResult<Vec<Diagnostic>> {
// Aggregate all diagnostics.
let mut diagnostics = vec![];
let mut imports = None;
let mut error = None;
// Collect doc lines. This requires a rare mix of tokens (for comments) and AST
@@ -153,7 +142,7 @@ pub fn check_path(
));
}
if use_imports {
let (import_diagnostics, module_imports) = check_imports(
diagnostics.extend(check_imports(
&python_ast,
locator,
indexer,
@@ -163,9 +152,7 @@ pub fn check_path(
autofix,
path,
package,
);
imports = module_imports;
diagnostics.extend(import_diagnostics);
));
}
if use_doc_lines {
doc_lines.extend(doc_lines_from_ast(&python_ast));
@@ -253,7 +240,7 @@ pub fn check_path(
}
}
LinterResult::new((diagnostics, imports), error)
LinterResult::new(diagnostics, error)
}
const MAX_ITERATIONS: usize = 100;
@@ -310,7 +297,7 @@ pub fn add_noqa_to_path(path: &Path, package: Option<&Path>, settings: &Settings
// Add any missing `# noqa` pragmas.
add_noqa(
path,
&diagnostics.0,
&diagnostics,
&contents,
indexer.commented_lines(),
&directives.noqa_line_for,
@@ -327,7 +314,7 @@ pub fn lint_only(
settings: &Settings,
noqa: flags::Noqa,
autofix: flags::Autofix,
) -> LinterResult<(Vec<Message>, Option<ImportMap>)> {
) -> LinterResult<Vec<Message>> {
// Tokenize once.
let tokens: Vec<LexResult> = ruff_rustpython::tokenize(contents);
@@ -361,23 +348,20 @@ pub fn lint_only(
// Convert from diagnostics to messages.
let path_lossy = path.to_string_lossy();
result.map(|(messages, imports)| {
(
messages
.into_iter()
.map(|diagnostic| {
let source = if settings.show_source {
Some(Source::from_diagnostic(&diagnostic, &locator))
} else {
None
};
let lineno = diagnostic.location.row();
let noqa_row = *directives.noqa_line_for.get(&lineno).unwrap_or(&lineno);
Message::from_diagnostic(diagnostic, path_lossy.to_string(), source, noqa_row)
})
.collect(),
imports,
)
result.map(|diagnostics| {
diagnostics
.into_iter()
.map(|diagnostic| {
let source = if settings.show_source {
Some(Source::from_diagnostic(&diagnostic, &locator))
} else {
None
};
let lineno = diagnostic.location.row();
let noqa_row = *directives.noqa_line_for.get(&lineno).unwrap_or(&lineno);
Message::from_diagnostic(diagnostic, path_lossy.to_string(), source, noqa_row)
})
.collect()
})
}
@@ -389,7 +373,7 @@ pub fn lint_fix<'a>(
package: Option<&Path>,
noqa: flags::Noqa,
settings: &Settings,
) -> Result<FixerResult<'a>> {
) -> Result<(LinterResult<Vec<Message>>, Cow<'a, str>, FixTable)> {
let mut transformed = Cow::Borrowed(contents);
// Track the number of fixed errors across iterations.
@@ -464,7 +448,7 @@ This indicates a bug in `{}`. If you could open an issue at:
}
// Apply autofix.
if let Some((fixed_contents, applied)) = fix_file(&result.data.0, &locator) {
if let Some((fixed_contents, applied)) = fix_file(&result.data, &locator) {
if iterations < MAX_ITERATIONS {
// Count the number of fixed errors.
for (rule, count) in applied {
@@ -504,33 +488,29 @@ This indicates a bug in `{}`. If you could open an issue at:
// Convert to messages.
let path_lossy = path.to_string_lossy();
return Ok(FixerResult {
result: result.map(|(messages, imports)| {
(
messages
.into_iter()
.map(|diagnostic| {
let source = if settings.show_source {
Some(Source::from_diagnostic(&diagnostic, &locator))
} else {
None
};
let lineno = diagnostic.location.row();
let noqa_row =
*directives.noqa_line_for.get(&lineno).unwrap_or(&lineno);
Message::from_diagnostic(
diagnostic,
path_lossy.to_string(),
source,
noqa_row,
)
})
.collect(),
imports,
)
return Ok((
result.map(|diagnostics| {
diagnostics
.into_iter()
.map(|diagnostic| {
let source = if settings.show_source {
Some(Source::from_diagnostic(&diagnostic, &locator))
} else {
None
};
let lineno = diagnostic.location.row();
let noqa_row = *directives.noqa_line_for.get(&lineno).unwrap_or(&lineno);
Message::from_diagnostic(
diagnostic,
path_lossy.to_string(),
source,
noqa_row,
)
})
.collect()
}),
transformed,
fixed,
});
));
}
}

View File

@@ -322,7 +322,6 @@ ruff_macros::register_rules!(
rules::flake8_simplify::rules::ExprAndFalse,
rules::flake8_simplify::rules::YodaConditions,
rules::flake8_simplify::rules::IfElseBlockInsteadOfDictGet,
rules::flake8_simplify::rules::DictGetWithNoneDefault,
// pyupgrade
rules::pyupgrade::rules::UselessMetaclassType,
rules::pyupgrade::rules::TypeOfPrimitive,

View File

@@ -1,7 +1,7 @@
use rustpython_parser::ast::{Arguments, Expr, Stmt, StmtKind};
use ruff_python_ast::cast;
use ruff_python_semantic::analyze::visibility;
use ruff_python_ast::visibility;
use crate::checkers::ast::Checker;
use crate::docstrings::definition::{Definition, DefinitionKind};

View File

@@ -4,10 +4,10 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::ReturnStatementVisitor;
use ruff_python_ast::types::Range;
use ruff_python_ast::visibility::Visibility;
use ruff_python_ast::visibility::{self};
use ruff_python_ast::visitor::Visitor;
use ruff_python_ast::{cast, helpers};
use ruff_python_semantic::analyze::visibility;
use ruff_python_semantic::analyze::visibility::Visibility;
use ruff_python_stdlib::typing::SIMPLE_MAGIC_RETURN_TYPES;
use crate::checkers::ast::Checker;

View File

@@ -3,8 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{find_keyword, is_const_true};
use ruff_python_ast::logging;
use ruff_python_ast::types::Range;
use ruff_python_semantic::analyze::logging;
use crate::checkers::ast::Checker;

View File

@@ -3,7 +3,7 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Stmt, StmtKind};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::Range;
use ruff_python_semantic::analyze::visibility::{is_abstract, is_overload};
use ruff_python_ast::visibility::{is_abstract, is_overload};
use crate::checkers::ast::Checker;
use crate::registry::Rule;

View File

@@ -2,8 +2,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::scope::ScopeKind;
use ruff_python_ast::types::Range;
use ruff_python_semantic::scope::ScopeKind;
use crate::checkers::ast::Checker;

View File

@@ -13,17 +13,17 @@ pub struct ExceptWithEmptyTuple;
impl Violation for ExceptWithEmptyTuple {
#[derive_message_formats]
fn message(&self) -> String {
format!("Using `except ():` with an empty tuple does not catch anything; add exceptions to handle")
format!("Using except (): with an empty tuple does not handle/catch anything. Add exceptions to handle.")
}
}
/// B029
pub fn except_with_empty_tuple(checker: &mut Checker, excepthandler: &Excepthandler) {
let ExcepthandlerKind::ExceptHandler { type_, .. } = &excepthandler.node;
let Some(type_) = type_ else {
if type_.is_none() {
return;
};
let ExprKind::Tuple { elts, .. } = &type_.node else {
}
let ExprKind::Tuple { elts, .. } = &type_.as_ref().unwrap().node else {
return;
};
if elts.is_empty() {

View File

@@ -33,7 +33,7 @@ fn flatten_starred_iterables(expr: &Expr) -> Vec<&Expr> {
ExprKind::Tuple { elts, .. } | ExprKind::List { elts, .. } => {
exprs_to_process.append(&mut elts.iter().collect());
}
_ => flattened_exprs.push(value),
_ => flattened_exprs.push(expr),
},
_ => flattened_exprs.push(expr),
}
@@ -48,17 +48,12 @@ pub fn except_with_non_exception_classes(checker: &mut Checker, excepthandler: &
return;
};
for expr in flatten_starred_iterables(type_) {
if !matches!(
&expr.node,
ExprKind::Subscript { .. }
| ExprKind::Attribute { .. }
| ExprKind::Name { .. }
| ExprKind::Call { .. },
) {
checker.diagnostics.push(Diagnostic::new(
match expr.node {
ExprKind::Attribute { .. } | ExprKind::Name { .. } | ExprKind::Call { .. } => (),
_ => checker.diagnostics.push(Diagnostic::new(
ExceptWithNonExceptionClasses,
Range::from(expr),
));
)),
}
}
}

View File

@@ -49,24 +49,13 @@ struct GroupNameFinder<'a> {
/// Variable name for the group.
group_name: &'a str,
/// Number of times the `group_name` variable was seen during the visit.
usage_count: u32,
usage_count: u8,
/// A flag indicating that the visitor is inside a nested `for` or `while`
/// loop or inside a `dict`, `list` or `set` comprehension.
nested: bool,
/// A flag indicating that the `group_name` variable has been overridden
/// during the visit.
overridden: bool,
/// A stack of `if` statements.
parent_ifs: Vec<&'a Stmt>,
/// A stack of counters where each counter is itself a list of usage count.
/// This is used specifically for mutually exclusive statements such as an
/// `if` or `match`.
///
/// The stack element represents an entire `if` or `match` statement while
/// the number inside the element represents the usage count for one of
/// the branches of the statement. The order of the count corresponds the
/// branch order.
counter_stack: Vec<Vec<u32>>,
/// A list of reused expressions.
exprs: Vec<&'a Expr>,
}
@@ -78,8 +67,6 @@ impl<'a> GroupNameFinder<'a> {
usage_count: 0,
nested: false,
overridden: false,
parent_ifs: Vec::new(),
counter_stack: Vec::new(),
exprs: Vec::new(),
}
}
@@ -132,78 +119,6 @@ where
visitor::walk_body(self, body);
self.nested = false;
}
StmtKind::If { test, body, orelse } => {
// Determine whether we're on an `if` arm (as opposed to an `elif`).
let is_if_arm = !self.parent_ifs.iter().any(|parent| {
if let StmtKind::If { orelse, .. } = &parent.node {
orelse.len() == 1 && &orelse[0] == stmt
} else {
false
}
});
if is_if_arm {
// Initialize the vector with the count for current branch.
self.counter_stack.push(vec![0]);
} else {
// SAFETY: `unwrap` is safe because we're either in `elif` or
// `else` branch which can come only after an `if` branch.
// When inside an `if` branch, a new vector will be pushed
// onto the stack.
self.counter_stack.last_mut().unwrap().push(0);
}
let has_else = orelse
.first()
.map_or(false, |expr| !matches!(expr.node, StmtKind::If { .. }));
self.parent_ifs.push(stmt);
if has_else {
// There's no `StmtKind::Else`; instead, the `else` contents are directly on
// the `orelse` of the `StmtKind::If` node. We want to add a new counter for
// the `orelse` branch, but first, we need to visit the `if` body manually.
self.visit_expr(test);
self.visit_body(body);
// Now, we're in an `else` block.
self.counter_stack.last_mut().unwrap().push(0);
self.visit_body(orelse);
} else {
visitor::walk_stmt(self, stmt);
}
self.parent_ifs.pop();
if is_if_arm {
if let Some(last) = self.counter_stack.pop() {
// This is the max number of group usage from all the
// branches of this `if` statement.
let max_count = last.into_iter().max().unwrap_or(0);
if let Some(current_last) = self.counter_stack.last_mut() {
*current_last.last_mut().unwrap() += max_count;
} else {
self.usage_count += max_count;
}
}
}
}
StmtKind::Match { subject, cases } => {
self.counter_stack.push(Vec::with_capacity(cases.len()));
self.visit_expr(subject);
for match_case in cases {
self.counter_stack.last_mut().unwrap().push(0);
self.visit_match_case(match_case);
}
if let Some(last) = self.counter_stack.pop() {
// This is the max number of group usage from all the
// branches of this `match` statement.
let max_count = last.into_iter().max().unwrap_or(0);
if let Some(current_last) = self.counter_stack.last_mut() {
*current_last.last_mut().unwrap() += max_count;
} else {
self.usage_count += max_count;
}
}
}
StmtKind::Assign { targets, .. } => {
if targets.iter().any(|target| self.name_matches(target)) {
self.overridden = true;
@@ -235,25 +150,10 @@ where
visitor::walk_expr(self, expr);
self.nested = false;
} else if self.name_matches(expr) {
// If the stack isn't empty, then we're in one of the branches of
// a mutually exclusive statement. Otherwise, we'll add it to the
// global count.
if let Some(last) = self.counter_stack.last_mut() {
*last.last_mut().unwrap() += 1;
} else {
self.usage_count += 1;
}
let current_usage_count = self.usage_count
+ self
.counter_stack
.iter()
.map(|count| count.last().unwrap_or(&0))
.sum::<u32>();
self.usage_count += 1;
// For nested loops, the variable usage could be once but the
// loop makes it being used multiple times.
if self.nested || current_usage_count > 1 {
if self.nested || self.usage_count > 1 {
self.exprs.push(expr);
}
} else {

View File

@@ -140,9 +140,7 @@ pub fn unused_loop_control_variable(
}
// Avoid fixing any variables that _may_ be used, but undetectably so.
let certainty = Certainty::from(!helpers::uses_magic_variable_access(body, |id| {
checker.ctx.is_builtin(id)
}));
let certainty = Certainty::from(!helpers::uses_magic_variable_access(&checker.ctx, body));
// Attempt to rename the variable by prepending an underscore, but avoid
// applying the fix if doing so wouldn't actually cause us to ignore the
@@ -166,13 +164,17 @@ pub fn unused_loop_control_variable(
if certainty.into() && checker.patch(diagnostic.kind.rule()) {
// Find the `BindingKind::LoopVar` corresponding to the name.
let scope = checker.ctx.scope();
let binding = scope.bindings_for_name(name).find_map(|index| {
let binding = &checker.ctx.bindings[*index];
binding
.source
.as_ref()
.and_then(|source| (source == &RefEquality(stmt)).then_some(binding))
});
let binding = scope
.get(name)
.into_iter()
.chain(scope.rebounds.get(name).into_iter().flatten())
.find_map(|index| {
let binding = &checker.ctx.bindings[*index];
binding
.source
.as_ref()
.and_then(|source| (source == &RefEquality(stmt)).then_some(binding))
});
if let Some(binding) = binding {
if binding.kind.is_loop_var() {
if !binding.used() {

View File

@@ -54,7 +54,7 @@ pub fn useless_expression(checker: &mut Checker, value: &Expr) {
}
// Ignore statements that have side effects.
if contains_effect(value, |id| checker.ctx.is_builtin(id)) {
if contains_effect(&checker.ctx, value) {
// Flag attributes as useless expressions, even if they're attached to calls or other
// expressions.
if matches!(value.node, ExprKind::Attribute { .. }) {

View File

@@ -4,7 +4,7 @@ expression: diagnostics
---
- kind:
name: ExceptWithEmptyTuple
body: "Using `except ():` with an empty tuple does not catch anything; add exceptions to handle"
body: "Using except (): with an empty tuple does not handle/catch anything. Add exceptions to handle."
suggestion: ~
fixable: false
location:
@@ -18,7 +18,7 @@ expression: diagnostics
parent: ~
- kind:
name: ExceptWithEmptyTuple
body: "Using `except ():` with an empty tuple does not catch anything; add exceptions to handle"
body: "Using except (): with an empty tuple does not handle/catch anything. Add exceptions to handle."
suggestion: ~
fixable: false
location:

View File

@@ -58,18 +58,4 @@ expression: diagnostics
fix:
edits: []
parent: ~
- kind:
name: ExceptWithNonExceptionClasses
body: "`except` handlers should only be exception classes or tuples of exception classes"
suggestion: ~
fixable: false
location:
row: 33
column: 28
end_location:
row: 33
column: 49
fix:
edits: []
parent: ~

View File

@@ -100,158 +100,4 @@ expression: diagnostics
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 86
column: 36
end_location:
row: 86
column: 49
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 93
column: 40
end_location:
row: 93
column: 53
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 95
column: 40
end_location:
row: 95
column: 53
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 97
column: 40
end_location:
row: 97
column: 53
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 98
column: 36
end_location:
row: 98
column: 49
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 105
column: 48
end_location:
row: 105
column: 61
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 111
column: 32
end_location:
row: 111
column: 45
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 120
column: 48
end_location:
row: 120
column: 61
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 122
column: 48
end_location:
row: 122
column: 61
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 125
column: 40
end_location:
row: 125
column: 53
fix:
edits: []
parent: ~
- kind:
name: ReuseOfGroupbyGenerator
body: "Using the generator returned from `itertools.groupby()` more than once will do nothing on the second usage"
suggestion: ~
fixable: false
location:
row: 129
column: 32
end_location:
row: 129
column: 45
fix:
edits: []
parent: ~

View File

@@ -1,6 +1,6 @@
use rustpython_parser::ast::Expr;
use ruff_python_semantic::context::Context;
use ruff_python_ast::context::Context;
/// Return `true` if a Python class appears to be a Django model, based on its base classes.
pub fn is_model(context: &Context, base: &Expr) -> bool {

View File

@@ -2,9 +2,8 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Location, Operat
use ruff_diagnostics::{Diagnostic, Edit};
use ruff_python_ast::helpers::{find_keyword, SimpleCallArgs};
use ruff_python_ast::logging;
use ruff_python_ast::types::Range;
use ruff_python_semantic::analyze::logging;
use ruff_python_stdlib::logging::LoggingLevel;
use crate::checkers::ast::Checker;
use crate::registry::{AsRule, Rule};
@@ -129,7 +128,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
#[derive(Copy, Clone)]
enum LoggingCallType {
/// Logging call with a level method, e.g., `logging.info`.
LevelCall(LoggingLevel),
LevelCall(logging::LoggingLevel),
/// Logging call with an integer level as an argument, e.g., `logger.log(level, ...)`.
LogCall,
}
@@ -139,7 +138,7 @@ impl LoggingCallType {
if attr == "log" {
Some(LoggingCallType::LogCall)
} else {
LoggingLevel::from_attribute(attr).map(LoggingCallType::LevelCall)
logging::LoggingLevel::from_attribute(attr).map(LoggingCallType::LevelCall)
}
}
}
@@ -174,7 +173,7 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
if checker.settings.rules.enabled(Rule::LoggingWarn)
&& matches!(
logging_call_type,
LoggingCallType::LevelCall(LoggingLevel::Warn)
LoggingCallType::LevelCall(logging::LoggingLevel::Warn)
)
{
let mut diagnostic = Diagnostic::new(LoggingWarn, level_call_range);
@@ -229,14 +228,14 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
if let LoggingCallType::LevelCall(logging_level) = logging_call_type {
match logging_level {
LoggingLevel::Error => {
logging::LoggingLevel::Error => {
if checker.settings.rules.enabled(Rule::LoggingExcInfo) {
checker
.diagnostics
.push(Diagnostic::new(LoggingExcInfo, level_call_range));
}
}
LoggingLevel::Exception => {
logging::LoggingLevel::Exception => {
if checker
.settings
.rules

View File

@@ -8,19 +8,19 @@ expression: diagnostics
suggestion: "Convert to `warn`"
fixable: true
location:
row: 4
row: 3
column: 8
end_location:
row: 4
row: 3
column: 12
fix:
edits:
- content: warning
location:
row: 4
row: 3
column: 8
end_location:
row: 4
row: 3
column: 12
parent: ~

View File

@@ -16,7 +16,7 @@ use ruff_python_ast::helpers::{any_over_expr, create_expr, match_trailing_commen
use ruff_python_ast::types::{Range, RefEquality};
use ruff_python_stdlib::identifiers::is_identifier;
use crate::autofix::actions::delete_stmt;
use crate::autofix::helpers::delete_stmt;
use crate::checkers::ast::Checker;
use crate::message::Location;
use crate::registry::AsRule;

View File

@@ -1,4 +1,4 @@
use crate::autofix::actions::delete_stmt;
use crate::autofix::helpers::delete_stmt;
use log::error;
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_macros::{derive_message_formats, violation};

View File

@@ -221,23 +221,6 @@ fn is_valid_default_value_with_annotation(
false
}
pub fn is_type_var_call(checker: &Checker, expr: &Expr) -> bool {
let ExprKind::Call {func, ..} = &expr.node else {
return false;
};
checker
.ctx
.resolve_call_path(func)
.map_or(false, |call_path| {
call_path.as_slice() == ["typing", "TypeVar"]
|| call_path.as_slice() == ["typing", "TypeVarTuple"]
|| call_path.as_slice() == ["typing_extensions", "TypeVarTuple"]
|| call_path.as_slice() == ["typing", "NewType"]
|| call_path.as_slice() == ["typing", "ParamSpec"]
|| call_path.as_slice() == ["typing_extensions", "ParamSpec"]
})
}
/// PYI011
pub fn typed_argument_simple_defaults(checker: &mut Checker, args: &Arguments) {
if !args.defaults.is_empty() {
@@ -359,9 +342,6 @@ pub fn assignment_default_in_stub(checker: &mut Checker, value: &Expr, annotatio
}) {
return;
}
if is_type_var_call(checker, value) {
return;
}
if !is_valid_default_value_with_annotation(value, checker, true) {
let mut diagnostic = Diagnostic::new(AssignmentDefaultInStub, Range::from(value));

View File

@@ -8,19 +8,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 44
row: 40
column: 22
end_location:
row: 44
row: 40
column: 57
fix:
edits:
- content: "..."
location:
row: 44
row: 40
column: 22
end_location:
row: 44
row: 40
column: 57
parent: ~
- kind:
@@ -29,19 +29,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 45
row: 41
column: 22
end_location:
row: 45
row: 41
column: 34
fix:
edits:
- content: "..."
location:
row: 45
row: 41
column: 22
end_location:
row: 45
row: 41
column: 34
parent: ~
- kind:
@@ -50,19 +50,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 46
row: 42
column: 22
end_location:
row: 46
row: 42
column: 37
fix:
edits:
- content: "..."
location:
row: 46
row: 42
column: 22
end_location:
row: 46
row: 42
column: 37
parent: ~
- kind:
@@ -71,19 +71,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 47
row: 43
column: 25
end_location:
row: 47
row: 43
column: 35
fix:
edits:
- content: "..."
location:
row: 47
row: 43
column: 25
end_location:
row: 47
row: 43
column: 35
parent: ~
- kind:
@@ -92,19 +92,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 48
row: 44
column: 46
end_location:
row: 48
row: 44
column: 69
fix:
edits:
- content: "..."
location:
row: 48
row: 44
column: 46
end_location:
row: 48
row: 44
column: 69
parent: ~
- kind:
@@ -113,19 +113,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 49
row: 45
column: 30
end_location:
row: 49
row: 45
column: 53
fix:
edits:
- content: "..."
location:
row: 49
row: 45
column: 30
end_location:
row: 49
row: 45
column: 53
parent: ~
- kind:
@@ -134,19 +134,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 50
row: 46
column: 36
end_location:
row: 50
row: 46
column: 47
fix:
edits:
- content: "..."
location:
row: 50
row: 46
column: 36
end_location:
row: 50
row: 46
column: 47
parent: ~
- kind:
@@ -155,19 +155,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 52
row: 48
column: 27
end_location:
row: 52
row: 48
column: 43
fix:
edits:
- content: "..."
location:
row: 52
row: 48
column: 27
end_location:
row: 52
row: 48
column: 43
parent: ~
- kind:
@@ -176,19 +176,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 53
row: 49
column: 10
end_location:
row: 53
row: 49
column: 23
fix:
edits:
- content: "..."
location:
row: 53
row: 49
column: 10
end_location:
row: 53
row: 49
column: 23
parent: ~
- kind:
@@ -197,19 +197,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 54
row: 50
column: 10
end_location:
row: 54
row: 50
column: 25
fix:
edits:
- content: "..."
location:
row: 54
row: 50
column: 10
end_location:
row: 54
row: 50
column: 25
parent: ~
- kind:
@@ -218,19 +218,19 @@ expression: diagnostics
suggestion: "Replace default value with `...`"
fixable: true
location:
row: 55
row: 51
column: 10
end_location:
row: 55
row: 51
column: 15
fix:
edits:
- content: "..."
location:
row: 55
row: 51
column: 10
end_location:
row: 55
row: 51
column: 15
parent: ~

View File

@@ -11,7 +11,7 @@ use ruff_python_ast::types::Range;
use ruff_python_ast::visitor;
use ruff_python_ast::visitor::Visitor;
use crate::autofix::actions::remove_argument;
use crate::autofix::helpers::remove_argument;
use crate::checkers::ast::Checker;
use crate::registry::{AsRule, Rule};

View File

@@ -3,8 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::call_path::collect_call_path;
use ruff_python_ast::scope::ScopeKind;
use ruff_python_ast::types::Range;
use ruff_python_semantic::scope::ScopeKind;
use crate::checkers::ast::Checker;

View File

@@ -38,7 +38,6 @@ mod tests {
#[test_case(Rule::ExprAndFalse, Path::new("SIM223.py"); "SIM223")]
#[test_case(Rule::YodaConditions, Path::new("SIM300.py"); "SIM300")]
#[test_case(Rule::IfElseBlockInsteadOfDictGet, Path::new("SIM401.py"); "SIM401")]
#[test_case(Rule::DictGetWithNoneDefault, Path::new("SIM910.py"); "SIM910")]
#[test_case(Rule::IfElseBlockInsteadOfDictLookup, Path::new("SIM116.py"); "SIM116")]
#[test_case(Rule::IfWithSameArms, Path::new("SIM114.py"); "SIM114")]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {

View File

@@ -11,9 +11,9 @@ use rustpython_parser::ast::{
use ruff_diagnostics::{AlwaysAutofixableViolation, AutofixKind, Diagnostic, Edit, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::comparable::ComparableExpr;
use ruff_python_ast::context::Context;
use ruff_python_ast::helpers::{contains_effect, create_expr, has_comments, unparse_expr};
use ruff_python_ast::types::Range;
use ruff_python_semantic::context::Context;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
@@ -213,7 +213,7 @@ pub fn duplicate_isinstance_call(checker: &mut Checker, expr: &Expr) {
} else {
unreachable!("Indices should only contain `isinstance` calls")
};
let fixable = !contains_effect(target, |id| checker.ctx.is_builtin(id));
let fixable = !contains_effect(&checker.ctx, target);
let mut diagnostic = Diagnostic::new(
DuplicateIsinstanceCall {
name: if let ExprKind::Name { id, .. } = &target.node {
@@ -341,7 +341,7 @@ pub fn compare_with_tuple(checker: &mut Checker, expr: &Expr) {
// Avoid rewriting (e.g.) `a == "foo" or a == f()`.
if comparators
.iter()
.any(|expr| contains_effect(expr, |id| checker.ctx.is_builtin(id)))
.any(|expr| contains_effect(&checker.ctx, expr))
{
continue;
}
@@ -423,7 +423,7 @@ pub fn expr_and_not_expr(checker: &mut Checker, expr: &Expr) {
return;
}
if contains_effect(expr, |id| checker.ctx.is_builtin(id)) {
if contains_effect(&checker.ctx, expr) {
return;
}
@@ -477,7 +477,7 @@ pub fn expr_or_not_expr(checker: &mut Checker, expr: &Expr) {
return;
}
if contains_effect(expr, |id| checker.ctx.is_builtin(id)) {
if contains_effect(&checker.ctx, expr) {
return;
}
@@ -522,7 +522,7 @@ pub fn is_short_circuit(
let mut location = expr.location;
for (value, next_value) in values.iter().tuple_windows() {
// Keep track of the location of the furthest-right, non-effectful expression.
if contains_effect(value, |id| ctx.is_builtin(id)) {
if contains_effect(ctx, value) {
location = next_value.location;
continue;
}

View File

@@ -27,25 +27,6 @@ impl AlwaysAutofixableViolation for UncapitalizedEnvironmentVariables {
}
}
#[violation]
pub struct DictGetWithNoneDefault {
pub expected: String,
pub original: String,
}
impl AlwaysAutofixableViolation for DictGetWithNoneDefault {
#[derive_message_formats]
fn message(&self) -> String {
let DictGetWithNoneDefault { expected, original } = self;
format!("Use `{expected}` instead of `{original}`")
}
fn autofix_title(&self) -> String {
let DictGetWithNoneDefault { expected, original } = self;
format!("Replace `{original}` with `{expected}`")
}
}
/// SIM112
pub fn use_capital_environment_variables(checker: &mut Checker, expr: &Expr) {
// check `os.environ['foo']`
@@ -142,64 +123,3 @@ fn check_os_environ_subscript(checker: &mut Checker, expr: &Expr) {
}
checker.diagnostics.push(diagnostic);
}
/// SIM910
pub fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) {
let ExprKind::Call { func, args, keywords } = &expr.node else {
return;
};
if !keywords.is_empty() {
return;
}
let ExprKind::Attribute { value, attr, .. } = &func.node else {
return;
};
if !matches!(value.node, ExprKind::Dict { .. }) {
return;
}
if attr != "get" {
return;
}
let Some(key) = args.get(0) else {
return;
};
if !matches!(key.node, ExprKind::Constant { .. } | ExprKind::Name { .. }) {
return;
}
let Some(default) = args.get(1) else {
return;
};
if !matches!(
default.node,
ExprKind::Constant {
value: Constant::None,
..
}
) {
return;
};
let expected = format!(
"{}({})",
checker.locator.slice(func),
checker.locator.slice(key)
);
let original = checker.locator.slice(expr).to_string();
let mut diagnostic = Diagnostic::new(
DictGetWithNoneDefault {
expected: expected.clone(),
original,
},
Range::from(expr),
);
if checker.patch(diagnostic.kind.rule()) {
diagnostic.set_fix(Edit::replacement(
expected,
expr.location,
expr.end_location.unwrap(),
));
}
checker.diagnostics.push(diagnostic);
}

View File

@@ -7,12 +7,11 @@ use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::comparable::{ComparableConstant, ComparableExpr, ComparableStmt};
use ruff_python_ast::helpers::{
any_over_expr, contains_effect, create_expr, create_stmt, first_colon_range, has_comments,
contains_call_path, contains_effect, create_expr, create_stmt, first_colon_range, has_comments,
has_comments_in, unparse_expr, unparse_stmt,
};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::types::Range;
use ruff_python_semantic::context::Context;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
@@ -416,14 +415,6 @@ fn ternary(target_var: &Expr, body_value: &Expr, test: &Expr, orelse_value: &Exp
})
}
/// Return `true` if the `Expr` contains a reference to `${module}.${target}`.
fn contains_call_path(ctx: &Context, expr: &Expr, target: &[&str]) -> bool {
any_over_expr(expr, &|expr| {
ctx.resolve_call_path(expr)
.map_or(false, |call_path| call_path.as_slice() == target)
})
}
/// SIM108
pub fn use_ternary_operator(checker: &mut Checker, stmt: &Stmt, parent: Option<&Stmt>) {
let StmtKind::If { test, body, orelse } = &stmt.node else {
@@ -648,9 +639,10 @@ pub fn manual_dict_lookup(
let StmtKind::Return { value, .. } = &body[0].node else {
return;
};
if value.as_ref().map_or(false, |value| {
contains_effect(value, |id| checker.ctx.is_builtin(id))
}) {
if value
.as_ref()
.map_or(false, |value| contains_effect(&checker.ctx, value))
{
return;
}
@@ -720,9 +712,10 @@ pub fn manual_dict_lookup(
let StmtKind::Return { value, .. } = &body[0].node else {
return;
};
if value.as_ref().map_or(false, |value| {
contains_effect(value, |id| checker.ctx.is_builtin(id))
}) {
if value
.as_ref()
.map_or(false, |value| contains_effect(&checker.ctx, value))
{
return;
};
@@ -764,13 +757,13 @@ pub fn use_dict_get_with_default(
if body.len() != 1 || orelse.len() != 1 {
return;
}
let StmtKind::Assign { targets: body_var, value: body_value, ..} = &body[0].node else {
let StmtKind::Assign { targets: body_var, value: body_val, ..} = &body[0].node else {
return;
};
if body_var.len() != 1 {
return;
};
let StmtKind::Assign { targets: orelse_var, value: orelse_value, .. } = &orelse[0].node else {
let StmtKind::Assign { targets: orelse_var, value: orelse_val, .. } = &orelse[0].node else {
return;
};
if orelse_var.len() != 1 {
@@ -782,15 +775,15 @@ pub fn use_dict_get_with_default(
if test_dict.len() != 1 {
return;
}
let (expected_var, expected_value, default_var, default_value) = match ops[..] {
[Cmpop::In] => (&body_var[0], body_value, &orelse_var[0], orelse_value),
[Cmpop::NotIn] => (&orelse_var[0], orelse_value, &body_var[0], body_value),
let (expected_var, expected_val, default_var, default_val) = match ops[..] {
[Cmpop::In] => (&body_var[0], body_val, &orelse_var[0], orelse_val),
[Cmpop::NotIn] => (&orelse_var[0], orelse_val, &body_var[0], body_val),
_ => {
return;
}
};
let test_dict = &test_dict[0];
let ExprKind::Subscript { value: expected_subscript, slice: expected_slice, .. } = &expected_value.node else {
let ExprKind::Subscript { value: expected_subscript, slice: expected_slice, .. } = &expected_val.node else {
return;
};
@@ -804,7 +797,7 @@ pub fn use_dict_get_with_default(
}
// Check that the default value is not "complex".
if contains_effect(default_value, |id| checker.ctx.is_builtin(id)) {
if contains_effect(&checker.ctx, default_val) {
return;
}
@@ -849,7 +842,7 @@ pub fn use_dict_get_with_default(
})),
args: vec![
create_expr(test_key.node.clone()),
create_expr(default_value.node.clone()),
create_expr(default_val.node.clone()),
],
keywords: vec![],
})),

View File

@@ -3,8 +3,8 @@ use rustpython_parser::ast::{Cmpop, Expr, ExprKind, Stmt, StmtKind, Unaryop};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{create_expr, unparse_expr};
use ruff_python_ast::scope::ScopeKind;
use ruff_python_ast::types::Range;
use ruff_python_semantic::scope::ScopeKind;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View File

@@ -3,10 +3,7 @@ pub use ast_bool_op::{
expr_or_not_expr, expr_or_true, CompareWithTuple, DuplicateIsinstanceCall, ExprAndFalse,
ExprAndNotExpr, ExprOrNotExpr, ExprOrTrue,
};
pub use ast_expr::{
dict_get_with_none_default, use_capital_environment_variables, DictGetWithNoneDefault,
UncapitalizedEnvironmentVariables,
};
pub use ast_expr::{use_capital_environment_variables, UncapitalizedEnvironmentVariables};
pub use ast_if::{
if_with_same_arms, manual_dict_lookup, needless_bool, nested_if_statements,
use_dict_get_with_default, use_ternary_operator, CollapsibleIf, IfElseBlockInsteadOfDictGet,

View File

@@ -86,88 +86,4 @@ expression: diagnostics
row: 10
column: 15
parent: ~
- kind:
name: UncapitalizedEnvironmentVariables
body: "Use capitalized environment variable `FOO` instead of `foo`"
suggestion: "Replace `foo` with `FOO`"
fixable: true
location:
row: 12
column: 21
end_location:
row: 12
column: 26
fix:
edits:
- content: "'FOO'"
location:
row: 12
column: 21
end_location:
row: 12
column: 26
parent: ~
- kind:
name: UncapitalizedEnvironmentVariables
body: "Use capitalized environment variable `FOO` instead of `foo`"
suggestion: "Replace `foo` with `FOO`"
fixable: true
location:
row: 14
column: 17
end_location:
row: 14
column: 22
fix:
edits:
- content: "'FOO'"
location:
row: 14
column: 17
end_location:
row: 14
column: 22
parent: ~
- kind:
name: UncapitalizedEnvironmentVariables
body: "Use capitalized environment variable `FOO` instead of `foo`"
suggestion: "Replace `foo` with `FOO`"
fixable: true
location:
row: 16
column: 25
end_location:
row: 16
column: 30
fix:
edits:
- content: "'FOO'"
location:
row: 16
column: 25
end_location:
row: 16
column: 30
parent: ~
- kind:
name: UncapitalizedEnvironmentVariables
body: "Use capitalized environment variable `FOO` instead of `foo`"
suggestion: "Replace `foo` with `FOO`"
fixable: true
location:
row: 19
column: 21
end_location:
row: 19
column: 26
fix:
edits:
- content: "'FOO'"
location:
row: 19
column: 21
end_location:
row: 19
column: 26
parent: ~

View File

@@ -1,110 +0,0 @@
---
source: crates/ruff/src/rules/flake8_simplify/mod.rs
expression: diagnostics
---
- kind:
name: DictGetWithNoneDefault
body: "Use `{}.get(key)` instead of `{}.get(key, None)`"
suggestion: "Replace `{}.get(key, None)` with `{}.get(key)`"
fixable: true
location:
row: 2
column: 0
end_location:
row: 2
column: 17
fix:
edits:
- content: "{}.get(key)"
location:
row: 2
column: 0
end_location:
row: 2
column: 17
parent: ~
- kind:
name: DictGetWithNoneDefault
body: "Use `{}.get(\"key\")` instead of `{}.get(\"key\", None)`"
suggestion: "Replace `{}.get(\"key\", None)` with `{}.get(\"key\")`"
fixable: true
location:
row: 5
column: 0
end_location:
row: 5
column: 19
fix:
edits:
- content: "{}.get(\"key\")"
location:
row: 5
column: 0
end_location:
row: 5
column: 19
parent: ~
- kind:
name: DictGetWithNoneDefault
body: "Use `{}.get(key)` instead of `{}.get(key, None)`"
suggestion: "Replace `{}.get(key, None)` with `{}.get(key)`"
fixable: true
location:
row: 20
column: 8
end_location:
row: 20
column: 25
fix:
edits:
- content: "{}.get(key)"
location:
row: 20
column: 8
end_location:
row: 20
column: 25
parent: ~
- kind:
name: DictGetWithNoneDefault
body: "Use `{}.get(key)` instead of `{}.get(key, None)`"
suggestion: "Replace `{}.get(key, None)` with `{}.get(key)`"
fixable: true
location:
row: 24
column: 4
end_location:
row: 24
column: 21
fix:
edits:
- content: "{}.get(key)"
location:
row: 24
column: 4
end_location:
row: 24
column: 21
parent: ~
- kind:
name: DictGetWithNoneDefault
body: "Use `({}).get(key)` instead of `({}).get(key, None)`"
suggestion: "Replace `({}).get(key, None)` with `({}).get(key)`"
fixable: true
location:
row: 27
column: 0
end_location:
row: 27
column: 19
fix:
edits:
- content: "({}).get(key)"
location:
row: 27
column: 0
end_location:
row: 27
column: 19
parent: ~

View File

@@ -1,11 +1,11 @@
use num_traits::Zero;
use rustpython_parser::ast::{Constant, Expr, ExprKind};
use ruff_python_ast::binding::{Binding, BindingKind, ExecutionContext};
use ruff_python_ast::call_path::from_qualified_name;
use ruff_python_ast::context::Context;
use ruff_python_ast::helpers::map_callable;
use ruff_python_semantic::binding::{Binding, BindingKind, ExecutionContext};
use ruff_python_semantic::context::Context;
use ruff_python_semantic::scope::ScopeKind;
use ruff_python_ast::scope::ScopeKind;
/// Return `true` if [`Expr`] is a guard for a type-checking block.
pub fn is_type_checking_block(context: &Context, test: &Expr) -> bool {

View File

@@ -5,7 +5,7 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::{Range, RefEquality};
use crate::autofix::actions::delete_stmt;
use crate::autofix::helpers::delete_stmt;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View File

@@ -1,6 +1,6 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::binding::{
use ruff_python_ast::binding::{
Binding, BindingKind, ExecutionContext, FromImportation, Importation, SubmoduleImportation,
};

View File

@@ -2,7 +2,7 @@ use std::path::Path;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::binding::{
use ruff_python_ast::binding::{
Binding, BindingKind, ExecutionContext, FromImportation, Importation, SubmoduleImportation,
};

View File

@@ -5,11 +5,11 @@ use rustpython_parser::ast::{Arg, Arguments};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::analyze::function_type;
use ruff_python_semantic::analyze::function_type::FunctionType;
use ruff_python_semantic::analyze::visibility;
use ruff_python_semantic::binding::Bindings;
use ruff_python_semantic::scope::{FunctionDef, Lambda, Scope, ScopeKind};
use ruff_python_ast::binding::Bindings;
use ruff_python_ast::function_type;
use ruff_python_ast::function_type::FunctionType;
use ruff_python_ast::scope::{FunctionDef, Lambda, Scope, ScopeKind};
use ruff_python_ast::visibility;
use crate::checkers::ast::Checker;

View File

@@ -3,7 +3,7 @@ use rustpython_parser::ast::{Expr, ExprKind, Keyword, Location};
use ruff_diagnostics::{Edit, Fix};
use ruff_python_ast::source_code::Locator;
use crate::autofix::actions::remove_argument;
use crate::autofix::helpers::remove_argument;
fn match_name(expr: &Expr) -> Option<&str> {
if let ExprKind::Call { func, .. } = &expr.node {

View File

@@ -31,8 +31,7 @@ mod tests {
let directives =
directives::extract_directives(&tokens, directives::Flags::from_settings(&settings));
let LinterResult {
data: (diagnostics, _imports),
..
data: diagnostics, ..
} = check_path(
Path::new("<filename>"),
None,

View File

@@ -3,8 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
use ruff_diagnostics::Violation;
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::binding::BindingKind;
use ruff_python_ast::types::Range;
use ruff_python_semantic::binding::BindingKind;
use crate::checkers::ast::Checker;
use crate::registry::Rule;

View File

@@ -3,8 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
use ruff_diagnostics::Violation;
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::binding::{BindingKind, Importation};
use ruff_python_ast::types::Range;
use ruff_python_semantic::binding::{BindingKind, Importation};
use crate::checkers::ast::Checker;
use crate::registry::Rule;

View File

@@ -3,8 +3,8 @@ use rustpython_parser::ast::Stmt;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::identifier_range;
use ruff_python_ast::scope::{Scope, ScopeKind};
use ruff_python_ast::source_code::Locator;
use ruff_python_semantic::scope::{Scope, ScopeKind};
/// ## What it does
/// Checks for functions with "dunder" names (that is, names with two

View File

@@ -2,9 +2,9 @@ use rustpython_parser::ast::{Arguments, Expr};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::function_type;
use ruff_python_ast::scope::Scope;
use ruff_python_ast::types::Range;
use ruff_python_semantic::analyze::function_type;
use ruff_python_semantic::scope::Scope;
use crate::checkers::ast::Checker;

View File

@@ -2,9 +2,9 @@ use rustpython_parser::ast::{Arguments, Expr};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::function_type;
use ruff_python_ast::scope::Scope;
use ruff_python_ast::types::Range;
use ruff_python_semantic::analyze::function_type;
use ruff_python_semantic::scope::Scope;
use crate::checkers::ast::Checker;

View File

@@ -4,10 +4,10 @@ use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::{match_leading_content, match_trailing_content, unparse_stmt};
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::scope::ScopeKind;
use ruff_python_ast::source_code::Stylist;
use ruff_python_ast::types::Range;
use ruff_python_ast::whitespace::leading_space;
use ruff_python_semantic::scope::ScopeKind;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View File

@@ -60,9 +60,6 @@ mod tests {
#[test_case(Rule::UndocumentedPublicMethod, Path::new("D.py"); "D102_0")]
#[test_case(Rule::UndocumentedPublicMethod, Path::new("setter.py"); "D102_1")]
#[test_case(Rule::UndocumentedPublicModule, Path::new("D.py"); "D100")]
#[test_case(Rule::UndocumentedPublicModule, Path::new("_unrelated/pkg/D100_pub.py"); "D100_ignore_unrelated_pub")]
#[test_case(Rule::UndocumentedPublicModule, Path::new("_unrelated/pkg/_priv/no_D100_priv.py"); "no_d100_priv")]
#[test_case(Rule::UndocumentedPublicModule, Path::new("_unrelated/_no_pkg_priv.py"); "no_d100_priv_script")]
#[test_case(Rule::UndocumentedPublicNestedClass, Path::new("D.py"); "D106")]
#[test_case(Rule::UndocumentedPublicPackage, Path::new("D.py"); "D104_0")]
#[test_case(Rule::UndocumentedPublicPackage, Path::new("D104/__init__.py"); "D104_1")]

View File

@@ -2,7 +2,7 @@ use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::cast;
use ruff_python_ast::helpers::identifier_range;
use ruff_python_semantic::analyze::visibility::is_overload;
use ruff_python_ast::visibility::is_overload;
use crate::checkers::ast::Checker;
use crate::docstrings::definition::{DefinitionKind, Docstring};

View File

@@ -9,7 +9,7 @@ use ruff_python_ast::call_path::{from_qualified_name, CallPath};
use ruff_python_ast::cast;
use ruff_python_ast::newlines::StrExt;
use ruff_python_ast::types::Range;
use ruff_python_semantic::analyze::visibility::{is_property, is_test};
use ruff_python_ast::visibility::{is_property, is_test};
use crate::checkers::ast::Checker;
use crate::docstrings::definition::{DefinitionKind, Docstring};

View File

@@ -3,7 +3,7 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::cast;
use ruff_python_ast::helpers::identifier_range;
use ruff_python_ast::types::Range;
use ruff_python_semantic::analyze::visibility::{
use ruff_python_ast::visibility::{
is_call, is_init, is_magic, is_new, is_overload, is_override, Visibility,
};

View File

@@ -10,8 +10,8 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::identifier_range;
use ruff_python_ast::newlines::NewlineWithTrailingNewline;
use ruff_python_ast::types::Range;
use ruff_python_ast::visibility::is_staticmethod;
use ruff_python_ast::{cast, whitespace};
use ruff_python_semantic::analyze::visibility::is_staticmethod;
use crate::checkers::ast::Checker;
use crate::docstrings::definition::{DefinitionKind, Docstring};

View File

@@ -1,6 +0,0 @@
---
source: crates/ruff/src/rules/pydocstyle/mod.rs
expression: diagnostics
---
[]

View File

@@ -1,19 +0,0 @@
---
source: crates/ruff/src/rules/pydocstyle/mod.rs
expression: diagnostics
---
- kind:
name: UndocumentedPublicModule
body: Missing docstring in public module
suggestion: ~
fixable: false
location:
row: 1
column: 0
end_location:
row: 1
column: 0
fix:
edits: []
parent: ~

View File

@@ -1,6 +0,0 @@
---
source: crates/ruff/src/rules/pydocstyle/mod.rs
expression: diagnostics
---
[]

View File

@@ -23,7 +23,7 @@ pub(crate) fn error_to_string(err: &FormatParseError) -> String {
#[derive(Debug)]
pub(crate) struct FormatSummary {
pub autos: Vec<usize>,
pub indices: Vec<usize>,
pub indexes: Vec<usize>,
pub keywords: Vec<String>,
pub has_nested_parts: bool,
pub format_string: FormatString,
@@ -36,7 +36,7 @@ impl TryFrom<&str> for FormatSummary {
let format_string = FormatString::from_str(literal)?;
let mut autos = Vec::new();
let mut indices = Vec::new();
let mut indexes = Vec::new();
let mut keywords = Vec::new();
let mut has_nested_parts = false;
@@ -51,7 +51,7 @@ impl TryFrom<&str> for FormatSummary {
let parsed = FieldName::parse(field_name)?;
match parsed.field_type {
FieldType::Auto => autos.push(autos.len()),
FieldType::Index(i) => indices.push(i),
FieldType::Index(i) => indexes.push(i),
FieldType::Keyword(k) => keywords.push(k),
};
@@ -63,7 +63,7 @@ impl TryFrom<&str> for FormatSummary {
let parsed = FieldName::parse(&field_name)?;
match parsed.field_type {
FieldType::Auto => autos.push(autos.len()),
FieldType::Index(i) => indices.push(i),
FieldType::Index(i) => indexes.push(i),
FieldType::Keyword(k) => keywords.push(k),
};
has_nested_parts = true;
@@ -72,7 +72,7 @@ impl TryFrom<&str> for FormatSummary {
Ok(FormatSummary {
autos,
indices,
indexes,
keywords,
has_nested_parts,
format_string,
@@ -89,7 +89,7 @@ mod tests {
let literal = "foo{foo}a{}b{2}c{2}d{1}{}{}e{bar}{foo}f{spam}";
let expected_autos = [0usize, 1usize, 2usize].to_vec();
let expected_indices = [2usize, 2usize, 1usize].to_vec();
let expected_indexes = [2usize, 2usize, 1usize].to_vec();
let expected_keywords: Vec<_> = ["foo", "bar", "foo", "spam"]
.into_iter()
.map(String::from)
@@ -98,7 +98,7 @@ mod tests {
let format_summary = FormatSummary::try_from(literal).unwrap();
assert_eq!(format_summary.autos, expected_autos);
assert_eq!(format_summary.indices, expected_indices);
assert_eq!(format_summary.indexes, expected_indexes);
assert_eq!(format_summary.keywords, expected_keywords);
assert!(!format_summary.has_nested_parts);
}
@@ -108,7 +108,7 @@ mod tests {
let literal = "foo{foo}a{:{}{}}b{2:{3}{4}}c{2}d{1}{}e{bar:{spam}{eggs}}";
let expected_autos = [0usize, 1usize, 2usize, 3usize].to_vec();
let expected_indices = [2usize, 3usize, 4usize, 2usize, 1usize].to_vec();
let expected_indexes = [2usize, 3usize, 4usize, 2usize, 1usize].to_vec();
let expected_keywords: Vec<_> = ["foo", "bar", "spam", "eggs"]
.into_iter()
.map(String::from)
@@ -117,7 +117,7 @@ mod tests {
let format_summary = FormatSummary::try_from(literal).unwrap();
assert_eq!(format_summary.autos, expected_autos);
assert_eq!(format_summary.indices, expected_indices);
assert_eq!(format_summary.indexes, expected_indexes);
assert_eq!(format_summary.keywords, expected_keywords);
assert!(format_summary.has_nested_parts);
}

View File

@@ -258,7 +258,7 @@ mod tests {
let directives =
directives::extract_directives(&tokens, directives::Flags::from_settings(&settings));
let LinterResult {
data: (mut diagnostics, _imports),
data: mut diagnostics,
..
} = check_path(
Path::new("<filename>"),

View File

@@ -2,8 +2,8 @@ use rustpython_parser::ast::Stmt;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::scope::ScopeKind;
use ruff_python_ast::types::Range;
use ruff_python_semantic::scope::ScopeKind;
use crate::checkers::ast::Checker;

View File

@@ -498,7 +498,7 @@ pub(crate) fn string_dot_format_extra_positional_arguments(
}
let missing: Vec<usize> = (0..args.len())
.filter(|i| !(summary.autos.contains(i) || summary.indices.contains(i)))
.filter(|i| !(summary.autos.contains(i) || summary.indexes.contains(i)))
.collect();
if missing.is_empty() {
@@ -551,7 +551,7 @@ pub(crate) fn string_dot_format_missing_argument(
let missing: Vec<String> = summary
.autos
.iter()
.chain(summary.indices.iter())
.chain(summary.indexes.iter())
.filter(|&&i| i >= args.len())
.map(ToString::to_string)
.chain(
@@ -577,7 +577,7 @@ pub(crate) fn string_dot_format_mixing_automatic(
summary: &FormatSummary,
location: Range,
) {
if !(summary.autos.is_empty() || summary.indices.is_empty()) {
if !(summary.autos.is_empty() || summary.indexes.is_empty()) {
checker
.diagnostics
.push(Diagnostic::new(StringDotFormatMixingAutomatic, location));

View File

@@ -1,7 +1,7 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::scope::Scope;
use ruff_python_ast::types::Range;
use ruff_python_semantic::scope::Scope;
#[violation]
pub struct UndefinedExport {

View File

@@ -2,8 +2,8 @@ use std::string::ToString;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::binding::Bindings;
use ruff_python_semantic::scope::{Scope, ScopeKind};
use ruff_python_ast::binding::Bindings;
use ruff_python_ast::scope::{Scope, ScopeKind};
#[violation]
pub struct UndefinedLocal {

View File

@@ -1,6 +1,6 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::scope::ScopeId;
use ruff_python_ast::scope::ScopeId;
use crate::checkers::ast::Checker;

View File

@@ -6,11 +6,11 @@ use rustpython_parser::{lexer, Mode, Tok};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::contains_effect;
use ruff_python_ast::scope::{ScopeId, ScopeKind};
use ruff_python_ast::source_code::Locator;
use ruff_python_ast::types::{Range, RefEquality};
use ruff_python_semantic::scope::{ScopeId, ScopeKind};
use crate::autofix::actions::delete_stmt;
use crate::autofix::helpers::delete_stmt;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
@@ -202,9 +202,7 @@ fn remove_unused_variable(
range.location == target.location && range.end_location == target.end_location.unwrap()
}) {
if matches!(target.node, ExprKind::Name { .. }) {
return if targets.len() > 1
|| contains_effect(value, |id| checker.ctx.is_builtin(id))
{
return if targets.len() > 1 || contains_effect(&checker.ctx, value) {
// If the expression is complex (`x = foo()`), remove the assignment,
// but preserve the right-hand side.
Some((
@@ -250,7 +248,7 @@ fn remove_unused_variable(
} = &stmt.node
{
if matches!(target.node, ExprKind::Name { .. }) {
return if contains_effect(value, |id| checker.ctx.is_builtin(id)) {
return if contains_effect(&checker.ctx, value) {
// If the expression is complex (`x = foo()`), remove the assignment,
// but preserve the right-hand side.
Some((

View File

@@ -4,8 +4,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::scope::ScopeKind;
use ruff_python_ast::types::Range;
use ruff_python_semantic::scope::ScopeKind;
use crate::checkers::ast::Checker;

View File

@@ -1,6 +1,6 @@
use ruff_python_semantic::analyze::function_type;
use ruff_python_semantic::analyze::function_type::FunctionType;
use ruff_python_semantic::scope::{FunctionDef, ScopeKind};
use ruff_python_ast::function_type;
use ruff_python_ast::function_type::FunctionType;
use ruff_python_ast::scope::{FunctionDef, ScopeKind};
use crate::checkers::ast::Checker;

View File

@@ -2,8 +2,8 @@ use rustpython_parser::ast::Expr;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::scope::{FunctionDef, ScopeKind};
use ruff_python_ast::types::Range;
use ruff_python_semantic::scope::{FunctionDef, ScopeKind};
use crate::checkers::ast::Checker;

View File

@@ -2,8 +2,8 @@ use rustpython_parser::ast::Expr;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::scope::ScopeKind;
use ruff_python_ast::types::Range;
use ruff_python_semantic::scope::ScopeKind;
use crate::checkers::ast::Checker;

View File

@@ -3,9 +3,8 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword};
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::SimpleCallArgs;
use ruff_python_ast::logging;
use ruff_python_ast::types::Range;
use ruff_python_semantic::analyze::logging;
use ruff_python_stdlib::logging::LoggingLevel;
use crate::checkers::ast::Checker;
use crate::registry::Rule;
@@ -106,7 +105,7 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
}
if let ExprKind::Attribute { attr, .. } = &func.node {
if LoggingLevel::from_attribute(attr.as_str()).is_some() {
if logging::LoggingLevel::from_attribute(attr.as_str()).is_some() {
let call_args = SimpleCallArgs::new(args, keywords);
if let Some(msg) = call_args.argument("msg", 0) {
if let ExprKind::Constant {

View File

@@ -4,7 +4,7 @@ use ruff_diagnostics::{AutofixKind, Diagnostic, Edit, Fix, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::Range;
use crate::autofix::actions::get_or_import_symbol;
use crate::autofix::helpers::get_or_import_symbol;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View File

@@ -7,7 +7,7 @@ use ruff_python_ast::helpers::{is_const_none, ReturnStatementVisitor};
use ruff_python_ast::types::{Range, RefEquality};
use ruff_python_ast::visitor::Visitor;
use crate::autofix::actions::delete_stmt;
use crate::autofix::helpers::delete_stmt;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View File

@@ -24,7 +24,7 @@ impl AlwaysAutofixableViolation for FormatLiterals {
}
fn autofix_title(&self) -> String {
"Remove explicit positional indices".to_string()
"Remove explicit positional indexes".to_string()
}
}
@@ -135,7 +135,7 @@ pub(crate) fn format_literals(checker: &mut Checker, summary: &FormatSummary, ex
if !summary.autos.is_empty() {
return;
}
if !(0..summary.indices.len()).all(|index| summary.indices.contains(&index)) {
if !(0..summary.indexes.len()).all(|index| summary.indexes.contains(&index)) {
return;
}
@@ -144,7 +144,7 @@ pub(crate) fn format_literals(checker: &mut Checker, summary: &FormatSummary, ex
// Currently, the only issue we know of is in LibCST:
// https://github.com/Instagram/LibCST/issues/846
if let Ok(contents) =
generate_call(expr, &summary.indices, checker.locator, checker.stylist)
generate_call(expr, &summary.indexes, checker.locator, checker.stylist)
{
diagnostic.set_fix(Edit::replacement(
contents,

View File

@@ -4,7 +4,7 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::types::Range;
use crate::autofix::actions::get_or_import_symbol;
use crate::autofix::helpers::get_or_import_symbol;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View File

@@ -3,9 +3,9 @@ use rustpython_parser::ast::{Excepthandler, ExcepthandlerKind, Expr, ExprContext
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Edit};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::call_path::compose_call_path;
use ruff_python_ast::context::Context;
use ruff_python_ast::helpers::{create_expr, unparse_expr};
use ruff_python_ast::types::Range;
use ruff_python_semantic::context::Context;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View File

@@ -11,7 +11,7 @@ use ruff_python_ast::source_code::Locator;
use ruff_python_ast::types::{Range, RefEquality};
use ruff_python_ast::whitespace::indentation;
use crate::autofix::actions::delete_stmt;
use crate::autofix::helpers::delete_stmt;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;
use crate::rules::pyupgrade::fixes::adjust_indentation;

View File

@@ -7,7 +7,7 @@ use ruff_python_ast::helpers::find_keyword;
use ruff_python_ast::source_code::Locator;
use ruff_python_ast::types::Range;
use crate::autofix::actions::remove_argument;
use crate::autofix::helpers::remove_argument;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View File

@@ -2,8 +2,8 @@ use rustpython_parser::ast::{ArgData, Expr, ExprKind, Stmt, StmtKind};
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::scope::ScopeKind;
use ruff_python_ast::types::Range;
use ruff_python_semantic::scope::ScopeKind;
use crate::checkers::ast::Checker;
use crate::registry::AsRule;

View File

@@ -112,7 +112,7 @@ pub fn unnecessary_builtin_import(
.iter()
.map(|alias| format!("{module}.{}", alias.node.name))
.collect();
match autofix::actions::remove_unused_imports(
match autofix::helpers::remove_unused_imports(
unused_imports.iter().map(String::as_str),
defined_by.into(),
defined_in.map(Into::into),

View File

@@ -6,7 +6,7 @@ use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::source_code::Locator;
use ruff_python_ast::types::Range;
use crate::autofix::actions::remove_argument;
use crate::autofix::helpers::remove_argument;
use crate::checkers::ast::Checker;
use crate::registry::Rule;

Some files were not shown because too many files have changed in this diff Show More