Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf718fdf26 | ||
|
|
3b3466f6da | ||
|
|
f981f491aa | ||
|
|
95fef43c4d | ||
|
|
097c679cf3 | ||
|
|
3bca987665 | ||
|
|
60ee1d2c17 |
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -747,7 +747,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.4",
|
||||
@@ -1896,7 +1896,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bisection",
|
||||
@@ -1953,7 +1953,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1989,7 +1989,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.4",
|
||||
@@ -2010,7 +2010,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
@@ -2021,7 +2021,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"regex",
|
||||
|
||||
@@ -230,7 +230,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.242'
|
||||
rev: 'v0.0.243'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -1113,6 +1113,7 @@ For more, see [flake8-pie](https://pypi.org/project/flake8-pie/) on PyPI.
|
||||
| PIE800 | no-unnecessary-spread | Unnecessary spread `**` | |
|
||||
| PIE804 | no-unnecessary-dict-kwargs | Unnecessary `dict` kwargs | |
|
||||
| PIE807 | prefer-list-builtin | Prefer `list` over useless lambda | 🛠 |
|
||||
| PIE810 | single-starts-ends-with | Call `{attr}` once with a `tuple` | |
|
||||
|
||||
### flake8-print (T20)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
@@ -39,8 +39,8 @@ num-traits = "0.2.15"
|
||||
once_cell = { version = "1.16.0" }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
regex = { version = "1.6.0" }
|
||||
ruff_macros = { version = "0.0.242", path = "../ruff_macros" }
|
||||
ruff_python = { version = "0.0.242", path = "../ruff_python" }
|
||||
ruff_macros = { version = "0.0.243", path = "../ruff_macros" }
|
||||
ruff_python = { version = "0.0.243", path = "../ruff_python" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "adc23253e4b58980b407ba2760dbe61681d752fc" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "adc23253e4b58980b407ba2760dbe61681d752fc" }
|
||||
|
||||
17
crates/ruff/resources/test/fixtures/flake8_pie/PIE810.py
vendored
Normal file
17
crates/ruff/resources/test/fixtures/flake8_pie/PIE810.py
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# error
|
||||
obj.startswith("foo") or obj.startswith("bar")
|
||||
# error
|
||||
obj.endswith("foo") or obj.endswith("bar")
|
||||
# error
|
||||
obj.startswith(foo) or obj.startswith(bar)
|
||||
# error
|
||||
obj.startswith(foo) or obj.startswith("foo")
|
||||
|
||||
# ok
|
||||
obj.startswith(("foo", "bar"))
|
||||
# ok
|
||||
obj.endswith(("foo", "bar"))
|
||||
# ok
|
||||
obj.startswith("foo") or obj.endswith("bar")
|
||||
# ok
|
||||
obj.startswith("foo") or abc.startswith("bar")
|
||||
@@ -5,3 +5,7 @@ def func(_, a, A):
|
||||
class Class:
|
||||
def method(self, _, a, A):
|
||||
return _, a, A
|
||||
|
||||
|
||||
def func(_, setUp):
|
||||
return _, setUp
|
||||
|
||||
@@ -2,6 +2,7 @@ import collections
|
||||
from collections import namedtuple
|
||||
from typing import TypeVar
|
||||
from typing import NewType
|
||||
from typing import NamedTuple, TypedDict
|
||||
|
||||
GLOBAL: str = "foo"
|
||||
|
||||
@@ -20,6 +21,10 @@ def assign():
|
||||
T = TypeVar("T")
|
||||
UserId = NewType("UserId", int)
|
||||
|
||||
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
|
||||
|
||||
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
|
||||
|
||||
|
||||
def aug_assign(rank, world_size):
|
||||
global CURRENT_PORT
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import collections
|
||||
from collections import namedtuple
|
||||
from typing import NamedTuple, TypedDict
|
||||
|
||||
|
||||
class C:
|
||||
@@ -10,3 +11,5 @@ class C:
|
||||
mixed_Case = 0
|
||||
myObj1 = collections.namedtuple("MyObj1", ["a", "b"])
|
||||
myObj2 = namedtuple("MyObj2", ["a", "b"])
|
||||
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
|
||||
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import collections
|
||||
from collections import namedtuple
|
||||
from typing import NamedTuple, TypedDict
|
||||
|
||||
lower = 0
|
||||
CONSTANT = 0
|
||||
@@ -8,3 +9,5 @@ _mixedCase = 0
|
||||
mixed_Case = 0
|
||||
myObj1 = collections.namedtuple("MyObj1", ["a", "b"])
|
||||
myObj2 = namedtuple("MyObj2", ["a", "b"])
|
||||
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
|
||||
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
|
||||
|
||||
0
crates/ruff/resources/test/fixtures/pyflakes/project/foo/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pyflakes/project/foo/__init__.py
vendored
Normal file
26
crates/ruff/resources/test/fixtures/pyflakes/project/foo/bar.py
vendored
Normal file
26
crates/ruff/resources/test/fixtures/pyflakes/project/foo/bar.py
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
def f():
|
||||
from typing import Literal
|
||||
|
||||
# OK
|
||||
x: Literal["foo"]
|
||||
|
||||
|
||||
def f():
|
||||
from .typical import Literal
|
||||
|
||||
# OK
|
||||
x: Literal["foo"]
|
||||
|
||||
|
||||
def f():
|
||||
from . import typical
|
||||
|
||||
# OK
|
||||
x: typical.Literal["foo"]
|
||||
|
||||
|
||||
def f():
|
||||
from .atypical import Literal
|
||||
|
||||
# F821
|
||||
x: Literal["foo"]
|
||||
0
crates/ruff/resources/test/fixtures/pyflakes/project/foo/bop/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pyflakes/project/foo/bop/__init__.py
vendored
Normal file
33
crates/ruff/resources/test/fixtures/pyflakes/project/foo/bop/baz.py
vendored
Normal file
33
crates/ruff/resources/test/fixtures/pyflakes/project/foo/bop/baz.py
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
def f():
|
||||
from typing import Literal
|
||||
|
||||
# OK
|
||||
x: Literal["foo"]
|
||||
|
||||
|
||||
def f():
|
||||
from ..typical import Literal
|
||||
|
||||
# OK
|
||||
x: Literal["foo"]
|
||||
|
||||
|
||||
def f():
|
||||
from .. import typical
|
||||
|
||||
# OK
|
||||
x: typical.Literal["foo"]
|
||||
|
||||
|
||||
def f():
|
||||
from .typical import Literal
|
||||
|
||||
# F821
|
||||
x: Literal["foo"]
|
||||
|
||||
|
||||
def f():
|
||||
from .atypical import Literal
|
||||
|
||||
# F821
|
||||
x: Literal["foo"]
|
||||
@@ -66,12 +66,6 @@ x: NamedTuple("X", fields=[("foo", "int"), ("bar", "str")])
|
||||
|
||||
x: NamedTuple(typename="X", fields=[("foo", "int")])
|
||||
|
||||
x = TypeVar("x", "str", "int")
|
||||
|
||||
x = cast("str", x)
|
||||
|
||||
X = List["MyClass"]
|
||||
|
||||
X: MyCallable("X")
|
||||
|
||||
|
||||
@@ -106,3 +100,9 @@ def foo(*, inplace):
|
||||
|
||||
|
||||
x: Annotated[1:2] = ...
|
||||
|
||||
x = TypeVar("x", "str", "int")
|
||||
|
||||
x = cast("str", x)
|
||||
|
||||
X = List["MyClass"]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::path::Path;
|
||||
|
||||
use itertools::Itertools;
|
||||
use log::error;
|
||||
use once_cell::sync::Lazy;
|
||||
@@ -10,7 +12,7 @@ use rustpython_ast::{
|
||||
use rustpython_parser::lexer;
|
||||
use rustpython_parser::lexer::Tok;
|
||||
use rustpython_parser::token::StringKind;
|
||||
use smallvec::smallvec;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::ast::types::{Binding, BindingKind, CallPath, Range};
|
||||
use crate::ast::visitor;
|
||||
@@ -657,6 +659,38 @@ pub fn to_call_path(target: &str) -> CallPath {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a module path from a (package, path) pair.
|
||||
///
|
||||
/// For example, if the package is `foo/bar` and the path is `foo/bar/baz.py`, the call path is
|
||||
/// `["baz"]`.
|
||||
pub fn to_module_path(package: &Path, path: &Path) -> Option<Vec<String>> {
|
||||
path.strip_prefix(package.parent()?)
|
||||
.ok()?
|
||||
.iter()
|
||||
.map(Path::new)
|
||||
.map(std::path::Path::file_stem)
|
||||
.map(|path| path.and_then(|path| path.to_os_string().into_string().ok()))
|
||||
.collect::<Option<Vec<String>>>()
|
||||
}
|
||||
|
||||
/// Create a call path from a relative import.
|
||||
pub fn from_relative_import<'a>(module: &'a [String], name: &'a str) -> CallPath<'a> {
|
||||
let mut call_path: CallPath = SmallVec::with_capacity(module.len() + 1);
|
||||
|
||||
// Start with the module path.
|
||||
call_path.extend(module.iter().map(String::as_str));
|
||||
|
||||
// Remove segments based on the number of dots.
|
||||
for _ in 0..name.chars().take_while(|c| *c == '.').count() {
|
||||
call_path.pop();
|
||||
}
|
||||
|
||||
// Add the remaining segments.
|
||||
call_path.extend(name.trim_start_matches('.').split('.'));
|
||||
|
||||
call_path
|
||||
}
|
||||
|
||||
/// A [`Visitor`] that collects all return statements in a function or method.
|
||||
#[derive(Default)]
|
||||
pub struct ReturnStatementVisitor<'a> {
|
||||
|
||||
@@ -19,7 +19,9 @@ use smallvec::smallvec;
|
||||
use ruff_python::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||
use ruff_python::typing::TYPING_EXTENSIONS;
|
||||
|
||||
use crate::ast::helpers::{binding_range, collect_call_path, extract_handler_names};
|
||||
use crate::ast::helpers::{
|
||||
binding_range, collect_call_path, extract_handler_names, from_relative_import, to_module_path,
|
||||
};
|
||||
use crate::ast::operations::{extract_all_names, AllNamesFlags};
|
||||
use crate::ast::relocate::relocate_expr;
|
||||
use crate::ast::types::{
|
||||
@@ -55,6 +57,7 @@ type DeferralContext<'a> = (Vec<usize>, Vec<RefEquality<'a, Stmt>>);
|
||||
pub struct Checker<'a> {
|
||||
// Input data.
|
||||
pub(crate) path: &'a Path,
|
||||
module_path: Option<Vec<String>>,
|
||||
package: Option<&'a Path>,
|
||||
autofix: flags::Autofix,
|
||||
noqa: flags::Noqa,
|
||||
@@ -119,6 +122,7 @@ impl<'a> Checker<'a> {
|
||||
noqa: flags::Noqa,
|
||||
path: &'a Path,
|
||||
package: Option<&'a Path>,
|
||||
module_path: Option<Vec<String>>,
|
||||
locator: &'a Locator,
|
||||
style: &'a Stylist,
|
||||
indexer: &'a Indexer,
|
||||
@@ -130,6 +134,7 @@ impl<'a> Checker<'a> {
|
||||
noqa,
|
||||
path,
|
||||
package,
|
||||
module_path,
|
||||
locator,
|
||||
stylist: style,
|
||||
indexer,
|
||||
@@ -234,32 +239,36 @@ impl<'a> Checker<'a> {
|
||||
if let Some(head) = call_path.first() {
|
||||
if let Some(binding) = self.find_binding(head) {
|
||||
match &binding.kind {
|
||||
BindingKind::Importation(.., name) => {
|
||||
// Ignore relative imports.
|
||||
if name.starts_with('.') {
|
||||
return None;
|
||||
}
|
||||
let mut source_path: CallPath = name.split('.').collect();
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
return Some(source_path);
|
||||
}
|
||||
BindingKind::SubmoduleImportation(name, ..) => {
|
||||
// Ignore relative imports.
|
||||
if name.starts_with('.') {
|
||||
return None;
|
||||
}
|
||||
let mut source_path: CallPath = name.split('.').collect();
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
return Some(source_path);
|
||||
BindingKind::Importation(.., name)
|
||||
| BindingKind::SubmoduleImportation(name, ..) => {
|
||||
return if name.starts_with('.') {
|
||||
if let Some(module) = &self.module_path {
|
||||
let mut source_path = from_relative_import(module, name);
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
Some(source_path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
let mut source_path: CallPath = name.split('.').collect();
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
Some(source_path)
|
||||
};
|
||||
}
|
||||
BindingKind::FromImportation(.., name) => {
|
||||
// Ignore relative imports.
|
||||
if name.starts_with('.') {
|
||||
return None;
|
||||
}
|
||||
let mut source_path: CallPath = name.split('.').collect();
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
return Some(source_path);
|
||||
return if name.starts_with('.') {
|
||||
if let Some(module) = &self.module_path {
|
||||
let mut source_path = from_relative_import(module, name);
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
Some(source_path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
let mut source_path: CallPath = name.split('.').collect();
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
Some(source_path)
|
||||
};
|
||||
}
|
||||
BindingKind::Builtin => {
|
||||
let mut source_path: CallPath = smallvec![];
|
||||
@@ -3178,6 +3187,9 @@ where
|
||||
{
|
||||
pylint::rules::merge_isinstance(self, expr, op, values);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::SingleStartsEndsWith) {
|
||||
flake8_pie::rules::single_starts_ends_with(self, values, op);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::DuplicateIsinstanceCall) {
|
||||
flake8_simplify::rules::duplicate_isinstance_call(self, expr);
|
||||
}
|
||||
@@ -3702,8 +3714,11 @@ where
|
||||
}
|
||||
|
||||
if self.settings.rules.enabled(&Rule::InvalidArgumentName) {
|
||||
if let Some(diagnostic) = pep8_naming::rules::invalid_argument_name(&arg.node.arg, arg)
|
||||
{
|
||||
if let Some(diagnostic) = pep8_naming::rules::invalid_argument_name(
|
||||
&arg.node.arg,
|
||||
arg,
|
||||
&self.settings.pep8_naming.ignore_names,
|
||||
) {
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
@@ -4391,7 +4406,7 @@ impl<'a> Checker<'a> {
|
||||
self.deferred_string_type_definitions.pop()
|
||||
{
|
||||
if let Ok(mut expr) = parser::parse_expression(expression, "<filename>") {
|
||||
if self.annotations_future_enabled {
|
||||
if in_annotation && self.annotations_future_enabled {
|
||||
if self.settings.rules.enabled(&Rule::QuotedAnnotation) {
|
||||
pyupgrade::rules::quoted_annotation(self, expression, range);
|
||||
}
|
||||
@@ -5285,6 +5300,7 @@ pub fn check_ast(
|
||||
noqa,
|
||||
path,
|
||||
package,
|
||||
package.and_then(|package| to_module_path(package, path)),
|
||||
locator,
|
||||
stylist,
|
||||
indexer,
|
||||
|
||||
@@ -453,6 +453,7 @@ ruff_macros::define_rule_mapping!(
|
||||
PIE800 => rules::flake8_pie::rules::NoUnnecessarySpread,
|
||||
PIE804 => rules::flake8_pie::rules::NoUnnecessaryDictKwargs,
|
||||
PIE807 => rules::flake8_pie::rules::PreferListBuiltin,
|
||||
PIE810 => rules::flake8_pie::rules::SingleStartsEndsWith,
|
||||
// flake8-commas
|
||||
COM812 => rules::flake8_commas::rules::TrailingCommaMissing,
|
||||
COM818 => rules::flake8_commas::rules::TrailingCommaOnBareTupleProhibited,
|
||||
|
||||
@@ -14,6 +14,7 @@ mod tests {
|
||||
|
||||
#[test_case(Rule::DupeClassFieldDefinitions, Path::new("PIE794.py"); "PIE794")]
|
||||
#[test_case(Rule::NoUnnecessaryDictKwargs, Path::new("PIE804.py"); "PIE804")]
|
||||
#[test_case(Rule::SingleStartsEndsWith, Path::new("PIE810.py"); "PIE810")]
|
||||
#[test_case(Rule::NoUnnecessaryPass, Path::new("PIE790.py"); "PIE790")]
|
||||
#[test_case(Rule::NoUnnecessarySpread, Path::new("PIE800.py"); "PIE800")]
|
||||
#[test_case(Rule::PreferListBuiltin, Path::new("PIE807.py"); "PIE807")]
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use log::error;
|
||||
use ruff_macros::derive_message_formats;
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustpython_ast::{Constant, Expr, ExprKind, Keyword, Stmt, StmtKind};
|
||||
use rustpython_ast::{Boolop, Constant, Expr, ExprKind, Keyword, Stmt, StmtKind};
|
||||
|
||||
use ruff_macros::derive_message_formats;
|
||||
use ruff_python::identifiers::is_identifier;
|
||||
|
||||
use crate::ast::comparable::ComparableExpr;
|
||||
use crate::ast::helpers::{match_trailing_comment, unparse_expr};
|
||||
@@ -13,7 +15,6 @@ use crate::fix::Fix;
|
||||
use crate::message::Location;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::{AlwaysAutofixableViolation, Violation};
|
||||
use ruff_python::identifiers::is_identifier;
|
||||
|
||||
define_violation!(
|
||||
pub struct NoUnnecessaryPass;
|
||||
@@ -68,6 +69,19 @@ impl Violation for NoUnnecessarySpread {
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct SingleStartsEndsWith {
|
||||
pub attr: String,
|
||||
}
|
||||
);
|
||||
impl Violation for SingleStartsEndsWith {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let SingleStartsEndsWith { attr } = self;
|
||||
format!("Call `{attr}` once with a `tuple`")
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct NoUnnecessaryDictKwargs;
|
||||
);
|
||||
@@ -302,6 +316,44 @@ pub fn no_unnecessary_dict_kwargs(checker: &mut Checker, expr: &Expr, kwargs: &[
|
||||
}
|
||||
}
|
||||
|
||||
/// PIE810
|
||||
pub fn single_starts_ends_with(checker: &mut Checker, values: &[Expr], node: &Boolop) {
|
||||
if *node != Boolop::Or {
|
||||
return;
|
||||
}
|
||||
|
||||
// Given `foo.startswith`, insert ("foo", "startswith") into the set.
|
||||
let mut seen = FxHashSet::default();
|
||||
for expr in values {
|
||||
if let ExprKind::Call {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
..
|
||||
} = &expr.node
|
||||
{
|
||||
if !(args.len() == 1 && keywords.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
if let ExprKind::Attribute { value, attr, .. } = &func.node {
|
||||
if attr != "startswith" && attr != "endswith" {
|
||||
continue;
|
||||
}
|
||||
if let ExprKind::Name { id, .. } = &value.node {
|
||||
if !seen.insert((id, attr)) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SingleStartsEndsWith {
|
||||
attr: attr.to_string(),
|
||||
},
|
||||
Range::from_located(value),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// PIE807
|
||||
pub fn prefer_list_builtin(checker: &mut Checker, expr: &Expr) {
|
||||
let ExprKind::Lambda { args, body } = &expr.node else {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_pie/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
SingleStartsEndsWith:
|
||||
attr: startswith
|
||||
location:
|
||||
row: 2
|
||||
column: 25
|
||||
end_location:
|
||||
row: 2
|
||||
column: 28
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
SingleStartsEndsWith:
|
||||
attr: endswith
|
||||
location:
|
||||
row: 4
|
||||
column: 23
|
||||
end_location:
|
||||
row: 4
|
||||
column: 26
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
SingleStartsEndsWith:
|
||||
attr: startswith
|
||||
location:
|
||||
row: 6
|
||||
column: 23
|
||||
end_location:
|
||||
row: 6
|
||||
column: 26
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
SingleStartsEndsWith:
|
||||
attr: startswith
|
||||
location:
|
||||
row: 8
|
||||
column: 23
|
||||
end_location:
|
||||
row: 8
|
||||
column: 26
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -28,6 +28,16 @@ pub fn is_namedtuple_assignment(checker: &Checker, stmt: &Stmt) -> bool {
|
||||
};
|
||||
checker.resolve_call_path(value).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["collections", "namedtuple"]
|
||||
|| call_path.as_slice() == ["typing", "NamedTuple"]
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_typeddict_assignment(checker: &Checker, stmt: &Stmt) -> bool {
|
||||
let StmtKind::Assign { value, .. } = &stmt.node else {
|
||||
return false;
|
||||
};
|
||||
checker.resolve_call_path(value).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["typing", "TypedDict"]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -224,7 +224,10 @@ pub fn invalid_function_name(
|
||||
ignore_names: &[String],
|
||||
locator: &Locator,
|
||||
) -> Option<Diagnostic> {
|
||||
if name.to_lowercase() != name && !ignore_names.iter().any(|ignore_name| ignore_name == name) {
|
||||
if ignore_names.iter().any(|ignore_name| ignore_name == name) {
|
||||
return None;
|
||||
}
|
||||
if name.to_lowercase() != name {
|
||||
return Some(Diagnostic::new(
|
||||
InvalidFunctionName {
|
||||
name: name.to_string(),
|
||||
@@ -236,7 +239,10 @@ pub fn invalid_function_name(
|
||||
}
|
||||
|
||||
/// N803
|
||||
pub fn invalid_argument_name(name: &str, arg: &Arg) -> Option<Diagnostic> {
|
||||
pub fn invalid_argument_name(name: &str, arg: &Arg, ignore_names: &[String]) -> Option<Diagnostic> {
|
||||
if ignore_names.iter().any(|ignore_name| ignore_name == name) {
|
||||
return None;
|
||||
}
|
||||
if name.to_lowercase() != name {
|
||||
return Some(Diagnostic::new(
|
||||
InvalidArgumentName {
|
||||
@@ -269,15 +275,17 @@ pub fn invalid_first_argument_name_for_class_method(
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
if let Some(arg) = args.posonlyargs.first() {
|
||||
if arg.node.arg != "cls" {
|
||||
return Some(Diagnostic::new(
|
||||
InvalidFirstArgumentNameForClassMethod,
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
} else if let Some(arg) = args.args.first() {
|
||||
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
||||
if arg.node.arg != "cls" {
|
||||
if checker
|
||||
.settings
|
||||
.pep8_naming
|
||||
.ignore_names
|
||||
.iter()
|
||||
.any(|ignore_name| ignore_name == name)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
return Some(Diagnostic::new(
|
||||
InvalidFirstArgumentNameForClassMethod,
|
||||
Range::from_located(arg),
|
||||
@@ -312,6 +320,15 @@ pub fn invalid_first_argument_name_for_method(
|
||||
if arg.node.arg == "self" {
|
||||
return None;
|
||||
}
|
||||
if checker
|
||||
.settings
|
||||
.pep8_naming
|
||||
.ignore_names
|
||||
.iter()
|
||||
.any(|ignore_name| ignore_name == name)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
Some(Diagnostic::new(
|
||||
InvalidFirstArgumentNameForMethod,
|
||||
Range::from_located(arg),
|
||||
@@ -325,8 +342,19 @@ pub fn non_lowercase_variable_in_function(
|
||||
stmt: &Stmt,
|
||||
name: &str,
|
||||
) {
|
||||
if checker
|
||||
.settings
|
||||
.pep8_naming
|
||||
.ignore_names
|
||||
.iter()
|
||||
.any(|ignore_name| ignore_name == name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if name.to_lowercase() != name
|
||||
&& !helpers::is_namedtuple_assignment(checker, stmt)
|
||||
&& !helpers::is_typeddict_assignment(checker, stmt)
|
||||
&& !helpers::is_type_var_assignment(checker, stmt)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
@@ -449,6 +477,15 @@ pub fn mixed_case_variable_in_class_scope(
|
||||
stmt: &Stmt,
|
||||
name: &str,
|
||||
) {
|
||||
if checker
|
||||
.settings
|
||||
.pep8_naming
|
||||
.ignore_names
|
||||
.iter()
|
||||
.any(|ignore_name| ignore_name == name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if helpers::is_mixed_case(name) && !helpers::is_namedtuple_assignment(checker, stmt) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
MixedCaseVariableInClassScope {
|
||||
@@ -466,6 +503,15 @@ pub fn mixed_case_variable_in_global_scope(
|
||||
stmt: &Stmt,
|
||||
name: &str,
|
||||
) {
|
||||
if checker
|
||||
.settings
|
||||
.pep8_naming
|
||||
.ignore_names
|
||||
.iter()
|
||||
.any(|ignore_name| ignore_name == name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if helpers::is_mixed_case(name) && !helpers::is_namedtuple_assignment(checker, stmt) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
MixedCaseVariableInGlobalScope {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
source: src/rules/pep8_naming/mod.rs
|
||||
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
NonLowercaseVariableInFunction:
|
||||
name: Camel
|
||||
location:
|
||||
row: 13
|
||||
row: 14
|
||||
column: 4
|
||||
end_location:
|
||||
row: 13
|
||||
row: 14
|
||||
column: 9
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -17,10 +17,10 @@ expression: diagnostics
|
||||
NonLowercaseVariableInFunction:
|
||||
name: CONSTANT
|
||||
location:
|
||||
row: 14
|
||||
row: 15
|
||||
column: 4
|
||||
end_location:
|
||||
row: 14
|
||||
row: 15
|
||||
column: 12
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
source: src/rules/pep8_naming/mod.rs
|
||||
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
MixedCaseVariableInClassScope:
|
||||
name: mixedCase
|
||||
location:
|
||||
row: 8
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
row: 9
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -17,10 +17,10 @@ expression: diagnostics
|
||||
MixedCaseVariableInClassScope:
|
||||
name: _mixedCase
|
||||
location:
|
||||
row: 9
|
||||
row: 10
|
||||
column: 4
|
||||
end_location:
|
||||
row: 9
|
||||
row: 10
|
||||
column: 14
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -28,10 +28,10 @@ expression: diagnostics
|
||||
MixedCaseVariableInClassScope:
|
||||
name: mixed_Case
|
||||
location:
|
||||
row: 10
|
||||
row: 11
|
||||
column: 4
|
||||
end_location:
|
||||
row: 10
|
||||
row: 11
|
||||
column: 14
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
source: src/rules/pep8_naming/mod.rs
|
||||
source: crates/ruff/src/rules/pep8_naming/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
MixedCaseVariableInGlobalScope:
|
||||
name: mixedCase
|
||||
location:
|
||||
row: 6
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 6
|
||||
row: 7
|
||||
column: 9
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -17,10 +17,10 @@ expression: diagnostics
|
||||
MixedCaseVariableInGlobalScope:
|
||||
name: _mixedCase
|
||||
location:
|
||||
row: 7
|
||||
row: 8
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
row: 8
|
||||
column: 10
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -28,10 +28,10 @@ expression: diagnostics
|
||||
MixedCaseVariableInGlobalScope:
|
||||
name: mixed_Case
|
||||
location:
|
||||
row: 8
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 8
|
||||
row: 9
|
||||
column: 10
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -207,6 +207,32 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn relative_typing_module() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("pyflakes/project/foo/bar.py"),
|
||||
&settings::Settings {
|
||||
typing_modules: vec!["foo.typical".to_string()],
|
||||
..settings::Settings::for_rules(vec![Rule::UndefinedName])
|
||||
},
|
||||
)?;
|
||||
assert_yaml_snapshot!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_relative_typing_module() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("pyflakes/project/foo/bop/baz.py"),
|
||||
&settings::Settings {
|
||||
typing_modules: vec!["foo.typical".to_string()],
|
||||
..settings::Settings::for_rules(vec![Rule::UndefinedName])
|
||||
},
|
||||
)?;
|
||||
assert_yaml_snapshot!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A re-implementation of the Pyflakes test runner.
|
||||
/// Note that all tests marked with `#[ignore]` should be considered TODOs.
|
||||
fn flakes(contents: &str, expected: &[Rule]) {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/pyflakes/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
UndefinedName:
|
||||
name: foo
|
||||
location:
|
||||
row: 26
|
||||
column: 15
|
||||
end_location:
|
||||
row: 26
|
||||
column: 20
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
UndefinedName:
|
||||
name: foo
|
||||
location:
|
||||
row: 33
|
||||
column: 15
|
||||
end_location:
|
||||
row: 33
|
||||
column: 20
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/pyflakes/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
UndefinedName:
|
||||
name: foo
|
||||
location:
|
||||
row: 26
|
||||
column: 15
|
||||
end_location:
|
||||
row: 26
|
||||
column: 20
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
source: src/rules/pyupgrade/mod.rs
|
||||
source: crates/ruff/src/rules/pyupgrade/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
@@ -510,90 +510,18 @@ expression: diagnostics
|
||||
QuotedAnnotation: ~
|
||||
location:
|
||||
row: 69
|
||||
column: 17
|
||||
end_location:
|
||||
row: 69
|
||||
column: 22
|
||||
fix:
|
||||
content:
|
||||
- str
|
||||
location:
|
||||
row: 69
|
||||
column: 17
|
||||
end_location:
|
||||
row: 69
|
||||
column: 22
|
||||
parent: ~
|
||||
- kind:
|
||||
QuotedAnnotation: ~
|
||||
location:
|
||||
row: 69
|
||||
column: 24
|
||||
end_location:
|
||||
row: 69
|
||||
column: 29
|
||||
fix:
|
||||
content:
|
||||
- int
|
||||
location:
|
||||
row: 69
|
||||
column: 24
|
||||
end_location:
|
||||
row: 69
|
||||
column: 29
|
||||
parent: ~
|
||||
- kind:
|
||||
QuotedAnnotation: ~
|
||||
location:
|
||||
row: 71
|
||||
column: 9
|
||||
end_location:
|
||||
row: 71
|
||||
column: 14
|
||||
fix:
|
||||
content:
|
||||
- str
|
||||
location:
|
||||
row: 71
|
||||
column: 9
|
||||
end_location:
|
||||
row: 71
|
||||
column: 14
|
||||
parent: ~
|
||||
- kind:
|
||||
QuotedAnnotation: ~
|
||||
location:
|
||||
row: 73
|
||||
column: 9
|
||||
end_location:
|
||||
row: 73
|
||||
column: 18
|
||||
fix:
|
||||
content:
|
||||
- MyClass
|
||||
location:
|
||||
row: 73
|
||||
column: 9
|
||||
end_location:
|
||||
row: 73
|
||||
column: 18
|
||||
parent: ~
|
||||
- kind:
|
||||
QuotedAnnotation: ~
|
||||
location:
|
||||
row: 75
|
||||
column: 14
|
||||
end_location:
|
||||
row: 75
|
||||
row: 69
|
||||
column: 17
|
||||
fix:
|
||||
content:
|
||||
- X
|
||||
location:
|
||||
row: 75
|
||||
row: 69
|
||||
column: 14
|
||||
end_location:
|
||||
row: 75
|
||||
row: 69
|
||||
column: 17
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_python"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "ruff"
|
||||
version = "0.0.242"
|
||||
version = "0.0.243"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
authors = [{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }]
|
||||
maintainers = [{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" }]
|
||||
|
||||
@@ -1650,6 +1650,8 @@
|
||||
"PIE800",
|
||||
"PIE804",
|
||||
"PIE807",
|
||||
"PIE81",
|
||||
"PIE810",
|
||||
"PL",
|
||||
"PLC",
|
||||
"PLC0",
|
||||
|
||||
766
src/registry.rs
Normal file
766
src/registry.rs
Normal file
@@ -0,0 +1,766 @@
|
||||
//! Registry of [`Rule`] to [`DiagnosticKind`] mappings.
|
||||
|
||||
use ruff_macros::RuleNamespace;
|
||||
use rustpython_parser::ast::Location;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{AsRefStr, EnumIter};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::fix::Fix;
|
||||
use crate::rule_selector::{prefix_to_selector, RuleSelector};
|
||||
use crate::violation::Violation;
|
||||
use crate::{rules, violations};
|
||||
|
||||
ruff_macros::define_rule_mapping!(
|
||||
// pycodestyle errors
|
||||
E101 => rules::pycodestyle::rules::MixedSpacesAndTabs,
|
||||
E401 => violations::MultipleImportsOnOneLine,
|
||||
E402 => violations::ModuleImportNotAtTopOfFile,
|
||||
E501 => rules::pycodestyle::rules::LineTooLong,
|
||||
E711 => rules::pycodestyle::rules::NoneComparison,
|
||||
E712 => rules::pycodestyle::rules::TrueFalseComparison,
|
||||
E713 => rules::pycodestyle::rules::NotInTest,
|
||||
E714 => rules::pycodestyle::rules::NotIsTest,
|
||||
E721 => rules::pycodestyle::rules::TypeComparison,
|
||||
E722 => rules::pycodestyle::rules::DoNotUseBareExcept,
|
||||
E731 => rules::pycodestyle::rules::DoNotAssignLambda,
|
||||
E741 => rules::pycodestyle::rules::AmbiguousVariableName,
|
||||
E742 => rules::pycodestyle::rules::AmbiguousClassName,
|
||||
E743 => rules::pycodestyle::rules::AmbiguousFunctionName,
|
||||
E902 => violations::IOError,
|
||||
E999 => violations::SyntaxError,
|
||||
// pycodestyle warnings
|
||||
W292 => rules::pycodestyle::rules::NoNewLineAtEndOfFile,
|
||||
W505 => rules::pycodestyle::rules::DocLineTooLong,
|
||||
W605 => rules::pycodestyle::rules::InvalidEscapeSequence,
|
||||
// pyflakes
|
||||
F401 => violations::UnusedImport,
|
||||
F402 => violations::ImportShadowedByLoopVar,
|
||||
F403 => violations::ImportStarUsed,
|
||||
F404 => violations::LateFutureImport,
|
||||
F405 => violations::ImportStarUsage,
|
||||
F406 => violations::ImportStarNotPermitted,
|
||||
F407 => violations::FutureFeatureNotDefined,
|
||||
F501 => violations::PercentFormatInvalidFormat,
|
||||
F502 => violations::PercentFormatExpectedMapping,
|
||||
F503 => violations::PercentFormatExpectedSequence,
|
||||
F504 => violations::PercentFormatExtraNamedArguments,
|
||||
F505 => violations::PercentFormatMissingArgument,
|
||||
F506 => violations::PercentFormatMixedPositionalAndNamed,
|
||||
F507 => violations::PercentFormatPositionalCountMismatch,
|
||||
F508 => violations::PercentFormatStarRequiresSequence,
|
||||
F509 => violations::PercentFormatUnsupportedFormatCharacter,
|
||||
F521 => violations::StringDotFormatInvalidFormat,
|
||||
F522 => violations::StringDotFormatExtraNamedArguments,
|
||||
F523 => violations::StringDotFormatExtraPositionalArguments,
|
||||
F524 => violations::StringDotFormatMissingArguments,
|
||||
F525 => violations::StringDotFormatMixingAutomatic,
|
||||
F541 => violations::FStringMissingPlaceholders,
|
||||
F601 => violations::MultiValueRepeatedKeyLiteral,
|
||||
F602 => violations::MultiValueRepeatedKeyVariable,
|
||||
F621 => violations::ExpressionsInStarAssignment,
|
||||
F622 => violations::TwoStarredExpressions,
|
||||
F631 => violations::AssertTuple,
|
||||
F632 => violations::IsLiteral,
|
||||
F633 => violations::InvalidPrintSyntax,
|
||||
F634 => violations::IfTuple,
|
||||
F701 => violations::BreakOutsideLoop,
|
||||
F702 => violations::ContinueOutsideLoop,
|
||||
F704 => violations::YieldOutsideFunction,
|
||||
F706 => violations::ReturnOutsideFunction,
|
||||
F707 => violations::DefaultExceptNotLast,
|
||||
F722 => violations::ForwardAnnotationSyntaxError,
|
||||
F811 => violations::RedefinedWhileUnused,
|
||||
F821 => violations::UndefinedName,
|
||||
F822 => violations::UndefinedExport,
|
||||
F823 => violations::UndefinedLocal,
|
||||
F841 => violations::UnusedVariable,
|
||||
F842 => violations::UnusedAnnotation,
|
||||
F901 => violations::RaiseNotImplemented,
|
||||
// pylint
|
||||
PLC0414 => violations::UselessImportAlias,
|
||||
PLC3002 => violations::UnnecessaryDirectLambdaCall,
|
||||
PLE0117 => violations::NonlocalWithoutBinding,
|
||||
PLE0118 => violations::UsedPriorGlobalDeclaration,
|
||||
PLE1142 => violations::AwaitOutsideAsync,
|
||||
PLR0206 => violations::PropertyWithParameters,
|
||||
PLR0402 => violations::ConsiderUsingFromImport,
|
||||
PLR0133 => violations::ConstantComparison,
|
||||
PLR1701 => violations::ConsiderMergingIsinstance,
|
||||
PLR1722 => violations::UseSysExit,
|
||||
PLR2004 => violations::MagicValueComparison,
|
||||
PLW0120 => violations::UselessElseOnLoop,
|
||||
PLW0602 => violations::GlobalVariableNotAssigned,
|
||||
// flake8-builtins
|
||||
A001 => violations::BuiltinVariableShadowing,
|
||||
A002 => violations::BuiltinArgumentShadowing,
|
||||
A003 => violations::BuiltinAttributeShadowing,
|
||||
// flake8-bugbear
|
||||
B002 => violations::UnaryPrefixIncrement,
|
||||
B003 => violations::AssignmentToOsEnviron,
|
||||
B004 => violations::UnreliableCallableCheck,
|
||||
B005 => violations::StripWithMultiCharacters,
|
||||
B006 => violations::MutableArgumentDefault,
|
||||
B007 => violations::UnusedLoopControlVariable,
|
||||
B008 => violations::FunctionCallArgumentDefault,
|
||||
B009 => violations::GetAttrWithConstant,
|
||||
B010 => violations::SetAttrWithConstant,
|
||||
B011 => violations::DoNotAssertFalse,
|
||||
B012 => violations::JumpStatementInFinally,
|
||||
B013 => violations::RedundantTupleInExceptionHandler,
|
||||
B014 => violations::DuplicateHandlerException,
|
||||
B015 => violations::UselessComparison,
|
||||
B016 => violations::CannotRaiseLiteral,
|
||||
B017 => violations::NoAssertRaisesException,
|
||||
B018 => violations::UselessExpression,
|
||||
B019 => violations::CachedInstanceMethod,
|
||||
B020 => violations::LoopVariableOverridesIterator,
|
||||
B021 => violations::FStringDocstring,
|
||||
B022 => violations::UselessContextlibSuppress,
|
||||
B023 => violations::FunctionUsesLoopVariable,
|
||||
B024 => violations::AbstractBaseClassWithoutAbstractMethod,
|
||||
B025 => violations::DuplicateTryBlockException,
|
||||
B026 => violations::StarArgUnpackingAfterKeywordArg,
|
||||
B027 => violations::EmptyMethodWithoutAbstractDecorator,
|
||||
B904 => violations::RaiseWithoutFromInsideExcept,
|
||||
B905 => violations::ZipWithoutExplicitStrict,
|
||||
// flake8-blind-except
|
||||
BLE001 => violations::BlindExcept,
|
||||
// flake8-comprehensions
|
||||
C400 => violations::UnnecessaryGeneratorList,
|
||||
C401 => violations::UnnecessaryGeneratorSet,
|
||||
C402 => violations::UnnecessaryGeneratorDict,
|
||||
C403 => violations::UnnecessaryListComprehensionSet,
|
||||
C404 => violations::UnnecessaryListComprehensionDict,
|
||||
C405 => violations::UnnecessaryLiteralSet,
|
||||
C406 => violations::UnnecessaryLiteralDict,
|
||||
C408 => violations::UnnecessaryCollectionCall,
|
||||
C409 => violations::UnnecessaryLiteralWithinTupleCall,
|
||||
C410 => violations::UnnecessaryLiteralWithinListCall,
|
||||
C411 => violations::UnnecessaryListCall,
|
||||
C413 => violations::UnnecessaryCallAroundSorted,
|
||||
C414 => violations::UnnecessaryDoubleCastOrProcess,
|
||||
C415 => violations::UnnecessarySubscriptReversal,
|
||||
C416 => violations::UnnecessaryComprehension,
|
||||
C417 => violations::UnnecessaryMap,
|
||||
// flake8-debugger
|
||||
T100 => violations::Debugger,
|
||||
// mccabe
|
||||
C901 => violations::FunctionIsTooComplex,
|
||||
// flake8-tidy-imports
|
||||
TID251 => rules::flake8_tidy_imports::banned_api::BannedApi,
|
||||
TID252 => rules::flake8_tidy_imports::relative_imports::RelativeImports,
|
||||
// flake8-return
|
||||
RET501 => violations::UnnecessaryReturnNone,
|
||||
RET502 => violations::ImplicitReturnValue,
|
||||
RET503 => violations::ImplicitReturn,
|
||||
RET504 => violations::UnnecessaryAssign,
|
||||
RET505 => violations::SuperfluousElseReturn,
|
||||
RET506 => violations::SuperfluousElseRaise,
|
||||
RET507 => violations::SuperfluousElseContinue,
|
||||
RET508 => violations::SuperfluousElseBreak,
|
||||
// flake8-implicit-str-concat
|
||||
ISC001 => violations::SingleLineImplicitStringConcatenation,
|
||||
ISC002 => violations::MultiLineImplicitStringConcatenation,
|
||||
ISC003 => violations::ExplicitStringConcatenation,
|
||||
// flake8-print
|
||||
T201 => violations::PrintFound,
|
||||
T203 => violations::PPrintFound,
|
||||
// flake8-quotes
|
||||
Q000 => violations::BadQuotesInlineString,
|
||||
Q001 => violations::BadQuotesMultilineString,
|
||||
Q002 => violations::BadQuotesDocstring,
|
||||
Q003 => violations::AvoidQuoteEscape,
|
||||
// flake8-annotations
|
||||
ANN001 => violations::MissingTypeFunctionArgument,
|
||||
ANN002 => violations::MissingTypeArgs,
|
||||
ANN003 => violations::MissingTypeKwargs,
|
||||
ANN101 => violations::MissingTypeSelf,
|
||||
ANN102 => violations::MissingTypeCls,
|
||||
ANN201 => violations::MissingReturnTypePublicFunction,
|
||||
ANN202 => violations::MissingReturnTypePrivateFunction,
|
||||
ANN204 => violations::MissingReturnTypeSpecialMethod,
|
||||
ANN205 => violations::MissingReturnTypeStaticMethod,
|
||||
ANN206 => violations::MissingReturnTypeClassMethod,
|
||||
ANN401 => violations::DynamicallyTypedExpression,
|
||||
// flake8-2020
|
||||
YTT101 => violations::SysVersionSlice3Referenced,
|
||||
YTT102 => violations::SysVersion2Referenced,
|
||||
YTT103 => violations::SysVersionCmpStr3,
|
||||
YTT201 => violations::SysVersionInfo0Eq3Referenced,
|
||||
YTT202 => violations::SixPY3Referenced,
|
||||
YTT203 => violations::SysVersionInfo1CmpInt,
|
||||
YTT204 => violations::SysVersionInfoMinorCmpInt,
|
||||
YTT301 => violations::SysVersion0Referenced,
|
||||
YTT302 => violations::SysVersionCmpStr10,
|
||||
YTT303 => violations::SysVersionSlice1Referenced,
|
||||
// flake8-simplify
|
||||
SIM115 => violations::OpenFileWithContextHandler,
|
||||
SIM101 => violations::DuplicateIsinstanceCall,
|
||||
SIM102 => violations::NestedIfStatements,
|
||||
SIM103 => violations::ReturnBoolConditionDirectly,
|
||||
SIM105 => violations::UseContextlibSuppress,
|
||||
SIM107 => violations::ReturnInTryExceptFinally,
|
||||
SIM108 => violations::UseTernaryOperator,
|
||||
SIM109 => violations::CompareWithTuple,
|
||||
SIM110 => violations::ConvertLoopToAny,
|
||||
SIM111 => violations::ConvertLoopToAll,
|
||||
SIM112 => violations::UseCapitalEnvironmentVariables,
|
||||
SIM117 => violations::MultipleWithStatements,
|
||||
SIM118 => violations::KeyInDict,
|
||||
SIM201 => violations::NegateEqualOp,
|
||||
SIM202 => violations::NegateNotEqualOp,
|
||||
SIM208 => violations::DoubleNegation,
|
||||
SIM210 => violations::IfExprWithTrueFalse,
|
||||
SIM211 => violations::IfExprWithFalseTrue,
|
||||
SIM212 => violations::IfExprWithTwistedArms,
|
||||
SIM220 => violations::AAndNotA,
|
||||
SIM221 => violations::AOrNotA,
|
||||
SIM222 => violations::OrTrue,
|
||||
SIM223 => violations::AndFalse,
|
||||
SIM300 => violations::YodaConditions,
|
||||
SIM401 => violations::DictGetWithDefault,
|
||||
// pyupgrade
|
||||
UP001 => violations::UselessMetaclassType,
|
||||
UP003 => violations::TypeOfPrimitive,
|
||||
UP004 => violations::UselessObjectInheritance,
|
||||
UP005 => violations::DeprecatedUnittestAlias,
|
||||
UP006 => violations::UsePEP585Annotation,
|
||||
UP007 => violations::UsePEP604Annotation,
|
||||
UP008 => violations::SuperCallWithParameters,
|
||||
UP009 => violations::PEP3120UnnecessaryCodingComment,
|
||||
UP010 => violations::UnnecessaryFutureImport,
|
||||
UP011 => violations::LRUCacheWithoutParameters,
|
||||
UP012 => violations::UnnecessaryEncodeUTF8,
|
||||
UP013 => violations::ConvertTypedDictFunctionalToClass,
|
||||
UP014 => violations::ConvertNamedTupleFunctionalToClass,
|
||||
UP015 => violations::RedundantOpenModes,
|
||||
UP016 => violations::RemoveSixCompat,
|
||||
UP017 => violations::DatetimeTimezoneUTC,
|
||||
UP018 => violations::NativeLiterals,
|
||||
UP019 => violations::TypingTextStrAlias,
|
||||
UP020 => violations::OpenAlias,
|
||||
UP021 => violations::ReplaceUniversalNewlines,
|
||||
UP022 => violations::ReplaceStdoutStderr,
|
||||
UP023 => violations::RewriteCElementTree,
|
||||
UP024 => violations::OSErrorAlias,
|
||||
UP025 => violations::RewriteUnicodeLiteral,
|
||||
UP026 => violations::RewriteMockImport,
|
||||
UP027 => violations::RewriteListComprehension,
|
||||
UP028 => violations::RewriteYieldFrom,
|
||||
UP029 => violations::UnnecessaryBuiltinImport,
|
||||
UP030 => violations::FormatLiterals,
|
||||
UP031 => violations::PrintfStringFormatting,
|
||||
UP032 => violations::FString,
|
||||
UP033 => violations::FunctoolsCache,
|
||||
UP034 => violations::ExtraneousParentheses,
|
||||
// pydocstyle
|
||||
D100 => violations::PublicModule,
|
||||
D101 => violations::PublicClass,
|
||||
D102 => violations::PublicMethod,
|
||||
D103 => violations::PublicFunction,
|
||||
D104 => violations::PublicPackage,
|
||||
D105 => violations::MagicMethod,
|
||||
D106 => violations::PublicNestedClass,
|
||||
D107 => violations::PublicInit,
|
||||
D200 => violations::FitsOnOneLine,
|
||||
D201 => violations::NoBlankLineBeforeFunction,
|
||||
D202 => violations::NoBlankLineAfterFunction,
|
||||
D203 => violations::OneBlankLineBeforeClass,
|
||||
D204 => violations::OneBlankLineAfterClass,
|
||||
D205 => violations::BlankLineAfterSummary,
|
||||
D206 => violations::IndentWithSpaces,
|
||||
D207 => violations::NoUnderIndentation,
|
||||
D208 => violations::NoOverIndentation,
|
||||
D209 => violations::NewLineAfterLastParagraph,
|
||||
D210 => violations::NoSurroundingWhitespace,
|
||||
D211 => violations::NoBlankLineBeforeClass,
|
||||
D212 => violations::MultiLineSummaryFirstLine,
|
||||
D213 => violations::MultiLineSummarySecondLine,
|
||||
D214 => violations::SectionNotOverIndented,
|
||||
D215 => violations::SectionUnderlineNotOverIndented,
|
||||
D300 => violations::UsesTripleQuotes,
|
||||
D301 => violations::UsesRPrefixForBackslashedContent,
|
||||
D400 => violations::EndsInPeriod,
|
||||
D401 => crate::rules::pydocstyle::rules::non_imperative_mood::NonImperativeMood,
|
||||
D402 => violations::NoSignature,
|
||||
D403 => violations::FirstLineCapitalized,
|
||||
D404 => violations::NoThisPrefix,
|
||||
D405 => violations::CapitalizeSectionName,
|
||||
D406 => violations::NewLineAfterSectionName,
|
||||
D407 => violations::DashedUnderlineAfterSection,
|
||||
D408 => violations::SectionUnderlineAfterName,
|
||||
D409 => violations::SectionUnderlineMatchesSectionLength,
|
||||
D410 => violations::BlankLineAfterSection,
|
||||
D411 => violations::BlankLineBeforeSection,
|
||||
D412 => violations::NoBlankLinesBetweenHeaderAndContent,
|
||||
D413 => violations::BlankLineAfterLastSection,
|
||||
D414 => violations::NonEmptySection,
|
||||
D415 => violations::EndsInPunctuation,
|
||||
D416 => violations::SectionNameEndsInColon,
|
||||
D417 => violations::DocumentAllArguments,
|
||||
D418 => violations::SkipDocstring,
|
||||
D419 => violations::NonEmpty,
|
||||
// pep8-naming
|
||||
N801 => violations::InvalidClassName,
|
||||
N802 => violations::InvalidFunctionName,
|
||||
N803 => violations::InvalidArgumentName,
|
||||
N804 => violations::InvalidFirstArgumentNameForClassMethod,
|
||||
N805 => violations::InvalidFirstArgumentNameForMethod,
|
||||
N806 => violations::NonLowercaseVariableInFunction,
|
||||
N807 => violations::DunderFunctionName,
|
||||
N811 => violations::ConstantImportedAsNonConstant,
|
||||
N812 => violations::LowercaseImportedAsNonLowercase,
|
||||
N813 => violations::CamelcaseImportedAsLowercase,
|
||||
N814 => violations::CamelcaseImportedAsConstant,
|
||||
N815 => violations::MixedCaseVariableInClassScope,
|
||||
N816 => violations::MixedCaseVariableInGlobalScope,
|
||||
N817 => violations::CamelcaseImportedAsAcronym,
|
||||
N818 => violations::ErrorSuffixOnExceptionName,
|
||||
// isort
|
||||
I001 => rules::isort::rules::UnsortedImports,
|
||||
I002 => rules::isort::rules::MissingRequiredImport,
|
||||
// eradicate
|
||||
ERA001 => rules::eradicate::rules::CommentedOutCode,
|
||||
// flake8-bandit
|
||||
S101 => violations::AssertUsed,
|
||||
S102 => violations::ExecUsed,
|
||||
S103 => violations::BadFilePermissions,
|
||||
S104 => violations::HardcodedBindAllInterfaces,
|
||||
S105 => violations::HardcodedPasswordString,
|
||||
S106 => violations::HardcodedPasswordFuncArg,
|
||||
S107 => violations::HardcodedPasswordDefault,
|
||||
S108 => violations::HardcodedTempFile,
|
||||
S113 => violations::RequestWithoutTimeout,
|
||||
S324 => violations::HashlibInsecureHashFunction,
|
||||
S501 => violations::RequestWithNoCertValidation,
|
||||
S506 => violations::UnsafeYAMLLoad,
|
||||
S508 => violations::SnmpInsecureVersion,
|
||||
S509 => violations::SnmpWeakCryptography,
|
||||
S612 => rules::flake8_bandit::rules::LoggingConfigInsecureListen,
|
||||
S701 => violations::Jinja2AutoescapeFalse,
|
||||
// flake8-boolean-trap
|
||||
FBT001 => rules::flake8_boolean_trap::rules::BooleanPositionalArgInFunctionDefinition,
|
||||
FBT002 => rules::flake8_boolean_trap::rules::BooleanDefaultValueInFunctionDefinition,
|
||||
FBT003 => rules::flake8_boolean_trap::rules::BooleanPositionalValueInFunctionCall,
|
||||
// flake8-unused-arguments
|
||||
ARG001 => violations::UnusedFunctionArgument,
|
||||
ARG002 => violations::UnusedMethodArgument,
|
||||
ARG003 => violations::UnusedClassMethodArgument,
|
||||
ARG004 => violations::UnusedStaticMethodArgument,
|
||||
ARG005 => violations::UnusedLambdaArgument,
|
||||
// flake8-import-conventions
|
||||
ICN001 => rules::flake8_import_conventions::rules::ImportAliasIsNotConventional,
|
||||
// flake8-datetimez
|
||||
DTZ001 => violations::CallDatetimeWithoutTzinfo,
|
||||
DTZ002 => violations::CallDatetimeToday,
|
||||
DTZ003 => violations::CallDatetimeUtcnow,
|
||||
DTZ004 => violations::CallDatetimeUtcfromtimestamp,
|
||||
DTZ005 => violations::CallDatetimeNowWithoutTzinfo,
|
||||
DTZ006 => violations::CallDatetimeFromtimestamp,
|
||||
DTZ007 => violations::CallDatetimeStrptimeWithoutZone,
|
||||
DTZ011 => violations::CallDateToday,
|
||||
DTZ012 => violations::CallDateFromtimestamp,
|
||||
// pygrep-hooks
|
||||
PGH001 => violations::NoEval,
|
||||
PGH002 => violations::DeprecatedLogWarn,
|
||||
PGH003 => violations::BlanketTypeIgnore,
|
||||
PGH004 => violations::BlanketNOQA,
|
||||
// pandas-vet
|
||||
PD002 => violations::UseOfInplaceArgument,
|
||||
PD003 => violations::UseOfDotIsNull,
|
||||
PD004 => violations::UseOfDotNotNull,
|
||||
PD007 => violations::UseOfDotIx,
|
||||
PD008 => violations::UseOfDotAt,
|
||||
PD009 => violations::UseOfDotIat,
|
||||
PD010 => violations::UseOfDotPivotOrUnstack,
|
||||
PD011 => violations::UseOfDotValues,
|
||||
PD012 => violations::UseOfDotReadTable,
|
||||
PD013 => violations::UseOfDotStack,
|
||||
PD015 => violations::UseOfPdMerge,
|
||||
PD901 => violations::DfIsABadVariableName,
|
||||
// flake8-errmsg
|
||||
EM101 => violations::RawStringInException,
|
||||
EM102 => violations::FStringInException,
|
||||
EM103 => violations::DotFormatInException,
|
||||
// flake8-pytest-style
|
||||
PT001 => violations::IncorrectFixtureParenthesesStyle,
|
||||
PT002 => violations::FixturePositionalArgs,
|
||||
PT003 => violations::ExtraneousScopeFunction,
|
||||
PT004 => violations::MissingFixtureNameUnderscore,
|
||||
PT005 => violations::IncorrectFixtureNameUnderscore,
|
||||
PT006 => violations::ParametrizeNamesWrongType,
|
||||
PT007 => violations::ParametrizeValuesWrongType,
|
||||
PT008 => violations::PatchWithLambda,
|
||||
PT009 => violations::UnittestAssertion,
|
||||
PT010 => violations::RaisesWithoutException,
|
||||
PT011 => violations::RaisesTooBroad,
|
||||
PT012 => violations::RaisesWithMultipleStatements,
|
||||
PT013 => violations::IncorrectPytestImport,
|
||||
PT015 => violations::AssertAlwaysFalse,
|
||||
PT016 => violations::FailWithoutMessage,
|
||||
PT017 => violations::AssertInExcept,
|
||||
PT018 => violations::CompositeAssertion,
|
||||
PT019 => violations::FixtureParamWithoutValue,
|
||||
PT020 => violations::DeprecatedYieldFixture,
|
||||
PT021 => violations::FixtureFinalizerCallback,
|
||||
PT022 => violations::UselessYieldFixture,
|
||||
PT023 => violations::IncorrectMarkParenthesesStyle,
|
||||
PT024 => violations::UnnecessaryAsyncioMarkOnFixture,
|
||||
PT025 => violations::ErroneousUseFixturesOnFixture,
|
||||
PT026 => violations::UseFixturesWithoutParameters,
|
||||
// flake8-pie
|
||||
PIE790 => rules::flake8_pie::rules::NoUnnecessaryPass,
|
||||
PIE794 => rules::flake8_pie::rules::DupeClassFieldDefinitions,
|
||||
PIE796 => rules::flake8_pie::rules::PreferUniqueEnums,
|
||||
PIE800 => rules::flake8_pie::rules::NoUnnecessarySpread,
|
||||
PIE804 => rules::flake8_pie::rules::NoUnnecessaryDictKwargs,
|
||||
PIE807 => rules::flake8_pie::rules::PreferListBuiltin,
|
||||
PIE810 => rules::flake8_pie::rules::SingleStartsEndsWith,
|
||||
// flake8-commas
|
||||
COM812 => rules::flake8_commas::rules::TrailingCommaMissing,
|
||||
COM818 => rules::flake8_commas::rules::TrailingCommaOnBareTupleProhibited,
|
||||
COM819 => rules::flake8_commas::rules::TrailingCommaProhibited,
|
||||
// flake8-no-pep420
|
||||
INP001 => rules::flake8_no_pep420::rules::ImplicitNamespacePackage,
|
||||
// flake8-executable
|
||||
EXE001 => rules::flake8_executable::rules::ShebangNotExecutable,
|
||||
EXE002 => rules::flake8_executable::rules::ShebangMissingExecutableFile,
|
||||
EXE003 => rules::flake8_executable::rules::ShebangPython,
|
||||
EXE004 => rules::flake8_executable::rules::ShebangWhitespace,
|
||||
EXE005 => rules::flake8_executable::rules::ShebangNewline,
|
||||
// flake8-type-checking
|
||||
TCH001 => rules::flake8_type_checking::rules::TypingOnlyFirstPartyImport,
|
||||
TCH002 => rules::flake8_type_checking::rules::TypingOnlyThirdPartyImport,
|
||||
TCH003 => rules::flake8_type_checking::rules::TypingOnlyStandardLibraryImport,
|
||||
TCH004 => rules::flake8_type_checking::rules::RuntimeImportInTypeCheckingBlock,
|
||||
TCH005 => rules::flake8_type_checking::rules::EmptyTypeCheckingBlock,
|
||||
// tryceratops
|
||||
TRY002 => rules::tryceratops::rules::RaiseVanillaClass,
|
||||
TRY003 => rules::tryceratops::rules::RaiseVanillaArgs,
|
||||
TRY004 => rules::tryceratops::rules::PreferTypeError,
|
||||
TRY200 => rules::tryceratops::rules::ReraiseNoCause,
|
||||
TRY201 => rules::tryceratops::rules::VerboseRaise,
|
||||
TRY300 => rules::tryceratops::rules::TryConsiderElse,
|
||||
TRY301 => rules::tryceratops::rules::RaiseWithinTry,
|
||||
TRY400 => rules::tryceratops::rules::ErrorInsteadOfException,
|
||||
// flake8-use-pathlib
|
||||
PTH100 => rules::flake8_use_pathlib::violations::PathlibAbspath,
|
||||
PTH101 => rules::flake8_use_pathlib::violations::PathlibChmod,
|
||||
PTH102 => rules::flake8_use_pathlib::violations::PathlibMkdir,
|
||||
PTH103 => rules::flake8_use_pathlib::violations::PathlibMakedirs,
|
||||
PTH104 => rules::flake8_use_pathlib::violations::PathlibRename,
|
||||
PTH105 => rules::flake8_use_pathlib::violations::PathlibReplace,
|
||||
PTH106 => rules::flake8_use_pathlib::violations::PathlibRmdir,
|
||||
PTH107 => rules::flake8_use_pathlib::violations::PathlibRemove,
|
||||
PTH108 => rules::flake8_use_pathlib::violations::PathlibUnlink,
|
||||
PTH109 => rules::flake8_use_pathlib::violations::PathlibGetcwd,
|
||||
PTH110 => rules::flake8_use_pathlib::violations::PathlibExists,
|
||||
PTH111 => rules::flake8_use_pathlib::violations::PathlibExpanduser,
|
||||
PTH112 => rules::flake8_use_pathlib::violations::PathlibIsDir,
|
||||
PTH113 => rules::flake8_use_pathlib::violations::PathlibIsFile,
|
||||
PTH114 => rules::flake8_use_pathlib::violations::PathlibIsLink,
|
||||
PTH115 => rules::flake8_use_pathlib::violations::PathlibReadlink,
|
||||
PTH116 => rules::flake8_use_pathlib::violations::PathlibStat,
|
||||
PTH117 => rules::flake8_use_pathlib::violations::PathlibIsAbs,
|
||||
PTH118 => rules::flake8_use_pathlib::violations::PathlibJoin,
|
||||
PTH119 => rules::flake8_use_pathlib::violations::PathlibBasename,
|
||||
PTH120 => rules::flake8_use_pathlib::violations::PathlibDirname,
|
||||
PTH121 => rules::flake8_use_pathlib::violations::PathlibSamefile,
|
||||
PTH122 => rules::flake8_use_pathlib::violations::PathlibSplitext,
|
||||
PTH123 => rules::flake8_use_pathlib::violations::PathlibOpen,
|
||||
PTH124 => rules::flake8_use_pathlib::violations::PathlibPyPath,
|
||||
// flake8-logging-format
|
||||
G001 => rules::flake8_logging_format::violations::LoggingStringFormat,
|
||||
G002 => rules::flake8_logging_format::violations::LoggingPercentFormat,
|
||||
G003 => rules::flake8_logging_format::violations::LoggingStringConcat,
|
||||
G004 => rules::flake8_logging_format::violations::LoggingFString,
|
||||
G010 => rules::flake8_logging_format::violations::LoggingWarn,
|
||||
G101 => rules::flake8_logging_format::violations::LoggingExtraAttrClash,
|
||||
G201 => rules::flake8_logging_format::violations::LoggingExcInfo,
|
||||
G202 => rules::flake8_logging_format::violations::LoggingRedundantExcInfo,
|
||||
// ruff
|
||||
RUF001 => violations::AmbiguousUnicodeCharacterString,
|
||||
RUF002 => violations::AmbiguousUnicodeCharacterDocstring,
|
||||
RUF003 => violations::AmbiguousUnicodeCharacterComment,
|
||||
RUF004 => violations::KeywordArgumentBeforeStarArgument,
|
||||
RUF005 => violations::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
RUF100 => violations::UnusedNOQA,
|
||||
);
|
||||
|
||||
#[derive(EnumIter, Debug, PartialEq, Eq, RuleNamespace)]
|
||||
pub enum Linter {
|
||||
/// [Pyflakes](https://pypi.org/project/pyflakes/)
|
||||
#[prefix = "F"]
|
||||
Pyflakes,
|
||||
/// [pycodestyle](https://pypi.org/project/pycodestyle/)
|
||||
#[prefix = "E"]
|
||||
#[prefix = "W"]
|
||||
Pycodestyle,
|
||||
/// [mccabe](https://pypi.org/project/mccabe/)
|
||||
#[prefix = "C90"]
|
||||
McCabe,
|
||||
/// [isort](https://pypi.org/project/isort/)
|
||||
#[prefix = "I"]
|
||||
Isort,
|
||||
/// [pep8-naming](https://pypi.org/project/pep8-naming/)
|
||||
#[prefix = "N"]
|
||||
PEP8Naming,
|
||||
/// [pydocstyle](https://pypi.org/project/pydocstyle/)
|
||||
#[prefix = "D"]
|
||||
Pydocstyle,
|
||||
/// [pyupgrade](https://pypi.org/project/pyupgrade/)
|
||||
#[prefix = "UP"]
|
||||
Pyupgrade,
|
||||
/// [flake8-2020](https://pypi.org/project/flake8-2020/)
|
||||
#[prefix = "YTT"]
|
||||
Flake82020,
|
||||
/// [flake8-annotations](https://pypi.org/project/flake8-annotations/)
|
||||
#[prefix = "ANN"]
|
||||
Flake8Annotations,
|
||||
/// [flake8-bandit](https://pypi.org/project/flake8-bandit/)
|
||||
#[prefix = "S"]
|
||||
Flake8Bandit,
|
||||
/// [flake8-blind-except](https://pypi.org/project/flake8-blind-except/)
|
||||
#[prefix = "BLE"]
|
||||
Flake8BlindExcept,
|
||||
/// [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/)
|
||||
#[prefix = "FBT"]
|
||||
Flake8BooleanTrap,
|
||||
/// [flake8-bugbear](https://pypi.org/project/flake8-bugbear/)
|
||||
#[prefix = "B"]
|
||||
Flake8Bugbear,
|
||||
/// [flake8-builtins](https://pypi.org/project/flake8-builtins/)
|
||||
#[prefix = "A"]
|
||||
Flake8Builtins,
|
||||
/// [flake8-commas](https://pypi.org/project/flake8-commas/)
|
||||
#[prefix = "COM"]
|
||||
Flake8Commas,
|
||||
/// [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
|
||||
#[prefix = "C4"]
|
||||
Flake8Comprehensions,
|
||||
/// [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
|
||||
#[prefix = "DTZ"]
|
||||
Flake8Datetimez,
|
||||
/// [flake8-debugger](https://pypi.org/project/flake8-debugger/)
|
||||
#[prefix = "T10"]
|
||||
Flake8Debugger,
|
||||
/// [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
|
||||
#[prefix = "EM"]
|
||||
Flake8ErrMsg,
|
||||
/// [flake8-executable](https://pypi.org/project/flake8-executable/)
|
||||
#[prefix = "EXE"]
|
||||
Flake8Executable,
|
||||
/// [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
#[prefix = "ISC"]
|
||||
Flake8ImplicitStrConcat,
|
||||
/// [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
#[prefix = "ICN"]
|
||||
Flake8ImportConventions,
|
||||
/// [flake8-logging-format](https://pypi.org/project/flake8-logging-format/0.9.0/)
|
||||
#[prefix = "G"]
|
||||
Flake8LoggingFormat,
|
||||
/// [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420/)
|
||||
#[prefix = "INP"]
|
||||
Flake8NoPep420,
|
||||
/// [flake8-pie](https://pypi.org/project/flake8-pie/)
|
||||
#[prefix = "PIE"]
|
||||
Flake8Pie,
|
||||
/// [flake8-print](https://pypi.org/project/flake8-print/)
|
||||
#[prefix = "T20"]
|
||||
Flake8Print,
|
||||
/// [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/)
|
||||
#[prefix = "PT"]
|
||||
Flake8PytestStyle,
|
||||
/// [flake8-quotes](https://pypi.org/project/flake8-quotes/)
|
||||
#[prefix = "Q"]
|
||||
Flake8Quotes,
|
||||
/// [flake8-return](https://pypi.org/project/flake8-return/)
|
||||
#[prefix = "RET"]
|
||||
Flake8Return,
|
||||
/// [flake8-simplify](https://pypi.org/project/flake8-simplify/)
|
||||
#[prefix = "SIM"]
|
||||
Flake8Simplify,
|
||||
/// [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
||||
#[prefix = "TID"]
|
||||
Flake8TidyImports,
|
||||
/// [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
||||
#[prefix = "TCH"]
|
||||
Flake8TypeChecking,
|
||||
/// [flake8-unused-arguments](https://pypi.org/project/flake8-unused-arguments/)
|
||||
#[prefix = "ARG"]
|
||||
Flake8UnusedArguments,
|
||||
/// [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
||||
#[prefix = "PTH"]
|
||||
Flake8UsePathlib,
|
||||
/// [eradicate](https://pypi.org/project/eradicate/)
|
||||
#[prefix = "ERA"]
|
||||
Eradicate,
|
||||
/// [pandas-vet](https://pypi.org/project/pandas-vet/)
|
||||
#[prefix = "PD"]
|
||||
PandasVet,
|
||||
/// [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks)
|
||||
#[prefix = "PGH"]
|
||||
PygrepHooks,
|
||||
/// [Pylint](https://pypi.org/project/pylint/)
|
||||
#[prefix = "PL"]
|
||||
Pylint,
|
||||
/// [tryceratops](https://pypi.org/project/tryceratops/1.1.0/)
|
||||
#[prefix = "TRY"]
|
||||
Tryceratops,
|
||||
/// Ruff-specific rules
|
||||
#[prefix = "RUF"]
|
||||
Ruff,
|
||||
}
|
||||
|
||||
pub trait RuleNamespace: Sized {
|
||||
fn parse_code(code: &str) -> Option<(Self, &str)>;
|
||||
|
||||
fn prefixes(&self) -> &'static [&'static str];
|
||||
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
fn url(&self) -> Option<&'static str>;
|
||||
}
|
||||
|
||||
/// The prefix, name and selector for an upstream linter category.
|
||||
pub struct LinterCategory(pub &'static str, pub &'static str, pub RuleSelector);
|
||||
|
||||
// TODO(martin): Move these constant definitions back to Linter::categories impl
|
||||
// once RuleSelector is an enum with a Linter variant
|
||||
const PYCODESTYLE_CATEGORIES: &[LinterCategory] = &[
|
||||
LinterCategory("E", "Error", prefix_to_selector(RuleCodePrefix::E)),
|
||||
LinterCategory("W", "Warning", prefix_to_selector(RuleCodePrefix::W)),
|
||||
];
|
||||
|
||||
const PYLINT_CATEGORIES: &[LinterCategory] = &[
|
||||
LinterCategory("PLC", "Convention", prefix_to_selector(RuleCodePrefix::PLC)),
|
||||
LinterCategory("PLE", "Error", prefix_to_selector(RuleCodePrefix::PLE)),
|
||||
LinterCategory("PLR", "Refactor", prefix_to_selector(RuleCodePrefix::PLR)),
|
||||
LinterCategory("PLW", "Warning", prefix_to_selector(RuleCodePrefix::PLW)),
|
||||
];
|
||||
|
||||
impl Linter {
|
||||
pub fn categories(&self) -> Option<&'static [LinterCategory]> {
|
||||
match self {
|
||||
Linter::Pycodestyle => Some(PYCODESTYLE_CATEGORIES),
|
||||
Linter::Pylint => Some(PYLINT_CATEGORIES),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum LintSource {
|
||||
Ast,
|
||||
Io,
|
||||
Lines,
|
||||
Tokens,
|
||||
Imports,
|
||||
NoQa,
|
||||
Filesystem,
|
||||
}
|
||||
|
||||
impl Rule {
|
||||
/// The source for the diagnostic (either the AST, the filesystem, or the
|
||||
/// physical lines).
|
||||
pub fn lint_source(&self) -> &'static LintSource {
|
||||
match self {
|
||||
Rule::UnusedNOQA => &LintSource::NoQa,
|
||||
Rule::BlanketNOQA
|
||||
| Rule::BlanketTypeIgnore
|
||||
| Rule::DocLineTooLong
|
||||
| Rule::LineTooLong
|
||||
| Rule::MixedSpacesAndTabs
|
||||
| Rule::NoNewLineAtEndOfFile
|
||||
| Rule::PEP3120UnnecessaryCodingComment
|
||||
| Rule::ShebangMissingExecutableFile
|
||||
| Rule::ShebangNotExecutable
|
||||
| Rule::ShebangNewline
|
||||
| Rule::ShebangPython
|
||||
| Rule::ShebangWhitespace => &LintSource::Lines,
|
||||
Rule::AmbiguousUnicodeCharacterComment
|
||||
| Rule::AmbiguousUnicodeCharacterDocstring
|
||||
| Rule::AmbiguousUnicodeCharacterString
|
||||
| Rule::AvoidQuoteEscape
|
||||
| Rule::BadQuotesDocstring
|
||||
| Rule::BadQuotesInlineString
|
||||
| Rule::BadQuotesMultilineString
|
||||
| Rule::CommentedOutCode
|
||||
| Rule::MultiLineImplicitStringConcatenation
|
||||
| Rule::ExtraneousParentheses
|
||||
| Rule::InvalidEscapeSequence
|
||||
| Rule::SingleLineImplicitStringConcatenation
|
||||
| Rule::TrailingCommaMissing
|
||||
| Rule::TrailingCommaOnBareTupleProhibited
|
||||
| Rule::TrailingCommaProhibited => &LintSource::Tokens,
|
||||
Rule::IOError => &LintSource::Io,
|
||||
Rule::UnsortedImports | Rule::MissingRequiredImport => &LintSource::Imports,
|
||||
Rule::ImplicitNamespacePackage => &LintSource::Filesystem,
|
||||
_ => &LintSource::Ast,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Diagnostic {
|
||||
pub kind: DiagnosticKind,
|
||||
pub location: Location,
|
||||
pub end_location: Location,
|
||||
pub fix: Option<Fix>,
|
||||
pub parent: Option<Location>,
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
pub fn new<K: Into<DiagnosticKind>>(kind: K, range: Range) -> Self {
|
||||
Self {
|
||||
kind: kind.into(),
|
||||
location: range.location,
|
||||
end_location: range.end_location,
|
||||
fix: None,
|
||||
parent: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn amend(&mut self, fix: Fix) -> &mut Self {
|
||||
self.fix = Some(fix);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn parent(&mut self, parent: Location) -> &mut Self {
|
||||
self.parent = Some(parent);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Pairs of checks that shouldn't be enabled together.
|
||||
pub const INCOMPATIBLE_CODES: &[(Rule, Rule, &str)] = &[(
|
||||
Rule::OneBlankLineBeforeClass,
|
||||
Rule::NoBlankLineBeforeClass,
|
||||
"`D203` (OneBlankLineBeforeClass) and `D211` (NoBlankLinesBeforeClass) are incompatible. \
|
||||
Consider adding `D203` to `ignore`.",
|
||||
)];
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use super::{Linter, Rule, RuleNamespace};
|
||||
|
||||
#[test]
|
||||
fn check_code_serialization() {
|
||||
for rule in Rule::iter() {
|
||||
assert!(
|
||||
Rule::from_code(rule.code()).is_ok(),
|
||||
"{rule:?} could not be round-trip serialized."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_linter_prefixes() {
|
||||
for rule in Rule::iter() {
|
||||
Linter::parse_code(rule.code())
|
||||
.unwrap_or_else(|| panic!("couldn't parse {:?}", rule.code()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user