Compare commits

...

31 Commits

Author SHA1 Message Date
Charlie Marsh
0152814a00 Bump version to 0.0.215 2023-01-07 22:17:29 -05:00
Harutaka Kawamura
0b3fab256b Remove assertNotContains (#1729)
`unittest.TestCase` doens't have a method named `assertNotContains`.
2023-01-07 22:15:48 -05:00
Chammika Mannakkara
212ce4d331 buf-fix: flake8_simplify SIM212 (#1732)
bug-fix in #1717

Use the correct `IfExprWithTwistedArms` struct.
2023-01-07 22:03:48 -05:00
Charlie Marsh
491b1e4968 Move RUFF_CACHE_DIR to Clap's env support (#1733) 2023-01-07 22:01:27 -05:00
Charlie Marsh
8b01b53d89 Move RUFF_CACHE_DIR to Clap's env support (#1733) 2023-01-07 22:01:20 -05:00
messense
f9a5867d3e Add RUFF_FORMAT environment variable support (#1731)
Resolves #1716
2023-01-07 21:54:19 -05:00
Harutaka Kawamura
4149627f19 Add more unittest assert methods to PT009 (#1730) 2023-01-07 21:52:48 -05:00
Charlie Marsh
7d24146df7 Implement --isolated CLI flag (#1727)
Closes #1724.
2023-01-07 18:43:58 -05:00
Charlie Marsh
1c6ef3666c Treat failures to fix TypedDict conversions as debug logs (#1723)
This also allows us to flag the error, even if we can't fix it.

Closes #1212.
2023-01-07 17:51:45 -05:00
Charlie Marsh
16d933fcf5 Respect isort:skip action comment (#1722)
Resolves: #1718.
2023-01-07 17:30:18 -05:00
Charlie Marsh
a9cc56b2ac Add ComparableExpr hierarchy for comparing expressions (#1721) 2023-01-07 17:29:21 -05:00
Charlie Marsh
4de6c26ff9 Automatically remove duplicate dictionary keys (#1710)
For now, to be safe, we're only removing keys with duplicate _values_.

See: #1647.
2023-01-07 16:16:42 -05:00
Charlie Marsh
98856e05d6 Fix clippy errors 2023-01-07 15:49:59 -05:00
Charlie Marsh
edf46c06d0 Bump version to 0.0.214 2023-01-07 15:34:45 -05:00
Chammika Mannakkara
9cfce61f36 flake8_simplify : SIM210, SIM211, SIM212 (#1717) 2023-01-07 15:32:34 -05:00
Charlie Marsh
bdb9a4d1a7 Update CONTRIBUTING.md to point to violations.rs (#1720) 2023-01-07 15:20:21 -05:00
Martin Fischer
82e0c0ced6 structs 9/9: Run cargo test and cargo insta accept 2023-01-07 15:14:58 -05:00
Martin Fischer
6a723b50c7 structs 8/9: Run cargo fix and cargo fmt 2023-01-07 15:14:58 -05:00
Martin Fischer
6208eb7bbf structs 7/9: Manually fix errors introduced in the previous commit 2023-01-07 15:14:58 -05:00
Martin Fischer
43db446dfa structs 6/9: Automatically change CheckKind::* to violations::*
The changes in this commit were generated by running:

for f in $(find src -name '*.rs'); do sed -Ei 's/use crate::registry::.*;/\0use crate::violations;/g' $f; done
for f in $(find src -name '*.rs'); do sed -Ei 's/CheckKind::([A-Z])/violations::\1/g' $f; done
git checkout src/registry.rs src/lib.rs src/lib_wasm.rs src/violations.rs
cargo +nightly fmt
2023-01-07 15:14:58 -05:00
Martin Fischer
3c8fdbf107 structs 5/9: Make Check::new call into() on the passed kind 2023-01-07 15:14:58 -05:00
Martin Fischer
54fb47ea6a structs 4/9: Implement define_rule_mapping! 2023-01-07 15:14:58 -05:00
Martin Fischer
efadfeda96 structs 3/9: Manually implement autofix_formatter for conditional autofixes 2023-01-07 15:14:58 -05:00
Martin Fischer
90198f7563 structs 2/9: Generate violations.rs from registry.rs
# The changes of this commit were generated using the following code:
# (followed by cargo +nightly fmt)

import re
import subprocess
import io

indent = ' ' * 4

def split_words(s):
    return re.split(r'\b', s)

def checkkind_match_arms(f, strip_some=False):
    bodies = {}

    while (line := next(f).rstrip()) != indent * 2 + '}':
        if line.lstrip().startswith('//'):
            continue

        if line.strip() == '':
            continue
        parts = line.split('=>', maxsplit=1)
        if parts[0].strip() == '_':
            break
        left, body = parts
        left = left.strip()
        body = body.strip()
        if body == '{':
            body = ''
            while (line := next(f).rstrip()) != indent * 3 + '}':
                body += line + '\n'
        else:
            body = body.rstrip(',')
        kind = split_words(left)[3]
        if strip_some:
            body = re.sub('\)$', '', re.sub(r'Some\(', '', body, 1).rstrip(), 1)
        if ('(' in left and not '(..)' in left) or '{' in left:
            body = (
                'let '
                + left.replace('CheckKind::', '').replace('CheckCode::', '')
                + ' = self;\n'
                + body
            )
        bodies[kind] = body

    return bodies

with open('src/registry.rs') as f:
    orig_registry_code = f.read()

    # simplify the parsing of multiline match arms
    registry_code = subprocess.check_output(
        ['rustfmt', '+nightly', '--config', 'force_multiline_blocks=true'],
        encoding='utf-8',
        input=orig_registry_code,
    )

    f = io.StringIO(registry_code)

    # 1. Parse the CheckCode enum
    while next(f).strip() != 'pub enum CheckCode {':
        pass

    checkcode_lines = []
    while (line := next(f).strip().rstrip(',')) != '}':
        checkcode_lines.append(line)

    # 2. Parse the CheckKind enum
    while next(f).strip() != 'pub enum CheckKind {':
        pass

    struct_defs = {}

    while (line := next(f).strip()) != '}':
        if line.startswith('//'):
            continue
        line = line.rstrip(',')
        line = re.sub(r'{', '{ pub ', line)
        line = re.sub(r'\(', '(pub ', line)
        line = re.sub(',', ', pub', line)
        kind = split_words(line)[1]
        struct_defs[kind] = 'pub struct ' + line + (';' * (line[-1] != '}'))

    # 3. parse the kind() impl for CheckKind
    while next(f).rstrip() != "    pub fn kind(&self) -> CheckKind {":
        pass
    assert next(f).strip() == 'match self {'

    placeholders = checkkind_match_arms(f)

    # 4. parse the CheckKind -> CheckCode mapping
    while next(f).strip() != "pub fn code(&self) -> &'static CheckCode {":
        pass
    assert next(f).strip() == 'match self {'

    kind2code = {}
    while (line := next(f).strip().rstrip(',')) != '}':
        if line.startswith('//'):
            continue
        parts = re.split(r'\b', line)
        kind2code[parts[3]] = parts[-2]

    code2kind = {code: kind for kind, code in kind2code.items()}

    # 5. parse the body() impl for CheckKind

    while next(f).rstrip() != "    pub fn body(&self) -> String {":
        pass
    assert next(f).strip() == 'match self {'

    bodies = checkkind_match_arms(f)

    # 6. find fixable
    always_fixable = []
    sometimes_fixable = []

    while next(f).strip() != "// Always-fixable checks.":
        pass

    while (line := next(f).strip()) != '// Conditionally-fixable checks.':
        always_fixable.append(split_words(line)[3])

    while (line := next(f).strip()) != '// Non-fixable checks.':
        sometimes_fixable.append(split_words(line)[3])

    # 7. find autofix message
    while next(f).rstrip() != indent + "pub fn commit(&self) -> Option<String> {":
        pass
    assert next(f).strip() == 'match self {'

    autofix_msg = checkkind_match_arms(f, strip_some=True)

reg = '''\
macro_rules! define_rule_mapping {
    ($($code:ident => $mod:ident::$name:ident,)+) => {
        // TODO: implement
    };
}

define_rule_mapping!(
'''
for line in checkcode_lines:
    if line.startswith('//'):
        reg += indent + line + '\n'
        continue
    code = line
    reg += indent + code + ' => violations::' + code2kind[code] + ',\n'
reg += ');\n\n'

with open('src/registry.rs', 'w') as f:
    marker = '#[derive'
    f.write(orig_registry_code.replace(marker, reg + marker, 1))

out = '''\
use itertools::Itertools;

use crate::define_violation;
use crate::flake8_debugger::types::DebuggerUsingType;
use crate::flake8_pytest_style::types::{ParametrizeNameType, ParametrizeValuesType, ParametrizeValuesRowType};
use crate::flake8_quotes::settings::Quote;
use crate::flake8_tidy_imports::settings::Strictness;
use crate::pyupgrade::types::Primitive;
use crate::registry::{
    Branch, DeferralKeyword, EqCmpop, IsCmpop, LiteralType, MockReference, UnusedCodes,
};
use crate::violation::{AlwaysAutofixableViolation, Violation};
'''

for line in checkcode_lines:
    if line.startswith('//'):
        out += '\n' + line + '\n\n'
        continue

    code = line
    kind = code2kind[code]
    out += 'define_violation!(' + struct_defs[kind] + ');\n'
    if kind in always_fixable:
        out += f'impl AlwaysAutofixableViolation for {kind} {{\n'
    else:
        out += f'impl Violation for {kind} {{\n'
    out += 'fn message(&self) -> String {'
    out += bodies[kind]
    out += '}'
    if kind in always_fixable:
        out += 'fn autofix_title(&self) -> String {'
        out += autofix_msg[kind]
        out += '}'
    elif kind in sometimes_fixable:
        out += 'fn autofix_title_formatter(&self) -> Option<fn(&Self) -> String> {'
        out += 'todo!()'
        out += '}'
    out += 'fn placeholder() -> Self {'
    out += placeholders[code].replace('CheckKind::', '')
    out += '}'
    out += '}\n\n'

with open('src/violations.rs', 'w') as f:
    f.write(out)

with open('src/lib.rs', 'r') as f:
    mod = f.read()
with open('src/lib.rs', 'w') as f:
    marker = 'mod violation;'
    f.write(mod.replace(marker, marker + '\nmod violations;'))
2023-01-07 15:14:58 -05:00
Martin Fischer
15084dff9d structs 1/9: Manually preprocess registry.rs 2023-01-07 15:14:58 -05:00
Martin Fischer
eea1379a74 structs 0/9: Introduce Violation trait
For every available rule registry.rs currently defines:

1. A CheckCode variant to identify the rule.
2. A CheckKind variant to represent violations of the rule.
3. A mapping from the CheckCode variant to a placeholder CheckKind instance.
4. A mapping from the CheckKind variant to CheckCode.
5. A mapping from the CheckKind to a string description.
6. A mapping from the CheckKind to a boolean indicating if autofix is available.
7. A mapping from the CheckKind to a string describing the autofix if available.

Since registry.rs defines all of this for every single rule and
ruff has hundreds of rules, this results in the lines specific to
a particular rule to be hundreds of lines apart, making the code
cumbersome to read and edit.

This commit introduces a new Violation trait so that the rule-specific
details of the above steps 5.-7. can be defined next to the rule
implementation. The idea is that once all CheckCode/CheckKind variants
have been converted to this new approach then the steps 1.-4. in
registry.rs could simply be generated via a declarative macro, e.g:

    define_rule_mapping!(
        E501 => pycodestyle::LineTooLong,
        ...
    );

(where `pycodestyle::LineTooLong` would be a struct that implements the
new Violation trait).

The define_rule_mapping! macro would then take care of generating the
CheckCode and CheckKind enums, as well as all of the implementations for
the previously mentioned mappings, by simply calling the methods of the
new Violation trait.

There is another nice benefit from this approach: We want to introduce
more thorough documentation for rules and we want the documentation of a
rule to be defined close by the implementation (so that it's easier to
check if they match and that they're less likely to become out of sync).
Since these new Violation structs can be defined close by the
implementation of a rule we can also use them as an anchor point for the
documentation of a rule by simply adding the documentation in the form
of a Rust doc comment to the struct.
2023-01-07 15:14:58 -05:00
Charlie Marsh
3e80c0d43e Fix clippy errors 2023-01-07 12:53:36 -05:00
Harutaka Kawamura
76a366e05a Trim trailing whitespace when extracting isort directives (#1715) 2023-01-07 12:39:31 -05:00
Harutaka Kawamura
07f72990a9 Implement autofix for PT009 (#1713) 2023-01-07 12:28:25 -05:00
messense
402feffe85 Implement flake8-simplify SIM103 (#1712)
Ref #998

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-01-07 07:33:24 -05:00
Harutaka Kawamura
5cdd7ccdb8 Use text in comment token (#1714)
https://github.com/RustPython/RustPython/pull/4426 has been merged. We
can simplify code using text in comment tokens.
2023-01-07 07:29:04 -05:00
387 changed files with 11478 additions and 5114 deletions

View File

@@ -56,33 +56,35 @@ prior to merging.
There are four phases to adding a new lint rule:
1. Define the rule in `src/registry.rs`.
2. Define the _logic_ for triggering the rule in `src/checkers/ast.rs` (for AST-based checks),
1. Define the violation in `src/violations.rs` (e.g., `ModuleImportNotAtTopOfFile`).
2. Map the violation to a code in `src/registry.rs` (e.g., `E402`).
3. Define the _logic_ for triggering the violation in `src/checkers/ast.rs` (for AST-based checks),
`src/checkers/tokens.rs` (for token-based checks), or `src/checkers/lines.rs` (for text-based checks).
3. Add a test fixture.
4. Update the generated files (documentation and generated code).
4. Add a test fixture.
5. Update the generated files (documentation and generated code).
To define the rule, open up `src/registry.rs`. You'll need to define both a `CheckCode` and
`CheckKind`. As an example, you can grep for `E402` and `ModuleImportNotAtTopOfFile`, and follow the
pattern implemented therein.
To define the violation, open up `src/violations.rs`, and define a new struct using the
`define_violation!` macro. There are plenty of examples in that file, so feel free to pattern-match
against the existing structs.
To trigger the rule, you'll likely want to augment the logic in `src/checkers/ast.rs`, which defines
the Python AST visitor, responsible for iterating over the abstract syntax tree and collecting
lint-rule violations as it goes. If you need to inspect the AST, you can run
`cargo +nightly dev print-ast` with a Python file. Grep for the `Check::new` invocations to
understand how other, similar rules are implemented.
To trigger the violation, you'll likely want to augment the logic in `src/checkers/ast.rs`, which
defines the Python AST visitor, responsible for iterating over the abstract syntax tree and
collecting diagnostics as it goes.
If you need to inspect the AST, you can run `cargo +nightly dev print-ast` with a Python file. Grep
for the `Check::new` invocations to understand how other, similar rules are implemented.
To add a test fixture, create a file under `resources/test/fixtures/[plugin-name]`, named to match
the `CheckCode` you defined earlier (e.g., `E402.py`). This file should contain a variety of
the code you defined earlier (e.g., `E402.py`). This file should contain a variety of
violations and non-violations designed to evaluate and demonstrate the behavior of your lint rule.
Run `cargo +nightly dev generate-all` to generate the code for your new fixture. Then run Ruff
locally with (e.g.) `cargo run resources/test/fixtures/pycodestyle/E402.py --no-cache --select E402`.
Once you're satisfied with the output, codify the behavior as a snapshot test by adding a new
`test_case` macro in the relevant `src/[plugin-name]/mod.rs` file. Then, run `cargo test`. Your
test will fail, but you'll be prompted to follow-up with `cargo insta review`. Accept the generated
snapshot, then commit the snapshot file alongside the rest of your changes.
`test_case` macro in the relevant `src/[plugin-name]/mod.rs` file. Then, run `cargo test --all`.
Your test will fail, but you'll be prompted to follow-up with `cargo insta review`. Accept the
generated snapshot, then commit the snapshot file alongside the rest of your changes.
Finally, regenerate the documentation and generated code with `cargo +nightly dev generate-all`.

View File

@@ -4,7 +4,7 @@ Thank you for taking the time to report an issue! We're glad to have you involve
If you're filing a bug report, please consider including the following information:
- A minimal code snippet that reproduces the bug.
- The command you invoked (e.g., `ruff /path/to/file.py --fix`).
- The command you invoked (e.g., `ruff /path/to/file.py --fix`), ideally including the `--isolated` flag.
- The current Ruff settings (any relevant sections from your `pyproject.toml`).
- The current Ruff version (`ruff --version`).
-->

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.213
rev: v0.0.215
hooks:
- id: ruff

16
Cargo.lock generated
View File

@@ -735,7 +735,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.0.213-dev.0"
version = "0.0.215-dev.0"
dependencies = [
"anyhow",
"clap 4.0.32",
@@ -1873,7 +1873,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.213"
version = "0.0.215"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -1941,7 +1941,7 @@ dependencies = [
[[package]]
name = "ruff_dev"
version = "0.0.213"
version = "0.0.215"
dependencies = [
"anyhow",
"clap 4.0.32",
@@ -1961,7 +1961,7 @@ dependencies = [
[[package]]
name = "ruff_macros"
version = "0.0.213"
version = "0.0.215"
dependencies = [
"once_cell",
"proc-macro2",
@@ -2005,7 +2005,7 @@ dependencies = [
[[package]]
name = "rustpython-ast"
version = "0.1.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=4d53c7cb27c0379adf8b51c4d3d0d2174f41d590#4d53c7cb27c0379adf8b51c4d3d0d2174f41d590"
source = "git+https://github.com/RustPython/RustPython.git?rev=d532160333ffeb6dbeca2c2728c2391cd1e53b7f#d532160333ffeb6dbeca2c2728c2391cd1e53b7f"
dependencies = [
"num-bigint",
"rustpython-common",
@@ -2015,7 +2015,7 @@ dependencies = [
[[package]]
name = "rustpython-common"
version = "0.0.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=4d53c7cb27c0379adf8b51c4d3d0d2174f41d590#4d53c7cb27c0379adf8b51c4d3d0d2174f41d590"
source = "git+https://github.com/RustPython/RustPython.git?rev=d532160333ffeb6dbeca2c2728c2391cd1e53b7f#d532160333ffeb6dbeca2c2728c2391cd1e53b7f"
dependencies = [
"ascii",
"bitflags",
@@ -2040,7 +2040,7 @@ dependencies = [
[[package]]
name = "rustpython-compiler-core"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=4d53c7cb27c0379adf8b51c4d3d0d2174f41d590#4d53c7cb27c0379adf8b51c4d3d0d2174f41d590"
source = "git+https://github.com/RustPython/RustPython.git?rev=d532160333ffeb6dbeca2c2728c2391cd1e53b7f#d532160333ffeb6dbeca2c2728c2391cd1e53b7f"
dependencies = [
"bincode",
"bitflags",
@@ -2057,7 +2057,7 @@ dependencies = [
[[package]]
name = "rustpython-parser"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=4d53c7cb27c0379adf8b51c4d3d0d2174f41d590#4d53c7cb27c0379adf8b51c4d3d0d2174f41d590"
source = "git+https://github.com/RustPython/RustPython.git?rev=d532160333ffeb6dbeca2c2728c2391cd1e53b7f#d532160333ffeb6dbeca2c2728c2391cd1e53b7f"
dependencies = [
"ahash",
"anyhow",

View File

@@ -6,7 +6,7 @@ members = [
[package]
name = "ruff"
version = "0.0.213"
version = "0.0.215"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
edition = "2021"
rust-version = "1.65.0"
@@ -29,7 +29,7 @@ bitflags = { version = "1.3.2" }
cachedir = { version = "0.3.0" }
cfg-if = { version = "1.0.0" }
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
clap = { version = "4.0.1", features = ["derive"] }
clap = { version = "4.0.1", features = ["derive", "env"] }
clap_complete_command = { version = "0.4.0" }
colored = { version = "2.0.0" }
dirs = { version = "4.0.0" }
@@ -51,11 +51,11 @@ path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix
quick-junit = { version = "0.3.2" }
regex = { version = "1.6.0" }
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
ruff_macros = { version = "0.0.213", path = "ruff_macros" }
ruff_macros = { version = "0.0.215", path = "ruff_macros" }
rustc-hash = { version = "1.1.0" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
schemars = { version = "0.8.11" }
semver = { version = "1.0.16" }
serde = { version = "1.0.147", features = ["derive"] }

View File

@@ -180,7 +180,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
```yaml
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.213'
rev: 'v0.0.215'
hooks:
- id: ruff
# Respect `exclude` and `extend-exclude` settings.
@@ -341,6 +341,8 @@ Options:
Avoid writing any fixed files back; instead, output a diff for each changed file to stdout
-n, --no-cache
Disable cache reads
--isolated
Ignore all configuration files
--select <SELECT>
Comma-separated list of error codes to enable (or ALL, to enable all checks)
--extend-select <EXTEND_SELECT>
@@ -360,11 +362,11 @@ Options:
--per-file-ignores <PER_FILE_IGNORES>
List of mappings from file pattern to code to exclude
--format <FORMAT>
Output serialization format for error messages [possible values: text, json, junit, grouped, github, gitlab]
Output serialization format for error messages [env: RUFF_FORMAT=] [possible values: text, json, junit, grouped, github, gitlab]
--stdin-filename <STDIN_FILENAME>
The name of the file when passing it through stdin
--cache-dir <CACHE_DIR>
Path to the cache directory
Path to the cache directory [env: RUFF_CACHE_DIR=]
--show-source
Show violations with source code
--respect-gitignore
@@ -551,8 +553,8 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/) on PyPI.
| F524 | StringDotFormatMissingArguments | '...'.format(...) is missing argument(s) for placeholder(s): ... | |
| F525 | StringDotFormatMixingAutomatic | '...'.format(...) mixes automatic and manual numbering | |
| F541 | FStringMissingPlaceholders | f-string without any placeholders | 🛠 |
| F601 | MultiValueRepeatedKeyLiteral | Dictionary key literal repeated | |
| F602 | MultiValueRepeatedKeyVariable | Dictionary key `...` repeated | |
| F601 | MultiValueRepeatedKeyLiteral | Dictionary key literal `...` repeated | 🛠 |
| F602 | MultiValueRepeatedKeyVariable | Dictionary key `...` repeated | 🛠 |
| F621 | ExpressionsInStarAssignment | Too many expressions in star-unpacking assignment | |
| F622 | TwoStarredExpressions | Two starred expressions in assignment | |
| F631 | AssertTuple | Assert test is a non-empty tuple, which is always `True` | |
@@ -919,7 +921,7 @@ For more, see [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style
| PT006 | ParametrizeNamesWrongType | Wrong name(s) type in `@pytest.mark.parametrize`, expected `tuple` | 🛠 |
| PT007 | ParametrizeValuesWrongType | Wrong values type in `@pytest.mark.parametrize` expected `list` of `tuple` | |
| PT008 | PatchWithLambda | Use `return_value=` instead of patching with `lambda` | |
| PT009 | UnittestAssertion | Use a regular `assert` instead of unittest-style `...` | |
| PT009 | UnittestAssertion | Use a regular `assert` instead of unittest-style `...` | 🛠 |
| PT010 | RaisesWithoutException | set the expected exception in `pytest.raises()` | |
| PT011 | RaisesTooBroad | `pytest.raises(...)` is too broad, set the `match` parameter or use a more specific exception | |
| PT012 | RaisesWithMultipleStatements | `pytest.raises()` block should contain a single simple statement | |
@@ -971,9 +973,10 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/
| ---- | ---- | ------- | --- |
| SIM101 | DuplicateIsinstanceCall | Multiple `isinstance` calls for `...`, merge into a single call | 🛠 |
| SIM102 | NestedIfStatements | Use a single `if` statement instead of nested `if` statements | |
| SIM103 | ReturnBoolConditionDirectly | Return the condition `...` directly | 🛠 |
| SIM105 | UseContextlibSuppress | Use `contextlib.suppress(...)` instead of try-except-pass | |
| SIM107 | ReturnInTryExceptFinally | Don't use `return` in `try`/`except` and `finally` | |
| SIM108 | UseTernaryOperator | Use ternary operator `..` instead of if-else-block | 🛠 |
| SIM108 | UseTernaryOperator | Use ternary operator `...` instead of if-else-block | 🛠 |
| SIM109 | CompareWithTuple | Use `value in (..., ...)` instead of `value == ... or value == ...` | 🛠 |
| SIM110 | ConvertLoopToAny | Use `return any(x for x in y)` instead of `for` loop | 🛠 |
| SIM111 | ConvertLoopToAll | Use `return all(x for x in y)` instead of `for` loop | 🛠 |
@@ -982,6 +985,9 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/
| SIM201 | NegateEqualOp | Use `left != right` instead of `not left == right` | 🛠 |
| SIM202 | NegateNotEqualOp | Use `left == right` instead of `not left != right` | 🛠 |
| SIM208 | DoubleNegation | Use `expr` instead of `not (not expr)` | 🛠 |
| SIM210 | IfExprWithTrueFalse | Use `bool(expr)` instead of `True if expr else False` | 🛠 |
| SIM211 | IfExprWithFalseTrue | Use `not expr` instead of `False if expr else True` | 🛠 |
| SIM212 | IfExprWithTwistedArms | Use `b if b else a` instead of `a if not b else b` | 🛠 |
| SIM220 | AAndNotA | Use `False` instead of `... and not ...` | 🛠 |
| SIM221 | AOrNotA | Use `True` instead of `... or not ...` | 🛠 |
| SIM222 | OrTrue | Use `True` instead of `... or True` | 🛠 |

View File

@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8_to_ruff"
version = "0.0.213"
version = "0.0.215"
dependencies = [
"anyhow",
"clap",
@@ -1975,7 +1975,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.213"
version = "0.0.215"
dependencies = [
"anyhow",
"bincode",

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.0.213-dev.0"
version = "0.0.215-dev.0"
edition = "2021"
[lib]

View File

@@ -4,7 +4,7 @@ build-backend = "maturin"
[project]
name = "ruff"
version = "0.0.213"
version = "0.0.215"
description = "An extremely fast Python linter, written in Rust."
authors = [
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },

View File

@@ -1,9 +1,76 @@
import pytest
import unittest
def test_xxx():
assert 1 == 1 # OK no parameters
class Test(unittest.TestCase):
def test_xxx(self):
assert 1 == 1 # OK no parameters
def test_assert_true(self):
expr = 1
msg = "Must be True"
self.assertTrue(expr) # Error
self.assertTrue(expr=expr) # Error
self.assertTrue(expr, msg) # Error
self.assertTrue(expr=expr, msg=msg) # Error
self.assertTrue(msg=msg, expr=expr) # Error
self.assertTrue(*(expr, msg)) # Error, unfixable
self.assertTrue(**{"expr": expr, "msg": msg}) # Error, unfixable
self.assertTrue(msg=msg, expr=expr, unexpected_arg=False) # Error, unfixable
self.assertTrue(msg=msg) # Error, unfixable
def test_xxx():
self.assertEqual(1, 1) # Error
def test_assert_false(self):
self.assertFalse(True) # Error
def test_assert_equal(self):
self.assertEqual(1, 2) # Error
def test_assert_not_equal(self):
self.assertNotEqual(1, 1) # Error
def test_assert_greater(self):
self.assertGreater(1, 2) # Error
def test_assert_greater_equal(self):
self.assertGreaterEqual(1, 2) # Error
def test_assert_less(self):
self.assertLess(2, 1) # Error
def test_assert_less_equal(self):
self.assertLessEqual(1, 2) # Error
def test_assert_in(self):
self.assertIn(1, [2, 3]) # Error
def test_assert_not_in(self):
self.assertNotIn(2, [2, 3]) # Error
def test_assert_is_none(self):
self.assertIsNone(0) # Error
def test_assert_is_not_none(self):
self.assertIsNotNone(0) # Error
def test_assert_is(self):
self.assertIs([], []) # Error
def test_assert_is_not(self):
self.assertIsNot(1, 1) # Error
def test_assert_is_instance(self):
self.assertIsInstance(1, str) # Error
def test_assert_is_not_instance(self):
self.assertNotIsInstance(1, int) # Error
def test_assert_regex(self):
self.assertRegex("abc", r"def") # Error
def test_assert_not_regex(self):
self.assertNotRegex("abc", r"abc") # Error
def test_assert_regexp_matches(self):
self.assertRegexpMatches("abc", r"def") # Error
def test_assert_not_regexp_matches(self):
self.assertNotRegex("abc", r"abc") # Error

View File

@@ -0,0 +1,20 @@
def f():
if a: # SIM103
return True
else:
return False
def f():
if a: # OK
foo()
return True
else:
return False
def f():
if a: # OK
return "foo"
else:
return False

View File

@@ -0,0 +1,7 @@
a = True if b else False # SIM210
a = True if b != c else False # SIM210
a = True if b + c else False # SIM210
a = False if b else True # OK

View File

@@ -0,0 +1,7 @@
a = False if b else True # SIM211
a = False if b != c else True # SIM211
a = False if b + c else True # SIM211
a = True if b else False # OK

View File

@@ -0,0 +1,7 @@
c = b if not a else a # SIM212
c = b + c if not a else a # SIM212
c = b if not x else a # OK
c = a if a else b # OK

View File

@@ -1,10 +1,20 @@
# isort: off
import sys
import os
import collections
# isort: on
def f():
# isort: off
import sys
import os
import collections
# isort: on
import sys
import os # isort: skip
import collections
import abc
def f():
import sys
import os # isort: skip
import collections
import abc
def f():
import sys
import os # isort:skip
import collections
import abc

View File

@@ -3,7 +3,10 @@ import f
# isort: split
import a
import b
import c
import d
# isort: split
import a
import b

View File

@@ -1,2 +1,4 @@
def x():

View File

@@ -10,3 +10,41 @@ x = {
b"123": 1,
b"123": 4,
}
x = {
"a": 1,
"a": 2,
"a": 3,
"a": 3,
}
x = {
"a": 1,
"a": 2,
"a": 3,
"a": 3,
"a": 4,
}
x = {
"a": 1,
"a": 1,
"a": 2,
"a": 3,
"a": 4,
}
x = {
a: 1,
"a": 1,
a: 1,
"a": 2,
a: 2,
"a": 3,
a: 3,
"a": 3,
a: 4,
}
x = {"a": 1, "a": 1}
x = {"a": 1, "b": 2, "a": 1}

View File

@@ -5,3 +5,41 @@ x = {
a: 2,
b: 3,
}
x = {
a: 1,
a: 2,
a: 3,
a: 3,
}
x = {
a: 1,
a: 2,
a: 3,
a: 3,
a: 4,
}
x = {
a: 1,
a: 1,
a: 2,
a: 3,
a: 4,
}
x = {
a: 1,
"a": 1,
a: 1,
"a": 2,
a: 2,
"a": 3,
a: 3,
"a": 3,
a: 4,
}
x = {a: 1, a: 1}
x = {a: 1, b: 2, a: 1}

View File

@@ -941,6 +941,7 @@
"SIM10",
"SIM101",
"SIM102",
"SIM103",
"SIM105",
"SIM107",
"SIM108",
@@ -955,6 +956,10 @@
"SIM201",
"SIM202",
"SIM208",
"SIM21",
"SIM210",
"SIM211",
"SIM212",
"SIM22",
"SIM220",
"SIM221",

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_dev"
version = "0.0.213"
version = "0.0.215"
edition = "2021"
[dependencies]
@@ -10,9 +10,9 @@ itertools = { version = "0.10.5" }
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
once_cell = { version = "1.16.0" }
ruff = { path = ".." }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "d532160333ffeb6dbeca2c2728c2391cd1e53b7f" }
schemars = { version = "0.8.11" }
serde_json = {version="1.0.91"}
strum = { version = "0.24.1", features = ["strum_macros"] }

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_macros"
version = "0.0.213"
version = "0.0.215"
edition = "2021"
[lib]

524
src/ast/comparable.rs Normal file
View File

@@ -0,0 +1,524 @@
//! An equivalent object hierarchy to the `Expr` hierarchy, but with the ability
//! to compare expressions for equality (via `Eq` and `Hash`).
use num_bigint::BigInt;
use rustpython_ast::{
Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, Expr, ExprContext, ExprKind, Keyword,
Operator, Unaryop,
};
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableExprContext {
Load,
Store,
Del,
}
impl From<&ExprContext> for ComparableExprContext {
fn from(ctx: &ExprContext) -> Self {
match ctx {
ExprContext::Load => Self::Load,
ExprContext::Store => Self::Store,
ExprContext::Del => Self::Del,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableBoolop {
And,
Or,
}
impl From<&Boolop> for ComparableBoolop {
fn from(op: &Boolop) -> Self {
match op {
Boolop::And => Self::And,
Boolop::Or => Self::Or,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableOperator {
Add,
Sub,
Mult,
MatMult,
Div,
Mod,
Pow,
LShift,
RShift,
BitOr,
BitXor,
BitAnd,
FloorDiv,
}
impl From<&Operator> for ComparableOperator {
fn from(op: &Operator) -> Self {
match op {
Operator::Add => Self::Add,
Operator::Sub => Self::Sub,
Operator::Mult => Self::Mult,
Operator::MatMult => Self::MatMult,
Operator::Div => Self::Div,
Operator::Mod => Self::Mod,
Operator::Pow => Self::Pow,
Operator::LShift => Self::LShift,
Operator::RShift => Self::RShift,
Operator::BitOr => Self::BitOr,
Operator::BitXor => Self::BitXor,
Operator::BitAnd => Self::BitAnd,
Operator::FloorDiv => Self::FloorDiv,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableUnaryop {
Invert,
Not,
UAdd,
USub,
}
impl From<&Unaryop> for ComparableUnaryop {
fn from(op: &Unaryop) -> Self {
match op {
Unaryop::Invert => Self::Invert,
Unaryop::Not => Self::Not,
Unaryop::UAdd => Self::UAdd,
Unaryop::USub => Self::USub,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableCmpop {
Eq,
NotEq,
Lt,
LtE,
Gt,
GtE,
Is,
IsNot,
In,
NotIn,
}
impl From<&Cmpop> for ComparableCmpop {
fn from(op: &Cmpop) -> Self {
match op {
Cmpop::Eq => Self::Eq,
Cmpop::NotEq => Self::NotEq,
Cmpop::Lt => Self::Lt,
Cmpop::LtE => Self::LtE,
Cmpop::Gt => Self::Gt,
Cmpop::GtE => Self::GtE,
Cmpop::Is => Self::Is,
Cmpop::IsNot => Self::IsNot,
Cmpop::In => Self::In,
Cmpop::NotIn => Self::NotIn,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableConstant<'a> {
None,
Bool(&'a bool),
Str(&'a str),
Bytes(&'a [u8]),
Int(&'a BigInt),
Tuple(Vec<ComparableConstant<'a>>),
Float(u64),
Complex { real: u64, imag: u64 },
Ellipsis,
}
impl<'a> From<&'a Constant> for ComparableConstant<'a> {
fn from(constant: &'a Constant) -> Self {
match constant {
Constant::None => Self::None,
Constant::Bool(value) => Self::Bool(value),
Constant::Str(value) => Self::Str(value),
Constant::Bytes(value) => Self::Bytes(value),
Constant::Int(value) => Self::Int(value),
Constant::Tuple(value) => {
Self::Tuple(value.iter().map(std::convert::Into::into).collect())
}
Constant::Float(value) => Self::Float(value.to_bits()),
Constant::Complex { real, imag } => Self::Complex {
real: real.to_bits(),
imag: imag.to_bits(),
},
Constant::Ellipsis => Self::Ellipsis,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ComparableArguments<'a> {
pub posonlyargs: Vec<ComparableArg<'a>>,
pub args: Vec<ComparableArg<'a>>,
pub vararg: Option<ComparableArg<'a>>,
pub kwonlyargs: Vec<ComparableArg<'a>>,
pub kw_defaults: Vec<ComparableExpr<'a>>,
pub kwarg: Option<ComparableArg<'a>>,
pub defaults: Vec<ComparableExpr<'a>>,
}
impl<'a> From<&'a Arguments> for ComparableArguments<'a> {
fn from(arguments: &'a Arguments) -> Self {
Self {
posonlyargs: arguments
.posonlyargs
.iter()
.map(std::convert::Into::into)
.collect(),
args: arguments
.args
.iter()
.map(std::convert::Into::into)
.collect(),
vararg: arguments.vararg.as_ref().map(std::convert::Into::into),
kwonlyargs: arguments
.kwonlyargs
.iter()
.map(std::convert::Into::into)
.collect(),
kw_defaults: arguments
.kw_defaults
.iter()
.map(std::convert::Into::into)
.collect(),
kwarg: arguments.vararg.as_ref().map(std::convert::Into::into),
defaults: arguments
.defaults
.iter()
.map(std::convert::Into::into)
.collect(),
}
}
}
impl<'a> From<&'a Box<Arg>> for ComparableArg<'a> {
fn from(arg: &'a Box<Arg>) -> Self {
(&**arg).into()
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ComparableArg<'a> {
pub arg: &'a str,
pub annotation: Option<Box<ComparableExpr<'a>>>,
pub type_comment: Option<&'a str>,
}
impl<'a> From<&'a Arg> for ComparableArg<'a> {
fn from(arg: &'a Arg) -> Self {
Self {
arg: &arg.node.arg,
annotation: arg.node.annotation.as_ref().map(std::convert::Into::into),
type_comment: arg.node.type_comment.as_deref(),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ComparableKeyword<'a> {
pub arg: Option<&'a str>,
pub value: ComparableExpr<'a>,
}
impl<'a> From<&'a Keyword> for ComparableKeyword<'a> {
fn from(keyword: &'a Keyword) -> Self {
Self {
arg: keyword.node.arg.as_deref(),
value: (&keyword.node.value).into(),
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ComparableComprehension<'a> {
pub target: ComparableExpr<'a>,
pub iter: ComparableExpr<'a>,
pub ifs: Vec<ComparableExpr<'a>>,
pub is_async: &'a usize,
}
impl<'a> From<&'a Comprehension> for ComparableComprehension<'a> {
fn from(comprehension: &'a Comprehension) -> Self {
Self {
target: (&comprehension.target).into(),
iter: (&comprehension.iter).into(),
ifs: comprehension
.ifs
.iter()
.map(std::convert::Into::into)
.collect(),
is_async: &comprehension.is_async,
}
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ComparableExpr<'a> {
BoolOp {
op: ComparableBoolop,
values: Vec<ComparableExpr<'a>>,
},
NamedExpr {
target: Box<ComparableExpr<'a>>,
value: Box<ComparableExpr<'a>>,
},
BinOp {
left: Box<ComparableExpr<'a>>,
op: ComparableOperator,
right: Box<ComparableExpr<'a>>,
},
UnaryOp {
op: ComparableUnaryop,
operand: Box<ComparableExpr<'a>>,
},
Lambda {
args: ComparableArguments<'a>,
body: Box<ComparableExpr<'a>>,
},
IfExp {
test: Box<ComparableExpr<'a>>,
body: Box<ComparableExpr<'a>>,
orelse: Box<ComparableExpr<'a>>,
},
Dict {
keys: Vec<ComparableExpr<'a>>,
values: Vec<ComparableExpr<'a>>,
},
Set {
elts: Vec<ComparableExpr<'a>>,
},
ListComp {
elt: Box<ComparableExpr<'a>>,
generators: Vec<ComparableComprehension<'a>>,
},
SetComp {
elt: Box<ComparableExpr<'a>>,
generators: Vec<ComparableComprehension<'a>>,
},
DictComp {
key: Box<ComparableExpr<'a>>,
value: Box<ComparableExpr<'a>>,
generators: Vec<ComparableComprehension<'a>>,
},
GeneratorExp {
elt: Box<ComparableExpr<'a>>,
generators: Vec<ComparableComprehension<'a>>,
},
Await {
value: Box<ComparableExpr<'a>>,
},
Yield {
value: Option<Box<ComparableExpr<'a>>>,
},
YieldFrom {
value: Box<ComparableExpr<'a>>,
},
Compare {
left: Box<ComparableExpr<'a>>,
ops: Vec<ComparableCmpop>,
comparators: Vec<ComparableExpr<'a>>,
},
Call {
func: Box<ComparableExpr<'a>>,
args: Vec<ComparableExpr<'a>>,
keywords: Vec<ComparableKeyword<'a>>,
},
FormattedValue {
value: Box<ComparableExpr<'a>>,
conversion: &'a usize,
format_spec: Option<Box<ComparableExpr<'a>>>,
},
JoinedStr {
values: Vec<ComparableExpr<'a>>,
},
Constant {
value: ComparableConstant<'a>,
kind: Option<&'a str>,
},
Attribute {
value: Box<ComparableExpr<'a>>,
attr: &'a str,
ctx: ComparableExprContext,
},
Subscript {
value: Box<ComparableExpr<'a>>,
slice: Box<ComparableExpr<'a>>,
ctx: ComparableExprContext,
},
Starred {
value: Box<ComparableExpr<'a>>,
ctx: ComparableExprContext,
},
Name {
id: &'a str,
ctx: ComparableExprContext,
},
List {
elts: Vec<ComparableExpr<'a>>,
ctx: ComparableExprContext,
},
Tuple {
elts: Vec<ComparableExpr<'a>>,
ctx: ComparableExprContext,
},
Slice {
lower: Option<Box<ComparableExpr<'a>>>,
upper: Option<Box<ComparableExpr<'a>>>,
step: Option<Box<ComparableExpr<'a>>>,
},
}
impl<'a> From<&'a Box<Expr>> for Box<ComparableExpr<'a>> {
fn from(expr: &'a Box<Expr>) -> Self {
Box::new((&**expr).into())
}
}
impl<'a> From<&'a Expr> for ComparableExpr<'a> {
fn from(expr: &'a Expr) -> Self {
match &expr.node {
ExprKind::BoolOp { op, values } => Self::BoolOp {
op: op.into(),
values: values.iter().map(std::convert::Into::into).collect(),
},
ExprKind::NamedExpr { target, value } => Self::NamedExpr {
target: target.into(),
value: value.into(),
},
ExprKind::BinOp { left, op, right } => Self::BinOp {
left: left.into(),
op: op.into(),
right: right.into(),
},
ExprKind::UnaryOp { op, operand } => Self::UnaryOp {
op: op.into(),
operand: operand.into(),
},
ExprKind::Lambda { args, body } => Self::Lambda {
args: (&**args).into(),
body: body.into(),
},
ExprKind::IfExp { test, body, orelse } => Self::IfExp {
test: test.into(),
body: body.into(),
orelse: orelse.into(),
},
ExprKind::Dict { keys, values } => Self::Dict {
keys: keys.iter().map(std::convert::Into::into).collect(),
values: values.iter().map(std::convert::Into::into).collect(),
},
ExprKind::Set { elts } => Self::Set {
elts: elts.iter().map(std::convert::Into::into).collect(),
},
ExprKind::ListComp { elt, generators } => Self::ListComp {
elt: elt.into(),
generators: generators.iter().map(std::convert::Into::into).collect(),
},
ExprKind::SetComp { elt, generators } => Self::SetComp {
elt: elt.into(),
generators: generators.iter().map(std::convert::Into::into).collect(),
},
ExprKind::DictComp {
key,
value,
generators,
} => Self::DictComp {
key: key.into(),
value: value.into(),
generators: generators.iter().map(std::convert::Into::into).collect(),
},
ExprKind::GeneratorExp { elt, generators } => Self::GeneratorExp {
elt: elt.into(),
generators: generators.iter().map(std::convert::Into::into).collect(),
},
ExprKind::Await { value } => Self::Await {
value: value.into(),
},
ExprKind::Yield { value } => Self::Yield {
value: value.as_ref().map(std::convert::Into::into),
},
ExprKind::YieldFrom { value } => Self::YieldFrom {
value: value.into(),
},
ExprKind::Compare {
left,
ops,
comparators,
} => Self::Compare {
left: left.into(),
ops: ops.iter().map(std::convert::Into::into).collect(),
comparators: comparators.iter().map(std::convert::Into::into).collect(),
},
ExprKind::Call {
func,
args,
keywords,
} => Self::Call {
func: func.into(),
args: args.iter().map(std::convert::Into::into).collect(),
keywords: keywords.iter().map(std::convert::Into::into).collect(),
},
ExprKind::FormattedValue {
value,
conversion,
format_spec,
} => Self::FormattedValue {
value: value.into(),
conversion,
format_spec: format_spec.as_ref().map(std::convert::Into::into),
},
ExprKind::JoinedStr { values } => Self::JoinedStr {
values: values.iter().map(std::convert::Into::into).collect(),
},
ExprKind::Constant { value, kind } => Self::Constant {
value: value.into(),
kind: kind.as_ref().map(String::as_str),
},
ExprKind::Attribute { value, attr, ctx } => Self::Attribute {
value: value.into(),
attr,
ctx: ctx.into(),
},
ExprKind::Subscript { value, slice, ctx } => Self::Subscript {
value: value.into(),
slice: slice.into(),
ctx: ctx.into(),
},
ExprKind::Starred { value, ctx } => Self::Starred {
value: value.into(),
ctx: ctx.into(),
},
ExprKind::Name { id, ctx } => Self::Name {
id,
ctx: ctx.into(),
},
ExprKind::List { elts, ctx } => Self::List {
elts: elts.iter().map(std::convert::Into::into).collect(),
ctx: ctx.into(),
},
ExprKind::Tuple { elts, ctx } => Self::Tuple {
elts: elts.iter().map(std::convert::Into::into).collect(),
ctx: ctx.into(),
},
ExprKind::Slice { lower, upper, step } => Self::Slice {
lower: lower.as_ref().map(std::convert::Into::into),
upper: upper.as_ref().map(std::convert::Into::into),
step: step.as_ref().map(std::convert::Into::into),
},
}
}
}

View File

@@ -1,5 +1,6 @@
pub mod branch_detection;
pub mod cast;
pub mod comparable;
pub mod function_type;
pub mod helpers;
pub mod operations;

View File

@@ -1,6 +1,5 @@
use std::collections::hash_map::DefaultHasher;
use std::fs;
use std::fs::{create_dir_all, File, Metadata};
use std::hash::{Hash, Hasher};
use std::io::Write;
use std::path::{Path, PathBuf};
@@ -8,16 +7,15 @@ use std::path::{Path, PathBuf};
use anyhow::Result;
use filetime::FileTime;
use log::error;
use once_cell::sync::Lazy;
use path_absolutize::Absolutize;
use serde::{Deserialize, Serialize};
use crate::message::Message;
use crate::settings::{flags, Settings};
pub const CACHE_DIR_NAME: &str = ".ruff_cache";
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
static CACHE_DIR: Lazy<Option<String>> = Lazy::new(|| std::env::var("RUFF_CACHE_DIR").ok());
pub const DEFAULT_CACHE_DIR_NAME: &str = ".ruff_cache";
#[derive(Serialize, Deserialize)]
struct CacheMetadata {
@@ -39,9 +37,7 @@ struct CheckResult {
/// Return the cache directory for a given project root. Defers to the
/// `RUFF_CACHE_DIR` environment variable, if set.
pub fn cache_dir(project_root: &Path) -> PathBuf {
CACHE_DIR
.as_ref()
.map_or_else(|| project_root.join(DEFAULT_CACHE_DIR_NAME), PathBuf::from)
project_root.join(CACHE_DIR_NAME)
}
fn content_dir() -> &'static Path {
@@ -60,7 +56,7 @@ fn cache_key<P: AsRef<Path>>(path: P, settings: &Settings, autofix: flags::Autof
/// Initialize the cache at the specified `Path`.
pub fn init(path: &Path) -> Result<()> {
// Create the cache directories.
create_dir_all(path.join(content_dir()))?;
fs::create_dir_all(path.join(content_dir()))?;
// Add the CACHEDIR.TAG.
if !cachedir::is_tagged(path)? {
@@ -70,7 +66,7 @@ pub fn init(path: &Path) -> Result<()> {
// Add the .gitignore.
let gitignore_path = path.join(".gitignore");
if !gitignore_path.exists() {
let mut file = File::create(gitignore_path)?;
let mut file = fs::File::create(gitignore_path)?;
file.write_all(b"*")?;
}
@@ -91,7 +87,7 @@ fn read_sync(cache_dir: &Path, key: u64) -> Result<Vec<u8>, std::io::Error> {
/// Get a value from the cache.
pub fn get<P: AsRef<Path>>(
path: P,
metadata: &Metadata,
metadata: &fs::Metadata,
settings: &Settings,
autofix: flags::Autofix,
) -> Option<Vec<Message>> {
@@ -115,7 +111,7 @@ pub fn get<P: AsRef<Path>>(
/// Set a value in the cache.
pub fn set<P: AsRef<Path>>(
path: P,
metadata: &Metadata,
metadata: &fs::Metadata,
settings: &Settings,
autofix: flags::Autofix,
messages: &[Message],

View File

@@ -30,7 +30,7 @@ use crate::python::builtins::{BUILTINS, MAGIC_GLOBALS};
use crate::python::future::ALL_FEATURE_NAMES;
use crate::python::typing;
use crate::python::typing::SubscriptKind;
use crate::registry::{Check, CheckCode, CheckKind, DeferralKeyword};
use crate::registry::{Check, CheckCode, DeferralKeyword};
use crate::settings::types::PythonVersion;
use crate::settings::{flags, Settings};
use crate::source_code_locator::SourceCodeLocator;
@@ -42,7 +42,8 @@ use crate::{
flake8_debugger, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions,
flake8_pie, flake8_print, flake8_pytest_style, flake8_return, flake8_simplify,
flake8_tidy_imports, flake8_unused_arguments, mccabe, noqa, pandas_vet, pep8_naming,
pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, visibility,
pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, violations,
visibility,
};
const GLOBAL_SCOPE_INDEX: usize = 0;
@@ -312,7 +313,7 @@ where
if !exists {
if self.settings.enabled.contains(&CheckCode::PLE0117) {
self.checks.push(Check::new(
CheckKind::NonlocalWithoutBinding(name.to_string()),
violations::NonlocalWithoutBinding(name.to_string()),
*range,
));
}
@@ -573,7 +574,7 @@ where
ScopeKind::Class(_) | ScopeKind::Module
) {
self.checks.push(Check::new(
CheckKind::ReturnOutsideFunction,
violations::ReturnOutsideFunction,
Range::from_located(stmt),
));
}
@@ -656,7 +657,7 @@ where
if self.settings.enabled.contains(&CheckCode::E401) {
if names.len() > 1 {
self.checks.push(Check::new(
CheckKind::MultipleImportsOnOneLine,
violations::MultipleImportsOnOneLine,
Range::from_located(stmt),
));
}
@@ -665,7 +666,7 @@ where
if self.settings.enabled.contains(&CheckCode::E402) {
if self.seen_import_boundary && stmt.location.column() == 0 {
self.checks.push(Check::new(
CheckKind::ModuleImportNotAtTopOfFile,
violations::ModuleImportNotAtTopOfFile,
Range::from_located(stmt),
));
}
@@ -886,7 +887,7 @@ where
if self.settings.enabled.contains(&CheckCode::E402) {
if self.seen_import_boundary && stmt.location.column() == 0 {
self.checks.push(Check::new(
CheckKind::ModuleImportNotAtTopOfFile,
violations::ModuleImportNotAtTopOfFile,
Range::from_located(stmt),
));
}
@@ -965,7 +966,9 @@ where
if self.settings.enabled.contains(&CheckCode::F407) {
if !ALL_FEATURE_NAMES.contains(&&*alias.node.name) {
self.checks.push(Check::new(
CheckKind::FutureFeatureNotDefined(alias.node.name.to_string()),
violations::FutureFeatureNotDefined(
alias.node.name.to_string(),
),
Range::from_located(alias),
));
}
@@ -974,7 +977,7 @@ where
if self.settings.enabled.contains(&CheckCode::F404) && !self.futures_allowed
{
self.checks.push(Check::new(
CheckKind::LateFutureImport,
violations::LateFutureImport,
Range::from_located(stmt),
));
}
@@ -994,10 +997,12 @@ where
[*(self.scope_stack.last().expect("No current scope found"))];
if !matches!(scope.kind, ScopeKind::Module) {
self.checks.push(Check::new(
CheckKind::ImportStarNotPermitted(helpers::format_import_from(
level.as_ref(),
module.as_deref(),
)),
violations::ImportStarNotPermitted(
helpers::format_import_from(
level.as_ref(),
module.as_deref(),
),
),
Range::from_located(stmt),
));
}
@@ -1005,7 +1010,7 @@ where
if self.settings.enabled.contains(&CheckCode::F403) {
self.checks.push(Check::new(
CheckKind::ImportStarUsed(helpers::format_import_from(
violations::ImportStarUsed(helpers::format_import_from(
level.as_ref(),
module.as_deref(),
)),
@@ -1184,6 +1189,9 @@ where
if self.settings.enabled.contains(&CheckCode::SIM102) {
flake8_simplify::plugins::nested_if_statements(self, stmt);
}
if self.settings.enabled.contains(&CheckCode::SIM103) {
flake8_simplify::plugins::return_bool_condition_directly(self, stmt);
}
if self.settings.enabled.contains(&CheckCode::SIM108) {
flake8_simplify::plugins::use_ternary_operator(
self,
@@ -1801,7 +1809,7 @@ where
Err(e) => {
if self.settings.enabled.contains(&CheckCode::F521) {
self.checks.push(Check::new(
CheckKind::StringDotFormatInvalidFormat(
violations::StringDotFormatInvalidFormat(
pyflakes::format::error_to_string(&e),
),
location,
@@ -2352,7 +2360,9 @@ where
}
}
if self.settings.enabled.contains(&CheckCode::PT009) {
if let Some(check) = flake8_pytest_style::plugins::unittest_assertion(func) {
if let Some(check) = flake8_pytest_style::plugins::unittest_assertion(
self, expr, func, args, keywords,
) {
self.checks.push(check);
}
}
@@ -2375,15 +2385,11 @@ where
));
}
}
ExprKind::Dict { keys, .. } => {
let check_repeated_literals = self.settings.enabled.contains(&CheckCode::F601);
let check_repeated_variables = self.settings.enabled.contains(&CheckCode::F602);
if check_repeated_literals || check_repeated_variables {
self.checks.extend(pyflakes::checks::repeated_keys(
keys,
check_repeated_literals,
check_repeated_variables,
));
ExprKind::Dict { keys, values } => {
if self.settings.enabled.contains(&CheckCode::F601)
|| self.settings.enabled.contains(&CheckCode::F602)
{
pyflakes::plugins::repeated_keys(self, keys, values);
}
}
ExprKind::Yield { .. } => {
@@ -2391,7 +2397,7 @@ where
let scope = self.current_scope();
if matches!(scope.kind, ScopeKind::Class(_) | ScopeKind::Module) {
self.checks.push(Check::new(
CheckKind::YieldOutsideFunction(DeferralKeyword::Yield),
violations::YieldOutsideFunction(DeferralKeyword::Yield),
Range::from_located(expr),
));
}
@@ -2402,7 +2408,7 @@ where
let scope = self.current_scope();
if matches!(scope.kind, ScopeKind::Class(_) | ScopeKind::Module) {
self.checks.push(Check::new(
CheckKind::YieldOutsideFunction(DeferralKeyword::YieldFrom),
violations::YieldOutsideFunction(DeferralKeyword::YieldFrom),
Range::from_located(expr),
));
}
@@ -2413,7 +2419,7 @@ where
let scope = self.current_scope();
if matches!(scope.kind, ScopeKind::Class(_) | ScopeKind::Module) {
self.checks.push(Check::new(
CheckKind::YieldOutsideFunction(DeferralKeyword::Await),
violations::YieldOutsideFunction(DeferralKeyword::Await),
Range::from_located(expr),
));
}
@@ -2464,7 +2470,7 @@ where
}) => {
if self.settings.enabled.contains(&CheckCode::F509) {
self.checks.push(Check::new(
CheckKind::PercentFormatUnsupportedFormatCharacter(c),
violations::PercentFormatUnsupportedFormatCharacter(c),
location,
));
}
@@ -2472,7 +2478,7 @@ where
Err(e) => {
if self.settings.enabled.contains(&CheckCode::F501) {
self.checks.push(Check::new(
CheckKind::PercentFormatInvalidFormat(e.to_string()),
violations::PercentFormatInvalidFormat(e.to_string()),
location,
));
}
@@ -2706,6 +2712,23 @@ where
}
self.push_scope(Scope::new(ScopeKind::Lambda(Lambda { args, body })));
}
ExprKind::IfExp { test, body, orelse } => {
if self.settings.enabled.contains(&CheckCode::SIM210) {
flake8_simplify::plugins::explicit_true_false_in_ifexpr(
self, expr, test, body, orelse,
);
}
if self.settings.enabled.contains(&CheckCode::SIM211) {
flake8_simplify::plugins::explicit_false_true_in_ifexpr(
self, expr, test, body, orelse,
);
}
if self.settings.enabled.contains(&CheckCode::SIM212) {
flake8_simplify::plugins::twisted_arms_in_ifexpr(
self, expr, test, body, orelse,
);
}
}
ExprKind::ListComp { elt, generators } | ExprKind::SetComp { elt, generators } => {
if self.settings.enabled.contains(&CheckCode::C416) {
if let Some(check) = flake8_comprehensions::checks::unnecessary_comprehension(
@@ -3063,7 +3086,7 @@ where
if self.bindings[*index].used.is_none() {
if self.settings.enabled.contains(&CheckCode::F841) {
let mut check = Check::new(
CheckKind::UnusedVariable(name.to_string()),
violations::UnusedVariable(name.to_string()),
name_range,
);
if self.patch(&CheckCode::F841) {
@@ -3349,7 +3372,7 @@ impl<'a> Checker<'a> {
overridden = Some((*scope_index, *existing_binding_index));
if self.settings.enabled.contains(&CheckCode::F402) {
self.checks.push(Check::new(
CheckKind::ImportShadowedByLoopVar(
violations::ImportShadowedByLoopVar(
name.to_string(),
existing.range.location.row(),
),
@@ -3369,7 +3392,7 @@ impl<'a> Checker<'a> {
overridden = Some((*scope_index, *existing_binding_index));
if self.settings.enabled.contains(&CheckCode::F811) {
self.checks.push(Check::new(
CheckKind::RedefinedWhileUnused(
violations::RedefinedWhileUnused(
name.to_string(),
existing.range.location.row(),
),
@@ -3495,7 +3518,7 @@ impl<'a> Checker<'a> {
from_list.sort();
self.checks.push(Check::new(
CheckKind::ImportStarUsage(id.to_string(), from_list),
violations::ImportStarUsage(id.to_string(), from_list),
Range::from_located(expr),
));
}
@@ -3526,7 +3549,7 @@ impl<'a> Checker<'a> {
}
self.checks.push(Check::new(
CheckKind::UndefinedName(id.clone()),
violations::UndefinedName(id.clone()),
Range::from_located(expr),
));
}
@@ -3697,7 +3720,7 @@ impl<'a> Checker<'a> {
&& self.settings.enabled.contains(&CheckCode::F821)
{
self.checks.push(Check::new(
CheckKind::UndefinedName(id.to_string()),
violations::UndefinedName(id.to_string()),
Range::from_located(expr),
));
}
@@ -3758,7 +3781,7 @@ impl<'a> Checker<'a> {
} else {
if self.settings.enabled.contains(&CheckCode::F722) {
self.checks.push(Check::new(
CheckKind::ForwardAnnotationSyntaxError(expression.to_string()),
violations::ForwardAnnotationSyntaxError(expression.to_string()),
range,
));
}
@@ -3864,7 +3887,7 @@ impl<'a> Checker<'a> {
let binding = &self.bindings[*index];
if matches!(binding.kind, BindingKind::Global) {
checks.push(Check::new(
CheckKind::GlobalVariableNotAssigned((*name).to_string()),
violations::GlobalVariableNotAssigned((*name).to_string()),
binding.range,
));
}
@@ -3893,7 +3916,7 @@ impl<'a> Checker<'a> {
for &name in names {
if !scope.values.contains_key(name) {
checks.push(Check::new(
CheckKind::UndefinedExport(name.to_string()),
violations::UndefinedExport(name.to_string()),
all_binding.range,
));
}
@@ -3931,7 +3954,7 @@ impl<'a> Checker<'a> {
if let Some(indices) = self.redefinitions.get(index) {
for index in indices {
checks.push(Check::new(
CheckKind::RedefinedWhileUnused(
violations::RedefinedWhileUnused(
(*name).to_string(),
binding.range.location.row(),
),
@@ -3962,7 +3985,7 @@ impl<'a> Checker<'a> {
for &name in names {
if !scope.values.contains_key(name) {
checks.push(Check::new(
CheckKind::ImportStarUsage(
violations::ImportStarUsage(
name.to_string(),
from_list.clone(),
),
@@ -4077,7 +4100,7 @@ impl<'a> Checker<'a> {
let multiple = unused_imports.len() > 1;
for (full_name, range) in unused_imports {
let mut check = Check::new(
CheckKind::UnusedImport(full_name.to_string(), ignore_init, multiple),
violations::UnusedImport(full_name.to_string(), ignore_init, multiple),
*range,
);
if matches!(child.node, StmtKind::ImportFrom { .. })
@@ -4099,7 +4122,7 @@ impl<'a> Checker<'a> {
let multiple = unused_imports.len() > 1;
for (full_name, range) in unused_imports {
let mut check = Check::new(
CheckKind::UnusedImport(full_name.to_string(), ignore_init, multiple),
violations::UnusedImport(full_name.to_string(), ignore_init, multiple),
*range,
);
if matches!(child.node, StmtKind::ImportFrom { .. })

View File

@@ -7,10 +7,10 @@ use rustpython_parser::ast::Location;
use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::noqa;
use crate::noqa::{is_file_exempt, Directive};
use crate::registry::{Check, CheckCode, CheckKind, UnusedCodes, CODE_REDIRECTS};
use crate::settings::{flags, Settings};
use crate::{noqa, violations};
pub fn check_noqa(
checks: &mut Vec<Check>,
@@ -42,7 +42,7 @@ pub fn check_noqa(
// Remove any ignored checks.
for (index, check) in checks.iter().enumerate() {
if check.kind == CheckKind::BlanketNOQA {
if matches!(check.kind, CheckKind::BlanketNOQA(..)) {
continue;
}
@@ -101,7 +101,7 @@ pub fn check_noqa(
Directive::All(spaces, start, end) => {
if matches.is_empty() {
let mut check = Check::new(
CheckKind::UnusedNOQA(None),
violations::UnusedNOQA(None),
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
);
if matches!(autofix, flags::Autofix::Enabled)
@@ -152,7 +152,7 @@ pub fn check_noqa(
&& unmatched_codes.is_empty())
{
let mut check = Check::new(
CheckKind::UnusedNOQA(Some(UnusedCodes {
violations::UnusedNOQA(Some(UnusedCodes {
disabled: disabled_codes
.iter()
.map(|code| (*code).to_string())

View File

@@ -39,7 +39,7 @@ pub fn check_tokens(
// RUF001, RUF002, RUF003
if enforce_ambiguous_unicode_character {
if matches!(tok, Tok::String { .. } | Tok::Comment) {
if matches!(tok, Tok::String { .. } | Tok::Comment(_)) {
checks.extend(ruff::checks::ambiguous_unicode_character(
locator,
start,
@@ -78,7 +78,7 @@ pub fn check_tokens(
// eradicate
if enforce_commented_out_code {
if matches!(tok, Tok::Comment) {
if matches!(tok, Tok::Comment(_)) {
if let Some(check) =
eradicate::checks::commented_out_code(locator, start, end, settings, autofix)
{

View File

@@ -20,7 +20,7 @@ pub struct Cli {
pub files: Vec<PathBuf>,
/// Path to the `pyproject.toml` or `ruff.toml` file to use for
/// configuration.
#[arg(long)]
#[arg(long, conflicts_with = "isolated")]
pub config: Option<PathBuf>,
/// Enable verbose logging.
#[arg(short, long, group = "verbosity")]
@@ -56,6 +56,9 @@ pub struct Cli {
/// Disable cache reads.
#[arg(short, long)]
pub no_cache: bool,
/// Ignore all configuration files.
#[arg(long, conflicts_with = "config")]
pub isolated: bool,
/// Comma-separated list of error codes to enable (or ALL, to enable all
/// checks).
#[arg(long, value_delimiter = ',')]
@@ -90,13 +93,13 @@ pub struct Cli {
#[arg(long, value_delimiter = ',')]
pub per_file_ignores: Option<Vec<PatternPrefixPair>>,
/// Output serialization format for error messages.
#[arg(long, value_enum)]
#[arg(long, value_enum, env = "RUFF_FORMAT")]
pub format: Option<SerializationFormat>,
/// The name of the file when passing it through stdin.
#[arg(long)]
pub stdin_filename: Option<PathBuf>,
/// Path to the cache directory.
#[arg(long)]
#[arg(long, env = "RUFF_CACHE_DIR")]
pub cache_dir: Option<PathBuf>,
/// Show violations with source code.
#[arg(long, overrides_with("no_show_source"))]
@@ -240,6 +243,7 @@ impl Cli {
explain: self.explain,
files: self.files,
generate_shell_completion: self.generate_shell_completion,
isolated: self.isolated,
no_cache: self.no_cache,
quiet: self.quiet,
show_files: self.show_files,
@@ -301,6 +305,7 @@ pub struct Arguments {
pub explain: Option<CheckCode>,
pub files: Vec<PathBuf>,
pub generate_shell_completion: Option<clap_complete_command::Shell>,
pub isolated: bool,
pub no_cache: bool,
pub quiet: bool,
pub show_files: bool,

View File

@@ -16,17 +16,17 @@ use serde::Serialize;
use walkdir::WalkDir;
use crate::autofix::fixer;
use crate::cache::DEFAULT_CACHE_DIR_NAME;
use crate::cache::CACHE_DIR_NAME;
use crate::cli::Overrides;
use crate::iterators::par_iter;
use crate::linter::{add_noqa_to_path, lint_path, lint_stdin, Diagnostics};
use crate::logging::LogLevel;
use crate::message::Message;
use crate::registry::{CheckCode, CheckKind};
use crate::registry::CheckCode;
use crate::resolver::{FileDiscovery, PyprojectDiscovery};
use crate::settings::flags;
use crate::settings::types::SerializationFormat;
use crate::{cache, fs, one_time_warning, packages, resolver};
use crate::{cache, fs, one_time_warning, packages, resolver, violations};
/// Run the linter over a collection of files.
pub fn run(
@@ -119,7 +119,7 @@ pub fn run(
let settings = resolver.resolve(path, pyproject_strategy);
if settings.enabled.contains(&CheckCode::E902) {
Diagnostics::new(vec![Message {
kind: CheckKind::IOError(message),
kind: violations::IOError(message).into(),
location: Location::default(),
end_location: Location::default(),
fix: None,
@@ -340,10 +340,10 @@ pub fn explain(code: &CheckCode, format: &SerializationFormat) -> Result<()> {
pub fn clean(level: &LogLevel) -> Result<()> {
for entry in WalkDir::new(&*path_dedot::CWD)
.into_iter()
.filter_map(std::result::Result::ok)
.filter_map(Result::ok)
.filter(|entry| entry.file_type().is_dir())
{
let cache = entry.path().join(DEFAULT_CACHE_DIR_NAME);
let cache = entry.path().join(CACHE_DIR_NAME);
if cache.is_dir() {
if level >= &LogLevel::Default {
eprintln!("Removing cache at: {}", fs::relativize_path(&cache).bold());

View File

@@ -5,9 +5,8 @@ use nohash_hasher::{IntMap, IntSet};
use rustpython_ast::Location;
use rustpython_parser::lexer::{LexResult, Tok};
use crate::ast::types::Range;
use crate::registry::LintSource;
use crate::{Settings, SourceCodeLocator};
use crate::Settings;
bitflags! {
pub struct Flags: u32 {
@@ -42,11 +41,7 @@ pub struct Directives {
pub isort: IsortDirectives,
}
pub fn extract_directives(
lxr: &[LexResult],
locator: &SourceCodeLocator,
flags: Flags,
) -> Directives {
pub fn extract_directives(lxr: &[LexResult], flags: Flags) -> Directives {
Directives {
commented_lines: extract_commented_lines(lxr),
noqa_line_for: if flags.contains(Flags::NOQA) {
@@ -55,7 +50,7 @@ pub fn extract_directives(
IntMap::default()
},
isort: if flags.contains(Flags::ISORT) {
extract_isort_directives(lxr, locator)
extract_isort_directives(lxr)
} else {
IsortDirectives::default()
},
@@ -65,7 +60,7 @@ pub fn extract_directives(
pub fn extract_commented_lines(lxr: &[LexResult]) -> Vec<usize> {
let mut commented_lines = Vec::new();
for (start, tok, ..) in lxr.iter().flatten() {
if matches!(tok, Tok::Comment) {
if matches!(tok, Tok::Comment(_)) {
commented_lines.push(start.row());
}
}
@@ -91,7 +86,7 @@ pub fn extract_noqa_line_for(lxr: &[LexResult]) -> IntMap<usize, usize> {
}
/// Extract a set of lines over which to disable isort.
pub fn extract_isort_directives(lxr: &[LexResult], locator: &SourceCodeLocator) -> IsortDirectives {
pub fn extract_isort_directives(lxr: &[LexResult]) -> IsortDirectives {
let mut exclusions: IntSet<usize> = IntSet::default();
let mut splits: Vec<usize> = Vec::default();
let mut skip_file: bool = false;
@@ -105,16 +100,17 @@ pub fn extract_isort_directives(lxr: &[LexResult], locator: &SourceCodeLocator)
continue;
}
if !matches!(tok, Tok::Comment) {
let Tok::Comment(comment_text) = tok else {
continue;
}
// TODO(charlie): Modify RustPython to include the comment text in the token.
let comment_text = locator.slice_source_code_range(&Range::new(start, end));
};
// `isort` allows for `# isort: skip` and `# isort: skip_file` to include or
// omit a space after the colon. The remaining action comments are
// required to include the space, and must appear on their own lines.
let comment_text = comment_text.trim_end();
if comment_text == "# isort: split" {
splits.push(start.row());
} else if comment_text == "# isort: skip_file" {
} else if comment_text == "# isort: skip_file" || comment_text == "# isort:skip_file" {
skip_file = true;
} else if off.is_some() {
if comment_text == "# isort: on" {
@@ -126,13 +122,14 @@ pub fn extract_isort_directives(lxr: &[LexResult], locator: &SourceCodeLocator)
off = None;
}
} else {
if comment_text.contains("isort: skip") {
if comment_text.contains("isort: skip") || comment_text.contains("isort:skip") {
exclusions.insert(start.row());
} else if comment_text == "# isort: off" {
off = Some(start);
}
}
}
if skip_file {
// Enforce `isort: skip_file`.
if let Some(end) = last {
@@ -158,7 +155,6 @@ mod tests {
use rustpython_parser::lexer::LexResult;
use crate::directives::{extract_isort_directives, extract_noqa_line_for};
use crate::SourceCodeLocator;
#[test]
fn noqa_extraction() {
@@ -246,11 +242,7 @@ z = x + 1",
y = 2
z = x + 1";
let lxr: Vec<LexResult> = lexer::make_tokenizer(contents).collect();
let locator = SourceCodeLocator::new(contents);
assert_eq!(
extract_isort_directives(&lxr, &locator).exclusions,
IntSet::default()
);
assert_eq!(extract_isort_directives(&lxr).exclusions, IntSet::default());
let contents = "# isort: off
x = 1
@@ -258,9 +250,8 @@ y = 2
# isort: on
z = x + 1";
let lxr: Vec<LexResult> = lexer::make_tokenizer(contents).collect();
let locator = SourceCodeLocator::new(contents);
assert_eq!(
extract_isort_directives(&lxr, &locator).exclusions,
extract_isort_directives(&lxr).exclusions,
IntSet::from_iter([2, 3, 4])
);
@@ -272,9 +263,8 @@ y = 2
z = x + 1
# isort: on";
let lxr: Vec<LexResult> = lexer::make_tokenizer(contents).collect();
let locator = SourceCodeLocator::new(contents);
assert_eq!(
extract_isort_directives(&lxr, &locator).exclusions,
extract_isort_directives(&lxr).exclusions,
IntSet::from_iter([2, 3, 4, 5])
);
@@ -283,9 +273,8 @@ x = 1
y = 2
z = x + 1";
let lxr: Vec<LexResult> = lexer::make_tokenizer(contents).collect();
let locator = SourceCodeLocator::new(contents);
assert_eq!(
extract_isort_directives(&lxr, &locator).exclusions,
extract_isort_directives(&lxr).exclusions,
IntSet::from_iter([2, 3, 4])
);
@@ -294,9 +283,8 @@ x = 1
y = 2
z = x + 1";
let lxr: Vec<LexResult> = lexer::make_tokenizer(contents).collect();
let locator = SourceCodeLocator::new(contents);
assert_eq!(
extract_isort_directives(&lxr, &locator).exclusions,
extract_isort_directives(&lxr).exclusions,
IntSet::from_iter([1, 2, 3, 4])
);
@@ -307,9 +295,8 @@ y = 2
# isort: skip_file
z = x + 1";
let lxr: Vec<LexResult> = lexer::make_tokenizer(contents).collect();
let locator = SourceCodeLocator::new(contents);
assert_eq!(
extract_isort_directives(&lxr, &locator).exclusions,
extract_isort_directives(&lxr).exclusions,
IntSet::from_iter([1, 2, 3, 4, 5, 6])
);
}
@@ -320,25 +307,19 @@ z = x + 1";
y = 2
z = x + 1";
let lxr: Vec<LexResult> = lexer::make_tokenizer(contents).collect();
let locator = SourceCodeLocator::new(contents);
assert_eq!(
extract_isort_directives(&lxr, &locator).splits,
Vec::<usize>::new()
);
assert_eq!(extract_isort_directives(&lxr).splits, Vec::<usize>::new());
let contents = "x = 1
y = 2
# isort: split
z = x + 1";
let lxr: Vec<LexResult> = lexer::make_tokenizer(contents).collect();
let locator = SourceCodeLocator::new(contents);
assert_eq!(extract_isort_directives(&lxr, &locator).splits, vec![3]);
assert_eq!(extract_isort_directives(&lxr).splits, vec![3]);
let contents = "x = 1
y = 2 # isort: split
z = x + 1";
let lxr: Vec<LexResult> = lexer::make_tokenizer(contents).collect();
let locator = SourceCodeLocator::new(contents);
assert_eq!(extract_isort_directives(&lxr, &locator).splits, vec![2]);
assert_eq!(extract_isort_directives(&lxr).splits, vec![2]);
}
}

View File

@@ -3,9 +3,9 @@ use rustpython_ast::Location;
use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::eradicate::detection::comment_contains_code;
use crate::registry::{CheckCode, CheckKind};
use crate::registry::CheckCode;
use crate::settings::flags;
use crate::{Check, Settings, SourceCodeLocator};
use crate::{violations, Check, Settings, SourceCodeLocator};
fn is_standalone_comment(line: &str) -> bool {
for char in line.chars() {
@@ -32,7 +32,7 @@ pub fn commented_out_code(
// Verify that the comment is on its own line, and that it contains code.
if is_standalone_comment(&line) && comment_contains_code(&line, &settings.task_tags[..]) {
let mut check = Check::new(CheckKind::CommentedOutCode, Range::new(start, end));
let mut check = Check::new(violations::CommentedOutCode, Range::new(start, end));
if matches!(autofix, flags::Autofix::Enabled)
&& settings.fixable.contains(&CheckCode::ERA001)
{

View File

@@ -2,7 +2,8 @@
source: src/eradicate/mod.rs
expression: checks
---
- kind: CommentedOutCode
- kind:
CommentedOutCode: ~
location:
row: 1
column: 0
@@ -18,7 +19,8 @@ expression: checks
row: 2
column: 0
parent: ~
- kind: CommentedOutCode
- kind:
CommentedOutCode: ~
location:
row: 2
column: 0
@@ -34,7 +36,8 @@ expression: checks
row: 3
column: 0
parent: ~
- kind: CommentedOutCode
- kind:
CommentedOutCode: ~
location:
row: 3
column: 0
@@ -50,7 +53,8 @@ expression: checks
row: 4
column: 0
parent: ~
- kind: CommentedOutCode
- kind:
CommentedOutCode: ~
location:
row: 5
column: 0
@@ -66,7 +70,8 @@ expression: checks
row: 6
column: 0
parent: ~
- kind: CommentedOutCode
- kind:
CommentedOutCode: ~
location:
row: 12
column: 4

View File

@@ -4,7 +4,8 @@ use rustpython_ast::{Cmpop, Constant, Expr, ExprKind, Located};
use crate::ast::helpers::match_module_member;
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckCode, CheckKind};
use crate::registry::{Check, CheckCode};
use crate::violations;
fn is_sys(checker: &Checker, expr: &Expr, target: &str) -> bool {
match_module_member(
@@ -35,14 +36,14 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
&& checker.settings.enabled.contains(&CheckCode::YTT303)
{
checker.checks.push(Check::new(
CheckKind::SysVersionSlice1Referenced,
violations::SysVersionSlice1Referenced,
Range::from_located(value),
));
} else if *i == BigInt::from(3)
&& checker.settings.enabled.contains(&CheckCode::YTT101)
{
checker.checks.push(Check::new(
CheckKind::SysVersionSlice3Referenced,
violations::SysVersionSlice3Referenced,
Range::from_located(value),
));
}
@@ -55,14 +56,14 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
} => {
if *i == BigInt::from(2) && checker.settings.enabled.contains(&CheckCode::YTT102) {
checker.checks.push(Check::new(
CheckKind::SysVersion2Referenced,
violations::SysVersion2Referenced,
Range::from_located(value),
));
} else if *i == BigInt::from(0)
&& checker.settings.enabled.contains(&CheckCode::YTT301)
{
checker.checks.push(Check::new(
CheckKind::SysVersion0Referenced,
violations::SysVersion0Referenced,
Range::from_located(value),
));
}
@@ -99,7 +100,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
&& checker.settings.enabled.contains(&CheckCode::YTT201)
{
checker.checks.push(Check::new(
CheckKind::SysVersionInfo0Eq3Referenced,
violations::SysVersionInfo0Eq3Referenced,
Range::from_located(left),
));
}
@@ -119,7 +120,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
{
if checker.settings.enabled.contains(&CheckCode::YTT203) {
checker.checks.push(Check::new(
CheckKind::SysVersionInfo1CmpInt,
violations::SysVersionInfo1CmpInt,
Range::from_located(left),
));
}
@@ -145,7 +146,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
{
if checker.settings.enabled.contains(&CheckCode::YTT204) {
checker.checks.push(Check::new(
CheckKind::SysVersionInfoMinorCmpInt,
violations::SysVersionInfoMinorCmpInt,
Range::from_located(left),
));
}
@@ -171,13 +172,13 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
if s.len() == 1 {
if checker.settings.enabled.contains(&CheckCode::YTT302) {
checker.checks.push(Check::new(
CheckKind::SysVersionCmpStr10,
violations::SysVersionCmpStr10,
Range::from_located(left),
));
}
} else if checker.settings.enabled.contains(&CheckCode::YTT103) {
checker.checks.push(Check::new(
CheckKind::SysVersionCmpStr3,
violations::SysVersionCmpStr3,
Range::from_located(left),
));
}
@@ -195,7 +196,7 @@ pub fn name_or_attribute(checker: &mut Checker, expr: &Expr) {
&checker.import_aliases,
) {
checker.checks.push(Check::new(
CheckKind::SixPY3Referenced,
violations::SixPY3Referenced,
Range::from_located(expr),
));
}

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SysVersionSlice3Referenced
- kind:
SysVersionSlice3Referenced: ~
location:
row: 6
column: 6
@@ -11,7 +12,8 @@ expression: checks
column: 17
fix: ~
parent: ~
- kind: SysVersionSlice3Referenced
- kind:
SysVersionSlice3Referenced: ~
location:
row: 7
column: 6
@@ -20,7 +22,8 @@ expression: checks
column: 13
fix: ~
parent: ~
- kind: SysVersionSlice3Referenced
- kind:
SysVersionSlice3Referenced: ~
location:
row: 8
column: 6

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SysVersion2Referenced
- kind:
SysVersion2Referenced: ~
location:
row: 4
column: 11
@@ -11,7 +12,8 @@ expression: checks
column: 22
fix: ~
parent: ~
- kind: SysVersion2Referenced
- kind:
SysVersion2Referenced: ~
location:
row: 5
column: 11

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SysVersionCmpStr3
- kind:
SysVersionCmpStr3: ~
location:
row: 4
column: 0
@@ -11,7 +12,8 @@ expression: checks
column: 7
fix: ~
parent: ~
- kind: SysVersionCmpStr3
- kind:
SysVersionCmpStr3: ~
location:
row: 5
column: 0
@@ -20,7 +22,8 @@ expression: checks
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr3
- kind:
SysVersionCmpStr3: ~
location:
row: 6
column: 0
@@ -29,7 +32,8 @@ expression: checks
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr3
- kind:
SysVersionCmpStr3: ~
location:
row: 7
column: 0
@@ -38,7 +42,8 @@ expression: checks
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr3
- kind:
SysVersionCmpStr3: ~
location:
row: 8
column: 0

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SysVersionInfo0Eq3Referenced
- kind:
SysVersionInfo0Eq3Referenced: ~
location:
row: 7
column: 6
@@ -11,7 +12,8 @@ expression: checks
column: 25
fix: ~
parent: ~
- kind: SysVersionInfo0Eq3Referenced
- kind:
SysVersionInfo0Eq3Referenced: ~
location:
row: 8
column: 6
@@ -20,7 +22,8 @@ expression: checks
column: 21
fix: ~
parent: ~
- kind: SysVersionInfo0Eq3Referenced
- kind:
SysVersionInfo0Eq3Referenced: ~
location:
row: 9
column: 6
@@ -29,7 +32,8 @@ expression: checks
column: 25
fix: ~
parent: ~
- kind: SysVersionInfo0Eq3Referenced
- kind:
SysVersionInfo0Eq3Referenced: ~
location:
row: 10
column: 6

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SixPY3Referenced
- kind:
SixPY3Referenced: ~
location:
row: 4
column: 3
@@ -11,7 +12,8 @@ expression: checks
column: 10
fix: ~
parent: ~
- kind: SixPY3Referenced
- kind:
SixPY3Referenced: ~
location:
row: 6
column: 3

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SysVersionInfo1CmpInt
- kind:
SysVersionInfo1CmpInt: ~
location:
row: 4
column: 0
@@ -11,7 +12,8 @@ expression: checks
column: 19
fix: ~
parent: ~
- kind: SysVersionInfo1CmpInt
- kind:
SysVersionInfo1CmpInt: ~
location:
row: 5
column: 0

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SysVersionInfoMinorCmpInt
- kind:
SysVersionInfoMinorCmpInt: ~
location:
row: 4
column: 0
@@ -11,7 +12,8 @@ expression: checks
column: 22
fix: ~
parent: ~
- kind: SysVersionInfoMinorCmpInt
- kind:
SysVersionInfoMinorCmpInt: ~
location:
row: 5
column: 0

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SysVersion0Referenced
- kind:
SysVersion0Referenced: ~
location:
row: 4
column: 11
@@ -11,7 +12,8 @@ expression: checks
column: 22
fix: ~
parent: ~
- kind: SysVersion0Referenced
- kind:
SysVersion0Referenced: ~
location:
row: 5
column: 11

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SysVersionCmpStr10
- kind:
SysVersionCmpStr10: ~
location:
row: 4
column: 0
@@ -11,7 +12,8 @@ expression: checks
column: 7
fix: ~
parent: ~
- kind: SysVersionCmpStr10
- kind:
SysVersionCmpStr10: ~
location:
row: 5
column: 0
@@ -20,7 +22,8 @@ expression: checks
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr10
- kind:
SysVersionCmpStr10: ~
location:
row: 6
column: 0
@@ -29,7 +32,8 @@ expression: checks
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr10
- kind:
SysVersionCmpStr10: ~
location:
row: 7
column: 0
@@ -38,7 +42,8 @@ expression: checks
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr10
- kind:
SysVersionCmpStr10: ~
location:
row: 8
column: 0

View File

@@ -2,7 +2,8 @@
source: src/flake8_2020/mod.rs
expression: checks
---
- kind: SysVersionSlice1Referenced
- kind:
SysVersionSlice1Referenced: ~
location:
row: 4
column: 6
@@ -11,7 +12,8 @@ expression: checks
column: 17
fix: ~
parent: ~
- kind: SysVersionSlice1Referenced
- kind:
SysVersionSlice1Referenced: ~
location:
row: 5
column: 6

View File

@@ -8,9 +8,9 @@ use crate::checkers::ast::Checker;
use crate::docstrings::definition::{Definition, DefinitionKind};
use crate::flake8_annotations::fixes;
use crate::flake8_annotations::helpers::match_function_def;
use crate::registry::{CheckCode, CheckKind};
use crate::registry::CheckCode;
use crate::visibility::Visibility;
use crate::{visibility, Check};
use crate::{violations, visibility, Check};
#[derive(Default)]
struct ReturnStatementVisitor<'a> {
@@ -58,7 +58,7 @@ where
{
if checker.match_typing_expr(annotation, "Any") {
checker.checks.push(Check::new(
CheckKind::DynamicallyTypedExpression(func()),
violations::DynamicallyTypedExpression(func()),
Range::from_located(annotation),
));
};
@@ -94,7 +94,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
{
if checker.settings.enabled.contains(&CheckCode::ANN001) {
checker.checks.push(Check::new(
CheckKind::MissingTypeFunctionArgument(arg.node.arg.to_string()),
violations::MissingTypeFunctionArgument(arg.node.arg.to_string()),
Range::from_located(arg),
));
}
@@ -117,7 +117,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
{
if checker.settings.enabled.contains(&CheckCode::ANN002) {
checker.checks.push(Check::new(
CheckKind::MissingTypeArgs(arg.node.arg.to_string()),
violations::MissingTypeArgs(arg.node.arg.to_string()),
Range::from_located(arg),
));
}
@@ -140,7 +140,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
{
if checker.settings.enabled.contains(&CheckCode::ANN003) {
checker.checks.push(Check::new(
CheckKind::MissingTypeKwargs(arg.node.arg.to_string()),
violations::MissingTypeKwargs(arg.node.arg.to_string()),
Range::from_located(arg),
));
}
@@ -166,7 +166,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
Visibility::Public => {
if checker.settings.enabled.contains(&CheckCode::ANN201) {
checker.checks.push(Check::new(
CheckKind::MissingReturnTypePublicFunction(name.to_string()),
violations::MissingReturnTypePublicFunction(name.to_string()),
helpers::identifier_range(stmt, checker.locator),
));
}
@@ -174,7 +174,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
Visibility::Private => {
if checker.settings.enabled.contains(&CheckCode::ANN202) {
checker.checks.push(Check::new(
CheckKind::MissingReturnTypePrivateFunction(name.to_string()),
violations::MissingReturnTypePrivateFunction(name.to_string()),
helpers::identifier_range(stmt, checker.locator),
));
}
@@ -212,7 +212,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
{
if checker.settings.enabled.contains(&CheckCode::ANN001) {
checker.checks.push(Check::new(
CheckKind::MissingTypeFunctionArgument(arg.node.arg.to_string()),
violations::MissingTypeFunctionArgument(arg.node.arg.to_string()),
Range::from_located(arg),
));
}
@@ -236,7 +236,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
{
if checker.settings.enabled.contains(&CheckCode::ANN002) {
checker.checks.push(Check::new(
CheckKind::MissingTypeArgs(arg.node.arg.to_string()),
violations::MissingTypeArgs(arg.node.arg.to_string()),
Range::from_located(arg),
));
}
@@ -260,7 +260,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
{
if checker.settings.enabled.contains(&CheckCode::ANN003) {
checker.checks.push(Check::new(
CheckKind::MissingTypeKwargs(arg.node.arg.to_string()),
violations::MissingTypeKwargs(arg.node.arg.to_string()),
Range::from_located(arg),
));
}
@@ -275,14 +275,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
if visibility::is_classmethod(checker, cast::decorator_list(stmt)) {
if checker.settings.enabled.contains(&CheckCode::ANN102) {
checker.checks.push(Check::new(
CheckKind::MissingTypeCls(arg.node.arg.to_string()),
violations::MissingTypeCls(arg.node.arg.to_string()),
Range::from_located(arg),
));
}
} else {
if checker.settings.enabled.contains(&CheckCode::ANN101) {
checker.checks.push(Check::new(
CheckKind::MissingTypeSelf(arg.node.arg.to_string()),
violations::MissingTypeSelf(arg.node.arg.to_string()),
Range::from_located(arg),
));
}
@@ -308,14 +308,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
if visibility::is_classmethod(checker, cast::decorator_list(stmt)) {
if checker.settings.enabled.contains(&CheckCode::ANN206) {
checker.checks.push(Check::new(
CheckKind::MissingReturnTypeClassMethod(name.to_string()),
violations::MissingReturnTypeClassMethod(name.to_string()),
helpers::identifier_range(stmt, checker.locator),
));
}
} else if visibility::is_staticmethod(checker, cast::decorator_list(stmt)) {
if checker.settings.enabled.contains(&CheckCode::ANN205) {
checker.checks.push(Check::new(
CheckKind::MissingReturnTypeStaticMethod(name.to_string()),
violations::MissingReturnTypeStaticMethod(name.to_string()),
helpers::identifier_range(stmt, checker.locator),
));
}
@@ -327,7 +327,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
&& has_any_typed_arg)
{
let mut check = Check::new(
CheckKind::MissingReturnTypeSpecialMethod(name.to_string()),
violations::MissingReturnTypeSpecialMethod(name.to_string()),
helpers::identifier_range(stmt, checker.locator),
);
if checker.patch(check.kind.code()) {
@@ -344,7 +344,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
} else if visibility::is_magic(stmt) {
if checker.settings.enabled.contains(&CheckCode::ANN204) {
checker.checks.push(Check::new(
CheckKind::MissingReturnTypeSpecialMethod(name.to_string()),
violations::MissingReturnTypeSpecialMethod(name.to_string()),
helpers::identifier_range(stmt, checker.locator),
));
}
@@ -353,7 +353,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
Visibility::Public => {
if checker.settings.enabled.contains(&CheckCode::ANN201) {
checker.checks.push(Check::new(
CheckKind::MissingReturnTypePublicFunction(name.to_string()),
violations::MissingReturnTypePublicFunction(name.to_string()),
helpers::identifier_range(stmt, checker.locator),
));
}
@@ -361,7 +361,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
Visibility::Private => {
if checker.settings.enabled.contains(&CheckCode::ANN202) {
checker.checks.push(Check::new(
CheckKind::MissingReturnTypePrivateFunction(name.to_string()),
violations::MissingReturnTypePrivateFunction(name.to_string()),
helpers::identifier_range(stmt, checker.locator),
));
}

View File

@@ -1,9 +1,10 @@
use rustpython_ast::{Located, StmtKind};
use crate::ast::types::Range;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// S101
pub fn assert_used(stmt: &Located<StmtKind>) -> Check {
Check::new(CheckKind::AssertUsed, Range::from_located(stmt))
Check::new(violations::AssertUsed, Range::from_located(stmt))
}

View File

@@ -5,7 +5,8 @@ use rustpython_ast::{Constant, Expr, ExprKind, Keyword, Operator};
use crate::ast::helpers::{compose_call_path, match_module_member, SimpleCallArgs};
use crate::ast::types::Range;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
const WRITE_WORLD: u16 = 0o2;
const EXECUTE_GROUP: u16 = 0o10;
@@ -97,7 +98,7 @@ pub fn bad_file_permissions(
if let Some(int_value) = get_int_value(mode_arg) {
if (int_value & WRITE_WORLD > 0) || (int_value & EXECUTE_GROUP > 0) {
return Some(Check::new(
CheckKind::BadFilePermissions(int_value),
violations::BadFilePermissions(int_value),
Range::from_located(mode_arg),
));
}

View File

@@ -1,7 +1,8 @@
use rustpython_ast::{Expr, ExprKind};
use crate::ast::types::Range;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// S102
pub fn exec_used(expr: &Expr, func: &Expr) -> Option<Check> {
@@ -11,5 +12,5 @@ pub fn exec_used(expr: &Expr, func: &Expr) -> Option<Check> {
if id != "exec" {
return None;
}
Some(Check::new(CheckKind::ExecUsed, Range::from_located(expr)))
Some(Check::new(violations::ExecUsed, Range::from_located(expr)))
}

View File

@@ -1,10 +1,11 @@
use crate::ast::types::Range;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// S104
pub fn hardcoded_bind_all_interfaces(value: &str, range: &Range) -> Option<Check> {
if value == "0.0.0.0" {
Some(Check::new(CheckKind::HardcodedBindAllInterfaces, *range))
Some(Check::new(violations::HardcodedBindAllInterfaces, *range))
} else {
None
}

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{ArgData, Arguments, Expr, Located};
use crate::ast::types::Range;
use crate::flake8_bandit::helpers::{matches_password_name, string_literal};
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
fn check_password_kwarg(arg: &Located<ArgData>, default: &Expr) -> Option<Check> {
let string = string_literal(default)?;
@@ -11,7 +12,7 @@ fn check_password_kwarg(arg: &Located<ArgData>, default: &Expr) -> Option<Check>
return None;
}
Some(Check::new(
CheckKind::HardcodedPasswordDefault(string.to_string()),
violations::HardcodedPasswordDefault(string.to_string()),
Range::from_located(default),
))
}

View File

@@ -2,7 +2,8 @@ use rustpython_ast::Keyword;
use crate::ast::types::Range;
use crate::flake8_bandit::helpers::{matches_password_name, string_literal};
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// S106
pub fn hardcoded_password_func_arg(keywords: &[Keyword]) -> Vec<Check> {
@@ -15,7 +16,7 @@ pub fn hardcoded_password_func_arg(keywords: &[Keyword]) -> Vec<Check> {
return None;
}
Some(Check::new(
CheckKind::HardcodedPasswordFuncArg(string.to_string()),
violations::HardcodedPasswordFuncArg(string.to_string()),
Range::from_located(keyword),
))
})

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{Constant, Expr, ExprKind};
use crate::ast::types::Range;
use crate::flake8_bandit::helpers::{matches_password_name, string_literal};
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
fn is_password_target(target: &Expr) -> bool {
let target_name = match &target.node {
@@ -34,7 +35,7 @@ pub fn compare_to_hardcoded_password_string(left: &Expr, comparators: &[Expr]) -
return None;
}
Some(Check::new(
CheckKind::HardcodedPasswordString(string.to_string()),
violations::HardcodedPasswordString(string.to_string()),
Range::from_located(comp),
))
})
@@ -47,7 +48,7 @@ pub fn assign_hardcoded_password_string(value: &Expr, targets: &[Expr]) -> Optio
for target in targets {
if is_password_target(target) {
return Some(Check::new(
CheckKind::HardcodedPasswordString(string.to_string()),
violations::HardcodedPasswordString(string.to_string()),
Range::from_located(value),
));
}

View File

@@ -1,13 +1,14 @@
use rustpython_ast::Expr;
use crate::ast::types::Range;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// S108
pub fn hardcoded_tmp_directory(expr: &Expr, value: &str, prefixes: &[String]) -> Option<Check> {
if prefixes.iter().any(|prefix| value.starts_with(prefix)) {
Some(Check::new(
CheckKind::HardcodedTempFile(value.to_string()),
violations::HardcodedTempFile(value.to_string()),
Range::from_located(expr),
))
} else {

View File

@@ -4,7 +4,8 @@ use rustpython_ast::{Constant, Expr, ExprKind, Keyword};
use crate::ast::helpers::{match_module_member, SimpleCallArgs};
use crate::ast::types::Range;
use crate::flake8_bandit::helpers::string_literal;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
const WEAK_HASHES: [&str; 4] = ["md4", "md5", "sha", "sha1"];
@@ -41,7 +42,7 @@ pub fn hashlib_insecure_hash_functions(
if WEAK_HASHES.contains(&hash_func_name.to_lowercase().as_str()) {
return Some(Check::new(
CheckKind::HashlibInsecureHashFunction(hash_func_name.to_string()),
violations::HashlibInsecureHashFunction(hash_func_name.to_string()),
Range::from_located(name_arg),
));
}
@@ -56,7 +57,7 @@ pub fn hashlib_insecure_hash_functions(
}
return Some(Check::new(
CheckKind::HashlibInsecureHashFunction((*func_name).to_string()),
violations::HashlibInsecureHashFunction((*func_name).to_string()),
Range::from_located(func),
));
}

View File

@@ -4,7 +4,8 @@ use rustpython_parser::ast::Constant;
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path, SimpleCallArgs};
use crate::ast::types::Range;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
const REQUESTS_HTTP_VERBS: [&str; 7] = ["get", "options", "head", "post", "put", "patch", "delete"];
const HTTPX_METHODS: [&str; 11] = [
@@ -41,7 +42,7 @@ pub fn request_with_no_cert_validation(
} = &verify_arg.node
{
return Some(Check::new(
CheckKind::RequestWithNoCertValidation("requests".to_string()),
violations::RequestWithNoCertValidation("requests".to_string()),
Range::from_located(verify_arg),
));
}
@@ -58,7 +59,7 @@ pub fn request_with_no_cert_validation(
} = &verify_arg.node
{
return Some(Check::new(
CheckKind::RequestWithNoCertValidation("httpx".to_string()),
violations::RequestWithNoCertValidation("httpx".to_string()),
Range::from_located(verify_arg),
));
}

View File

@@ -4,7 +4,8 @@ use rustpython_parser::ast::Constant;
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path, SimpleCallArgs};
use crate::ast::types::Range;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
const HTTP_VERBS: [&str; 7] = ["get", "options", "head", "post", "put", "patch", "delete"];
@@ -29,13 +30,13 @@ pub fn request_without_timeout(
_ => None,
} {
return Some(Check::new(
CheckKind::RequestWithoutTimeout(Some(timeout)),
violations::RequestWithoutTimeout(Some(timeout)),
Range::from_located(timeout_arg),
));
}
} else {
return Some(Check::new(
CheckKind::RequestWithoutTimeout(None),
violations::RequestWithoutTimeout(None),
Range::from_located(func),
));
}

View File

@@ -3,7 +3,8 @@ use rustpython_ast::{Expr, ExprKind, Keyword};
use crate::ast::helpers::{match_module_member, SimpleCallArgs};
use crate::ast::types::Range;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// S506
pub fn unsafe_yaml_load(
@@ -35,13 +36,13 @@ pub fn unsafe_yaml_load(
_ => None,
};
return Some(Check::new(
CheckKind::UnsafeYAMLLoad(loader),
violations::UnsafeYAMLLoad(loader),
Range::from_located(loader_arg),
));
}
} else {
return Some(Check::new(
CheckKind::UnsafeYAMLLoad(None),
violations::UnsafeYAMLLoad(None),
Range::from_located(func),
));
}

View File

@@ -2,7 +2,8 @@
source: src/flake8_bandit/mod.rs
expression: checks
---
- kind: AssertUsed
- kind:
AssertUsed: ~
location:
row: 2
column: 0
@@ -11,7 +12,8 @@ expression: checks
column: 11
fix: ~
parent: ~
- kind: AssertUsed
- kind:
AssertUsed: ~
location:
row: 8
column: 4
@@ -20,7 +22,8 @@ expression: checks
column: 17
fix: ~
parent: ~
- kind: AssertUsed
- kind:
AssertUsed: ~
location:
row: 11
column: 4

View File

@@ -2,7 +2,8 @@
source: src/flake8_bandit/mod.rs
expression: checks
---
- kind: ExecUsed
- kind:
ExecUsed: ~
location:
row: 3
column: 4
@@ -11,7 +12,8 @@ expression: checks
column: 17
fix: ~
parent: ~
- kind: ExecUsed
- kind:
ExecUsed: ~
location:
row: 5
column: 0

View File

@@ -2,7 +2,8 @@
source: src/flake8_bandit/mod.rs
expression: checks
---
- kind: HardcodedBindAllInterfaces
- kind:
HardcodedBindAllInterfaces: ~
location:
row: 9
column: 0
@@ -11,7 +12,8 @@ expression: checks
column: 9
fix: ~
parent: ~
- kind: HardcodedBindAllInterfaces
- kind:
HardcodedBindAllInterfaces: ~
location:
row: 10
column: 0
@@ -20,7 +22,8 @@ expression: checks
column: 9
fix: ~
parent: ~
- kind: HardcodedBindAllInterfaces
- kind:
HardcodedBindAllInterfaces: ~
location:
row: 14
column: 5
@@ -29,7 +32,8 @@ expression: checks
column: 14
fix: ~
parent: ~
- kind: HardcodedBindAllInterfaces
- kind:
HardcodedBindAllInterfaces: ~
location:
row: 18
column: 8

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{Expr, ExprKind, Stmt, StmtKind};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// BLE001
pub fn blind_except(
@@ -36,7 +37,7 @@ pub fn blind_except(
}
}) {
checker.checks.push(Check::new(
CheckKind::BlindExcept(id.to_string()),
violations::BlindExcept(id.to_string()),
Range::from_located(type_),
));
}

View File

@@ -4,6 +4,7 @@ use rustpython_parser::ast::{Constant, Expr};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::violations;
const FUNC_NAME_ALLOWLIST: &[&str] = &[
"assertEqual",
@@ -76,7 +77,7 @@ pub fn check_positional_boolean_in_def(checker: &mut Checker, arguments: &Argume
continue;
}
checker.checks.push(Check::new(
CheckKind::BooleanPositionalArgInFunctionDefinition,
violations::BooleanPositionalArgInFunctionDefinition,
Range::from_located(arg),
));
}
@@ -90,7 +91,7 @@ pub fn check_boolean_default_value_in_function_definition(
add_if_boolean(
checker,
arg,
CheckKind::BooleanDefaultValueInFunctionDefinition,
violations::BooleanDefaultValueInFunctionDefinition.into(),
);
}
}
@@ -107,7 +108,7 @@ pub fn check_boolean_positional_value_in_function_call(
add_if_boolean(
checker,
arg,
CheckKind::BooleanPositionalValueInFunctionCall,
violations::BooleanPositionalValueInFunctionCall.into(),
);
}
}

View File

@@ -2,7 +2,8 @@
source: src/flake8_boolean_trap/mod.rs
expression: checks
---
- kind: BooleanPositionalArgInFunctionDefinition
- kind:
BooleanPositionalArgInFunctionDefinition: ~
location:
row: 4
column: 4
@@ -11,7 +12,8 @@ expression: checks
column: 26
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
- kind:
BooleanPositionalArgInFunctionDefinition: ~
location:
row: 5
column: 4
@@ -20,7 +22,8 @@ expression: checks
column: 31
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
- kind:
BooleanPositionalArgInFunctionDefinition: ~
location:
row: 10
column: 4
@@ -29,7 +32,8 @@ expression: checks
column: 36
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
- kind:
BooleanPositionalArgInFunctionDefinition: ~
location:
row: 11
column: 4
@@ -38,7 +42,8 @@ expression: checks
column: 41
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
- kind:
BooleanPositionalArgInFunctionDefinition: ~
location:
row: 14
column: 4
@@ -47,7 +52,8 @@ expression: checks
column: 37
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
- kind:
BooleanPositionalArgInFunctionDefinition: ~
location:
row: 15
column: 4
@@ -56,7 +62,8 @@ expression: checks
column: 42
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
- kind:
BooleanPositionalArgInFunctionDefinition: ~
location:
row: 18
column: 4
@@ -65,7 +72,8 @@ expression: checks
column: 40
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
- kind:
BooleanPositionalArgInFunctionDefinition: ~
location:
row: 19
column: 4

View File

@@ -2,7 +2,8 @@
source: src/flake8_boolean_trap/mod.rs
expression: checks
---
- kind: BooleanDefaultValueInFunctionDefinition
- kind:
BooleanDefaultValueInFunctionDefinition: ~
location:
row: 12
column: 30
@@ -11,7 +12,8 @@ expression: checks
column: 34
fix: ~
parent: ~
- kind: BooleanDefaultValueInFunctionDefinition
- kind:
BooleanDefaultValueInFunctionDefinition: ~
location:
row: 13
column: 42
@@ -20,7 +22,8 @@ expression: checks
column: 46
fix: ~
parent: ~
- kind: BooleanDefaultValueInFunctionDefinition
- kind:
BooleanDefaultValueInFunctionDefinition: ~
location:
row: 14
column: 40
@@ -29,7 +32,8 @@ expression: checks
column: 44
fix: ~
parent: ~
- kind: BooleanDefaultValueInFunctionDefinition
- kind:
BooleanDefaultValueInFunctionDefinition: ~
location:
row: 15
column: 45

View File

@@ -2,7 +2,8 @@
source: src/flake8_boolean_trap/mod.rs
expression: checks
---
- kind: BooleanPositionalValueInFunctionCall
- kind:
BooleanPositionalValueInFunctionCall: ~
location:
row: 42
column: 10
@@ -11,7 +12,8 @@ expression: checks
column: 14
fix: ~
parent: ~
- kind: BooleanPositionalValueInFunctionCall
- kind:
BooleanPositionalValueInFunctionCall: ~
location:
row: 57
column: 10
@@ -20,7 +22,8 @@ expression: checks
column: 14
fix: ~
parent: ~
- kind: BooleanPositionalValueInFunctionCall
- kind:
BooleanPositionalValueInFunctionCall: ~
location:
row: 57
column: 16

View File

@@ -4,7 +4,8 @@ use rustpython_ast::{Constant, Expr, ExprKind, Keyword, Stmt, StmtKind};
use crate::ast::helpers::match_module_member;
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckCode, CheckKind};
use crate::registry::{Check, CheckCode};
use crate::violations;
fn is_abc_class(
bases: &[Expr],
@@ -118,7 +119,7 @@ pub fn abstract_base_class(
.any(|d| is_overload(d, &checker.from_imports, &checker.import_aliases))
{
checker.checks.push(Check::new(
CheckKind::EmptyMethodWithoutAbstractDecorator(name.to_string()),
violations::EmptyMethodWithoutAbstractDecorator(name.to_string()),
Range::from_located(stmt),
));
}
@@ -126,7 +127,7 @@ pub fn abstract_base_class(
if checker.settings.enabled.contains(&CheckCode::B024) {
if !has_abstract_method {
checker.checks.push(Check::new(
CheckKind::AbstractBaseClassWithoutAbstractMethod(name.to_string()),
violations::AbstractBaseClassWithoutAbstractMethod(name.to_string()),
Range::from_located(stmt),
));
}

View File

@@ -3,8 +3,9 @@ use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location, Stmt, Stmt
use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::source_code_generator::SourceCodeGenerator;
use crate::violations;
fn assertion_error(msg: Option<&Expr>) -> Stmt {
Stmt::new(
@@ -45,7 +46,7 @@ pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option
return;
};
let mut check = Check::new(CheckKind::DoNotAssertFalse, Range::from_located(test));
let mut check = Check::new(violations::DoNotAssertFalse, Range::from_located(test));
if checker.patch(check.kind.code()) {
let mut generator: SourceCodeGenerator = checker.style.into();
generator.unparse_stmt(&assertion_error(msg));

View File

@@ -3,7 +3,8 @@ use rustpython_ast::{ExprKind, Stmt, Withitem};
use crate::ast::helpers::match_module_member;
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B017
pub fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: &[Withitem]) {
@@ -34,7 +35,7 @@ pub fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: &[With
}
checker.checks.push(Check::new(
CheckKind::NoAssertRaisesException,
violations::NoAssertRaisesException,
Range::from_located(stmt),
));
}

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{Expr, ExprKind};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B003
pub fn assignment_to_os_environ(checker: &mut Checker, targets: &[Expr]) {
@@ -23,7 +24,7 @@ pub fn assignment_to_os_environ(checker: &mut Checker, targets: &[Expr]) {
return;
}
checker.checks.push(Check::new(
CheckKind::AssignmentToOsEnviron,
violations::AssignmentToOsEnviron,
Range::from_located(target),
));
}

View File

@@ -3,7 +3,8 @@ use rustpython_ast::{Expr, ExprKind};
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
use crate::ast::types::{Range, ScopeKind};
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
fn is_cache_func(checker: &Checker, expr: &Expr) -> bool {
let call_path = dealias_call_path(collect_call_paths(expr), &checker.import_aliases);
@@ -34,7 +35,7 @@ pub fn cached_instance_method(checker: &mut Checker, decorator_list: &[Expr]) {
},
) {
checker.checks.push(Check::new(
CheckKind::CachedInstanceMethod,
violations::CachedInstanceMethod,
Range::from_located(decorator),
));
}

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{Expr, ExprKind};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B016
pub fn cannot_raise_literal(checker: &mut Checker, expr: &Expr) {
@@ -10,7 +11,7 @@ pub fn cannot_raise_literal(checker: &mut Checker, expr: &Expr) {
return;
};
checker.checks.push(Check::new(
CheckKind::CannotRaiseLiteral,
violations::CannotRaiseLiteral,
Range::from_located(expr),
));
}

View File

@@ -6,8 +6,9 @@ use crate::ast::helpers;
use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckCode, CheckKind};
use crate::registry::{Check, CheckCode};
use crate::source_code_generator::SourceCodeGenerator;
use crate::violations;
fn type_pattern(elts: Vec<&Expr>) -> Expr {
Expr::new(
@@ -44,7 +45,7 @@ fn duplicate_handler_exceptions<'a>(
// TODO(charlie): Handle "BaseException" and redundant exception aliases.
if !duplicates.is_empty() {
let mut check = Check::new(
CheckKind::DuplicateHandlerException(
violations::DuplicateHandlerException(
duplicates
.into_iter()
.map(|call_path| call_path.join("."))
@@ -108,7 +109,7 @@ pub fn duplicate_exceptions(checker: &mut Checker, handlers: &[Excepthandler]) {
for (name, exprs) in duplicates {
for expr in exprs {
checker.checks.push(Check::new(
CheckKind::DuplicateTryBlockException(name.join(".")),
violations::DuplicateTryBlockException(name.join(".")),
Range::from_located(expr),
));
}

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{ExprKind, Stmt, StmtKind};
use crate::ast::helpers;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B021
pub fn f_string_docstring(checker: &mut Checker, body: &[Stmt]) {
@@ -16,7 +17,7 @@ pub fn f_string_docstring(checker: &mut Checker, body: &[Stmt]) {
return;
};
checker.checks.push(Check::new(
CheckKind::FStringDocstring,
violations::FStringDocstring,
helpers::identifier_range(stmt, checker.locator),
));
}

View File

@@ -10,6 +10,7 @@ use crate::ast::visitor::Visitor;
use crate::checkers::ast::Checker;
use crate::flake8_bugbear::plugins::mutable_argument_default::is_mutable_func;
use crate::registry::{Check, CheckKind};
use crate::violations;
const IMMUTABLE_FUNCS: [(&str, &str); 7] = [
("", "tuple"),
@@ -58,7 +59,7 @@ where
&& !is_nan_or_infinity(func, args)
{
self.checks.push((
CheckKind::FunctionCallArgumentDefault(compose_call_path(expr)),
violations::FunctionCallArgumentDefault(compose_call_path(expr)).into(),
Range::from_located(expr),
));
}

View File

@@ -6,7 +6,8 @@ use crate::ast::types::{Node, Range};
use crate::ast::visitor;
use crate::ast::visitor::Visitor;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
#[derive(Default)]
struct LoadedNamesVisitor<'a> {
@@ -212,7 +213,7 @@ where
if !checker.flake8_bugbear_seen.contains(&expr) {
checker.flake8_bugbear_seen.push(expr);
checker.checks.push(Check::new(
CheckKind::FunctionUsesLoopVariable(name.to_string()),
violations::FunctionUsesLoopVariable(name.to_string()),
range,
));
}

View File

@@ -5,8 +5,9 @@ use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::python::identifiers::IDENTIFIER_REGEX;
use crate::python::keyword::KWLIST;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::source_code_generator::SourceCodeGenerator;
use crate::violations;
fn attribute(value: &Expr, attr: &str) -> Expr {
Expr::new(
@@ -44,7 +45,7 @@ pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
return;
}
let mut check = Check::new(CheckKind::GetAttrWithConstant, Range::from_located(expr));
let mut check = Check::new(violations::GetAttrWithConstant, Range::from_located(expr));
if checker.patch(check.kind.code()) {
let mut generator: SourceCodeGenerator = checker.style.into();
generator.unparse_expr(&attribute(obj, value), 0);

View File

@@ -2,13 +2,14 @@ use rustpython_ast::{Stmt, StmtKind};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
fn walk_stmt(checker: &mut Checker, body: &[Stmt], f: fn(&Stmt) -> bool) {
for stmt in body {
if f(stmt) {
checker.checks.push(Check::new(
CheckKind::JumpStatementInFinally(match &stmt.node {
violations::JumpStatementInFinally(match &stmt.node {
StmtKind::Break { .. } => "break".to_string(),
StmtKind::Continue { .. } => "continue".to_string(),
StmtKind::Return { .. } => "return".to_string(),

View File

@@ -5,7 +5,8 @@ use crate::ast::types::Range;
use crate::ast::visitor;
use crate::ast::visitor::Visitor;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
#[derive(Default)]
struct NameFinder<'a> {
@@ -56,7 +57,7 @@ pub fn loop_variable_overrides_iterator(checker: &mut Checker, target: &Expr, it
for (name, expr) in target_names {
if iter_names.contains_key(name) {
checker.checks.push(Check::new(
CheckKind::LoopVariableOverridesIterator(name.to_string()),
violations::LoopVariableOverridesIterator(name.to_string()),
Range::from_located(expr),
));
}

View File

@@ -4,7 +4,8 @@ use rustpython_ast::{Arguments, Constant, Expr, ExprKind, Operator};
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
const MUTABLE_FUNCS: &[(&str, &str)] = &[
("", "dict"),
@@ -165,7 +166,7 @@ pub fn mutable_argument_default(checker: &mut Checker, arguments: &Arguments) {
})
{
checker.checks.push(Check::new(
CheckKind::MutableArgumentDefault,
violations::MutableArgumentDefault,
Range::from_located(default),
));
}

View File

@@ -4,7 +4,8 @@ use crate::ast::types::Range;
use crate::ast::visitor::Visitor;
use crate::checkers::ast::Checker;
use crate::python::string::is_lower;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
struct RaiseVisitor {
checks: Vec<Check>,
@@ -20,7 +21,7 @@ impl<'a> Visitor<'a> for RaiseVisitor {
ExprKind::Name { id, .. } if is_lower(id) => {}
_ => {
self.checks.push(Check::new(
CheckKind::RaiseWithoutFromInsideExcept,
violations::RaiseWithoutFromInsideExcept,
Range::from_located(stmt),
));
}

View File

@@ -3,8 +3,9 @@ use rustpython_ast::{Excepthandler, ExcepthandlerKind, ExprKind};
use crate::ast::types::Range;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::source_code_generator::SourceCodeGenerator;
use crate::violations;
/// B013
pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[Excepthandler]) {
@@ -19,7 +20,7 @@ pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[E
continue;
};
let mut check = Check::new(
CheckKind::RedundantTupleInExceptionHandler(elt.to_string()),
violations::RedundantTupleInExceptionHandler(elt.to_string()),
Range::from_located(type_),
);
if checker.patch(check.kind.code()) {

View File

@@ -5,9 +5,10 @@ use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::python::identifiers::IDENTIFIER_REGEX;
use crate::python::keyword::KWLIST;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::source_code_generator::SourceCodeGenerator;
use crate::source_code_style::SourceCodeStyleDetector;
use crate::violations;
fn assignment(obj: &Expr, name: &str, value: &Expr, stylist: &SourceCodeStyleDetector) -> String {
let stmt = Stmt::new(
@@ -60,7 +61,7 @@ pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
// (i.e., it's directly within an `StmtKind::Expr`).
if let StmtKind::Expr { value: child } = &checker.current_stmt().node {
if expr == child.as_ref() {
let mut check = Check::new(CheckKind::SetAttrWithConstant, Range::from_located(expr));
let mut check = Check::new(violations::SetAttrWithConstant, Range::from_located(expr));
if checker.patch(check.kind.code()) {
check.amend(Fix::replacement(
assignment(obj, name, value, checker.style),

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{Expr, ExprKind, Keyword};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B026
pub fn star_arg_unpacking_after_keyword_arg(
@@ -21,7 +22,7 @@ pub fn star_arg_unpacking_after_keyword_arg(
continue;
}
checker.checks.push(Check::new(
CheckKind::StarArgUnpackingAfterKeywordArg,
violations::StarArgUnpackingAfterKeywordArg,
Range::from_located(arg),
));
}

View File

@@ -3,7 +3,8 @@ use rustpython_ast::{Constant, Expr, ExprKind};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B005
pub fn strip_with_multi_characters(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
@@ -26,7 +27,7 @@ pub fn strip_with_multi_characters(checker: &mut Checker, expr: &Expr, func: &Ex
if value.len() > 1 && value.chars().unique().count() != value.len() {
checker.checks.push(Check::new(
CheckKind::StripWithMultiCharacters,
violations::StripWithMultiCharacters,
Range::from_located(expr),
));
}

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{Expr, ExprKind, Unaryop};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B002
pub fn unary_prefix_increment(checker: &mut Checker, expr: &Expr, op: &Unaryop, operand: &Expr) {
@@ -16,7 +17,7 @@ pub fn unary_prefix_increment(checker: &mut Checker, expr: &Expr, op: &Unaryop,
return;
}
checker.checks.push(Check::new(
CheckKind::UnaryPrefixIncrement,
violations::UnaryPrefixIncrement,
Range::from_located(expr),
));
}

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{Constant, Expr, ExprKind};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B004
pub fn unreliable_callable_check(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
@@ -26,7 +27,7 @@ pub fn unreliable_callable_check(checker: &mut Checker, expr: &Expr, func: &Expr
return;
}
checker.checks.push(Check::new(
CheckKind::UnreliableCallableCheck,
violations::UnreliableCallableCheck,
Range::from_located(expr),
));
}

View File

@@ -6,7 +6,8 @@ use crate::ast::visitor;
use crate::ast::visitor::Visitor;
use crate::autofix::Fix;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// Identify all `ExprKind::Name` nodes in an AST.
struct NameFinder<'a> {
@@ -62,7 +63,7 @@ pub fn unused_loop_control_variable(checker: &mut Checker, target: &Expr, body:
}
let mut check = Check::new(
CheckKind::UnusedLoopControlVariable(name.to_string()),
violations::UnusedLoopControlVariable(name.to_string()),
Range::from_located(expr),
);
if checker.patch(check.kind.code()) {

View File

@@ -2,12 +2,13 @@ use rustpython_ast::{Expr, ExprKind};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
pub fn useless_comparison(checker: &mut Checker, expr: &Expr) {
if matches!(expr.node, ExprKind::Compare { .. }) {
checker.checks.push(Check::new(
CheckKind::UselessComparison,
violations::UselessComparison,
Range::from_located(expr),
));
}

View File

@@ -3,7 +3,8 @@ use rustpython_ast::Expr;
use crate::ast::helpers::{collect_call_paths, match_call_path};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B005
pub fn useless_contextlib_suppress(checker: &mut Checker, expr: &Expr, args: &[Expr]) {
@@ -15,7 +16,7 @@ pub fn useless_contextlib_suppress(checker: &mut Checker, expr: &Expr, args: &[E
) && args.is_empty()
{
checker.checks.push(Check::new(
CheckKind::UselessContextlibSuppress,
violations::UselessContextlibSuppress,
Range::from_located(expr),
));
}

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{Constant, ExprKind, Stmt, StmtKind};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
// B018
pub fn useless_expression(checker: &mut Checker, body: &[Stmt]) {
@@ -11,7 +12,7 @@ pub fn useless_expression(checker: &mut Checker, body: &[Stmt]) {
match &value.node {
ExprKind::List { .. } | ExprKind::Dict { .. } | ExprKind::Set { .. } => {
checker.checks.push(Check::new(
CheckKind::UselessExpression,
violations::UselessExpression,
Range::from_located(value),
));
}
@@ -19,7 +20,7 @@ pub fn useless_expression(checker: &mut Checker, body: &[Stmt]) {
Constant::Str { .. } | Constant::Ellipsis => {}
_ => {
checker.checks.push(Check::new(
CheckKind::UselessExpression,
violations::UselessExpression,
Range::from_located(value),
));
}

View File

@@ -2,7 +2,8 @@ use rustpython_ast::{Expr, ExprKind, Keyword};
use crate::ast::types::Range;
use crate::checkers::ast::Checker;
use crate::registry::{Check, CheckKind};
use crate::registry::Check;
use crate::violations;
/// B905
pub fn zip_without_explicit_strict(
@@ -23,7 +24,7 @@ pub fn zip_without_explicit_strict(
})
{
checker.checks.push(Check::new(
CheckKind::ZipWithoutExplicitStrict,
violations::ZipWithoutExplicitStrict,
Range::from_located(expr),
));
}

View File

@@ -2,7 +2,8 @@
source: src/flake8_bugbear/mod.rs
expression: checks
---
- kind: UnaryPrefixIncrement
- kind:
UnaryPrefixIncrement: ~
location:
row: 15
column: 8
@@ -11,7 +12,8 @@ expression: checks
column: 11
fix: ~
parent: ~
- kind: UnaryPrefixIncrement
- kind:
UnaryPrefixIncrement: ~
location:
row: 20
column: 11

View File

@@ -2,7 +2,8 @@
source: src/flake8_bugbear/mod.rs
expression: checks
---
- kind: AssignmentToOsEnviron
- kind:
AssignmentToOsEnviron: ~
location:
row: 9
column: 0

View File

@@ -2,7 +2,8 @@
source: src/flake8_bugbear/mod.rs
expression: checks
---
- kind: UnreliableCallableCheck
- kind:
UnreliableCallableCheck: ~
location:
row: 3
column: 7
@@ -11,7 +12,8 @@ expression: checks
column: 29
fix: ~
parent: ~
- kind: UnreliableCallableCheck
- kind:
UnreliableCallableCheck: ~
location:
row: 5
column: 7

View File

@@ -2,7 +2,8 @@
source: src/flake8_bugbear/mod.rs
expression: checks
---
- kind: StripWithMultiCharacters
- kind:
StripWithMultiCharacters: ~
location:
row: 4
column: 0
@@ -11,7 +12,8 @@ expression: checks
column: 24
fix: ~
parent: ~
- kind: StripWithMultiCharacters
- kind:
StripWithMultiCharacters: ~
location:
row: 7
column: 0
@@ -20,7 +22,8 @@ expression: checks
column: 17
fix: ~
parent: ~
- kind: StripWithMultiCharacters
- kind:
StripWithMultiCharacters: ~
location:
row: 10
column: 0
@@ -29,7 +32,8 @@ expression: checks
column: 25
fix: ~
parent: ~
- kind: StripWithMultiCharacters
- kind:
StripWithMultiCharacters: ~
location:
row: 13
column: 0
@@ -38,7 +42,8 @@ expression: checks
column: 18
fix: ~
parent: ~
- kind: StripWithMultiCharacters
- kind:
StripWithMultiCharacters: ~
location:
row: 16
column: 0
@@ -47,7 +52,8 @@ expression: checks
column: 25
fix: ~
parent: ~
- kind: StripWithMultiCharacters
- kind:
StripWithMultiCharacters: ~
location:
row: 19
column: 0

View File

@@ -2,7 +2,8 @@
source: src/flake8_bugbear/mod.rs
expression: checks
---
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 60
column: 24
@@ -11,7 +12,8 @@ expression: checks
column: 33
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 64
column: 29
@@ -20,7 +22,8 @@ expression: checks
column: 31
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 68
column: 19
@@ -29,7 +32,8 @@ expression: checks
column: 24
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 72
column: 19
@@ -38,7 +42,8 @@ expression: checks
column: 44
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 76
column: 31
@@ -47,7 +52,8 @@ expression: checks
column: 56
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 80
column: 25
@@ -56,7 +62,8 @@ expression: checks
column: 44
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 85
column: 45
@@ -65,7 +72,8 @@ expression: checks
column: 69
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 89
column: 45
@@ -74,7 +82,8 @@ expression: checks
column: 72
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 93
column: 44
@@ -83,7 +92,8 @@ expression: checks
column: 68
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 97
column: 32
@@ -92,7 +102,8 @@ expression: checks
column: 34
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 170
column: 19
@@ -101,7 +112,8 @@ expression: checks
column: 48
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 203
column: 26
@@ -110,7 +122,8 @@ expression: checks
column: 28
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 204
column: 34
@@ -119,7 +132,8 @@ expression: checks
column: 36
fix: ~
parent: ~
- kind: MutableArgumentDefault
- kind:
MutableArgumentDefault: ~
location:
row: 205
column: 61

View File

@@ -2,7 +2,8 @@
source: src/flake8_bugbear/mod.rs
expression: checks
---
- kind: GetAttrWithConstant
- kind:
GetAttrWithConstant: ~
location:
row: 18
column: 0
@@ -18,7 +19,8 @@ expression: checks
row: 18
column: 19
parent: ~
- kind: GetAttrWithConstant
- kind:
GetAttrWithConstant: ~
location:
row: 19
column: 0
@@ -34,7 +36,8 @@ expression: checks
row: 19
column: 23
parent: ~
- kind: GetAttrWithConstant
- kind:
GetAttrWithConstant: ~
location:
row: 20
column: 0
@@ -50,7 +53,8 @@ expression: checks
row: 20
column: 22
parent: ~
- kind: GetAttrWithConstant
- kind:
GetAttrWithConstant: ~
location:
row: 21
column: 0
@@ -66,7 +70,8 @@ expression: checks
row: 21
column: 23
parent: ~
- kind: GetAttrWithConstant
- kind:
GetAttrWithConstant: ~
location:
row: 22
column: 14
@@ -82,7 +87,8 @@ expression: checks
row: 22
column: 31
parent: ~
- kind: GetAttrWithConstant
- kind:
GetAttrWithConstant: ~
location:
row: 23
column: 3

View File

@@ -2,7 +2,8 @@
source: src/flake8_bugbear/mod.rs
expression: checks
---
- kind: SetAttrWithConstant
- kind:
SetAttrWithConstant: ~
location:
row: 37
column: 0
@@ -18,7 +19,8 @@ expression: checks
row: 37
column: 25
parent: ~
- kind: SetAttrWithConstant
- kind:
SetAttrWithConstant: ~
location:
row: 38
column: 0
@@ -34,7 +36,8 @@ expression: checks
row: 38
column: 29
parent: ~
- kind: SetAttrWithConstant
- kind:
SetAttrWithConstant: ~
location:
row: 39
column: 0
@@ -50,7 +53,8 @@ expression: checks
row: 39
column: 28
parent: ~
- kind: SetAttrWithConstant
- kind:
SetAttrWithConstant: ~
location:
row: 40
column: 0
@@ -66,7 +70,8 @@ expression: checks
row: 40
column: 29
parent: ~
- kind: SetAttrWithConstant
- kind:
SetAttrWithConstant: ~
location:
row: 41
column: 0

View File

@@ -2,7 +2,8 @@
source: src/flake8_bugbear/mod.rs
expression: checks
---
- kind: DoNotAssertFalse
- kind:
DoNotAssertFalse: ~
location:
row: 8
column: 7
@@ -18,7 +19,8 @@ expression: checks
row: 8
column: 12
parent: ~
- kind: DoNotAssertFalse
- kind:
DoNotAssertFalse: ~
location:
row: 10
column: 7

View File

@@ -2,7 +2,8 @@
source: src/flake8_bugbear/mod.rs
expression: checks
---
- kind: UselessComparison
- kind:
UselessComparison: ~
location:
row: 3
column: 0
@@ -11,7 +12,8 @@ expression: checks
column: 6
fix: ~
parent: ~
- kind: UselessComparison
- kind:
UselessComparison: ~
location:
row: 7
column: 0
@@ -20,7 +22,8 @@ expression: checks
column: 11
fix: ~
parent: ~
- kind: UselessComparison
- kind:
UselessComparison: ~
location:
row: 17
column: 4
@@ -29,7 +32,8 @@ expression: checks
column: 15
fix: ~
parent: ~
- kind: UselessComparison
- kind:
UselessComparison: ~
location:
row: 24
column: 4

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