Compare commits
1 Commits
v0.0.129
...
charlie/bi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e187c66573 |
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.129
|
||||
rev: v0.0.128
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -940,7 +940,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.129-dev.0"
|
||||
version = "0.0.128-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
@@ -2248,7 +2248,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.129"
|
||||
version = "0.0.128"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -2298,7 +2298,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.129"
|
||||
version = "0.0.128"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
|
||||
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.129"
|
||||
version = "0.0.128"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -380,7 +380,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI
|
||||
| E714 | NotIsTest | Test for object identity should be `is not` | 🛠 |
|
||||
| E721 | TypeComparison | Do not compare types, use `isinstance()` | |
|
||||
| E722 | DoNotUseBareExcept | Do not use bare `except` | |
|
||||
| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | 🛠 |
|
||||
| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | |
|
||||
| E741 | AmbiguousVariableName | Ambiguous variable name: `...` | |
|
||||
| E742 | AmbiguousClassName | Ambiguous class name: `...` | |
|
||||
| E743 | AmbiguousFunctionName | Ambiguous function name: `...` | |
|
||||
|
||||
4
flake8_to_ruff/Cargo.lock
generated
4
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.129"
|
||||
version = "0.0.128"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.129"
|
||||
version = "0.0.128"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.129-dev.0"
|
||||
version = "0.0.128-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
20
resources/test/fixtures/B006_B008.py
vendored
20
resources/test/fixtures/B006_B008.py
vendored
@@ -185,23 +185,3 @@ def nested_b008(a=random.randint(0, dt.datetime.now().year)):
|
||||
# Ignore lambda contents since they are evaluated at call time.
|
||||
def foo(f=lambda x: print(x)):
|
||||
f(1)
|
||||
|
||||
|
||||
from collections import abc
|
||||
from typing import Annotated, Dict, Optional, Sequence, Union, Set
|
||||
|
||||
|
||||
def immutable_annotations(
|
||||
a: Sequence[int] | None = [],
|
||||
b: Optional[abc.Mapping[int, int]] = {},
|
||||
c: Annotated[Union[abc.Set[str], abc.Sized], "annotation"] = set(),
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
def mutable_annotations(
|
||||
a: list[int] | None = [],
|
||||
b: Optional[Dict[int, int]] = {},
|
||||
c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
||||
):
|
||||
pass
|
||||
|
||||
17
resources/test/fixtures/F841.py
vendored
17
resources/test/fixtures/F841.py
vendored
@@ -35,20 +35,3 @@ def f4():
|
||||
_ = 1
|
||||
__ = 1
|
||||
_discarded = 1
|
||||
|
||||
|
||||
a = 1
|
||||
|
||||
|
||||
def f5():
|
||||
global a
|
||||
|
||||
# Used in `f7` via `nonlocal`.
|
||||
b = 1
|
||||
|
||||
def f6():
|
||||
# F841
|
||||
b = 1
|
||||
|
||||
def f7():
|
||||
nonlocal b
|
||||
|
||||
8
resources/test/fixtures/M001.py
vendored
8
resources/test/fixtures/M001.py
vendored
@@ -18,14 +18,6 @@ def f() -> None:
|
||||
# Invalid (and unimplemented)
|
||||
d = 1 # noqa: F841, W191
|
||||
|
||||
# fmt: off
|
||||
# Invalid - no space before #
|
||||
d = 1# noqa: E501
|
||||
|
||||
# Invalid - many spaces before #
|
||||
d = 1 # noqa: E501
|
||||
# fmt: on
|
||||
|
||||
|
||||
# Valid
|
||||
_ = """Lorem ipsum dolor sit amet.
|
||||
|
||||
4
resources/test/fixtures/U013.py
vendored
4
resources/test/fixtures/U013.py
vendored
@@ -1,5 +1,4 @@
|
||||
from typing import TypedDict, NotRequired, Literal
|
||||
import typing
|
||||
|
||||
# dict literal
|
||||
MyType1 = TypedDict("MyType1", {"a": int, "b": str})
|
||||
@@ -28,6 +27,3 @@ MyType9 = TypedDict("MyType9", {"in": int, "x-y": int})
|
||||
|
||||
# using Literal type
|
||||
MyType10 = TypedDict("MyType10", {"key": Literal["value"]})
|
||||
|
||||
# using namespace TypedDict
|
||||
MyType11 = typing.TypedDict("MyType11", {"key": int})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.129"
|
||||
version = "0.0.128"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprKind, Location, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::SourceCodeLocator;
|
||||
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprKind, Location, StmtKind};
|
||||
|
||||
#[inline(always)]
|
||||
fn collect_call_path_inner<'a>(expr: &'a Expr, parts: &mut Vec<&'a str>) {
|
||||
@@ -264,34 +261,6 @@ pub fn to_absolute(relative: &Location, base: &Location) -> Location {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if a `Stmt` has leading content.
|
||||
pub fn match_leading_content(stmt: &Stmt, locator: &SourceCodeLocator) -> bool {
|
||||
let range = Range {
|
||||
location: Location::new(stmt.location.row(), 0),
|
||||
end_location: stmt.location,
|
||||
};
|
||||
let prefix = locator.slice_source_code_range(&range);
|
||||
prefix.chars().any(|char| !char.is_whitespace())
|
||||
}
|
||||
|
||||
/// Return `true` if a `Stmt` has trailing content.
|
||||
pub fn match_trailing_content(stmt: &Stmt, locator: &SourceCodeLocator) -> bool {
|
||||
let range = Range {
|
||||
location: stmt.end_location.unwrap(),
|
||||
end_location: Location::new(stmt.end_location.unwrap().row() + 1, 0),
|
||||
};
|
||||
let suffix = locator.slice_source_code_range(&range);
|
||||
for char in suffix.chars() {
|
||||
if char == '#' {
|
||||
return false;
|
||||
}
|
||||
if !char.is_whitespace() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
|
||||
@@ -3,4 +3,3 @@ pub mod operations;
|
||||
pub mod relocate;
|
||||
pub mod types;
|
||||
pub mod visitor;
|
||||
pub mod whitespace;
|
||||
|
||||
@@ -83,7 +83,6 @@ pub enum BindingKind {
|
||||
Binding,
|
||||
LoopVar,
|
||||
Global,
|
||||
Nonlocal,
|
||||
Builtin,
|
||||
ClassDefinition,
|
||||
Definition,
|
||||
|
||||
481
src/check_ast.rs
481
src/check_ast.rs
File diff suppressed because it is too large
Load Diff
@@ -39,9 +39,9 @@ pub fn check_lines(
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
) {
|
||||
let enforce_unnecessary_coding_comment = settings.enabled.contains(&CheckCode::U009);
|
||||
let enforce_line_too_long = settings.enabled.contains(&CheckCode::E501);
|
||||
let enforce_noqa = settings.enabled.contains(&CheckCode::M001);
|
||||
let enforce_unnecessary_coding_comment = settings.enabled[CheckCode::U009 as usize];
|
||||
let enforce_line_too_long = settings.enabled[CheckCode::E501 as usize];
|
||||
let enforce_noqa = settings.enabled[CheckCode::M001 as usize];
|
||||
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<&str>)> = IntMap::default();
|
||||
let mut line_checks = vec![];
|
||||
@@ -103,7 +103,7 @@ pub fn check_lines(
|
||||
matches.push(check.kind.code().as_ref());
|
||||
ignored.push(index)
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
(Directive::Codes(_, _, codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_ref()) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
ignored.push(index);
|
||||
@@ -133,7 +133,7 @@ pub fn check_lines(
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
(Directive::Codes(_, _, codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_ref()) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
} else {
|
||||
@@ -147,7 +147,7 @@ pub fn check_lines(
|
||||
}
|
||||
|
||||
// Enforce newlines at end of files.
|
||||
if settings.enabled.contains(&CheckCode::W292) && !contents.ends_with('\n') {
|
||||
if settings.enabled[CheckCode::W292 as usize] && !contents.ends_with('\n') {
|
||||
// Note: if `lines.last()` is `None`, then `contents` is empty (and so we don't
|
||||
// want to raise W292 anyway).
|
||||
if let Some(line) = lines.last() {
|
||||
@@ -170,7 +170,7 @@ pub fn check_lines(
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
(Directive::Codes(_, _, codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_ref()) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
} else {
|
||||
@@ -186,7 +186,7 @@ pub fn check_lines(
|
||||
if enforce_noqa {
|
||||
for (row, (directive, matches)) in noqa_directives {
|
||||
match directive {
|
||||
Directive::All(spaces, start, end) => {
|
||||
Directive::All(start, end) => {
|
||||
if matches.is_empty() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnusedNOQA(None),
|
||||
@@ -197,14 +197,14 @@ pub fn check_lines(
|
||||
);
|
||||
if autofix.patch() && settings.fixable.contains(check.kind.code()) {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
}
|
||||
line_checks.push(check);
|
||||
}
|
||||
}
|
||||
Directive::Codes(spaces, start, end, codes) => {
|
||||
Directive::Codes(start, end, codes) => {
|
||||
let mut invalid_codes = vec![];
|
||||
let mut valid_codes = vec![];
|
||||
for code in codes {
|
||||
@@ -226,12 +226,12 @@ pub fn check_lines(
|
||||
if autofix.patch() && settings.fixable.contains(check.kind.code()) {
|
||||
if valid_codes.is_empty() {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
} else {
|
||||
check.amend(Fix::replacement(
|
||||
format!("# noqa: {}", valid_codes.join(", ")),
|
||||
format!(" # noqa: {}", valid_codes.join(", ")),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
|
||||
@@ -16,14 +16,14 @@ pub fn check_tokens(
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
) {
|
||||
let enforce_ambiguous_unicode_character = settings.enabled.contains(&CheckCode::RUF001)
|
||||
|| settings.enabled.contains(&CheckCode::RUF002)
|
||||
|| settings.enabled.contains(&CheckCode::RUF003);
|
||||
let enforce_quotes = settings.enabled.contains(&CheckCode::Q000)
|
||||
|| settings.enabled.contains(&CheckCode::Q001)
|
||||
|| settings.enabled.contains(&CheckCode::Q002)
|
||||
|| settings.enabled.contains(&CheckCode::Q003);
|
||||
let enforce_invalid_escape_sequence = settings.enabled.contains(&CheckCode::W605);
|
||||
let enforce_ambiguous_unicode_character = settings.enabled[CheckCode::RUF001 as usize]
|
||||
|| settings.enabled[CheckCode::RUF002 as usize]
|
||||
|| settings.enabled[CheckCode::RUF003 as usize];
|
||||
let enforce_quotes = settings.enabled[CheckCode::Q000 as usize]
|
||||
|| settings.enabled[CheckCode::Q001 as usize]
|
||||
|| settings.enabled[CheckCode::Q002 as usize]
|
||||
|| settings.enabled[CheckCode::Q003 as usize];
|
||||
let enforce_invalid_escape_sequence = settings.enabled[CheckCode::W605 as usize];
|
||||
|
||||
let mut state_machine: StateMachine = Default::default();
|
||||
for (start, tok, end) in tokens.iter().flatten() {
|
||||
@@ -65,7 +65,7 @@ pub fn check_tokens(
|
||||
is_docstring,
|
||||
&settings.flake8_quotes,
|
||||
) {
|
||||
if settings.enabled.contains(check.kind.code()) {
|
||||
if settings.enabled[check.kind.code().clone() as usize] {
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ use crate::pyupgrade::types::Primitive;
|
||||
PartialOrd,
|
||||
Ord,
|
||||
)]
|
||||
#[repr(u8)]
|
||||
pub enum CheckCode {
|
||||
// pycodestyle errors
|
||||
E402,
|
||||
@@ -2038,51 +2039,46 @@ impl CheckKind {
|
||||
pub fn fixable(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
CheckKind::AmbiguousUnicodeCharacterString(..)
|
||||
| CheckKind::AmbiguousUnicodeCharacterDocstring(..)
|
||||
| CheckKind::BlankLineAfterLastSection(..)
|
||||
| CheckKind::BlankLineAfterSection(..)
|
||||
CheckKind::AmbiguousUnicodeCharacterString(_, _)
|
||||
| CheckKind::AmbiguousUnicodeCharacterDocstring(_, _)
|
||||
| CheckKind::BlankLineAfterLastSection(_)
|
||||
| CheckKind::BlankLineAfterSection(_)
|
||||
| CheckKind::BlankLineAfterSummary
|
||||
| CheckKind::BlankLineBeforeSection(..)
|
||||
| CheckKind::CapitalizeSectionName(..)
|
||||
| CheckKind::ConvertTypedDictFunctionalToClass
|
||||
| CheckKind::DashedUnderlineAfterSection(..)
|
||||
| CheckKind::DeprecatedUnittestAlias(..)
|
||||
| CheckKind::BlankLineBeforeSection(_)
|
||||
| CheckKind::CapitalizeSectionName(_)
|
||||
| CheckKind::DashedUnderlineAfterSection(_)
|
||||
| CheckKind::DeprecatedUnittestAlias(_, _)
|
||||
| CheckKind::DoNotAssertFalse
|
||||
| CheckKind::DoNotAssignLambda
|
||||
| CheckKind::DuplicateHandlerException(..)
|
||||
| CheckKind::DuplicateHandlerException(_)
|
||||
| CheckKind::GetAttrWithConstant
|
||||
| CheckKind::IsLiteral
|
||||
| CheckKind::NewLineAfterLastParagraph
|
||||
| CheckKind::NewLineAfterSectionName(..)
|
||||
| CheckKind::NoBlankLineAfterFunction(..)
|
||||
| CheckKind::NoBlankLineBeforeClass(..)
|
||||
| CheckKind::NoBlankLineBeforeFunction(..)
|
||||
| CheckKind::NoBlankLinesBetweenHeaderAndContent(..)
|
||||
| CheckKind::NewLineAfterSectionName(_)
|
||||
| CheckKind::NoBlankLineAfterFunction(_)
|
||||
| CheckKind::NoBlankLineBeforeClass(_)
|
||||
| CheckKind::NoBlankLineBeforeFunction(_)
|
||||
| CheckKind::NoBlankLinesBetweenHeaderAndContent(_)
|
||||
| CheckKind::NoOverIndentation
|
||||
| CheckKind::NoSurroundingWhitespace
|
||||
| CheckKind::NoUnderIndentation
|
||||
| CheckKind::NoneComparison(..)
|
||||
| CheckKind::NotInTest
|
||||
| CheckKind::NotIsTest
|
||||
| CheckKind::OneBlankLineAfterClass(..)
|
||||
| CheckKind::OneBlankLineBeforeClass(..)
|
||||
| CheckKind::OneBlankLineAfterClass(_)
|
||||
| CheckKind::OneBlankLineBeforeClass(_)
|
||||
| CheckKind::PEP3120UnnecessaryCodingComment
|
||||
| CheckKind::PPrintFound
|
||||
| CheckKind::PrintFound
|
||||
| CheckKind::RaiseNotImplemented
|
||||
| CheckKind::SectionNameEndsInColon(..)
|
||||
| CheckKind::SectionNotOverIndented(..)
|
||||
| CheckKind::SectionUnderlineAfterName(..)
|
||||
| CheckKind::SectionUnderlineMatchesSectionLength(..)
|
||||
| CheckKind::SectionUnderlineNotOverIndented(..)
|
||||
| CheckKind::SectionNameEndsInColon(_)
|
||||
| CheckKind::SectionNotOverIndented(_)
|
||||
| CheckKind::SectionUnderlineAfterName(_)
|
||||
| CheckKind::SectionUnderlineMatchesSectionLength(_)
|
||||
| CheckKind::SectionUnderlineNotOverIndented(_)
|
||||
| CheckKind::SuperCallWithParameters
|
||||
| CheckKind::TrueFalseComparison(..)
|
||||
| CheckKind::TypeOfPrimitive(..)
|
||||
| CheckKind::UnnecessaryCollectionCall(..)
|
||||
| CheckKind::UnnecessaryComprehension(..)
|
||||
| CheckKind::TypeOfPrimitive(_)
|
||||
| CheckKind::UnnecessaryCollectionCall(_)
|
||||
| CheckKind::UnnecessaryComprehension(_)
|
||||
| CheckKind::UnnecessaryEncodeUTF8
|
||||
| CheckKind::UnnecessaryFutureImport(..)
|
||||
| CheckKind::ConvertTypedDictFunctionalToClass
|
||||
| CheckKind::UnnecessaryFutureImport(_)
|
||||
| CheckKind::UnnecessaryGeneratorDict
|
||||
| CheckKind::UnnecessaryGeneratorList
|
||||
| CheckKind::UnnecessaryGeneratorSet
|
||||
@@ -2090,18 +2086,18 @@ impl CheckKind {
|
||||
| CheckKind::UnnecessaryListCall
|
||||
| CheckKind::UnnecessaryListComprehensionDict
|
||||
| CheckKind::UnnecessaryListComprehensionSet
|
||||
| CheckKind::UnnecessaryLiteralDict(..)
|
||||
| CheckKind::UnnecessaryLiteralSet(..)
|
||||
| CheckKind::UnnecessaryLiteralWithinListCall(..)
|
||||
| CheckKind::UnnecessaryLiteralWithinTupleCall(..)
|
||||
| CheckKind::UnnecessaryLiteralDict(_)
|
||||
| CheckKind::UnnecessaryLiteralSet(_)
|
||||
| CheckKind::UnnecessaryLiteralWithinListCall(_)
|
||||
| CheckKind::UnnecessaryLiteralWithinTupleCall(_)
|
||||
| CheckKind::UnsortedImports
|
||||
| CheckKind::UnusedImport(_, false)
|
||||
| CheckKind::UnusedLoopControlVariable(..)
|
||||
| CheckKind::UnusedNOQA(..)
|
||||
| CheckKind::UsePEP585Annotation(..)
|
||||
| CheckKind::UnusedLoopControlVariable(_)
|
||||
| CheckKind::UnusedNOQA(_)
|
||||
| CheckKind::UsePEP585Annotation(_)
|
||||
| CheckKind::UsePEP604Annotation
|
||||
| CheckKind::UselessMetaclassType
|
||||
| CheckKind::UselessObjectInheritance(..)
|
||||
| CheckKind::UselessObjectInheritance(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,15 +18,16 @@ bitflags! {
|
||||
|
||||
impl Flags {
|
||||
pub fn from_settings(settings: &Settings) -> Self {
|
||||
if settings
|
||||
.enabled
|
||||
.iter()
|
||||
.any(|check_code| matches!(check_code.lint_source(), LintSource::Imports))
|
||||
{
|
||||
Flags::NOQA | Flags::ISORT
|
||||
} else {
|
||||
Flags::NOQA
|
||||
}
|
||||
Flags::NOQA
|
||||
// if settings
|
||||
// .enabled
|
||||
// .iter()
|
||||
// .any(|check_code| matches!(check_code.lint_source(), LintSource::Imports))
|
||||
// {
|
||||
// Flags::NOQA | Flags::ISORT
|
||||
// } else {
|
||||
// Flags::NOQA
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
pub const TRIPLE_QUOTE_PREFIXES: &[&str] = &[
|
||||
"ur\"\"\"", "ur'''", "u\"\"\"", "u'''", "r\"\"\"", "r'''", "\"\"\"", "'''",
|
||||
];
|
||||
|
||||
pub const SINGLE_QUOTE_PREFIXES: &[&str] = &["ur\"", "ur'", "u\"", "u'", "r\"", "r'", "\"", "'"];
|
||||
@@ -3,6 +3,12 @@ use rustpython_ast::{Located, Location};
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
|
||||
pub const TRIPLE_QUOTE_PREFIXES: &[&str] = &[
|
||||
"ur\"\"\"", "ur'''", "u\"\"\"", "u'''", "r\"\"\"", "r'''", "\"\"\"", "'''",
|
||||
];
|
||||
|
||||
pub const SINGLE_QUOTE_PREFIXES: &[&str] = &["ur\"", "ur'", "u\"", "u'", "r\"", "r'", "\"", "'"];
|
||||
|
||||
/// Extract the leading words from a line of text.
|
||||
pub fn leading_words(line: &str) -> String {
|
||||
line.trim()
|
||||
@@ -1,7 +1,7 @@
|
||||
pub mod constants;
|
||||
pub mod definition;
|
||||
pub mod extraction;
|
||||
pub mod google;
|
||||
pub mod helpers;
|
||||
pub mod numpy;
|
||||
pub mod sections;
|
||||
pub mod styles;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::ast::whitespace;
|
||||
use crate::docstrings::helpers;
|
||||
use crate::docstrings::styles::SectionStyle;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -14,7 +14,7 @@ pub(crate) struct SectionContext<'a> {
|
||||
fn suspected_as_section(line: &str, style: &SectionStyle) -> bool {
|
||||
style
|
||||
.lowercase_section_names()
|
||||
.contains(&whitespace::leading_words(line).to_lowercase().as_str())
|
||||
.contains(&helpers::leading_words(line).to_lowercase().as_str())
|
||||
}
|
||||
|
||||
/// Check if the suspected context is really a section header.
|
||||
@@ -64,7 +64,7 @@ pub(crate) fn section_contexts<'a>(
|
||||
let mut contexts = vec![];
|
||||
for lineno in suspected_section_indices {
|
||||
let context = SectionContext {
|
||||
section_name: whitespace::leading_words(lines[lineno]),
|
||||
section_name: helpers::leading_words(lines[lineno]),
|
||||
previous_line: lines[lineno - 1],
|
||||
line: lines[lineno],
|
||||
following_lines: &lines[lineno + 1..],
|
||||
|
||||
@@ -31,15 +31,14 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
..
|
||||
} = &upper.node
|
||||
{
|
||||
if *i == BigInt::from(1)
|
||||
&& checker.settings.enabled.contains(&CheckCode::YTT303)
|
||||
if *i == BigInt::from(1) && checker.settings.enabled[CheckCode::YTT303 as usize]
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SysVersionSlice1Referenced,
|
||||
Range::from_located(value),
|
||||
));
|
||||
} else if *i == BigInt::from(3)
|
||||
&& checker.settings.enabled.contains(&CheckCode::YTT101)
|
||||
&& checker.settings.enabled[CheckCode::YTT101 as usize]
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SysVersionSlice3Referenced,
|
||||
@@ -53,13 +52,13 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
value: Constant::Int(i),
|
||||
..
|
||||
} => {
|
||||
if *i == BigInt::from(2) && checker.settings.enabled.contains(&CheckCode::YTT102) {
|
||||
if *i == BigInt::from(2) && checker.settings.enabled[CheckCode::YTT102 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SysVersion2Referenced,
|
||||
Range::from_located(value),
|
||||
));
|
||||
} else if *i == BigInt::from(0)
|
||||
&& checker.settings.enabled.contains(&CheckCode::YTT301)
|
||||
&& checker.settings.enabled[CheckCode::YTT301 as usize]
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SysVersion0Referenced,
|
||||
@@ -96,7 +95,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if *n == BigInt::from(3)
|
||||
&& checker.settings.enabled.contains(&CheckCode::YTT201)
|
||||
&& checker.settings.enabled[CheckCode::YTT201 as usize]
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SysVersionInfo0Eq3Referenced,
|
||||
@@ -117,7 +116,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
}],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::YTT203) {
|
||||
if checker.settings.enabled[CheckCode::YTT203 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SysVersionInfo1CmpInt,
|
||||
Range::from_located(left),
|
||||
@@ -143,7 +142,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
}],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::YTT204) {
|
||||
if checker.settings.enabled[CheckCode::YTT204 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SysVersionInfoMinorCmpInt,
|
||||
Range::from_located(left),
|
||||
@@ -169,13 +168,13 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if s.len() == 1 {
|
||||
if checker.settings.enabled.contains(&CheckCode::YTT302) {
|
||||
if checker.settings.enabled[CheckCode::YTT302 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SysVersionCmpStr10,
|
||||
Range::from_located(left),
|
||||
));
|
||||
}
|
||||
} else if checker.settings.enabled.contains(&CheckCode::YTT103) {
|
||||
} else if checker.settings.enabled[CheckCode::YTT103 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SysVersionCmpStr3,
|
||||
Range::from_located(left),
|
||||
|
||||
@@ -106,14 +106,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
.chain(args.kwonlyargs.iter())
|
||||
{
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
if checker.settings.enabled[CheckCode::ANN401 as usize] {
|
||||
check_dynamically_typed(checker, expr, || arg.node.arg.to_string());
|
||||
};
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN001) {
|
||||
if checker.settings.enabled[CheckCode::ANN001 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeFunctionArgument(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -127,7 +127,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if let Some(arg) = &args.vararg {
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
if checker.settings.enabled[CheckCode::ANN401 as usize] {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, || format!("*{name}"));
|
||||
}
|
||||
@@ -136,7 +136,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN002) {
|
||||
if checker.settings.enabled[CheckCode::ANN002 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeArgs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -150,7 +150,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if let Some(arg) = &args.kwarg {
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
if checker.settings.enabled[CheckCode::ANN401 as usize] {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, || format!("**{name}"));
|
||||
}
|
||||
@@ -159,7 +159,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN003) {
|
||||
if checker.settings.enabled[CheckCode::ANN003 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeKwargs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -171,7 +171,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
|
||||
// ANN201, ANN202, ANN401
|
||||
if let Some(expr) = &returns {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
if checker.settings.enabled[CheckCode::ANN401 as usize] {
|
||||
check_dynamically_typed(checker, expr, || name.to_string());
|
||||
};
|
||||
} else {
|
||||
@@ -185,7 +185,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
|
||||
match visibility {
|
||||
Visibility::Public => {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN201) {
|
||||
if checker.settings.enabled[CheckCode::ANN201 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypePublicFunction(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
@@ -193,7 +193,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
}
|
||||
}
|
||||
Visibility::Private => {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN202) {
|
||||
if checker.settings.enabled[CheckCode::ANN202 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypePrivateFunction(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
@@ -221,14 +221,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
// ANN401 for dynamically typed arguments
|
||||
if let Some(annotation) = &arg.node.annotation {
|
||||
has_any_typed_arg = true;
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
if checker.settings.enabled[CheckCode::ANN401 as usize] {
|
||||
check_dynamically_typed(checker, annotation, || arg.node.arg.to_string());
|
||||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN001) {
|
||||
if checker.settings.enabled[CheckCode::ANN001 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeFunctionArgument(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -243,7 +243,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
has_any_typed_arg = true;
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
if checker.settings.enabled[CheckCode::ANN401 as usize] {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, || format!("*{name}"));
|
||||
}
|
||||
@@ -252,7 +252,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN002) {
|
||||
if checker.settings.enabled[CheckCode::ANN002 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeArgs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -267,7 +267,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
has_any_typed_arg = true;
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
if checker.settings.enabled[CheckCode::ANN401 as usize] {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, || format!("**{name}"));
|
||||
}
|
||||
@@ -276,7 +276,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN003) {
|
||||
if checker.settings.enabled[CheckCode::ANN003 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeKwargs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -291,14 +291,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if let Some(arg) = args.args.first() {
|
||||
if arg.node.annotation.is_none() {
|
||||
if visibility::is_classmethod(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN102) {
|
||||
if checker.settings.enabled[CheckCode::ANN102 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeCls(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN101) {
|
||||
if checker.settings.enabled[CheckCode::ANN101 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeSelf(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
@@ -311,7 +311,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
|
||||
// ANN201, ANN202
|
||||
if let Some(expr) = &returns {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
if checker.settings.enabled[CheckCode::ANN401 as usize] {
|
||||
check_dynamically_typed(checker, expr, || name.to_string());
|
||||
}
|
||||
} else {
|
||||
@@ -324,21 +324,21 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
}
|
||||
|
||||
if visibility::is_classmethod(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN206) {
|
||||
if checker.settings.enabled[CheckCode::ANN206 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeClassMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if visibility::is_staticmethod(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN205) {
|
||||
if checker.settings.enabled[CheckCode::ANN205 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeStaticMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if visibility::is_magic(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN204) {
|
||||
if checker.settings.enabled[CheckCode::ANN204 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeMagicMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
@@ -347,7 +347,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
} else if visibility::is_init(stmt) {
|
||||
// Allow omission of return annotation in `__init__` functions, as long as at
|
||||
// least one argument is typed.
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN204) {
|
||||
if checker.settings.enabled[CheckCode::ANN204 as usize] {
|
||||
if !(checker.settings.flake8_annotations.mypy_init_return
|
||||
&& has_any_typed_arg)
|
||||
{
|
||||
@@ -360,7 +360,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
} else {
|
||||
match visibility {
|
||||
Visibility::Public => {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN201) {
|
||||
if checker.settings.enabled[CheckCode::ANN201 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypePublicFunction(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
@@ -368,7 +368,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
}
|
||||
}
|
||||
Visibility::Private => {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN202) {
|
||||
if checker.settings.enabled[CheckCode::ANN202 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypePrivateFunction(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
|
||||
@@ -102,7 +102,7 @@ pub fn abstract_base_class(
|
||||
|
||||
has_abstract_method |= has_abstract_decorator;
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::B027) {
|
||||
if checker.settings.enabled[CheckCode::B027 as usize] {
|
||||
if !has_abstract_decorator
|
||||
&& is_empty_body(body)
|
||||
&& !decorator_list
|
||||
@@ -117,7 +117,7 @@ pub fn abstract_base_class(
|
||||
}
|
||||
}
|
||||
}
|
||||
if checker.settings.enabled.contains(&CheckCode::B024) {
|
||||
if checker.settings.enabled[CheckCode::B024 as usize] {
|
||||
if !has_abstract_method {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::AbstractBaseClassWithoutAbstractMethod(name.to_string()),
|
||||
|
||||
@@ -41,7 +41,7 @@ fn duplicate_handler_exceptions<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::B014) {
|
||||
if checker.settings.enabled[CheckCode::B014 as usize] {
|
||||
// TODO(charlie): Handle "BaseException" and redundant exception aliases.
|
||||
if !duplicates.is_empty() {
|
||||
let mut check = Check::new(
|
||||
@@ -108,7 +108,7 @@ pub fn duplicate_exceptions(checker: &mut Checker, stmt: &Stmt, handlers: &[Exce
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::B025) {
|
||||
if checker.settings.enabled[CheckCode::B025 as usize] {
|
||||
for duplicate in duplicates.into_iter().sorted() {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::DuplicateTryBlockException(duplicate.join(".")),
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use rustpython_ast::{Arguments, Constant, Expr, ExprKind, Operator};
|
||||
use rustpython_ast::{Arguments, Expr, ExprKind};
|
||||
|
||||
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
const MUTABLE_FUNCS: &[(&str, &str)] = &[
|
||||
const MUTABLE_FUNCS: [(&str, &str); 7] = [
|
||||
("", "dict"),
|
||||
("", "list"),
|
||||
("", "set"),
|
||||
@@ -16,47 +16,6 @@ const MUTABLE_FUNCS: &[(&str, &str)] = &[
|
||||
("collections", "deque"),
|
||||
];
|
||||
|
||||
const IMMUTABLE_TYPES: &[(&str, &str)] = &[
|
||||
("", "bool"),
|
||||
("", "bytes"),
|
||||
("", "complex"),
|
||||
("", "float"),
|
||||
("", "frozenset"),
|
||||
("", "int"),
|
||||
("", "object"),
|
||||
("", "range"),
|
||||
("", "str"),
|
||||
("collections.abc", "Sized"),
|
||||
("typing", "LiteralString"),
|
||||
("typing", "Sized"),
|
||||
];
|
||||
|
||||
const IMMUTABLE_GENERIC_TYPES: &[(&str, &str)] = &[
|
||||
("", "tuple"),
|
||||
("collections.abc", "ByteString"),
|
||||
("collections.abc", "Collection"),
|
||||
("collections.abc", "Container"),
|
||||
("collections.abc", "Iterable"),
|
||||
("collections.abc", "Mapping"),
|
||||
("collections.abc", "Reversible"),
|
||||
("collections.abc", "Sequence"),
|
||||
("collections.abc", "Set"),
|
||||
("typing", "AbstractSet"),
|
||||
("typing", "ByteString"),
|
||||
("typing", "Callable"),
|
||||
("typing", "Collection"),
|
||||
("typing", "Container"),
|
||||
("typing", "FrozenSet"),
|
||||
("typing", "Iterable"),
|
||||
("typing", "Literal"),
|
||||
("typing", "Mapping"),
|
||||
("typing", "Never"),
|
||||
("typing", "NoReturn"),
|
||||
("typing", "Reversible"),
|
||||
("typing", "Sequence"),
|
||||
("typing", "Tuple"),
|
||||
];
|
||||
|
||||
pub fn is_mutable_func(
|
||||
expr: &Expr,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
@@ -68,106 +27,34 @@ pub fn is_mutable_func(
|
||||
.any(|(module, member)| match_call_path(&call_path, module, member, from_imports))
|
||||
}
|
||||
|
||||
fn is_mutable_expr(
|
||||
expr: &Expr,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
) -> bool {
|
||||
match &expr.node {
|
||||
ExprKind::List { .. }
|
||||
| ExprKind::Dict { .. }
|
||||
| ExprKind::Set { .. }
|
||||
| ExprKind::ListComp { .. }
|
||||
| ExprKind::DictComp { .. }
|
||||
| ExprKind::SetComp { .. } => true,
|
||||
ExprKind::Call { func, .. } => is_mutable_func(func, from_imports, import_aliases),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_immutable_annotation(
|
||||
expr: &Expr,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
) -> bool {
|
||||
match &expr.node {
|
||||
ExprKind::Name { .. } | ExprKind::Attribute { .. } => {
|
||||
let call_path = dealias_call_path(collect_call_paths(expr), import_aliases);
|
||||
IMMUTABLE_TYPES
|
||||
.iter()
|
||||
.chain(IMMUTABLE_GENERIC_TYPES)
|
||||
.any(|(module, member)| match_call_path(&call_path, module, member, from_imports))
|
||||
}
|
||||
ExprKind::Subscript { value, slice, .. } => {
|
||||
let call_path = dealias_call_path(collect_call_paths(value), import_aliases);
|
||||
if IMMUTABLE_GENERIC_TYPES
|
||||
.iter()
|
||||
.any(|(module, member)| match_call_path(&call_path, module, member, from_imports))
|
||||
{
|
||||
true
|
||||
} else if match_call_path(&call_path, "typing", "Union", from_imports) {
|
||||
if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.iter()
|
||||
.all(|elt| is_immutable_annotation(elt, from_imports, import_aliases))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if match_call_path(&call_path, "typing", "Optional", from_imports) {
|
||||
is_immutable_annotation(slice, from_imports, import_aliases)
|
||||
} else if match_call_path(&call_path, "typing", "Annotated", from_imports) {
|
||||
if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.first().map_or(false, |elt| {
|
||||
is_immutable_annotation(elt, from_imports, import_aliases)
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ExprKind::BinOp {
|
||||
left,
|
||||
op: Operator::BitOr,
|
||||
right,
|
||||
} => {
|
||||
is_immutable_annotation(left, from_imports, import_aliases)
|
||||
&& is_immutable_annotation(right, from_imports, import_aliases)
|
||||
}
|
||||
ExprKind::Constant {
|
||||
value: Constant::None,
|
||||
..
|
||||
} => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// B006
|
||||
pub fn mutable_argument_default(checker: &mut Checker, arguments: &Arguments) {
|
||||
// Scan in reverse order to right-align zip()
|
||||
for (arg, default) in arguments
|
||||
.kwonlyargs
|
||||
for expr in arguments
|
||||
.defaults
|
||||
.iter()
|
||||
.rev()
|
||||
.zip(arguments.kw_defaults.iter().rev())
|
||||
.chain(
|
||||
arguments
|
||||
.args
|
||||
.iter()
|
||||
.rev()
|
||||
.chain(arguments.posonlyargs.iter().rev())
|
||||
.zip(arguments.defaults.iter().rev()),
|
||||
)
|
||||
.chain(arguments.kw_defaults.iter())
|
||||
{
|
||||
if is_mutable_expr(default, &checker.from_imports, &checker.import_aliases)
|
||||
&& arg.node.annotation.as_ref().map_or(true, |expr| {
|
||||
!is_immutable_annotation(expr, &checker.from_imports, &checker.import_aliases)
|
||||
})
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MutableArgumentDefault,
|
||||
Range::from_located(default),
|
||||
));
|
||||
match &expr.node {
|
||||
ExprKind::List { .. }
|
||||
| ExprKind::Dict { .. }
|
||||
| ExprKind::Set { .. }
|
||||
| ExprKind::ListComp { .. }
|
||||
| ExprKind::DictComp { .. }
|
||||
| ExprKind::SetComp { .. } => {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MutableArgumentDefault,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
ExprKind::Call { func, .. } => {
|
||||
if is_mutable_func(func, &checker.from_imports, &checker.import_aliases) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MutableArgumentDefault,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ pub fn print_call(checker: &mut Checker, expr: &Expr, func: &Expr) {
|
||||
if let Some(mut check) = checks::print_call(
|
||||
expr,
|
||||
func,
|
||||
checker.settings.enabled.contains(&CheckCode::T201),
|
||||
checker.settings.enabled.contains(&CheckCode::T203),
|
||||
checker.settings.enabled[CheckCode::T201 as usize],
|
||||
checker.settings.enabled[CheckCode::T203 as usize],
|
||||
Range::from_located(expr),
|
||||
) {
|
||||
if checker.patch(check.kind.code()) {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use rustpython_ast::{Location, Stmt};
|
||||
use textwrap::{dedent, indent};
|
||||
|
||||
use crate::ast::helpers::{match_leading_content, match_trailing_content};
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace::leading_space;
|
||||
use crate::autofix::{fixer, Fix};
|
||||
use crate::checks::CheckKind;
|
||||
use crate::docstrings::helpers::leading_space;
|
||||
use crate::isort::{comments, format_imports};
|
||||
use crate::{Check, Settings, SourceCodeLocator};
|
||||
|
||||
@@ -28,6 +27,34 @@ fn extract_indentation(body: &[&Stmt], locator: &SourceCodeLocator) -> String {
|
||||
leading_space(&existing)
|
||||
}
|
||||
|
||||
fn match_leading_content(body: &[&Stmt], locator: &SourceCodeLocator) -> bool {
|
||||
let location = body.first().unwrap().location;
|
||||
let range = Range {
|
||||
location: Location::new(location.row(), 0),
|
||||
end_location: location,
|
||||
};
|
||||
let prefix = locator.slice_source_code_range(&range);
|
||||
prefix.chars().any(|char| !char.is_whitespace())
|
||||
}
|
||||
|
||||
fn match_trailing_content(body: &[&Stmt], locator: &SourceCodeLocator) -> bool {
|
||||
let end_location = body.last().unwrap().end_location.unwrap();
|
||||
let range = Range {
|
||||
location: end_location,
|
||||
end_location: Location::new(end_location.row() + 1, 0),
|
||||
};
|
||||
let suffix = locator.slice_source_code_range(&range);
|
||||
for char in suffix.chars() {
|
||||
if char == '#' {
|
||||
return false;
|
||||
}
|
||||
if !char.is_whitespace() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// I001
|
||||
pub fn check_imports(
|
||||
body: Vec<&Stmt>,
|
||||
@@ -48,8 +75,8 @@ pub fn check_imports(
|
||||
);
|
||||
|
||||
// Special-cases: there's leading or trailing content in the import block.
|
||||
let has_leading_content = match_leading_content(body.first().unwrap(), locator);
|
||||
let has_trailing_content = match_trailing_content(body.last().unwrap(), locator);
|
||||
let has_leading_content = match_leading_content(&body, locator);
|
||||
let has_trailing_content = match_trailing_content(&body, locator);
|
||||
|
||||
// Generate the sorted import block.
|
||||
let expected = format_imports(
|
||||
|
||||
@@ -15,6 +15,7 @@ use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
mod ast;
|
||||
pub mod autofix;
|
||||
mod bits;
|
||||
pub mod cache;
|
||||
pub mod check_ast;
|
||||
mod check_imports;
|
||||
|
||||
@@ -65,23 +65,26 @@ pub(crate) fn check_path(
|
||||
let mut checks: Vec<Check> = vec![];
|
||||
|
||||
// Run the token-based checks.
|
||||
let use_tokens = settings
|
||||
.enabled
|
||||
.iter()
|
||||
.any(|check_code| matches!(check_code.lint_source(), LintSource::Tokens));
|
||||
let use_tokens = false;
|
||||
// settings
|
||||
// .enabled
|
||||
// .iter()
|
||||
// .any(|check_code| matches!(check_code.lint_source(), LintSource::Tokens));
|
||||
if use_tokens {
|
||||
check_tokens(&mut checks, locator, &tokens, settings, autofix);
|
||||
}
|
||||
|
||||
// Run the AST-based checks.
|
||||
let use_ast = settings
|
||||
.enabled
|
||||
.iter()
|
||||
.any(|check_code| matches!(check_code.lint_source(), LintSource::AST));
|
||||
let use_imports = settings
|
||||
.enabled
|
||||
.iter()
|
||||
.any(|check_code| matches!(check_code.lint_source(), LintSource::Imports));
|
||||
let use_ast = true;
|
||||
// settings
|
||||
// .enabled
|
||||
// .iter()
|
||||
// .any(|check_code| matches!(check_code.lint_source(), LintSource::AST));
|
||||
let use_imports = false;
|
||||
// settings
|
||||
// .enabled
|
||||
// .iter()
|
||||
// .any(|check_code| matches!(check_code.lint_source(), LintSource::Imports));
|
||||
if use_ast || use_imports {
|
||||
match parse_program_tokens(tokens, "<filename>") {
|
||||
Ok(python_ast) => {
|
||||
@@ -99,7 +102,7 @@ pub(crate) fn check_path(
|
||||
}
|
||||
}
|
||||
Err(parse_error) => {
|
||||
if settings.enabled.contains(&CheckCode::E999) {
|
||||
if settings.enabled[CheckCode::E999 as usize] {
|
||||
checks.push(Check::new(
|
||||
CheckKind::SyntaxError(parse_error.error.to_string()),
|
||||
Range {
|
||||
|
||||
@@ -110,7 +110,7 @@ fn run_once(
|
||||
}
|
||||
.unwrap_or_else(|(path, message)| {
|
||||
if let Some(path) = path {
|
||||
if settings.enabled.contains(&CheckCode::E902) {
|
||||
if settings.enabled[CheckCode::E902 as usize] {
|
||||
vec![Message {
|
||||
kind: CheckKind::IOError(message),
|
||||
fixed: false,
|
||||
|
||||
48
src/noqa.rs
48
src/noqa.rs
@@ -10,40 +10,32 @@ use regex::Regex;
|
||||
use crate::checks::{Check, CheckCode};
|
||||
|
||||
static NO_QA_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
Regex::new(
|
||||
r"(?P<spaces>\s*)(?P<noqa>(?i:# noqa)(?::\s?(?P<codes>([A-Z]+[0-9]+(?:[,\s]+)?)+))?)",
|
||||
)
|
||||
.expect("Invalid regex")
|
||||
Regex::new(r"(?P<noqa>\s*(?i:# noqa)(?::\s?(?P<codes>([A-Z]+[0-9]+(?:[,\s]+)?)+))?)")
|
||||
.expect("Invalid regex")
|
||||
});
|
||||
static SPLIT_COMMA_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").expect("Invalid regex"));
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Directive<'a> {
|
||||
None,
|
||||
All(usize, usize, usize),
|
||||
Codes(usize, usize, usize, Vec<&'a str>),
|
||||
All(usize, usize),
|
||||
Codes(usize, usize, Vec<&'a str>),
|
||||
}
|
||||
|
||||
pub fn extract_noqa_directive(line: &str) -> Directive {
|
||||
match NO_QA_REGEX.captures(line) {
|
||||
Some(caps) => match caps.name("spaces") {
|
||||
Some(spaces) => match caps.name("noqa") {
|
||||
Some(noqa) => match caps.name("codes") {
|
||||
Some(codes) => Directive::Codes(
|
||||
spaces.as_str().chars().count(),
|
||||
noqa.start(),
|
||||
noqa.end(),
|
||||
SPLIT_COMMA_REGEX
|
||||
.split(codes.as_str())
|
||||
.map(|code| code.trim())
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect(),
|
||||
),
|
||||
None => {
|
||||
Directive::All(spaces.as_str().chars().count(), noqa.start(), noqa.end())
|
||||
}
|
||||
},
|
||||
None => Directive::None,
|
||||
Some(caps) => match caps.name("noqa") {
|
||||
Some(noqa) => match caps.name("codes") {
|
||||
Some(codes) => Directive::Codes(
|
||||
noqa.start(),
|
||||
noqa.end(),
|
||||
SPLIT_COMMA_REGEX
|
||||
.split(codes.as_str())
|
||||
.map(|code| code.trim())
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect(),
|
||||
),
|
||||
None => Directive::All(noqa.start(), noqa.end()),
|
||||
},
|
||||
None => Directive::None,
|
||||
},
|
||||
@@ -100,14 +92,12 @@ fn add_noqa_inner(
|
||||
match extract_noqa_directive(line) {
|
||||
Directive::None => {
|
||||
output.push_str(line);
|
||||
output.push_str(" # noqa: ");
|
||||
}
|
||||
Directive::All(_, start, _) | Directive::Codes(_, start, ..) => {
|
||||
output.push_str(&line[..start]);
|
||||
output.push_str("# noqa: ");
|
||||
}
|
||||
Directive::All(start, _) => output.push_str(&line[..start]),
|
||||
Directive::Codes(start, ..) => output.push_str(&line[..start]),
|
||||
};
|
||||
let codes: Vec<&str> = codes.iter().map(|code| code.as_ref()).collect();
|
||||
output.push_str(" # noqa: ");
|
||||
output.push_str(&codes.join(", "));
|
||||
output.push('\n');
|
||||
count += 1;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use itertools::izip;
|
||||
use rustpython_ast::Location;
|
||||
use rustpython_parser::ast::{Cmpop, Expr, ExprKind};
|
||||
use rustpython_parser::ast::{Cmpop, Expr, ExprKind, Stmt};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
@@ -46,6 +46,19 @@ pub fn ambiguous_function_name(name: &str, location: Range) -> Option<Check> {
|
||||
}
|
||||
}
|
||||
|
||||
/// E731
|
||||
pub fn do_not_assign_lambda(target: &Expr, value: &Expr, stmt: &Stmt) -> Option<Check> {
|
||||
if let ExprKind::Name { .. } = &target.node {
|
||||
if let ExprKind::Lambda { .. } = &value.node {
|
||||
return Some(Check::new(
|
||||
CheckKind::DoNotAssignLambda,
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// E721
|
||||
pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) -> Vec<Check> {
|
||||
let mut checks: Vec<Check> = vec![];
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
use anyhow::Result;
|
||||
use fnv::FnvHashMap;
|
||||
use itertools::izip;
|
||||
use log::error;
|
||||
use rustpython_ast::{Arguments, Location, StmtKind};
|
||||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Stmt, Unaryop};
|
||||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Unaryop};
|
||||
|
||||
use crate::ast::helpers::{match_leading_content, match_trailing_content};
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace::leading_space;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckKind, RejectedCmpop};
|
||||
@@ -265,69 +260,3 @@ pub fn not_tests(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn function(name: &str, args: &Arguments, body: &Expr) -> Result<String> {
|
||||
let body = Stmt::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
StmtKind::Return {
|
||||
value: Some(Box::new(body.clone())),
|
||||
},
|
||||
);
|
||||
let func = Stmt::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
StmtKind::FunctionDef {
|
||||
name: name.to_string(),
|
||||
args: Box::new(args.clone()),
|
||||
body: vec![body],
|
||||
decorator_list: vec![],
|
||||
returns: None,
|
||||
type_comment: None,
|
||||
},
|
||||
);
|
||||
let mut generator = SourceGenerator::new();
|
||||
generator.unparse_stmt(&func)?;
|
||||
generator.generate().map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// E731
|
||||
pub fn do_not_assign_lambda(checker: &mut Checker, target: &Expr, value: &Expr, stmt: &Stmt) {
|
||||
if let ExprKind::Name { id, .. } = &target.node {
|
||||
if let ExprKind::Lambda { args, body } = &value.node {
|
||||
let mut check = Check::new(CheckKind::DoNotAssignLambda, Range::from_located(stmt));
|
||||
if checker.patch(check.kind.code()) {
|
||||
if !match_leading_content(stmt, checker.locator)
|
||||
&& !match_trailing_content(stmt, checker.locator)
|
||||
{
|
||||
match function(id, args, body) {
|
||||
Ok(content) => {
|
||||
let indentation =
|
||||
&leading_space(&checker.locator.slice_source_code_range(&Range {
|
||||
location: Location::new(stmt.location.row(), 0),
|
||||
end_location: Location::new(stmt.location.row() + 1, 0),
|
||||
}));
|
||||
let mut indented = String::new();
|
||||
for (idx, line) in content.lines().enumerate() {
|
||||
if idx == 0 {
|
||||
indented.push_str(line);
|
||||
} else {
|
||||
indented.push('\n');
|
||||
indented.push_str(indentation);
|
||||
indented.push_str(line);
|
||||
}
|
||||
}
|
||||
check.amend(Fix::replacement(
|
||||
indented,
|
||||
stmt.location,
|
||||
stmt.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,11 @@ use regex::Regex;
|
||||
use rustpython_ast::{Arg, Constant, ExprKind, Location, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
use crate::docstrings::constants;
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
use crate::docstrings::helpers;
|
||||
use crate::docstrings::sections::{section_contexts, SectionContext};
|
||||
use crate::docstrings::styles::SectionStyle;
|
||||
use crate::visibility::{is_init, is_magic, is_overload, is_staticmethod, Visibility};
|
||||
@@ -33,7 +32,7 @@ pub fn not_missing(
|
||||
|
||||
match definition.kind {
|
||||
DefinitionKind::Module => {
|
||||
if checker.settings.enabled.contains(&CheckCode::D100) {
|
||||
if checker.settings.enabled[CheckCode::D100 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::PublicModule,
|
||||
Range {
|
||||
@@ -45,7 +44,7 @@ pub fn not_missing(
|
||||
false
|
||||
}
|
||||
DefinitionKind::Package => {
|
||||
if checker.settings.enabled.contains(&CheckCode::D104) {
|
||||
if checker.settings.enabled[CheckCode::D104 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::PublicPackage,
|
||||
Range {
|
||||
@@ -57,7 +56,7 @@ pub fn not_missing(
|
||||
false
|
||||
}
|
||||
DefinitionKind::Class(stmt) => {
|
||||
if checker.settings.enabled.contains(&CheckCode::D101) {
|
||||
if checker.settings.enabled[CheckCode::D101 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::PublicClass,
|
||||
Range::from_located(stmt),
|
||||
@@ -66,7 +65,7 @@ pub fn not_missing(
|
||||
false
|
||||
}
|
||||
DefinitionKind::NestedClass(stmt) => {
|
||||
if checker.settings.enabled.contains(&CheckCode::D106) {
|
||||
if checker.settings.enabled[CheckCode::D106 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::PublicNestedClass,
|
||||
Range::from_located(stmt),
|
||||
@@ -78,7 +77,7 @@ pub fn not_missing(
|
||||
if is_overload(stmt) {
|
||||
true
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&CheckCode::D103) {
|
||||
if checker.settings.enabled[CheckCode::D103 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::PublicFunction,
|
||||
Range::from_located(stmt),
|
||||
@@ -91,7 +90,7 @@ pub fn not_missing(
|
||||
if is_overload(stmt) {
|
||||
true
|
||||
} else if is_magic(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::D105) {
|
||||
if checker.settings.enabled[CheckCode::D105 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MagicMethod,
|
||||
Range::from_located(stmt),
|
||||
@@ -99,12 +98,12 @@ pub fn not_missing(
|
||||
}
|
||||
true
|
||||
} else if is_init(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::D107) {
|
||||
if checker.settings.enabled[CheckCode::D107 as usize] {
|
||||
checker.add_check(Check::new(CheckKind::PublicInit, Range::from_located(stmt)));
|
||||
}
|
||||
true
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&CheckCode::D102) {
|
||||
if checker.settings.enabled[CheckCode::D102 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::PublicMethod,
|
||||
Range::from_located(stmt),
|
||||
@@ -163,7 +162,7 @@ pub fn blank_before_after_function(checker: &mut Checker, definition: &Definitio
|
||||
..
|
||||
} = &docstring.node
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::D201) {
|
||||
if checker.settings.enabled[CheckCode::D201 as usize] {
|
||||
let (before, ..) = checker.locator.partition_source_code_at(
|
||||
&Range::from_located(parent),
|
||||
&Range::from_located(docstring),
|
||||
@@ -191,7 +190,7 @@ pub fn blank_before_after_function(checker: &mut Checker, definition: &Definitio
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D202) {
|
||||
if checker.settings.enabled[CheckCode::D202 as usize] {
|
||||
let (_, _, after) = checker.locator.partition_source_code_at(
|
||||
&Range::from_located(parent),
|
||||
&Range::from_located(docstring),
|
||||
@@ -250,8 +249,8 @@ pub fn blank_before_after_class(checker: &mut Checker, definition: &Definition)
|
||||
..
|
||||
} = &docstring.node
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::D203)
|
||||
|| checker.settings.enabled.contains(&CheckCode::D211)
|
||||
if checker.settings.enabled[CheckCode::D203 as usize]
|
||||
|| checker.settings.enabled[CheckCode::D211 as usize]
|
||||
{
|
||||
let (before, ..) = checker.locator.partition_source_code_at(
|
||||
&Range::from_located(parent),
|
||||
@@ -264,7 +263,7 @@ pub fn blank_before_after_class(checker: &mut Checker, definition: &Definition)
|
||||
.skip(1)
|
||||
.take_while(|line| line.trim().is_empty())
|
||||
.count();
|
||||
if checker.settings.enabled.contains(&CheckCode::D211) {
|
||||
if checker.settings.enabled[CheckCode::D211 as usize] {
|
||||
if blank_lines_before != 0 {
|
||||
let mut check = Check::new(
|
||||
CheckKind::NoBlankLineBeforeClass(blank_lines_before),
|
||||
@@ -280,7 +279,7 @@ pub fn blank_before_after_class(checker: &mut Checker, definition: &Definition)
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
if checker.settings.enabled.contains(&CheckCode::D203) {
|
||||
if checker.settings.enabled[CheckCode::D203 as usize] {
|
||||
if blank_lines_before != 1 {
|
||||
let mut check = Check::new(
|
||||
CheckKind::OneBlankLineBeforeClass(blank_lines_before),
|
||||
@@ -299,7 +298,7 @@ pub fn blank_before_after_class(checker: &mut Checker, definition: &Definition)
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D204) {
|
||||
if checker.settings.enabled[CheckCode::D204 as usize] {
|
||||
let (_, _, after) = checker.locator.partition_source_code_at(
|
||||
&Range::from_located(parent),
|
||||
&Range::from_located(docstring),
|
||||
@@ -392,7 +391,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
return;
|
||||
}
|
||||
|
||||
let docstring_indent = whitespace::indentation(checker, docstring);
|
||||
let docstring_indent = helpers::indentation(checker, docstring);
|
||||
let mut has_seen_tab = docstring_indent.contains('\t');
|
||||
let mut is_over_indented = true;
|
||||
let mut over_indented_lines = vec![];
|
||||
@@ -409,13 +408,13 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let line_indent = whitespace::leading_space(lines[i]);
|
||||
let line_indent = helpers::leading_space(lines[i]);
|
||||
|
||||
// We only report tab indentation once, so only check if we haven't seen a tab
|
||||
// yet.
|
||||
has_seen_tab = has_seen_tab || line_indent.contains('\t');
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D207) {
|
||||
if checker.settings.enabled[CheckCode::D207 as usize] {
|
||||
// We report under-indentation on every line. This isn't great, but enables
|
||||
// autofix.
|
||||
if !is_blank && line_indent.len() < docstring_indent.len() {
|
||||
@@ -428,7 +427,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
whitespace::clean(&docstring_indent),
|
||||
helpers::clean(&docstring_indent),
|
||||
Location::new(docstring.location.row() + i, 0),
|
||||
Location::new(docstring.location.row() + i, line_indent.len()),
|
||||
));
|
||||
@@ -452,7 +451,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D206) {
|
||||
if checker.settings.enabled[CheckCode::D206 as usize] {
|
||||
if has_seen_tab {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::IndentWithSpaces,
|
||||
@@ -461,11 +460,11 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D208) {
|
||||
if checker.settings.enabled[CheckCode::D208 as usize] {
|
||||
// If every line (except the last) is over-indented...
|
||||
if is_over_indented {
|
||||
for i in over_indented_lines {
|
||||
let line_indent = whitespace::leading_space(lines[i]);
|
||||
let line_indent = helpers::leading_space(lines[i]);
|
||||
if line_indent.len() > docstring_indent.len() {
|
||||
// We report over-indentation on every line. This isn't great, but
|
||||
// enables autofix.
|
||||
@@ -478,7 +477,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
whitespace::clean(&docstring_indent),
|
||||
helpers::clean(&docstring_indent),
|
||||
Location::new(docstring.location.row() + i, 0),
|
||||
Location::new(docstring.location.row() + i, line_indent.len()),
|
||||
));
|
||||
@@ -491,7 +490,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
// If the last line is over-indented...
|
||||
if !lines.is_empty() {
|
||||
let i = lines.len() - 1;
|
||||
let line_indent = whitespace::leading_space(lines[i]);
|
||||
let line_indent = helpers::leading_space(lines[i]);
|
||||
if line_indent.len() > docstring_indent.len() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::NoOverIndentation,
|
||||
@@ -502,7 +501,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
whitespace::clean(&docstring_indent),
|
||||
helpers::clean(&docstring_indent),
|
||||
Location::new(docstring.location.row() + i, 0),
|
||||
Location::new(docstring.location.row() + i, line_indent.len()),
|
||||
));
|
||||
@@ -542,7 +541,7 @@ pub fn newline_after_last_paragraph(checker: &mut Checker, definition: &Definiti
|
||||
// Insert a newline just before the end-quote(s).
|
||||
let content = format!(
|
||||
"\n{}",
|
||||
whitespace::clean(&whitespace::indentation(checker, docstring))
|
||||
helpers::clean(&helpers::indentation(checker, docstring))
|
||||
);
|
||||
check.amend(Fix::insertion(
|
||||
content,
|
||||
@@ -589,9 +588,9 @@ pub fn no_surrounding_whitespace(checker: &mut Checker, definition: &Definition)
|
||||
.next()
|
||||
.map(|line| line.to_lowercase())
|
||||
{
|
||||
for pattern in constants::TRIPLE_QUOTE_PREFIXES
|
||||
for pattern in helpers::TRIPLE_QUOTE_PREFIXES
|
||||
.iter()
|
||||
.chain(constants::SINGLE_QUOTE_PREFIXES)
|
||||
.chain(helpers::SINGLE_QUOTE_PREFIXES)
|
||||
{
|
||||
if first_line.starts_with(pattern) {
|
||||
check.amend(Fix::replacement(
|
||||
@@ -635,15 +634,15 @@ pub fn multi_line_summary_start(checker: &mut Checker, definition: &Definition)
|
||||
.next()
|
||||
.map(|line| line.to_lowercase())
|
||||
{
|
||||
if constants::TRIPLE_QUOTE_PREFIXES.contains(&first_line.as_str()) {
|
||||
if checker.settings.enabled.contains(&CheckCode::D212) {
|
||||
if helpers::TRIPLE_QUOTE_PREFIXES.contains(&first_line.as_str()) {
|
||||
if checker.settings.enabled[CheckCode::D212 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MultiLineSummaryFirstLine,
|
||||
Range::from_located(docstring),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&CheckCode::D213) {
|
||||
if checker.settings.enabled[CheckCode::D213 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MultiLineSummarySecondLine,
|
||||
Range::from_located(docstring),
|
||||
@@ -849,7 +848,7 @@ pub fn not_empty(checker: &mut Checker, definition: &Definition) -> bool {
|
||||
} = &docstring.node
|
||||
{
|
||||
if string.trim().is_empty() {
|
||||
if checker.settings.enabled.contains(&CheckCode::D419) {
|
||||
if checker.settings.enabled[CheckCode::D419 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::NonEmpty,
|
||||
Range::from_located(docstring),
|
||||
@@ -912,7 +911,7 @@ fn blanks_and_section_underline(
|
||||
|
||||
// Nothing but blank lines after the section header.
|
||||
if blank_lines_after_header == context.following_lines.len() {
|
||||
if checker.settings.enabled.contains(&CheckCode::D407) {
|
||||
if checker.settings.enabled[CheckCode::D407 as usize] {
|
||||
let mut check = Check::new(
|
||||
CheckKind::DashedUnderlineAfterSection(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
@@ -921,7 +920,7 @@ fn blanks_and_section_underline(
|
||||
// Add a dashed line (of the appropriate length) under the section header.
|
||||
let content = format!(
|
||||
"{}{}\n",
|
||||
whitespace::clean(&whitespace::indentation(checker, docstring)),
|
||||
helpers::clean(&helpers::indentation(checker, docstring)),
|
||||
"-".repeat(context.section_name.len())
|
||||
);
|
||||
check.amend(Fix::insertion(
|
||||
@@ -931,7 +930,7 @@ fn blanks_and_section_underline(
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
if checker.settings.enabled.contains(&CheckCode::D414) {
|
||||
if checker.settings.enabled[CheckCode::D414 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::NonEmptySection(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
@@ -946,7 +945,7 @@ fn blanks_and_section_underline(
|
||||
.all(|char| char.is_whitespace() || char == '-');
|
||||
|
||||
if !dash_line_found {
|
||||
if checker.settings.enabled.contains(&CheckCode::D407) {
|
||||
if checker.settings.enabled[CheckCode::D407 as usize] {
|
||||
let mut check = Check::new(
|
||||
CheckKind::DashedUnderlineAfterSection(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
@@ -955,7 +954,7 @@ fn blanks_and_section_underline(
|
||||
// Add a dashed line (of the appropriate length) under the section header.
|
||||
let content = format!(
|
||||
"{}{}\n",
|
||||
whitespace::clean(&whitespace::indentation(checker, docstring)),
|
||||
helpers::clean(&helpers::indentation(checker, docstring)),
|
||||
"-".repeat(context.section_name.len())
|
||||
);
|
||||
check.amend(Fix::insertion(
|
||||
@@ -966,7 +965,7 @@ fn blanks_and_section_underline(
|
||||
checker.add_check(check);
|
||||
}
|
||||
if blank_lines_after_header > 0 {
|
||||
if checker.settings.enabled.contains(&CheckCode::D412) {
|
||||
if checker.settings.enabled[CheckCode::D412 as usize] {
|
||||
let mut check = Check::new(
|
||||
CheckKind::NoBlankLinesBetweenHeaderAndContent(
|
||||
context.section_name.to_string(),
|
||||
@@ -991,7 +990,7 @@ fn blanks_and_section_underline(
|
||||
}
|
||||
} else {
|
||||
if blank_lines_after_header > 0 {
|
||||
if checker.settings.enabled.contains(&CheckCode::D408) {
|
||||
if checker.settings.enabled[CheckCode::D408 as usize] {
|
||||
let mut check = Check::new(
|
||||
CheckKind::SectionUnderlineAfterName(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
@@ -1020,7 +1019,7 @@ fn blanks_and_section_underline(
|
||||
.count()
|
||||
!= context.section_name.len()
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::D409) {
|
||||
if checker.settings.enabled[CheckCode::D409 as usize] {
|
||||
let mut check = Check::new(
|
||||
CheckKind::SectionUnderlineMatchesSectionLength(
|
||||
context.section_name.to_string(),
|
||||
@@ -1031,7 +1030,7 @@ fn blanks_and_section_underline(
|
||||
// Replace the existing underline with a line of the appropriate length.
|
||||
let content = format!(
|
||||
"{}{}\n",
|
||||
whitespace::clean(&whitespace::indentation(checker, docstring)),
|
||||
helpers::clean(&helpers::indentation(checker, docstring)),
|
||||
"-".repeat(context.section_name.len())
|
||||
);
|
||||
check.amend(Fix::replacement(
|
||||
@@ -1057,9 +1056,9 @@ fn blanks_and_section_underline(
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D215) {
|
||||
let leading_space = whitespace::leading_space(non_empty_line);
|
||||
let indentation = whitespace::indentation(checker, docstring);
|
||||
if checker.settings.enabled[CheckCode::D215 as usize] {
|
||||
let leading_space = helpers::leading_space(non_empty_line);
|
||||
let indentation = helpers::indentation(checker, docstring);
|
||||
if leading_space.len() > indentation.len() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::SectionUnderlineNotOverIndented(context.section_name.to_string()),
|
||||
@@ -1068,7 +1067,7 @@ fn blanks_and_section_underline(
|
||||
if checker.patch(check.kind.code()) {
|
||||
// Replace the existing indentation with whitespace of the appropriate length.
|
||||
check.amend(Fix::replacement(
|
||||
whitespace::clean(&indentation),
|
||||
helpers::clean(&indentation),
|
||||
Location::new(
|
||||
docstring.location.row()
|
||||
+ context.original_index
|
||||
@@ -1100,14 +1099,14 @@ fn blanks_and_section_underline(
|
||||
.take_while(|line| line.trim().is_empty())
|
||||
.count();
|
||||
if blank_lines_after_dashes == rest_of_lines.len() {
|
||||
if checker.settings.enabled.contains(&CheckCode::D414) {
|
||||
if checker.settings.enabled[CheckCode::D414 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::NonEmptySection(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&CheckCode::D412) {
|
||||
if checker.settings.enabled[CheckCode::D412 as usize] {
|
||||
let mut check = Check::new(
|
||||
CheckKind::NoBlankLinesBetweenHeaderAndContent(
|
||||
context.section_name.to_string(),
|
||||
@@ -1139,7 +1138,7 @@ fn blanks_and_section_underline(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&CheckCode::D414) {
|
||||
if checker.settings.enabled[CheckCode::D414 as usize] {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::NonEmptySection(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
@@ -1159,7 +1158,7 @@ fn common_section(
|
||||
.docstring
|
||||
.expect("Sections are only available for docstrings.");
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D405) {
|
||||
if checker.settings.enabled[CheckCode::D405 as usize] {
|
||||
if !style
|
||||
.section_names()
|
||||
.contains(&context.section_name.as_str())
|
||||
@@ -1198,9 +1197,9 @@ fn common_section(
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D214) {
|
||||
let leading_space = whitespace::leading_space(context.line);
|
||||
let indentation = whitespace::indentation(checker, docstring);
|
||||
if checker.settings.enabled[CheckCode::D214 as usize] {
|
||||
let leading_space = helpers::leading_space(context.line);
|
||||
let indentation = helpers::indentation(checker, docstring);
|
||||
if leading_space.len() > indentation.len() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::SectionNotOverIndented(context.section_name.to_string()),
|
||||
@@ -1209,7 +1208,7 @@ fn common_section(
|
||||
if checker.patch(check.kind.code()) {
|
||||
// Replace the existing indentation with whitespace of the appropriate length.
|
||||
check.amend(Fix::replacement(
|
||||
whitespace::clean(&indentation),
|
||||
helpers::clean(&indentation),
|
||||
Location::new(docstring.location.row() + context.original_index, 0),
|
||||
Location::new(
|
||||
docstring.location.row() + context.original_index,
|
||||
@@ -1228,7 +1227,7 @@ fn common_section(
|
||||
.unwrap_or(true)
|
||||
{
|
||||
if context.is_last_section {
|
||||
if checker.settings.enabled.contains(&CheckCode::D413) {
|
||||
if checker.settings.enabled[CheckCode::D413 as usize] {
|
||||
let mut check = Check::new(
|
||||
CheckKind::BlankLineAfterLastSection(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
@@ -1249,7 +1248,7 @@ fn common_section(
|
||||
checker.add_check(check);
|
||||
}
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&CheckCode::D410) {
|
||||
if checker.settings.enabled[CheckCode::D410 as usize] {
|
||||
let mut check = Check::new(
|
||||
CheckKind::BlankLineAfterSection(context.section_name.to_string()),
|
||||
Range::from_located(docstring),
|
||||
@@ -1272,7 +1271,7 @@ fn common_section(
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D411) {
|
||||
if checker.settings.enabled[CheckCode::D411 as usize] {
|
||||
if !context.previous_line.is_empty() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::BlankLineBeforeSection(context.section_name.to_string()),
|
||||
@@ -1401,13 +1400,13 @@ fn args_section(checker: &mut Checker, definition: &Definition, context: &Sectio
|
||||
fn parameters_section(checker: &mut Checker, definition: &Definition, context: &SectionContext) {
|
||||
// Collect the list of arguments documented in the docstring.
|
||||
let mut docstring_args: FnvHashSet<&str> = FnvHashSet::default();
|
||||
let section_level_indent = whitespace::leading_space(context.line);
|
||||
let section_level_indent = helpers::leading_space(context.line);
|
||||
for i in 1..context.following_lines.len() {
|
||||
let current_line = context.following_lines[i - 1];
|
||||
let current_leading_space = whitespace::leading_space(current_line);
|
||||
let current_leading_space = helpers::leading_space(current_line);
|
||||
let next_line = context.following_lines[i];
|
||||
if current_leading_space == section_level_indent
|
||||
&& (whitespace::leading_space(next_line).len() > current_leading_space.len())
|
||||
&& (helpers::leading_space(next_line).len() > current_leading_space.len())
|
||||
&& !next_line.trim().is_empty()
|
||||
{
|
||||
let parameters = if let Some(semi_index) = current_line.find(':') {
|
||||
@@ -1431,7 +1430,7 @@ fn parameters_section(checker: &mut Checker, definition: &Definition, context: &
|
||||
fn numpy_section(checker: &mut Checker, definition: &Definition, context: &SectionContext) {
|
||||
common_section(checker, definition, context, &SectionStyle::NumPy);
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D406) {
|
||||
if checker.settings.enabled[CheckCode::D406 as usize] {
|
||||
let suffix = context
|
||||
.line
|
||||
.trim()
|
||||
@@ -1469,7 +1468,7 @@ fn numpy_section(checker: &mut Checker, definition: &Definition, context: &Secti
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D417) {
|
||||
if checker.settings.enabled[CheckCode::D417 as usize] {
|
||||
let capitalized_section_name = titlecase::titlecase(&context.section_name);
|
||||
if capitalized_section_name == "Parameters" {
|
||||
parameters_section(checker, definition, context);
|
||||
@@ -1480,7 +1479,7 @@ fn numpy_section(checker: &mut Checker, definition: &Definition, context: &Secti
|
||||
fn google_section(checker: &mut Checker, definition: &Definition, context: &SectionContext) {
|
||||
common_section(checker, definition, context, &SectionStyle::Google);
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D416) {
|
||||
if checker.settings.enabled[CheckCode::D416 as usize] {
|
||||
let suffix = context
|
||||
.line
|
||||
.trim()
|
||||
@@ -1519,7 +1518,7 @@ fn google_section(checker: &mut Checker, definition: &Definition, context: &Sect
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D417) {
|
||||
if checker.settings.enabled[CheckCode::D417 as usize] {
|
||||
let capitalized_section_name = titlecase::titlecase(&context.section_name);
|
||||
if capitalized_section_name == "Args" || capitalized_section_name == "Arguments" {
|
||||
args_section(checker, definition, context);
|
||||
|
||||
@@ -2,7 +2,6 @@ use anyhow::{bail, Result};
|
||||
use log::error;
|
||||
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Keyword, KeywordData, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::helpers::match_module_member;
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
@@ -11,13 +10,11 @@ use crate::code_gen::SourceGenerator;
|
||||
use crate::python::identifiers::IDENTIFIER_REGEX;
|
||||
use crate::python::keyword::KWLIST;
|
||||
|
||||
/// Return the class name, arguments, keywords and base class for a `TypedDict`
|
||||
/// assignment.
|
||||
/// Return the class name, arguments, and keywords for a `TypedDict` assignment.
|
||||
fn match_typed_dict_assign<'a>(
|
||||
checker: &Checker,
|
||||
targets: &'a [Expr],
|
||||
value: &'a Expr,
|
||||
) -> Option<(&'a str, &'a [Expr], &'a [Keyword], &'a ExprKind)> {
|
||||
) -> Option<(&'a str, &'a [Expr], &'a [Keyword])> {
|
||||
if let Some(target) = targets.get(0) {
|
||||
if let ExprKind::Name { id: class_name, .. } = &target.node {
|
||||
if let ExprKind::Call {
|
||||
@@ -26,14 +23,10 @@ fn match_typed_dict_assign<'a>(
|
||||
keywords,
|
||||
} = &value.node
|
||||
{
|
||||
if match_module_member(
|
||||
func,
|
||||
"typing",
|
||||
"TypedDict",
|
||||
&checker.from_imports,
|
||||
&checker.import_aliases,
|
||||
) {
|
||||
return Some((class_name, args, keywords, &func.node));
|
||||
if let ExprKind::Name { id: func_name, .. } = &func.node {
|
||||
if func_name == "TypedDict" {
|
||||
return Some((class_name, args, keywords));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,13 +65,12 @@ fn create_pass_stmt() -> Stmt {
|
||||
Stmt::new(Default::default(), Default::default(), StmtKind::Pass)
|
||||
}
|
||||
|
||||
/// Generate a `StmtKind:ClassDef` statement based on the provided body,
|
||||
/// keywords and base class.
|
||||
/// Generate a `StmtKind:ClassDef` statement bsaed on the provided body and
|
||||
/// keywords.
|
||||
fn create_class_def_stmt(
|
||||
class_name: &str,
|
||||
body: Vec<Stmt>,
|
||||
total_keyword: Option<KeywordData>,
|
||||
base_class: &ExprKind,
|
||||
) -> Stmt {
|
||||
let keywords = match total_keyword {
|
||||
Some(keyword) => vec![Keyword::new(
|
||||
@@ -96,7 +88,10 @@ fn create_class_def_stmt(
|
||||
bases: vec![Expr::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
base_class.clone(),
|
||||
ExprKind::Name {
|
||||
id: "TypedDict".to_string(),
|
||||
ctx: ExprContext::Load,
|
||||
},
|
||||
)],
|
||||
keywords,
|
||||
body,
|
||||
@@ -155,11 +150,11 @@ fn get_properties_from_keywords(keywords: &[Keyword]) -> Result<Vec<Stmt>> {
|
||||
|
||||
// The only way to have the `total` keyword is to use the args version, like:
|
||||
// (`TypedDict('name', {'a': int}, total=True)`)
|
||||
fn get_total_from_only_keyword(keywords: &[Keyword]) -> Option<&KeywordData> {
|
||||
fn get_total_from_only_keyword(keywords: &[Keyword]) -> Option<KeywordData> {
|
||||
match keywords.get(0) {
|
||||
Some(keyword) => match &keyword.node.arg {
|
||||
Some(arg) => match arg.as_str() {
|
||||
"total" => Some(&keyword.node),
|
||||
"total" => Some(keyword.node.clone()),
|
||||
_ => None,
|
||||
},
|
||||
None => None,
|
||||
@@ -176,7 +171,7 @@ fn get_properties_and_total(
|
||||
// dict and keywords. For example, the following is illegal:
|
||||
// MyType = TypedDict('MyType', {'a': int, 'b': str}, a=int, b=str)
|
||||
if let Some(dict) = args.get(1) {
|
||||
let total = get_total_from_only_keyword(keywords).cloned();
|
||||
let total = get_total_from_only_keyword(keywords);
|
||||
match &dict.node {
|
||||
ExprKind::Dict { keys, values } => {
|
||||
Ok((get_properties_from_dict_literal(keys, values)?, total))
|
||||
@@ -193,21 +188,15 @@ fn get_properties_and_total(
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a `Fix` to convert a `TypedDict` from functional to class.
|
||||
fn convert_to_class(
|
||||
/// Generate a `Fix` to convert a `TypedDict` to a functional class.
|
||||
fn convert_to_functional_class(
|
||||
stmt: &Stmt,
|
||||
class_name: &str,
|
||||
body: Vec<Stmt>,
|
||||
total_keyword: Option<KeywordData>,
|
||||
base_class: &ExprKind,
|
||||
) -> Result<Fix> {
|
||||
let mut generator = SourceGenerator::new();
|
||||
generator.unparse_stmt(&create_class_def_stmt(
|
||||
class_name,
|
||||
body,
|
||||
total_keyword,
|
||||
base_class,
|
||||
))?;
|
||||
generator.unparse_stmt(&create_class_def_stmt(class_name, body, total_keyword))?;
|
||||
let content = generator.generate()?;
|
||||
Ok(Fix::replacement(
|
||||
content,
|
||||
@@ -223,9 +212,7 @@ pub fn convert_typed_dict_functional_to_class(
|
||||
targets: &[Expr],
|
||||
value: &Expr,
|
||||
) {
|
||||
if let Some((class_name, args, keywords, base_class)) =
|
||||
match_typed_dict_assign(checker, targets, value)
|
||||
{
|
||||
if let Some((class_name, args, keywords)) = match_typed_dict_assign(targets, value) {
|
||||
match get_properties_and_total(args, keywords) {
|
||||
Err(err) => error!("Failed to parse TypedDict: {}", err),
|
||||
Ok((body, total_keyword)) => {
|
||||
@@ -234,7 +221,7 @@ pub fn convert_typed_dict_functional_to_class(
|
||||
Range::from_located(stmt),
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
match convert_to_class(stmt, class_name, body, total_keyword, base_class) {
|
||||
match convert_to_functional_class(stmt, class_name, body, total_keyword) {
|
||||
Ok(fix) => check.amend(fix),
|
||||
Err(err) => error!("Failed to convert TypedDict: {}", err),
|
||||
};
|
||||
|
||||
@@ -1646,7 +1646,7 @@ pub fn ambiguous_unicode_character(
|
||||
end_location,
|
||||
},
|
||||
);
|
||||
if settings.enabled.contains(check.kind.code()) {
|
||||
if settings.enabled[check.kind.code().clone() as usize] {
|
||||
if autofix.patch() && settings.fixable.contains(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
representant.to_string(),
|
||||
|
||||
@@ -27,7 +27,7 @@ pub mod user;
|
||||
#[derive(Debug)]
|
||||
pub struct Settings {
|
||||
pub dummy_variable_rgx: Regex,
|
||||
pub enabled: FnvHashSet<CheckCode>,
|
||||
pub enabled: Vec<bool>,
|
||||
pub exclude: Vec<FilePattern>,
|
||||
pub extend_exclude: Vec<FilePattern>,
|
||||
pub fixable: FnvHashSet<CheckCode>,
|
||||
@@ -64,7 +64,7 @@ impl Settings {
|
||||
),
|
||||
exclude: config.exclude,
|
||||
extend_exclude: config.extend_exclude,
|
||||
fixable: resolve_codes(&config.fixable, &config.unfixable),
|
||||
fixable: FnvHashSet::default(), // resolve_codes(&config.fixable, &config.unfixable),
|
||||
flake8_annotations: config.flake8_annotations,
|
||||
flake8_bugbear: config.flake8_bugbear,
|
||||
flake8_quotes: config.flake8_quotes,
|
||||
@@ -83,7 +83,7 @@ impl Settings {
|
||||
pub fn for_rule(check_code: CheckCode) -> Self {
|
||||
Self {
|
||||
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
|
||||
enabled: FnvHashSet::from_iter([check_code.clone()]),
|
||||
enabled: vec![], // FnvHashSet::from_iter([check_code.clone()]),
|
||||
fixable: FnvHashSet::from_iter([check_code]),
|
||||
exclude: Default::default(),
|
||||
extend_exclude: Default::default(),
|
||||
@@ -105,7 +105,7 @@ impl Settings {
|
||||
pub fn for_rules(check_codes: Vec<CheckCode>) -> Self {
|
||||
Self {
|
||||
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
|
||||
enabled: FnvHashSet::from_iter(check_codes.clone()),
|
||||
enabled: vec![], // FnvHashSet::from_iter(check_codes.clone()),
|
||||
fixable: FnvHashSet::from_iter(check_codes),
|
||||
exclude: Default::default(),
|
||||
extend_exclude: Default::default(),
|
||||
@@ -154,8 +154,8 @@ impl Hash for Settings {
|
||||
|
||||
/// Given a set of selected and ignored prefixes, resolve the set of enabled
|
||||
/// error codes.
|
||||
fn resolve_codes(select: &[CheckCodePrefix], ignore: &[CheckCodePrefix]) -> FnvHashSet<CheckCode> {
|
||||
let mut codes: FnvHashSet<CheckCode> = FnvHashSet::default();
|
||||
fn resolve_codes(select: &[CheckCodePrefix], ignore: &[CheckCodePrefix]) -> Vec<bool> {
|
||||
let mut codes = vec![false; 203];
|
||||
for specificity in [
|
||||
PrefixSpecificity::Category,
|
||||
PrefixSpecificity::Hundreds,
|
||||
@@ -164,13 +164,15 @@ fn resolve_codes(select: &[CheckCodePrefix], ignore: &[CheckCodePrefix]) -> FnvH
|
||||
] {
|
||||
for prefix in select {
|
||||
if prefix.specificity() == specificity {
|
||||
codes.extend(prefix.codes());
|
||||
for code in prefix.codes() {
|
||||
codes[code as usize] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for prefix in ignore {
|
||||
if prefix.specificity() == specificity {
|
||||
for code in prefix.codes() {
|
||||
codes.remove(&code);
|
||||
codes[code as usize] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,28 +90,4 @@ expression: checks
|
||||
row: 170
|
||||
column: 48
|
||||
fix: ~
|
||||
- kind: MutableArgumentDefault
|
||||
location:
|
||||
row: 203
|
||||
column: 26
|
||||
end_location:
|
||||
row: 203
|
||||
column: 28
|
||||
fix: ~
|
||||
- kind: MutableArgumentDefault
|
||||
location:
|
||||
row: 204
|
||||
column: 34
|
||||
end_location:
|
||||
row: 204
|
||||
column: 36
|
||||
fix: ~
|
||||
- kind: MutableArgumentDefault
|
||||
location:
|
||||
row: 205
|
||||
column: 61
|
||||
end_location:
|
||||
row: 205
|
||||
column: 66
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -9,16 +9,7 @@ expression: checks
|
||||
end_location:
|
||||
row: 2
|
||||
column: 19
|
||||
fix:
|
||||
patch:
|
||||
content: "def f(x):\n return (2 * x)"
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
end_location:
|
||||
row: 2
|
||||
column: 19
|
||||
applied: false
|
||||
fix: ~
|
||||
- kind: DoNotAssignLambda
|
||||
location:
|
||||
row: 4
|
||||
@@ -26,16 +17,7 @@ expression: checks
|
||||
end_location:
|
||||
row: 4
|
||||
column: 19
|
||||
fix:
|
||||
patch:
|
||||
content: "def f(x):\n return (2 * x)"
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 19
|
||||
applied: false
|
||||
fix: ~
|
||||
- kind: DoNotAssignLambda
|
||||
location:
|
||||
row: 7
|
||||
@@ -43,14 +25,5 @@ expression: checks
|
||||
end_location:
|
||||
row: 7
|
||||
column: 29
|
||||
fix:
|
||||
patch:
|
||||
content: "def this(y, z):\n return (2 * x)"
|
||||
location:
|
||||
row: 7
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
column: 29
|
||||
applied: false
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -47,13 +47,4 @@ expression: checks
|
||||
row: 21
|
||||
column: 9
|
||||
fix: ~
|
||||
- kind:
|
||||
UnusedVariable: b
|
||||
location:
|
||||
row: 51
|
||||
column: 8
|
||||
end_location:
|
||||
row: 51
|
||||
column: 9
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,172 +4,155 @@ expression: checks
|
||||
---
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 5
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 5
|
||||
row: 4
|
||||
column: 52
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType1(TypedDict):\n a: int\n b: str"
|
||||
location:
|
||||
row: 5
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 5
|
||||
row: 4
|
||||
column: 52
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 8
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 8
|
||||
row: 7
|
||||
column: 50
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType2(TypedDict):\n a: int\n b: str"
|
||||
location:
|
||||
row: 8
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 8
|
||||
row: 7
|
||||
column: 50
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 11
|
||||
row: 10
|
||||
column: 0
|
||||
end_location:
|
||||
row: 11
|
||||
row: 10
|
||||
column: 44
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType3(TypedDict):\n a: int\n b: str"
|
||||
location:
|
||||
row: 11
|
||||
row: 10
|
||||
column: 0
|
||||
end_location:
|
||||
row: 11
|
||||
row: 10
|
||||
column: 44
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 14
|
||||
row: 13
|
||||
column: 0
|
||||
end_location:
|
||||
row: 14
|
||||
row: 13
|
||||
column: 30
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType4(TypedDict):\n pass"
|
||||
location:
|
||||
row: 14
|
||||
row: 13
|
||||
column: 0
|
||||
end_location:
|
||||
row: 14
|
||||
row: 13
|
||||
column: 30
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 17
|
||||
row: 16
|
||||
column: 0
|
||||
end_location:
|
||||
row: 17
|
||||
row: 16
|
||||
column: 46
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType5(TypedDict):\n a: 'hello'"
|
||||
location:
|
||||
row: 17
|
||||
row: 16
|
||||
column: 0
|
||||
end_location:
|
||||
row: 17
|
||||
row: 16
|
||||
column: 46
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 18
|
||||
row: 17
|
||||
column: 0
|
||||
end_location:
|
||||
row: 18
|
||||
row: 17
|
||||
column: 41
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType6(TypedDict):\n a: 'hello'"
|
||||
location:
|
||||
row: 18
|
||||
row: 17
|
||||
column: 0
|
||||
end_location:
|
||||
row: 18
|
||||
row: 17
|
||||
column: 41
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 21
|
||||
row: 20
|
||||
column: 0
|
||||
end_location:
|
||||
row: 21
|
||||
row: 20
|
||||
column: 56
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType7(TypedDict):\n a: NotRequired[dict]"
|
||||
location:
|
||||
row: 21
|
||||
row: 20
|
||||
column: 0
|
||||
end_location:
|
||||
row: 21
|
||||
row: 20
|
||||
column: 56
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 24
|
||||
row: 23
|
||||
column: 0
|
||||
end_location:
|
||||
row: 24
|
||||
row: 23
|
||||
column: 65
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType8(TypedDict, total=False):\n x: int\n y: int"
|
||||
location:
|
||||
row: 24
|
||||
row: 23
|
||||
column: 0
|
||||
end_location:
|
||||
row: 24
|
||||
row: 23
|
||||
column: 65
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 30
|
||||
row: 29
|
||||
column: 0
|
||||
end_location:
|
||||
row: 30
|
||||
row: 29
|
||||
column: 59
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType10(TypedDict):\n key: Literal['value']"
|
||||
location:
|
||||
row: 30
|
||||
row: 29
|
||||
column: 0
|
||||
end_location:
|
||||
row: 30
|
||||
row: 29
|
||||
column: 59
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
location:
|
||||
row: 33
|
||||
column: 0
|
||||
end_location:
|
||||
row: 33
|
||||
column: 53
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType11(typing.TypedDict):\n key: int"
|
||||
location:
|
||||
row: 33
|
||||
column: 0
|
||||
end_location:
|
||||
row: 33
|
||||
column: 53
|
||||
applied: false
|
||||
|
||||
|
||||
@@ -65,13 +65,4 @@ expression: checks
|
||||
row: 37
|
||||
column: 14
|
||||
fix: ~
|
||||
- kind:
|
||||
UnusedVariable: b
|
||||
location:
|
||||
row: 51
|
||||
column: 8
|
||||
end_location:
|
||||
row: 51
|
||||
column: 9
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ expression: checks
|
||||
UnusedNOQA: ~
|
||||
location:
|
||||
row: 9
|
||||
column: 11
|
||||
column: 9
|
||||
end_location:
|
||||
row: 9
|
||||
column: 17
|
||||
@@ -25,7 +25,7 @@ expression: checks
|
||||
- E501
|
||||
location:
|
||||
row: 13
|
||||
column: 11
|
||||
column: 9
|
||||
end_location:
|
||||
row: 13
|
||||
column: 23
|
||||
@@ -45,7 +45,7 @@ expression: checks
|
||||
- E501
|
||||
location:
|
||||
row: 16
|
||||
column: 11
|
||||
column: 9
|
||||
end_location:
|
||||
row: 16
|
||||
column: 29
|
||||
@@ -61,17 +61,16 @@ expression: checks
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- F841
|
||||
- W191
|
||||
location:
|
||||
row: 19
|
||||
column: 11
|
||||
column: 9
|
||||
end_location:
|
||||
row: 19
|
||||
column: 29
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
content: " # noqa: F841"
|
||||
location:
|
||||
row: 19
|
||||
column: 9
|
||||
@@ -79,107 +78,60 @@ expression: checks
|
||||
row: 19
|
||||
column: 29
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- E501
|
||||
location:
|
||||
row: 23
|
||||
column: 9
|
||||
end_location:
|
||||
row: 23
|
||||
column: 21
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 23
|
||||
column: 9
|
||||
end_location:
|
||||
row: 23
|
||||
column: 21
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedVariable: d
|
||||
location:
|
||||
row: 26
|
||||
column: 4
|
||||
end_location:
|
||||
row: 26
|
||||
column: 5
|
||||
fix: ~
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- E501
|
||||
location:
|
||||
row: 26
|
||||
column: 32
|
||||
end_location:
|
||||
row: 26
|
||||
column: 44
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 26
|
||||
column: 9
|
||||
end_location:
|
||||
row: 26
|
||||
column: 44
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- F841
|
||||
location:
|
||||
row: 52
|
||||
column: 5
|
||||
row: 44
|
||||
column: 3
|
||||
end_location:
|
||||
row: 52
|
||||
row: 44
|
||||
column: 23
|
||||
fix:
|
||||
patch:
|
||||
content: "# noqa: E501"
|
||||
content: " # noqa: E501"
|
||||
location:
|
||||
row: 52
|
||||
column: 5
|
||||
row: 44
|
||||
column: 3
|
||||
end_location:
|
||||
row: 52
|
||||
row: 44
|
||||
column: 23
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- E501
|
||||
location:
|
||||
row: 60
|
||||
column: 5
|
||||
row: 52
|
||||
column: 3
|
||||
end_location:
|
||||
row: 60
|
||||
row: 52
|
||||
column: 17
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 60
|
||||
row: 52
|
||||
column: 3
|
||||
end_location:
|
||||
row: 60
|
||||
row: 52
|
||||
column: 17
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA: ~
|
||||
location:
|
||||
row: 68
|
||||
column: 5
|
||||
row: 60
|
||||
column: 3
|
||||
end_location:
|
||||
row: 68
|
||||
row: 60
|
||||
column: 11
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 68
|
||||
row: 60
|
||||
column: 3
|
||||
end_location:
|
||||
row: 68
|
||||
row: 60
|
||||
column: 11
|
||||
applied: false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user