Compare commits

..

33 Commits

Author SHA1 Message Date
Micha Reiser
5d2513e5a9 POC of Black's string preview style formatting 2023-09-21 12:38:03 +02:00
Micha Reiser
272306bf5a Introduce StringContinuation data structure 2023-09-21 08:01:39 +02:00
Micha Reiser
f8f1cd5016 Introduce FormatterSettings (#7545) 2023-09-21 08:01:24 +02:00
Charlie Marsh
87a0cd219f Detect asyncio.get_running_loop calls in RUF006 (#7562)
## Summary

We can do a good enough job detecting this with our existing semantic
model.

Closes https://github.com/astral-sh/ruff/issues/3237.
2023-09-21 04:37:38 +00:00
Charlie Marsh
b685ee4749 Enable tab completion for ruff rule (#7560)
## Summary

Writing `ruff rule E1`, then tab, shows:

<img width="724" alt="Screen Shot 2023-09-20 at 9 29 09 PM"
src="https://github.com/astral-sh/ruff/assets/1309177/00297f24-8828-4485-a00e-6af1ab4e7875">

Closes https://github.com/astral-sh/ruff/issues/2812.
2023-09-20 22:05:39 -04:00
Charlie Marsh
ad893f8295 Avoid invalid fix for parenthesized values in F601 (#7559)
Closes https://github.com/astral-sh/ruff/issues/4897.
2023-09-21 01:28:11 +00:00
Charlie Marsh
621bed55c0 Add padding in PERF102 fixes (#7554)
Closes https://github.com/astral-sh/ruff/issues/7097.
2023-09-20 19:33:54 -04:00
Charlie Marsh
86faee1522 Update CONTRIBUTING.md to reflect Settings refactor (#7555)
## Summary

See:
https://github.com/astral-sh/ruff/pull/7544#issuecomment-1728457885.
2023-09-20 19:33:33 -04:00
Charlie Marsh
a0917ec658 Avoid inserting imports directly after continuation (#7553)
## Summary

This is extremely rare in practice, but common in the fuzzer issues so
worth fixing quickly.

Closes https://github.com/astral-sh/ruff/issues/7199.
2023-09-20 21:26:48 +00:00
Mahesh Saripalli
ee9ee005c5 Update flake8-self license to MIT (#7552)
## Summary

This PR updates the flake8-self license from Freely Distributable to the
MIT License to match the upstream license, which was recently updated.


f5fc507515/LICENSE
2023-09-20 17:17:55 -04:00
Charlie Marsh
5df0326bc8 Treat parameters-with-newline as empty in function formatting (#7550)
## Summary

If a function has no parameters (and no comments within the parameters'
`()`), we're supposed to wrap the return annotation _whenever_ it
breaks. However, our `empty_parameters` test didn't properly account for
the case in which the parameters include a newline (but no other
content), like:

```python
def get_dashboards_hierarchy(
) -> Dict[Type['BaseDashboard'], List[Type['BaseDashboard']]]:
    """Get hierarchy of dashboards classes.

    Returns:
        Dict of dashboards classes.
    """
    dashboards_hierarchy = {}
```

This PR fixes that detection. Instead of lexing, it now checks if the
parameters itself is empty (or if it contains comments).

Closes https://github.com/astral-sh/ruff/issues/7457.
2023-09-20 16:20:22 -04:00
Micha Reiser
6540321966 Move Settings and ResolverSettings to ruff_workspace
## Summary

## Stack Summary

This stack splits `Settings` into `FormatterSettings` and `LinterSettings` and moves it into `ruff_workspace`. This change is necessary to add the `FormatterSettings` to `Settings` without adding `ruff_python_formatter` as a dependency to `ruff_linter` (and the linter should not contain the formatter settings). 

A quick overview of our settings struct at play:

* `Options`: 1:1 representation of the options in the `pyproject.toml` or `ruff.toml`.  Used for deserialization.
* `Configuration`: Resolved `Options`, potentially merged from multiple configurations (when using `extend`). The representation is very close if not identical to the `Options`.
* `Settings`: The resolved configuration that uses a data format optimized for reading. Optional fields are initialized with their default values. Initialized by `Configuration::into_settings` .

The goal of this stack is to split `Settings` into tool-specific resolved `Settings` that are independent of each other. This comes at the advantage that the individual crates don't need to know anything about the other tools. The downside is that information gets duplicated between `Settings`. Right now the duplication is minimal (`line-length`, `tab-width`) but we may need to come up with a solution if more expensive data needs sharing.

This stack focuses on `Settings`. Splitting `Configuration` into some smaller structs is something I'll follow up on later. 

## PR Summary

This PR moves the `ResolverSettings` and `Settings` struct to `ruff_workspace`. `LinterSettings` remains in `ruff_linter` because it gets passed to lint rules, the `Checker` etc.

## Test Plan

`cargo test`
2023-09-20 17:24:28 +02:00
Micha Reiser
b34278e0cd Introduce LinterSettings
## Stack Summary

This stack splits `Settings` into `FormatterSettings` and `LinterSettings` and moves it into `ruff_workspace`. This change is necessary to add the `FormatterSettings` to `Settings` without adding `ruff_python_formatter` as a dependency to `ruff_linter` (and the linter should not contain the formatter settings). 

A quick overview of our settings struct at play:

* `Options`: 1:1 representation of the options in the `pyproject.toml` or `ruff.toml`.  Used for deserialization.
* `Configuration`: Resolved `Options`, potentially merged from multiple configurations (when using `extend`). The representation is very close if not identical to the `Options`.
* `Settings`: The resolved configuration that uses a data format optimized for reading. Optional fields are initialized with their default values. Initialized by `Configuration::into_settings` .

The goal of this stack is to split `Settings` into tool-specific resolved `Settings` that are independent of each other. This comes at the advantage that the individual crates don't need to know anything about the other tools. The downside is that information gets duplicated between `Settings`. Right now the duplication is minimal (`line-length`, `tab-width`) but we may need to come up with a solution if more expensive data needs sharing.

This stack focuses on `Settings`. Splitting `Configuration` into some smaller structs is something I'll follow up on later. 

## PR Summary

This PR extracts the linter-specific settings into a new `LinterSettings` struct and adds it as a `linter` field to the `Settings` struct. This is in preparation for moving `Settings` from `ruff_linter` to `ruff_workspace`

## Test Plan

`cargo test`
2023-09-20 17:02:34 +02:00
Micha Reiser
222f1c37b8 Add empty lines between options and move documents (#7547) 2023-09-20 16:40:25 +02:00
Micha Reiser
8f41eab0c7 Extract ResolverSettings
## Stack Summary

This stack splits `Settings` into `FormatterSettings` and `LinterSettings` and moves it into `ruff_workspace`. This change is necessary to add the `FormatterSettings` to `Settings` without adding `ruff_python_formatter` as a dependency to `ruff_linter` (and the linter should not contain the formatter settings). 

A quick overview of our settings struct at play:

* `Options`: 1:1 representation of the options in the `pyproject.toml` or `ruff.toml`.  Used for deserialization.
* `Configuration`: Resolved `Options`, potentially merged from multiple configurations (when using `extend`). The representation is very close if not identical to the `Options`.
* `Settings`: The resolved configuration that uses a data format optimized for reading. Optional fields are initialized with their default values. Initialized by `Configuration::into_settings` .

The goal of this stack is to split `Settings` into tool-specific resolved `Settings` that are independent of each other. This comes at the advantage that the individual crates don't need to know anything about the other tools. The downside is that information gets duplicated between `Settings`. Right now the duplication is minimal (`line-length`, `tab-width`) but we may need to come up with a solution if more expensive data needs sharing.

This stack focuses on `Settings`. Splitting `Configuration` into some smaller structs is something I'll follow up on later. 

## PR Summary

This PR extracts a `ResolverSettings` struct that holds all the resolver-relevant fields (uninteresting for the `Formatter` or `Linter`). This will allow us to move the `ResolverSettings` out of `ruff_linter` further up in the stack.


## Test Plan

`cargo test`

(I'll to more extensive testing at the top of this stack)
2023-09-20 16:37:49 +02:00
Micha Reiser
83daddbeb7 Rename ConfigProcessor to ConfigurationTransformer (#7536) 2023-09-20 14:17:06 +00:00
Micha Reiser
b19eec9b2a Unify Settings and AllSettings (#7532) 2023-09-20 13:56:07 +00:00
Micha Reiser
ca3c15858d Use portable hash function for CacheKey (#7533) 2023-09-20 15:19:59 +02:00
Micha Reiser
bb4f7c681a Rename format option to output-format (#7514) 2023-09-20 15:18:58 +02:00
Dhruv Manilawala
0a167dd20b Use strict sorted and union for NoQA mapping insertion (#7531)
## Summary

This PR fixes the way NoQA range is inserted to the `NoqaMapping`.

Previously, the way the mapping insertion logic worked was as follows:
1. If the range which is to be inserted _touched_ the previous range, meaning
that the end of the previous range was the same as the start of the new
range, then the new range was added in addition to the previous range.
2. Else, if the new range intersected the previous range, then the previous
   range was replaced with the new _intersection_ of the two ranges.

The problem with this logic is that it does not work for the following case:
```python
assert foo, \
    """multi-line
    string"""
```

Now, the comments cannot be added to the same line which ends with a continuation
character. So, the `NoQA` directive has to be added to the next line. But, the
next line is also a triple-quoted string, so the `NoQA` directive for that line
needs to be added to the next line. This creates a **union** pattern instead of an
**intersection** pattern.

But, only union doesn't suffice because (1) means that for the edge case where
the range touch only at the end, the union won't take place.

### Solution

1. Replace '<=' with '<' to have a _strict_ insertion case
2. Use union instead of intersection

## Test Plan

Add a new test case. Run the test suite to ensure that nothing is broken.

### Integration

1. Make a `test.py` file with the following contents:

    ```python
    assert foo, \
        """multi-line
        string"""
    ```

2. Run the following command:

    ```console
	$ cargo run --bin ruff -- check --isolated --no-cache --select=F821 test.py
	/Users/dhruv/playground/ruff/fstring.py:1:8: F821 Undefined name `foo`
    Found 1 error.
    ```

3. Use `--add-noqa`:

    ```console
	$ cargo run --bin ruff -- check --isolated --no-cache --select=F821 --add-noqa test.py
    Added 1 noqa directive.
    ```

4. Check that the NoQA directive was added in the correct position:

    ```python
    assert foo, \
        """multi-line
        string"""  # noqa: F821
    ```

5. Run the `check` command to ensure that the NoQA directive is respected:

    ```console
	$ cargo run --bin ruff -- check --isolated --no-cache --select=F821 test.py
    ```

fixes: #7530
2023-09-20 11:07:19 +00:00
dependabot[bot]
c43542896f Bump unicode-width from 0.1.10 to 0.1.11 (#7534)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-20 10:26:54 +02:00
Micha Reiser
192463c2fb Allow parenthesized content exceed configured line width (#7490) 2023-09-20 08:39:25 +02:00
Charlie Marsh
5849a75223 Rename ruff crate to ruff_linter (#7529) 2023-09-20 08:38:27 +02:00
Mathieu Kniewallner
dcbd8eacd8 feat(rules): implement flake8-bandit S507 (ssh_no_host_key_verification) (#7528)
Part of #1646.

## Summary

Implement `S507`
([`ssh_no_host_key_verification`](https://bandit.readthedocs.io/en/latest/plugins/b507_ssh_no_host_key_verification.html))
rule from `bandit`.

## Test Plan

Snapshot test from
https://github.com/PyCQA/bandit/blob/1.7.5/examples/no_host_key_verification.py,
with several additions to test for more cases (most notably passing the
parameter as a named argument).
2023-09-19 20:31:45 -04:00
Micha Reiser
297ec2c2d2 Use Settings where AllSettings isn't required (#7518) 2023-09-19 23:16:20 +02:00
Tom Kuson
511cc25fc4 [refurb] Implement unnecessary-enumerate (FURB148) (#7454)
## Summary

Implement
[`no-ignored-enumerate-items`](https://github.com/dosisod/refurb/blob/master/refurb/checks/builtin/no_ignored_enumerate.py)
as `unnecessary-enumerate` (`FURB148`).

The auto-fix considers if a `start` argument is passed to the
`enumerate()` function. If only the index is used, then the suggested
fix is to pass the `start` value to the `range()` function. So,

```python
for i, _ in enumerate(xs, 1):
    ...
```

becomes

```python
for i in range(1, len(xs)):
    ...
```

If the index is ignored and only the value is ignored, and if a start
value greater than zero is passed to `enumerate()`, the rule doesn't
produce a suggestion. I couldn't find a unanimously accepted best way to
iterate over a collection whilst skipping the first n elements. The rule
still triggers, however.

Related to #1348.

## Test Plan

`cargo test`

---------

Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
2023-09-19 20:19:28 +00:00
Charlie Marsh
4c4eceee36 Add dangling comment handling for lambda expressions (#7493)
## Summary

This PR adds dangling comment handling for `lambda` expressions. In
short, comments around the `lambda` and the `:` are all considered
dangling. Comments that come between the `lambda` and the `:` may be
moved after the colon for simplicity (this is an odd position for a
comment anyway), unless they also precede the lambda parameters, in
which case they're formatted before the parameters.

Closes https://github.com/astral-sh/ruff/issues/7470.

## Test Plan

`cargo test`

No change in similarity.

Before:

| project | similarity index | total files | changed files |

|--------------|------------------:|------------------:|------------------:|
| cpython | 0.76083 | 1789 | 1632 |
| django | 0.99982 | 2760 | 37 |
| transformers | 0.99957 | 2587 | 398 |
| twine | 1.00000 | 33 | 0 |
| typeshed | 0.99983 | 3496 | 18 |
| warehouse | 0.99929 | 648 | 16 |
| zulip | 0.99962 | 1437 | 22 |

After:

| project | similarity index | total files | changed files |

|--------------|------------------:|------------------:|------------------:|
| cpython | 0.76083 | 1789 | 1632 |
| django | 0.99982 | 2760 | 37 |
| transformers | 0.99957 | 2587 | 398 |
| twine | 1.00000 | 33 | 0 |
| typeshed | 0.99983 | 3496 | 18 |
| warehouse | 0.99929 | 648 | 16 |
| zulip | 0.99962 | 1437 | 22 |
2023-09-19 15:23:51 -04:00
Charlie Marsh
e07670ad97 Add dangling comment handling to dictionary key-value pairs (#7495)
## Summary

This PR fixes a formatting instability by changing the comment handling
around the `:` in a dictionary to mirror that of the `:` in a lambda: we
treat comments around the `:` as dangling, then format them after the
`:`.

Closes https://github.com/astral-sh/ruff/issues/7458.

## Test Plan

`cargo test`

No change in similarity.

Before:

| project | similarity index | total files | changed files |

|--------------|------------------:|------------------:|------------------:|
| cpython | 0.76083 | 1789 | 1631 |
| django | 0.99983 | 2760 | 36 |
| transformers | 0.99956 | 2587 | 404 |
| twine | 1.00000 | 33 | 0 |
| typeshed | 0.99983 | 3496 | 18 |
| warehouse | 0.99929 | 648 | 16 |
| zulip | 0.99969 | 1437 | 21 |

After:

| project | similarity index | total files | changed files |

|--------------|------------------:|------------------:|------------------:|
| cpython | 0.76083 | 1789 | 1631 |
| django | 0.99983 | 2760 | 36 |
| transformers | 0.99956 | 2587 | 404 |
| twine | 1.00000 | 33 | 0 |
| typeshed | 0.99983 | 3496 | 18 |
| warehouse | 0.99929 | 648 | 16 |
| zulip | 0.99969 | 1437 | 21 |
2023-09-19 19:17:21 +00:00
Charlie Marsh
b792140579 Ensure that LOG007 only triggers on .exception() calls (#7524)
## Summary

Previously, this rule triggered for `logging.info("...",
exc_info=False)`.
2023-09-19 17:29:54 +00:00
Tom Kuson
36a60bd50e Add documentation to non-empty-stub-body (#7519)
## Summary

Add documentation to `non-empty-stub-body` (`PYI010`) rule. Related to
#2646.

## Test Plan

`python scripts/check_docs_formatted.py`
2023-09-19 13:21:11 -04:00
konsti
4ae463d04b Add a test for stmt assign breaking in preview mode (#7516)
In preview mode, black will consistently break the right side first.
This doesn't work yet, but we'll need the test later.
2023-09-19 16:16:40 +02:00
konsti
6dade5b9ab Tokenizer: Emit only a single bogus token (#7425)
**Summary** Instead of emitting a bogus token per char, we now only emit
on single last bogus token. This leads to much more concise output.

**Test Plan** Updated fixtures
2023-09-19 16:06:03 +02:00
Charlie Marsh
97510c888b Show --no-X variants in CLI help (#7504)
I'd really like this to render as `--preview / --no-preview`, but I
looked for a while in the Clap internals and issue tracker
(https://github.com/clap-rs/clap/issues/815) and I really can't figure
out a way to do it -- this seems like the best we can do? It's also what
they do in Orogene.

Closes https://github.com/astral-sh/ruff/issues/7486.
2023-09-19 12:27:30 +00:00
4552 changed files with 112103 additions and 111154 deletions

4
.gitattributes vendored
View File

@@ -1,7 +1,7 @@
* text=auto eol=lf
crates/ruff/resources/test/fixtures/isort/line_ending_crlf.py text eol=crlf
crates/ruff/resources/test/fixtures/pycodestyle/W605_1.py text eol=crlf
crates/ruff_linter/resources/test/fixtures/isort/line_ending_crlf.py text eol=crlf
crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_1.py text eol=crlf
ruff.schema.json linguist-generated=true text=auto eol=lf
*.md.snap linguist-language=Markdown

2
.github/CODEOWNERS vendored
View File

@@ -6,4 +6,4 @@
# - Order is important. The last matching pattern has the most precedence.
# Jupyter
/crates/ruff/src/jupyter/ @dhruvmanila
/crates/ruff_linter/src/jupyter/ @dhruvmanila

2
.gitignore vendored
View File

@@ -1,5 +1,5 @@
# Benchmarking cpython (CONTRIBUTING.md)
crates/ruff/resources/test/cpython
crates/ruff_linter/resources/test/cpython
# generate_mkdocs.py
mkdocs.generated.yml
# check_ecosystem.py

View File

@@ -2,8 +2,8 @@ fail_fast: true
exclude: |
(?x)^(
crates/ruff/resources/.*|
crates/ruff/src/rules/.*/snapshots/.*|
crates/ruff_linter/resources/.*|
crates/ruff_linter/src/rules/.*/snapshots/.*|
crates/ruff_cli/resources/.*|
crates/ruff_python_formatter/resources/.*|
crates/ruff_python_formatter/tests/snapshots/.*|
@@ -50,7 +50,7 @@ repos:
require_serial: true
exclude: |
(?x)^(
crates/ruff/resources/.*|
crates/ruff_linter/resources/.*|
crates/ruff_python_formatter/resources/.*
)$

View File

@@ -112,11 +112,11 @@ Ruff is structured as a monorepo with a [flat crate structure](https://matklad.g
such that all crates are contained in a flat `crates` directory.
The vast majority of the code, including all lint rules, lives in the `ruff` crate (located at
`crates/ruff`). As a contributor, that's the crate that'll be most relevant to you.
`crates/ruff_linter`). As a contributor, that's the crate that'll be most relevant to you.
At time of writing, the repository includes the following crates:
- `crates/ruff`: library crate containing all lint rules and the core logic for running them.
- `crates/ruff_linter`: library crate containing all lint rules and the core logic for running them.
If you're working on a rule, this is the crate for you.
- `crates/ruff_benchmark`: binary crate for running micro-benchmarks.
- `crates/ruff_cache`: library crate for caching lint results.
@@ -153,7 +153,7 @@ At a high level, the steps involved in adding a new lint rule are as follows:
1. Determine a name for the new rule as per our [rule naming convention](#rule-naming-convention)
(e.g., `AssertFalse`, as in, "allow `assert False`").
1. Create a file for your rule (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/assert_false.rs`).
1. Create a file for your rule (e.g., `crates/ruff_linter/src/rules/flake8_bugbear/rules/assert_false.rs`).
1. In that file, define a violation struct (e.g., `pub struct AssertFalse`). You can grep for
`#[violation]` to see examples.
@@ -162,21 +162,21 @@ At a high level, the steps involved in adding a new lint rule are as follows:
(e.g., `pub(crate) fn assert_false`) based on whatever inputs are required for the rule (e.g.,
an `ast::StmtAssert` node).
1. Define the logic for invoking the diagnostic in `crates/ruff/src/checkers/ast/analyze` (for
AST-based rules), `crates/ruff/src/checkers/tokens.rs` (for token-based rules),
`crates/ruff/src/checkers/physical_lines.rs` (for text-based rules),
`crates/ruff/src/checkers/filesystem.rs` (for filesystem-based rules), etc. For AST-based rules,
1. Define the logic for invoking the diagnostic in `crates/ruff_linter/src/checkers/ast/analyze` (for
AST-based rules), `crates/ruff_linter/src/checkers/tokens.rs` (for token-based rules),
`crates/ruff_linter/src/checkers/physical_lines.rs` (for text-based rules),
`crates/ruff_linter/src/checkers/filesystem.rs` (for filesystem-based rules), etc. For AST-based rules,
you'll likely want to modify `analyze/statement.rs` (if your rule is based on analyzing
statements, like imports) or `analyze/expression.rs` (if your rule is based on analyzing
expressions, like function calls).
1. Map the violation struct to a rule code in `crates/ruff/src/codes.rs` (e.g., `B011`).
1. Map the violation struct to a rule code in `crates/ruff_linter/src/codes.rs` (e.g., `B011`).
1. Add proper [testing](#rule-testing-fixtures-and-snapshots) for your rule.
1. Update the generated files (documentation and generated code).
To trigger the violation, you'll likely want to augment the logic in `crates/ruff/src/checkers/ast.rs`
To trigger the violation, you'll likely want to augment the logic in `crates/ruff_linter/src/checkers/ast.rs`
to call your new function at the appropriate time and with the appropriate inputs. The `Checker`
defined therein is a Python AST visitor, which iterates over the AST, building up a semantic model,
and calling out to lint rule analyzer functions as it goes.
@@ -221,7 +221,7 @@ Ruff's output for each fixture, which you can then commit alongside your changes
Once you've completed the code for the rule itself, you can define tests with the following steps:
1. Add a Python file to `crates/ruff/resources/test/fixtures/[linter]` that contains the code you
1. Add a Python file to `crates/ruff_linter/resources/test/fixtures/[linter]` that contains the code you
want to test. The file name should match the rule name (e.g., `E402.py`), and it should include
examples of both violations and non-violations.
@@ -230,16 +230,16 @@ Once you've completed the code for the rule itself, you can define tests with th
For example, if you're adding a new rule named `E402`, you would run:
```shell
cargo run -p ruff_cli -- check crates/ruff/resources/test/fixtures/pycodestyle/E402.py --no-cache --select E402
cargo run -p ruff_cli -- check crates/ruff_linter/resources/test/fixtures/pycodestyle/E402.py --no-cache --select E402
```
**Note:** Only a subset of rules are enabled by default. When testing a new rule, ensure that
you activate it by adding `--select ${rule_code}` to the command.
1. Add the test to the relevant `crates/ruff/src/rules/[linter]/mod.rs` file. If you're contributing
1. Add the test to the relevant `crates/ruff_linter/src/rules/[linter]/mod.rs` file. If you're contributing
a rule to a pre-existing set, you should be able to find a similar example to pattern-match
against. If you're adding a new linter, you'll need to create a new `mod.rs` file (see,
e.g., `crates/ruff/src/rules/flake8_bugbear/mod.rs`)
e.g., `crates/ruff_linter/src/rules/flake8_bugbear/mod.rs`)
1. Run `cargo test`. Your test will fail, but you'll be prompted to follow-up
with `cargo insta review`. Run `cargo insta review`, review and accept the generated snapshot,
@@ -251,25 +251,24 @@ Once you've completed the code for the rule itself, you can define tests with th
Ruff's user-facing settings live in a few different places.
First, the command-line options are defined via the `Cli` struct in `crates/ruff/src/cli.rs`.
First, the command-line options are defined via the `Args` struct in `crates/ruff_cli/src/args.rs`.
Second, the `pyproject.toml` options are defined in `crates/ruff/src/settings/options.rs` (via the
`Options` struct), `crates/ruff/src/settings/configuration.rs` (via the `Configuration` struct), and
`crates/ruff/src/settings/mod.rs` (via the `Settings` struct). These represent, respectively: the
schema used to parse the `pyproject.toml` file; an internal, intermediate representation; and the
final, internal representation used to power Ruff.
Second, the `pyproject.toml` options are defined in `crates/ruff_workspace/src/options.rs` (via the
`Options` struct), `crates/ruff_workspace/src/configuration.rs` (via the `Configuration` struct),
and `crates/ruff_workspace/src/settings.rs` (via the `Settings` struct), which then includes
the `LinterSettings` struct as a field.
These represent, respectively: the schema used to parse the `pyproject.toml` file; an internal,
intermediate representation; and the final, internal representation used to power Ruff.
To add a new configuration option, you'll likely want to modify these latter few files (along with
`cli.rs`, if appropriate). If you want to pattern-match against an existing example, grep for
`arg.rs`, if appropriate). If you want to pattern-match against an existing example, grep for
`dummy_variable_rgx`, which defines a regular expression to match against acceptable unused
variables (e.g., `_`).
Note that plugin-specific configuration options are defined in their own modules (e.g.,
`crates/ruff/src/flake8_unused_arguments/settings.rs`).
You may also want to add the new configuration option to the `flake8-to-ruff` tool, which is
responsible for converting `flake8` configuration files to Ruff's TOML format. This logic
lives in `crates/ruff/src/flake8_to_ruff/converter.rs`.
`Settings` in `crates/ruff_linter/src/flake8_unused_arguments/settings.rs` coupled with
`Flake8UnusedArgumentsOptions` in `crates/ruff_workspace/src/options.rs`).
Finally, regenerate the documentation and generated code with `cargo dev generate-all`.
@@ -362,46 +361,46 @@ First, clone [CPython](https://github.com/python/cpython). It's a large and dive
which makes it a good target for benchmarking.
```shell
git clone --branch 3.10 https://github.com/python/cpython.git crates/ruff/resources/test/cpython
git clone --branch 3.10 https://github.com/python/cpython.git crates/ruff_linter/resources/test/cpython
```
To benchmark the release build:
```shell
cargo build --release && hyperfine --warmup 10 \
"./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache -e" \
"./target/release/ruff ./crates/ruff/resources/test/cpython/ -e"
"./target/release/ruff ./crates/ruff_linter/resources/test/cpython/ --no-cache -e" \
"./target/release/ruff ./crates/ruff_linter/resources/test/cpython/ -e"
Benchmark 1: ./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache
Benchmark 1: ./target/release/ruff ./crates/ruff_linter/resources/test/cpython/ --no-cache
Time (mean ± σ): 293.8 ms ± 3.2 ms [User: 2384.6 ms, System: 90.3 ms]
Range (min … max): 289.9 ms … 301.6 ms 10 runs
Benchmark 2: ./target/release/ruff ./crates/ruff/resources/test/cpython/
Benchmark 2: ./target/release/ruff ./crates/ruff_linter/resources/test/cpython/
Time (mean ± σ): 48.0 ms ± 3.1 ms [User: 65.2 ms, System: 124.7 ms]
Range (min … max): 45.0 ms … 66.7 ms 62 runs
Summary
'./target/release/ruff ./crates/ruff/resources/test/cpython/' ran
6.12 ± 0.41 times faster than './target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache'
'./target/release/ruff ./crates/ruff_linter/resources/test/cpython/' ran
6.12 ± 0.41 times faster than './target/release/ruff ./crates/ruff_linter/resources/test/cpython/ --no-cache'
```
To benchmark against the ecosystem's existing tools:
```shell
hyperfine --ignore-failure --warmup 5 \
"./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache" \
"pyflakes crates/ruff/resources/test/cpython" \
"./target/release/ruff ./crates/ruff_linter/resources/test/cpython/ --no-cache" \
"pyflakes crates/ruff_linter/resources/test/cpython" \
"autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython" \
"pycodestyle crates/ruff/resources/test/cpython" \
"flake8 crates/ruff/resources/test/cpython"
"pycodestyle crates/ruff_linter/resources/test/cpython" \
"flake8 crates/ruff_linter/resources/test/cpython"
Benchmark 1: ./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache
Benchmark 1: ./target/release/ruff ./crates/ruff_linter/resources/test/cpython/ --no-cache
Time (mean ± σ): 294.3 ms ± 3.3 ms [User: 2467.5 ms, System: 89.6 ms]
Range (min … max): 291.1 ms … 302.8 ms 10 runs
Warning: Ignoring non-zero exit code.
Benchmark 2: pyflakes crates/ruff/resources/test/cpython
Benchmark 2: pyflakes crates/ruff_linter/resources/test/cpython
Time (mean ± σ): 15.786 s ± 0.143 s [User: 15.560 s, System: 0.214 s]
Range (min … max): 15.640 s … 16.157 s 10 runs
@@ -411,31 +410,31 @@ Benchmark 3: autoflake --recursive --expand-star-imports --remove-all-unused-imp
Time (mean ± σ): 6.175 s ± 0.169 s [User: 54.102 s, System: 1.057 s]
Range (min … max): 5.950 s … 6.391 s 10 runs
Benchmark 4: pycodestyle crates/ruff/resources/test/cpython
Benchmark 4: pycodestyle crates/ruff_linter/resources/test/cpython
Time (mean ± σ): 46.921 s ± 0.508 s [User: 46.699 s, System: 0.202 s]
Range (min … max): 46.171 s … 47.863 s 10 runs
Warning: Ignoring non-zero exit code.
Benchmark 5: flake8 crates/ruff/resources/test/cpython
Benchmark 5: flake8 crates/ruff_linter/resources/test/cpython
Time (mean ± σ): 12.260 s ± 0.321 s [User: 102.934 s, System: 1.230 s]
Range (min … max): 11.848 s … 12.933 s 10 runs
Warning: Ignoring non-zero exit code.
Summary
'./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache' ran
'./target/release/ruff ./crates/ruff_linter/resources/test/cpython/ --no-cache' ran
20.98 ± 0.62 times faster than 'autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython'
41.66 ± 1.18 times faster than 'flake8 crates/ruff/resources/test/cpython'
53.64 ± 0.77 times faster than 'pyflakes crates/ruff/resources/test/cpython'
159.43 ± 2.48 times faster than 'pycodestyle crates/ruff/resources/test/cpython'
41.66 ± 1.18 times faster than 'flake8 crates/ruff_linter/resources/test/cpython'
53.64 ± 0.77 times faster than 'pyflakes crates/ruff_linter/resources/test/cpython'
159.43 ± 2.48 times faster than 'pycodestyle crates/ruff_linter/resources/test/cpython'
```
To benchmark a subset of rules, e.g. `LineTooLong` and `DocLineTooLong`:
```shell
cargo build --release && hyperfine --warmup 10 \
"./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache -e --select W505,E501"
"./target/release/ruff ./crates/ruff_linter/resources/test/cpython/ --no-cache -e --select W505,E501"
```
You can run `poetry install` from `./scripts/benchmarks` to create a working environment for the
@@ -468,10 +467,10 @@ rm Lib/test/bad_coding.py \
Lib/test/test_typing.py
```
Then, from `crates/ruff/resources/test/cpython`, run: `time pylint -j 0 -E $(git ls-files '*.py')`. This
Then, from `crates/ruff_linter/resources/test/cpython`, run: `time pylint -j 0 -E $(git ls-files '*.py')`. This
will execute Pylint with maximum parallelism and only report errors.
To benchmark Pyupgrade, run the following from `crates/ruff/resources/test/cpython`:
To benchmark Pyupgrade, run the following from `crates/ruff_linter/resources/test/cpython`:
```shell
hyperfine --ignore-failure --warmup 5 --prepare "git reset --hard HEAD" \

516
Cargo.lock generated
View File

@@ -172,12 +172,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.3"
@@ -220,15 +214,6 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bstr"
version = "1.6.2"
@@ -510,15 +495,6 @@ version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
[[package]]
name = "cpufeatures"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
@@ -611,16 +587,6 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "darling"
version = "0.20.3"
@@ -668,16 +634,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "dirs"
version = "4.0.0"
@@ -764,18 +720,6 @@ version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "embed-doc-image"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af36f591236d9d822425cb6896595658fa558fcebf5ee8accac1d4b92c47166e"
dependencies = [
"base64 0.13.1",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "ena"
version = "0.14.2"
@@ -878,7 +822,7 @@ dependencies = [
"pep440_rs",
"pretty_assertions",
"regex",
"ruff",
"ruff_linter",
"ruff_workspace",
"rustc-hash",
"serde",
@@ -928,16 +872,6 @@ dependencies = [
"libc",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.10"
@@ -1233,15 +1167,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "keccak"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940"
dependencies = [
"cpufeatures",
]
[[package]]
name = "kqueue"
version = "1.0.8"
@@ -1395,41 +1320,6 @@ version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "malachite"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9fa232412d927f518cd873073911726943f432bac1bbc1288316d240635dc51"
dependencies = [
"malachite-base",
"malachite-nz",
]
[[package]]
name = "malachite-base"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "606a61b226dc58b8b283399b74754460433c193b193f26eaaad92f7966abd72b"
dependencies = [
"getrandom",
"itertools 0.11.0",
"rand",
"rand_chacha",
"ryu",
"sha3",
]
[[package]]
name = "malachite-nz"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "863d06218c83cc2269c425186cc15094d6284b1333a1184d0890aecfddb8916b"
dependencies = [
"embed-doc-image",
"itertools 0.11.0",
"malachite-base",
]
[[package]]
name = "matchers"
version = "0.1.0"
@@ -1564,6 +1454,27 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-bigint"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.16"
@@ -2118,7 +2029,176 @@ dependencies = [
]
[[package]]
name = "ruff"
name = "ruff_benchmark"
version = "0.0.0"
dependencies = [
"codspeed-criterion-compat",
"criterion",
"mimalloc",
"once_cell",
"ruff_linter",
"ruff_python_ast",
"ruff_python_formatter",
"ruff_python_index",
"ruff_python_parser",
"serde",
"serde_json",
"tikv-jemallocator",
"ureq",
"url",
]
[[package]]
name = "ruff_cache"
version = "0.0.0"
dependencies = [
"filetime",
"glob",
"globset",
"itertools 0.11.0",
"regex",
"ruff_macros",
"seahash",
]
[[package]]
name = "ruff_cli"
version = "0.0.290"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
"argfile",
"assert_cmd",
"bincode",
"bitflags 2.4.0",
"cachedir",
"chrono",
"clap",
"clap_complete_command",
"clearscreen",
"colored",
"filetime",
"glob",
"ignore",
"insta",
"insta-cmd",
"is-macro",
"itertools 0.11.0",
"itoa",
"log",
"mimalloc",
"notify",
"path-absolutize",
"rayon",
"regex",
"ruff_cache",
"ruff_diagnostics",
"ruff_formatter",
"ruff_linter",
"ruff_macros",
"ruff_notebook",
"ruff_python_ast",
"ruff_python_formatter",
"ruff_python_stdlib",
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"ruff_workspace",
"rustc-hash",
"serde",
"serde_json",
"shellexpand",
"similar",
"strum",
"tempfile",
"test-case",
"thiserror",
"tikv-jemallocator",
"tracing",
"ureq",
"walkdir",
"wild",
]
[[package]]
name = "ruff_dev"
version = "0.0.0"
dependencies = [
"anyhow",
"clap",
"ignore",
"imara-diff",
"indicatif",
"indoc",
"itertools 0.11.0",
"libcst",
"once_cell",
"pretty_assertions",
"rayon",
"regex",
"ruff_cli",
"ruff_diagnostics",
"ruff_formatter",
"ruff_linter",
"ruff_notebook",
"ruff_python_ast",
"ruff_python_codegen",
"ruff_python_formatter",
"ruff_python_literal",
"ruff_python_parser",
"ruff_python_stdlib",
"ruff_python_trivia",
"ruff_workspace",
"schemars",
"serde",
"serde_json",
"similar",
"strum",
"strum_macros",
"tempfile",
"toml",
"tracing",
"tracing-indicatif",
"tracing-subscriber",
]
[[package]]
name = "ruff_diagnostics"
version = "0.0.0"
dependencies = [
"anyhow",
"log",
"ruff_text_size",
"serde",
]
[[package]]
name = "ruff_formatter"
version = "0.0.0"
dependencies = [
"drop_bomb",
"insta",
"ruff_cache",
"ruff_macros",
"ruff_text_size",
"rustc-hash",
"schemars",
"serde",
"static_assertions",
"tracing",
"unicode-width",
]
[[package]]
name = "ruff_index"
version = "0.0.0"
dependencies = [
"ruff_macros",
"static_assertions",
]
[[package]]
name = "ruff_linter"
version = "0.0.290"
dependencies = [
"annotate-snippets 0.9.1",
@@ -2136,9 +2216,9 @@ dependencies = [
"itertools 0.11.0",
"libcst",
"log",
"malachite",
"memchr",
"natord",
"num-bigint",
"num-traits",
"once_cell",
"path-absolutize",
@@ -2183,172 +2263,6 @@ dependencies = [
"wsl",
]
[[package]]
name = "ruff_benchmark"
version = "0.0.0"
dependencies = [
"codspeed-criterion-compat",
"criterion",
"mimalloc",
"once_cell",
"ruff",
"ruff_python_ast",
"ruff_python_formatter",
"ruff_python_index",
"ruff_python_parser",
"serde",
"serde_json",
"tikv-jemallocator",
"ureq",
"url",
]
[[package]]
name = "ruff_cache"
version = "0.0.0"
dependencies = [
"filetime",
"glob",
"globset",
"itertools 0.11.0",
"regex",
"ruff_macros",
]
[[package]]
name = "ruff_cli"
version = "0.0.290"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
"argfile",
"assert_cmd",
"bincode",
"bitflags 2.4.0",
"cachedir",
"chrono",
"clap",
"clap_complete_command",
"clearscreen",
"colored",
"filetime",
"glob",
"ignore",
"insta",
"insta-cmd",
"is-macro",
"itertools 0.11.0",
"itoa",
"log",
"mimalloc",
"notify",
"path-absolutize",
"rayon",
"regex",
"ruff",
"ruff_cache",
"ruff_diagnostics",
"ruff_formatter",
"ruff_macros",
"ruff_notebook",
"ruff_python_ast",
"ruff_python_formatter",
"ruff_python_stdlib",
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"ruff_workspace",
"rustc-hash",
"serde",
"serde_json",
"shellexpand",
"similar",
"strum",
"tempfile",
"test-case",
"thiserror",
"tikv-jemallocator",
"tracing",
"ureq",
"walkdir",
"wild",
]
[[package]]
name = "ruff_dev"
version = "0.0.0"
dependencies = [
"anyhow",
"clap",
"ignore",
"imara-diff",
"indicatif",
"indoc",
"itertools 0.11.0",
"libcst",
"once_cell",
"pretty_assertions",
"rayon",
"regex",
"ruff",
"ruff_cli",
"ruff_diagnostics",
"ruff_formatter",
"ruff_notebook",
"ruff_python_ast",
"ruff_python_codegen",
"ruff_python_formatter",
"ruff_python_literal",
"ruff_python_parser",
"ruff_python_stdlib",
"ruff_python_trivia",
"ruff_workspace",
"schemars",
"serde",
"serde_json",
"similar",
"strum",
"strum_macros",
"tempfile",
"toml",
"tracing",
"tracing-indicatif",
"tracing-subscriber",
]
[[package]]
name = "ruff_diagnostics"
version = "0.0.0"
dependencies = [
"anyhow",
"log",
"ruff_text_size",
"serde",
]
[[package]]
name = "ruff_formatter"
version = "0.0.0"
dependencies = [
"drop_bomb",
"insta",
"ruff_text_size",
"rustc-hash",
"schemars",
"serde",
"static_assertions",
"tracing",
"unicode-width",
]
[[package]]
name = "ruff_index"
version = "0.0.0"
dependencies = [
"ruff_macros",
"static_assertions",
]
[[package]]
name = "ruff_macros"
version = "0.0.0"
@@ -2387,8 +2301,9 @@ dependencies = [
"insta",
"is-macro",
"itertools 0.11.0",
"malachite",
"memchr",
"num-bigint",
"num-traits",
"once_cell",
"ruff_python_parser",
"ruff_python_trivia",
@@ -2423,7 +2338,9 @@ dependencies = [
"itertools 0.11.0",
"memchr",
"once_cell",
"ruff_cache",
"ruff_formatter",
"ruff_macros",
"ruff_python_ast",
"ruff_python_index",
"ruff_python_parser",
@@ -2477,7 +2394,8 @@ dependencies = [
"itertools 0.11.0",
"lalrpop",
"lalrpop-util",
"malachite",
"num-bigint",
"num-traits",
"ruff_python_ast",
"ruff_text_size",
"rustc-hash",
@@ -2503,6 +2421,7 @@ version = "0.0.0"
dependencies = [
"bitflags 2.4.0",
"is-macro",
"num-traits",
"ruff_index",
"ruff_python_ast",
"ruff_python_parser",
@@ -2578,9 +2497,9 @@ dependencies = [
"console_log",
"js-sys",
"log",
"ruff",
"ruff_diagnostics",
"ruff_formatter",
"ruff_linter",
"ruff_python_ast",
"ruff_python_codegen",
"ruff_python_formatter",
@@ -2608,12 +2527,15 @@ dependencies = [
"ignore",
"itertools 0.11.0",
"log",
"once_cell",
"path-absolutize",
"pep440_rs",
"regex",
"ruff",
"ruff_cache",
"ruff_formatter",
"ruff_linter",
"ruff_macros",
"ruff_python_formatter",
"rustc-hash",
"schemars",
"serde",
@@ -2751,6 +2673,12 @@ dependencies = [
"untrusted",
]
[[package]]
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "semver"
version = "1.0.18"
@@ -2850,16 +2778,6 @@ dependencies = [
"syn 2.0.37",
]
[[package]]
name = "sha3"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
dependencies = [
"digest",
"keccak",
]
[[package]]
name = "sharded-slab"
version = "0.1.4"
@@ -3272,12 +3190,6 @@ version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unic-char-property"
version = "0.9.0"
@@ -3343,9 +3255,9 @@ dependencies = [
[[package]]
name = "unicode-width"
version = "0.1.10"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "unicode-xid"
@@ -3373,7 +3285,7 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9"
dependencies = [
"base64 0.21.3",
"base64",
"flate2",
"log",
"once_cell",

View File

@@ -25,8 +25,8 @@ insta = { version = "1.31.0", feature = ["filters", "glob"] }
is-macro = { version = "0.3.0" }
itertools = { version = "0.11.0" }
log = { version = "0.4.17" }
malachite = { version = "0.4.0", default-features = false, features = ["naturals_and_integers"] }
memchr = "2.6.3"
num-bigint = { version = "0.4.3" }
num-traits = { version = "0.2.15" }
once_cell = { version = "1.17.1" }
path-absolutize = { version = "3.1.1" }
@@ -51,7 +51,7 @@ tracing = "0.1.37"
tracing-indicatif = "0.3.4"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
unicode-ident = "1.0.12"
unicode-width = "0.1.10"
unicode-width = "0.1.11"
uuid = { version = "1.4.1", features = ["v4", "fast-rng", "macro-diagnostics", "js"] }
wsl = { version = "0.1.0" }

22
LICENSE
View File

@@ -1194,7 +1194,27 @@ are:
- flake8-self, licensed as follows:
"""
Freely Distributable
MIT License
Copyright (c) 2023 Korijn van Golen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- flake8-django, licensed under the GPL license.

View File

@@ -13,7 +13,7 @@ repository = { workspace = true }
license = { workspace = true }
[dependencies]
ruff = { path = "../ruff", default-features = false }
ruff_linter = { path = "../ruff_linter", default-features = false }
ruff_workspace = { path = "../ruff_workspace" }
anyhow = { workspace = true }

View File

@@ -1,7 +1,7 @@
//! Extract Black configuration settings from a pyproject.toml.
use ruff::line_width::LineLength;
use ruff::settings::types::PythonVersion;
use ruff_linter::line_width::LineLength;
use ruff_linter::settings::types::PythonVersion;
use serde::{Deserialize, Serialize};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]

View File

@@ -3,17 +3,17 @@ use std::str::FromStr;
use itertools::Itertools;
use ruff::line_width::LineLength;
use ruff::registry::Linter;
use ruff::rule_selector::RuleSelector;
use ruff::rules::flake8_pytest_style::types::{
use ruff_linter::line_width::LineLength;
use ruff_linter::registry::Linter;
use ruff_linter::rule_selector::RuleSelector;
use ruff_linter::rules::flake8_pytest_style::types::{
ParametrizeNameType, ParametrizeValuesRowType, ParametrizeValuesType,
};
use ruff::rules::flake8_quotes::settings::Quote;
use ruff::rules::flake8_tidy_imports::settings::Strictness;
use ruff::rules::pydocstyle::settings::Convention;
use ruff::settings::types::PythonVersion;
use ruff::warn_user;
use ruff_linter::rules::flake8_quotes::settings::Quote;
use ruff_linter::rules::flake8_tidy_imports::settings::Strictness;
use ruff_linter::rules::pydocstyle::settings::Convention;
use ruff_linter::settings::types::PythonVersion;
use ruff_linter::warn_user;
use ruff_workspace::options::{
Flake8AnnotationsOptions, Flake8BugbearOptions, Flake8BuiltinsOptions, Flake8ErrMsgOptions,
Flake8PytestStyleOptions, Flake8QuotesOptions, Flake8TidyImportsOptions, McCabeOptions,
@@ -458,12 +458,12 @@ mod tests {
use pep440_rs::VersionSpecifiers;
use pretty_assertions::assert_eq;
use ruff::line_width::LineLength;
use ruff::registry::Linter;
use ruff::rule_selector::RuleSelector;
use ruff::rules::flake8_quotes;
use ruff::rules::pydocstyle::settings::Convention;
use ruff::settings::types::PythonVersion;
use ruff_linter::line_width::LineLength;
use ruff_linter::registry::Linter;
use ruff_linter::rule_selector::RuleSelector;
use ruff_linter::rules::flake8_quotes;
use ruff_linter::rules::pydocstyle::settings::Convention;
use ruff_linter::settings::types::PythonVersion;
use ruff_workspace::options::{Flake8QuotesOptions, Options, PydocstyleOptions};
use ruff_workspace::pyproject::Pyproject;

View File

@@ -19,7 +19,7 @@ use crate::converter::convert;
use crate::external_config::ExternalConfig;
use crate::plugin::Plugin;
use crate::pyproject::parse;
use ruff::logging::{set_up_logging, LogLevel};
use ruff_linter::logging::{set_up_logging, LogLevel};
#[derive(Parser)]
#[command(

View File

@@ -3,10 +3,11 @@ use std::str::FromStr;
use anyhow::{bail, Result};
use once_cell::sync::Lazy;
use regex::Regex;
use ruff::settings::types::PatternPrefixPair;
use ruff::{warn_user, RuleSelector};
use rustc_hash::FxHashMap;
use ruff_linter::settings::types::PatternPrefixPair;
use ruff_linter::{warn_user, RuleSelector};
static COMMA_SEPARATED_LIST_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
/// Parse a comma-separated list of `RuleSelector` values (e.g.,
@@ -192,11 +193,11 @@ pub(crate) fn collect_per_file_ignores(
#[cfg(test)]
mod tests {
use anyhow::Result;
use ruff::RuleSelector;
use ruff::codes;
use ruff::registry::Linter;
use ruff::settings::types::PatternPrefixPair;
use ruff_linter::codes;
use ruff_linter::registry::Linter;
use ruff_linter::settings::types::PatternPrefixPair;
use ruff_linter::RuleSelector;
use super::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};

View File

@@ -3,9 +3,9 @@ use std::fmt;
use std::str::FromStr;
use anyhow::anyhow;
use ruff::registry::Linter;
use ruff::settings::types::PreviewMode;
use ruff::RuleSelector;
use ruff_linter::registry::Linter;
use ruff_linter::settings::types::PreviewMode;
use ruff_linter::RuleSelector;
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Plugin {

View File

@@ -1,96 +0,0 @@
# project
An example multi-package Python project used to test setting resolution and other complex
behaviors.
## Expected behavior
Running from the repo root should pick up and enforce the appropriate settings for each package:
```console
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:1: I001 [*] Import block is un-sorted or un-formatted
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
crates/ruff/resources/test/project/examples/docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
crates/ruff/resources/test/project/project/file.py:1:8: F401 [*] `os` imported but unused
crates/ruff/resources/test/project/project/import_file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
Found 7 errors.
[*] 7 potentially fixable with the --fix option.
```
Running from the project directory itself should exhibit the same behavior:
```console
∴ (cd crates/ruff/resources/test/project/ && cargo run -p ruff_cli -- check .)
examples/.dotfiles/script.py:1:1: I001 [*] Import block is un-sorted or un-formatted
examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
examples/docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
project/file.py:1:8: F401 [*] `os` imported but unused
project/import_file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
Found 7 errors.
[*] 7 potentially fixable with the --fix option.
```
Running from the sub-package directory should exhibit the same behavior, but omit the top-level
files:
```console
∴ (cd crates/ruff/resources/test/project/examples/docs && cargo run -p ruff_cli -- check .)
docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
Found 2 errors.
[*] 2 potentially fixable with the --fix option.
```
`--config` should force Ruff to use the specified `pyproject.toml` for all files, and resolve
file paths from the current working directory:
```console
∴ (cargo run -p ruff_cli -- check --config=crates/ruff/resources/test/project/pyproject.toml crates/ruff/resources/test/project/)
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
crates/ruff/resources/test/project/examples/docs/docs/concepts/file.py:1:8: F401 [*] `os` imported but unused
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:8: F401 [*] `os` imported but unused
crates/ruff/resources/test/project/examples/docs/docs/file.py:3:8: F401 [*] `numpy` imported but unused
crates/ruff/resources/test/project/examples/docs/docs/file.py:4:27: F401 [*] `docs.concepts.file` imported but unused
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 [*] `os` imported but unused
crates/ruff/resources/test/project/project/file.py:1:8: F401 [*] `os` imported but unused
Found 9 errors.
[*] 9 potentially fixable with the --fix option.
```
Running from a parent directory should "ignore" the `exclude` (hence, `concepts/file.py` gets
included in the output):
```console
∴ (cd crates/ruff/resources/test/project/examples && cargo run -p ruff_cli -- check --config=docs/ruff.toml .)
docs/docs/concepts/file.py:5:5: F841 [*] Local variable `x` is assigned to but never used
docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
excluded/script.py:5:5: F841 [*] Local variable `x` is assigned to but never used
Found 4 errors.
[*] 4 potentially fixable with the --fix option.
```
Passing an excluded directory directly should report errors in the contained files:
```console
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/examples/excluded/
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 [*] `os` imported but unused
Found 1 error.
[*] 1 potentially fixable with the --fix option.
```
Unless we `--force-exclude`:
```console
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/examples/excluded/ --force-exclude
warning: No Python files found under the given path(s)
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/examples/excluded/script.py --force-exclude
warning: No Python files found under the given path(s)
```

File diff suppressed because it is too large Load Diff

View File

@@ -1,243 +0,0 @@
//! `NoQA` enforcement and validation.
use std::path::Path;
use itertools::Itertools;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use ruff_diagnostics::{Diagnostic, Edit, Fix};
use ruff_python_trivia::CommentRanges;
use ruff_source_file::Locator;
use crate::noqa;
use crate::noqa::{Directive, FileExemption, NoqaDirectives, NoqaMapping};
use crate::registry::{AsRule, Rule};
use crate::rule_redirects::get_redirect_target;
use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA};
use crate::settings::Settings;
pub(crate) fn check_noqa(
diagnostics: &mut Vec<Diagnostic>,
path: &Path,
locator: &Locator,
comment_ranges: &CommentRanges,
noqa_line_for: &NoqaMapping,
analyze_directives: bool,
settings: &Settings,
) -> Vec<usize> {
// Identify any codes that are globally exempted (within the current file).
let exemption = FileExemption::try_extract(locator.contents(), comment_ranges, path, locator);
// Extract all `noqa` directives.
let mut noqa_directives = NoqaDirectives::from_commented_ranges(comment_ranges, path, locator);
// Indices of diagnostics that were ignored by a `noqa` directive.
let mut ignored_diagnostics = vec![];
// Remove any ignored diagnostics.
'outer: for (index, diagnostic) in diagnostics.iter().enumerate() {
if matches!(diagnostic.kind.rule(), Rule::BlanketNOQA) {
continue;
}
match &exemption {
Some(FileExemption::All) => {
// If the file is exempted, ignore all diagnostics.
ignored_diagnostics.push(index);
continue;
}
Some(FileExemption::Codes(codes)) => {
// If the diagnostic is ignored by a global exemption, ignore it.
if codes.contains(&diagnostic.kind.rule().noqa_code()) {
ignored_diagnostics.push(index);
continue;
}
}
None => {}
}
let noqa_offsets = diagnostic
.parent
.into_iter()
.chain(std::iter::once(diagnostic.start()))
.map(|position| noqa_line_for.resolve(position))
.unique();
for noqa_offset in noqa_offsets {
if let Some(directive_line) = noqa_directives.find_line_with_directive_mut(noqa_offset)
{
let suppressed = match &directive_line.directive {
Directive::All(_) => {
directive_line
.matches
.push(diagnostic.kind.rule().noqa_code());
ignored_diagnostics.push(index);
true
}
Directive::Codes(directive) => {
if noqa::includes(diagnostic.kind.rule(), directive.codes()) {
directive_line
.matches
.push(diagnostic.kind.rule().noqa_code());
ignored_diagnostics.push(index);
true
} else {
false
}
}
};
if suppressed {
continue 'outer;
}
}
}
}
// Enforce that the noqa directive was actually used (RUF100), unless RUF100 was itself
// suppressed.
if settings.rules.enabled(Rule::UnusedNOQA)
&& analyze_directives
&& !exemption.is_some_and(|exemption| match exemption {
FileExemption::All => true,
FileExemption::Codes(codes) => codes.contains(&Rule::UnusedNOQA.noqa_code()),
})
{
for line in noqa_directives.lines() {
match &line.directive {
Directive::All(directive) => {
if line.matches.is_empty() {
let mut diagnostic =
Diagnostic::new(UnusedNOQA { codes: None }, directive.range());
if settings.rules.should_fix(diagnostic.kind.rule()) {
diagnostic
.set_fix(Fix::suggested(delete_noqa(directive.range(), locator)));
}
diagnostics.push(diagnostic);
}
}
Directive::Codes(directive) => {
let mut disabled_codes = vec![];
let mut unknown_codes = vec![];
let mut unmatched_codes = vec![];
let mut valid_codes = vec![];
let mut self_ignore = false;
for code in directive.codes() {
let code = get_redirect_target(code).unwrap_or(code);
if Rule::UnusedNOQA.noqa_code() == code {
self_ignore = true;
break;
}
if line.matches.iter().any(|match_| *match_ == code)
|| settings.external.contains(code)
{
valid_codes.push(code);
} else {
if let Ok(rule) = Rule::from_code(code) {
if settings.rules.enabled(rule) {
unmatched_codes.push(code);
} else {
disabled_codes.push(code);
}
} else {
unknown_codes.push(code);
}
}
}
if self_ignore {
continue;
}
if !(disabled_codes.is_empty()
&& unknown_codes.is_empty()
&& unmatched_codes.is_empty())
{
let mut diagnostic = Diagnostic::new(
UnusedNOQA {
codes: Some(UnusedCodes {
disabled: disabled_codes
.iter()
.map(|code| (*code).to_string())
.collect(),
unknown: unknown_codes
.iter()
.map(|code| (*code).to_string())
.collect(),
unmatched: unmatched_codes
.iter()
.map(|code| (*code).to_string())
.collect(),
}),
},
directive.range(),
);
if settings.rules.should_fix(diagnostic.kind.rule()) {
if valid_codes.is_empty() {
diagnostic.set_fix(Fix::suggested(delete_noqa(
directive.range(),
locator,
)));
} else {
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
format!("# noqa: {}", valid_codes.join(", ")),
directive.range(),
)));
}
}
diagnostics.push(diagnostic);
}
}
}
}
}
ignored_diagnostics.sort_unstable();
ignored_diagnostics
}
/// Generate a [`Edit`] to delete a `noqa` directive.
fn delete_noqa(range: TextRange, locator: &Locator) -> Edit {
let line_range = locator.line_range(range.start());
// Compute the leading space.
let prefix = locator.slice(TextRange::new(line_range.start(), range.start()));
let leading_space = prefix
.rfind(|c: char| !c.is_whitespace())
.map_or(prefix.len(), |i| prefix.len() - i - 1);
let leading_space_len = TextSize::try_from(leading_space).unwrap();
// Compute the trailing space.
let suffix = locator.slice(TextRange::new(range.end(), line_range.end()));
let trailing_space = suffix
.find(|c: char| !c.is_whitespace())
.map_or(suffix.len(), |i| i);
let trailing_space_len = TextSize::try_from(trailing_space).unwrap();
// Ex) `# noqa`
if line_range
== TextRange::new(
range.start() - leading_space_len,
range.end() + trailing_space_len,
)
{
let full_line_end = locator.full_line_end(line_range.end());
Edit::deletion(line_range.start(), full_line_end)
}
// Ex) `x = 1 # noqa`
else if range.end() + trailing_space_len == line_range.end() {
Edit::deletion(range.start() - leading_space_len, line_range.end())
}
// Ex) `x = 1 # noqa # type: ignore`
else if locator.contents()[usize::from(range.end() + trailing_space_len)..].starts_with('#') {
Edit::deletion(range.start(), range.end() + trailing_space_len)
}
// Ex) `x = 1 # noqa here`
else {
Edit::deletion(
range.start() + "# ".text_len(),
range.end() + trailing_space_len,
)
}
}

View File

@@ -1,5 +0,0 @@
---
source: crates/ruff/src/comments/shebang.rs
expression: "ShebangDirective::try_extract(source)"
---
None

View File

@@ -1,5 +0,0 @@
---
source: crates/ruff/src/comments/shebang.rs
expression: "ShebangDirective::try_extract(source)"
---
None

View File

@@ -1,9 +0,0 @@
---
source: crates/ruff/src/comments/shebang.rs
expression: "ShebangDirective::try_extract(source)"
---
Some(
ShebangDirective(
"/usr/bin/env python",
),
)

View File

@@ -1,9 +0,0 @@
---
source: crates/ruff/src/comments/shebang.rs
expression: "ShebangDirective::try_extract(source)"
---
Some(
ShebangDirective(
"/usr/bin/env python # trailing comment",
),
)

View File

@@ -1,5 +0,0 @@
---
source: crates/ruff/src/comments/shebang.rs
expression: "ShebangDirective::try_extract(source)"
---
None

View File

@@ -1,8 +0,0 @@
---
source: crates/ruff/src/message/azure.rs
expression: content
---
##vso[task.logissue type=error;sourcepath=fib.py;linenumber=1;columnnumber=8;code=F401;]`os` imported but unused
##vso[task.logissue type=error;sourcepath=fib.py;linenumber=6;columnnumber=5;code=F841;]Local variable `x` is assigned to but never used
##vso[task.logissue type=error;sourcepath=undef.py;linenumber=1;columnnumber=4;code=F821;]Undefined name `a`

View File

@@ -1,8 +0,0 @@
---
source: crates/ruff/src/message/github.rs
expression: content
---
::error title=Ruff (F401),file=fib.py,line=1,col=8,endLine=1,endColumn=10::fib.py:1:8: F401 `os` imported but unused
::error title=Ruff (F841),file=fib.py,line=6,col=5,endLine=6,endColumn=6::fib.py:6:5: F841 Local variable `x` is assigned to but never used
::error title=Ruff (F821),file=undef.py,line=1,col=4,endLine=1,endColumn=5::undef.py:1:4: F821 Undefined name `a`

View File

@@ -1,42 +0,0 @@
---
source: crates/ruff/src/message/gitlab.rs
expression: redact_fingerprint(&content)
---
[
{
"description": "(F401) `os` imported but unused",
"fingerprint": "<redacted>",
"location": {
"lines": {
"begin": 1,
"end": 1
},
"path": "fib.py"
},
"severity": "major"
},
{
"description": "(F841) Local variable `x` is assigned to but never used",
"fingerprint": "<redacted>",
"location": {
"lines": {
"begin": 6,
"end": 6
},
"path": "fib.py"
},
"severity": "major"
},
{
"description": "(F821) Undefined name `a`",
"fingerprint": "<redacted>",
"location": {
"lines": {
"begin": 1,
"end": 1
},
"path": "undef.py"
},
"severity": "major"
}
]

View File

@@ -1,12 +0,0 @@
---
source: crates/ruff/src/message/grouped.rs
expression: content
---
fib.py:
1:8 F401 `os` imported but unused
6:5 F841 Local variable `x` is assigned to but never used
undef.py:
1:4 F821 Undefined name `a`

View File

@@ -1,31 +0,0 @@
---
source: crates/ruff/src/message/grouped.rs
expression: content
---
fib.py:
1:8 F401 [*] `os` imported but unused
|
1 | import os
| ^^ F401
|
= help: Remove unused import: `os`
6:5 F841 [*] Local variable `x` is assigned to but never used
|
4 | def fibonacci(n):
5 | """Compute the nth number in the Fibonacci sequence."""
6 | x = 1
| ^ F841
7 | if n == 0:
8 | return 0
|
= help: Remove assignment to unused variable `x`
undef.py:
1:4 F821 Undefined name `a`
|
1 | if a == 1: pass
| ^ F821
|

View File

@@ -1,31 +0,0 @@
---
source: crates/ruff/src/message/grouped.rs
expression: content
---
fib.py:
1:8 F401 `os` imported but unused
|
1 | import os
| ^^ F401
|
= help: Remove unused import: `os`
6:5 F841 Local variable `x` is assigned to but never used
|
4 | def fibonacci(n):
5 | """Compute the nth number in the Fibonacci sequence."""
6 | x = 1
| ^ F841
7 | if n == 0:
8 | return 0
|
= help: Remove assignment to unused variable `x`
undef.py:
1:4 F821 Undefined name `a`
|
1 | if a == 1: pass
| ^ F821
|

View File

@@ -1,86 +0,0 @@
---
source: crates/ruff/src/message/json.rs
expression: content
---
[
{
"code": "F401",
"end_location": {
"column": 10,
"row": 1
},
"filename": "fib.py",
"fix": {
"applicability": "Suggested",
"edits": [
{
"content": "",
"end_location": {
"column": 1,
"row": 2
},
"location": {
"column": 1,
"row": 1
}
}
],
"message": "Remove unused import: `os`"
},
"location": {
"column": 8,
"row": 1
},
"message": "`os` imported but unused",
"noqa_row": 1,
"url": "https://docs.astral.sh/ruff/rules/unused-import"
},
{
"code": "F841",
"end_location": {
"column": 6,
"row": 6
},
"filename": "fib.py",
"fix": {
"applicability": "Suggested",
"edits": [
{
"content": "",
"end_location": {
"column": 10,
"row": 6
},
"location": {
"column": 5,
"row": 6
}
}
],
"message": "Remove assignment to unused variable `x`"
},
"location": {
"column": 5,
"row": 6
},
"message": "Local variable `x` is assigned to but never used",
"noqa_row": 6,
"url": "https://docs.astral.sh/ruff/rules/unused-variable"
},
{
"code": "F821",
"end_location": {
"column": 5,
"row": 1
},
"filename": "undef.py",
"fix": null,
"location": {
"column": 4,
"row": 1
},
"message": "Undefined name `a`",
"noqa_row": 1,
"url": "https://docs.astral.sh/ruff/rules/undefined-name"
}
]

View File

@@ -1,8 +0,0 @@
---
source: crates/ruff/src/message/json_lines.rs
expression: content
---
{"code":"F401","end_location":{"column":10,"row":1},"filename":"fib.py","fix":{"applicability":"Suggested","edits":[{"content":"","end_location":{"column":1,"row":2},"location":{"column":1,"row":1}}],"message":"Remove unused import: `os`"},"location":{"column":8,"row":1},"message":"`os` imported but unused","noqa_row":1,"url":"https://docs.astral.sh/ruff/rules/unused-import"}
{"code":"F841","end_location":{"column":6,"row":6},"filename":"fib.py","fix":{"applicability":"Suggested","edits":[{"content":"","end_location":{"column":10,"row":6},"location":{"column":5,"row":6}}],"message":"Remove assignment to unused variable `x`"},"location":{"column":5,"row":6},"message":"Local variable `x` is assigned to but never used","noqa_row":6,"url":"https://docs.astral.sh/ruff/rules/unused-variable"}
{"code":"F821","end_location":{"column":5,"row":1},"filename":"undef.py","fix":null,"location":{"column":4,"row":1},"message":"Undefined name `a`","noqa_row":1,"url":"https://docs.astral.sh/ruff/rules/undefined-name"}

View File

@@ -1,21 +0,0 @@
---
source: crates/ruff/src/message/junit.rs
expression: content
---
<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="ruff" tests="3" failures="3" errors="0">
<testsuite name="fib.py" tests="2" disabled="0" errors="0" failures="2" package="org.ruff">
<testcase name="org.ruff.F401" classname="fib" line="1" column="8">
<failure message="`os` imported but unused">line 1, col 8, `os` imported but unused</failure>
</testcase>
<testcase name="org.ruff.F841" classname="fib" line="6" column="5">
<failure message="Local variable `x` is assigned to but never used">line 6, col 5, Local variable `x` is assigned to but never used</failure>
</testcase>
</testsuite>
<testsuite name="undef.py" tests="1" disabled="0" errors="0" failures="1" package="org.ruff">
<testcase name="org.ruff.F821" classname="undef" line="1" column="4">
<failure message="Undefined name `a`">line 1, col 4, Undefined name `a`</failure>
</testcase>
</testsuite>
</testsuites>

View File

@@ -1,8 +0,0 @@
---
source: crates/ruff/src/message/pylint.rs
expression: content
---
fib.py:1: [F401] `os` imported but unused
fib.py:6: [F841] Local variable `x` is assigned to but never used
undef.py:1: [F821] Undefined name `a`

View File

@@ -1,29 +0,0 @@
---
source: crates/ruff/src/message/text.rs
expression: content
---
fib.py:1:8: F401 `os` imported but unused
|
1 | import os
| ^^ F401
|
= help: Remove unused import: `os`
fib.py:6:5: F841 Local variable `x` is assigned to but never used
|
4 | def fibonacci(n):
5 | """Compute the nth number in the Fibonacci sequence."""
6 | x = 1
| ^ F841
7 | if n == 0:
8 | return 0
|
= help: Remove assignment to unused variable `x`
undef.py:1:4: F821 Undefined name `a`
|
1 | if a == 1: pass
| ^ F821
|

View File

@@ -1,29 +0,0 @@
---
source: crates/ruff/src/message/text.rs
expression: content
---
fib.py:1:8: F401 [*] `os` imported but unused
|
1 | import os
| ^^ F401
|
= help: Remove unused import: `os`
fib.py:6:5: F841 [*] Local variable `x` is assigned to but never used
|
4 | def fibonacci(n):
5 | """Compute the nth number in the Fibonacci sequence."""
6 | x = 1
| ^ F841
7 | if n == 0:
8 | return 0
|
= help: Remove assignment to unused variable `x`
undef.py:1:4: F821 Undefined name `a`
|
1 | if a == 1: pass
| ^ F821
|

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +0,0 @@
//! Airflow-specific rules.
pub(crate) mod rules;
#[cfg(test)]
mod tests {
use std::path::Path;
use anyhow::Result;
use test_case::test_case;
use crate::registry::Rule;
use crate::test::test_path;
use crate::{assert_messages, settings};
#[test_case(Rule::AirflowVariableNameTaskIdMismatch, Path::new("AIR001.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("airflow").join(path).as_path(),
&settings::Settings::for_rule(rule_code),
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -1,22 +0,0 @@
---
source: crates/ruff/src/rules/airflow/mod.rs
---
AIR001.py:11:1: AIR001 Task variable name should match the `task_id`: "my_task"
|
9 | my_task_2 = PythonOperator(callable=my_callable, task_id="my_task_2")
10 |
11 | incorrect_name = PythonOperator(task_id="my_task")
| ^^^^^^^^^^^^^^ AIR001
12 | incorrect_name_2 = PythonOperator(callable=my_callable, task_id="my_task_2")
|
AIR001.py:12:1: AIR001 Task variable name should match the `task_id`: "my_task_2"
|
11 | incorrect_name = PythonOperator(task_id="my_task")
12 | incorrect_name_2 = PythonOperator(callable=my_callable, task_id="my_task_2")
| ^^^^^^^^^^^^^^^^ AIR001
13 |
14 | from my_module import MyClass
|

View File

@@ -1,26 +0,0 @@
//! Rules from [eradicate](https://pypi.org/project/eradicate/).
pub(crate) mod detection;
pub(crate) mod rules;
#[cfg(test)]
mod tests {
use std::path::Path;
use anyhow::Result;
use test_case::test_case;
use crate::registry::Rule;
use crate::test::test_path;
use crate::{assert_messages, settings};
#[test_case(Rule::CommentedOutCode, Path::new("ERA001.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("eradicate").join(path).as_path(),
&settings::Settings::for_rule(rule_code),
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -1,151 +0,0 @@
---
source: crates/ruff/src/rules/eradicate/mod.rs
---
ERA001.py:1:1: ERA001 [*] Found commented-out code
|
1 | #import os
| ^^^^^^^^^^ ERA001
2 | # from foo import junk
3 | #a = 3
|
= help: Remove commented-out code
Possible fix
1 |-#import os
2 1 | # from foo import junk
3 2 | #a = 3
4 3 | a = 4
ERA001.py:2:1: ERA001 [*] Found commented-out code
|
1 | #import os
2 | # from foo import junk
| ^^^^^^^^^^^^^^^^^^^^^^ ERA001
3 | #a = 3
4 | a = 4
|
= help: Remove commented-out code
Possible fix
1 1 | #import os
2 |-# from foo import junk
3 2 | #a = 3
4 3 | a = 4
5 4 | #foo(1, 2, 3)
ERA001.py:3:1: ERA001 [*] Found commented-out code
|
1 | #import os
2 | # from foo import junk
3 | #a = 3
| ^^^^^^ ERA001
4 | a = 4
5 | #foo(1, 2, 3)
|
= help: Remove commented-out code
Possible fix
1 1 | #import os
2 2 | # from foo import junk
3 |-#a = 3
4 3 | a = 4
5 4 | #foo(1, 2, 3)
6 5 |
ERA001.py:5:1: ERA001 [*] Found commented-out code
|
3 | #a = 3
4 | a = 4
5 | #foo(1, 2, 3)
| ^^^^^^^^^^^^^ ERA001
6 |
7 | def foo(x, y, z):
|
= help: Remove commented-out code
Possible fix
2 2 | # from foo import junk
3 3 | #a = 3
4 4 | a = 4
5 |-#foo(1, 2, 3)
6 5 |
7 6 | def foo(x, y, z):
8 7 | content = 1 # print('hello')
ERA001.py:13:5: ERA001 [*] Found commented-out code
|
11 | # This is a real comment.
12 | # # This is a (nested) comment.
13 | #return True
| ^^^^^^^^^^^^ ERA001
14 | return False
|
= help: Remove commented-out code
Possible fix
10 10 |
11 11 | # This is a real comment.
12 12 | # # This is a (nested) comment.
13 |- #return True
14 13 | return False
15 14 |
16 15 | #import os # noqa: ERA001
ERA001.py:21:5: ERA001 [*] Found commented-out code
|
19 | class A():
20 | pass
21 | # b = c
| ^^^^^^^ ERA001
|
= help: Remove commented-out code
Possible fix
18 18 |
19 19 | class A():
20 20 | pass
21 |- # b = c
22 21 |
23 22 |
24 23 | dictionary = {
ERA001.py:26:5: ERA001 [*] Found commented-out code
|
24 | dictionary = {
25 | # "key1": 123, # noqa: ERA001
26 | # "key2": 456,
| ^^^^^^^^^^^^^^ ERA001
27 | # "key3": 789, # test
28 | }
|
= help: Remove commented-out code
Possible fix
23 23 |
24 24 | dictionary = {
25 25 | # "key1": 123, # noqa: ERA001
26 |- # "key2": 456,
27 26 | # "key3": 789, # test
28 27 | }
29 28 |
ERA001.py:27:5: ERA001 [*] Found commented-out code
|
25 | # "key1": 123, # noqa: ERA001
26 | # "key2": 456,
27 | # "key3": 789, # test
| ^^^^^^^^^^^^^^^^^^^^^^ ERA001
28 | }
|
= help: Remove commented-out code
Possible fix
24 24 | dictionary = {
25 25 | # "key1": 123, # noqa: ERA001
26 26 | # "key2": 456,
27 |- # "key3": 789, # test
28 27 | }
29 28 |
30 29 | #import os # noqa

View File

@@ -1,35 +0,0 @@
//! Rules from [flake8-2020](https://pypi.org/project/flake8-2020/).
mod helpers;
pub(crate) mod rules;
#[cfg(test)]
mod tests {
use std::path::Path;
use anyhow::Result;
use test_case::test_case;
use crate::registry::Rule;
use crate::test::test_path;
use crate::{assert_messages, settings};
#[test_case(Rule::SysVersionSlice3, Path::new("YTT101.py"))]
#[test_case(Rule::SysVersion2, Path::new("YTT102.py"))]
#[test_case(Rule::SysVersionCmpStr3, Path::new("YTT103.py"))]
#[test_case(Rule::SysVersionInfo0Eq3, Path::new("YTT201.py"))]
#[test_case(Rule::SixPY3, Path::new("YTT202.py"))]
#[test_case(Rule::SysVersionInfo1CmpInt, Path::new("YTT203.py"))]
#[test_case(Rule::SysVersionInfoMinorCmpInt, Path::new("YTT204.py"))]
#[test_case(Rule::SysVersion0, Path::new("YTT301.py"))]
#[test_case(Rule::SysVersionCmpStr10, Path::new("YTT302.py"))]
#[test_case(Rule::SysVersionSlice1, Path::new("YTT303.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("flake8_2020").join(path).as_path(),
&settings::Settings::for_rule(rule_code),
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -1,32 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT101.py:6:7: YTT101 `sys.version[:3]` referenced (python3.10), use `sys.version_info`
|
4 | print(sys.version)
5 |
6 | print(sys.version[:3])
| ^^^^^^^^^^^ YTT101
7 | print(version[:3])
8 | print(v[:3])
|
YTT101.py:7:7: YTT101 `sys.version[:3]` referenced (python3.10), use `sys.version_info`
|
6 | print(sys.version[:3])
7 | print(version[:3])
| ^^^^^^^ YTT101
8 | print(v[:3])
|
YTT101.py:8:7: YTT101 `sys.version[:3]` referenced (python3.10), use `sys.version_info`
|
6 | print(sys.version[:3])
7 | print(version[:3])
8 | print(v[:3])
| ^ YTT101
9 |
10 | # the tool is timid and only flags certain numeric slices
|

View File

@@ -1,20 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT102.py:4:12: YTT102 `sys.version[2]` referenced (python3.10), use `sys.version_info`
|
2 | from sys import version
3 |
4 | py_minor = sys.version[2]
| ^^^^^^^^^^^ YTT102
5 | py_minor = version[2]
|
YTT102.py:5:12: YTT102 `sys.version[2]` referenced (python3.10), use `sys.version_info`
|
4 | py_minor = sys.version[2]
5 | py_minor = version[2]
| ^^^^^^^ YTT102
|

View File

@@ -1,50 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT103.py:4:1: YTT103 `sys.version` compared to string (python3.10), use `sys.version_info`
|
2 | from sys import version
3 |
4 | version < "3.5"
| ^^^^^^^ YTT103
5 | sys.version < "3.5"
6 | sys.version <= "3.5"
|
YTT103.py:5:1: YTT103 `sys.version` compared to string (python3.10), use `sys.version_info`
|
4 | version < "3.5"
5 | sys.version < "3.5"
| ^^^^^^^^^^^ YTT103
6 | sys.version <= "3.5"
7 | sys.version > "3.5"
|
YTT103.py:6:1: YTT103 `sys.version` compared to string (python3.10), use `sys.version_info`
|
4 | version < "3.5"
5 | sys.version < "3.5"
6 | sys.version <= "3.5"
| ^^^^^^^^^^^ YTT103
7 | sys.version > "3.5"
8 | sys.version >= "3.5"
|
YTT103.py:7:1: YTT103 `sys.version` compared to string (python3.10), use `sys.version_info`
|
5 | sys.version < "3.5"
6 | sys.version <= "3.5"
7 | sys.version > "3.5"
| ^^^^^^^^^^^ YTT103
8 | sys.version >= "3.5"
|
YTT103.py:8:1: YTT103 `sys.version` compared to string (python3.10), use `sys.version_info`
|
6 | sys.version <= "3.5"
7 | sys.version > "3.5"
8 | sys.version >= "3.5"
| ^^^^^^^^^^^ YTT103
|

View File

@@ -1,40 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT201.py:7:7: YTT201 `sys.version_info[0] == 3` referenced (python4), use `>=`
|
5 | PY3 = sys.version_info[0] >= 3
6 |
7 | PY3 = sys.version_info[0] == 3
| ^^^^^^^^^^^^^^^^^^^ YTT201
8 | PY3 = version_info[0] == 3
9 | PY2 = sys.version_info[0] != 3
|
YTT201.py:8:7: YTT201 `sys.version_info[0] == 3` referenced (python4), use `>=`
|
7 | PY3 = sys.version_info[0] == 3
8 | PY3 = version_info[0] == 3
| ^^^^^^^^^^^^^^^ YTT201
9 | PY2 = sys.version_info[0] != 3
10 | PY2 = version_info[0] != 3
|
YTT201.py:9:7: YTT201 `sys.version_info[0] == 3` referenced (python4), use `>=`
|
7 | PY3 = sys.version_info[0] == 3
8 | PY3 = version_info[0] == 3
9 | PY2 = sys.version_info[0] != 3
| ^^^^^^^^^^^^^^^^^^^ YTT201
10 | PY2 = version_info[0] != 3
|
YTT201.py:10:7: YTT201 `sys.version_info[0] == 3` referenced (python4), use `>=`
|
8 | PY3 = version_info[0] == 3
9 | PY2 = sys.version_info[0] != 3
10 | PY2 = version_info[0] != 3
| ^^^^^^^^^^^^^^^ YTT201
|

View File

@@ -1,23 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT202.py:4:4: YTT202 `six.PY3` referenced (python4), use `not six.PY2`
|
2 | from six import PY3
3 |
4 | if six.PY3:
| ^^^^^^^ YTT202
5 | print("3")
6 | if PY3:
|
YTT202.py:6:4: YTT202 `six.PY3` referenced (python4), use `not six.PY2`
|
4 | if six.PY3:
5 | print("3")
6 | if PY3:
| ^^^ YTT202
7 | print("3")
|

View File

@@ -1,20 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT203.py:4:1: YTT203 `sys.version_info[1]` compared to integer (python4), compare `sys.version_info` to tuple
|
2 | from sys import version_info
3 |
4 | sys.version_info[1] >= 5
| ^^^^^^^^^^^^^^^^^^^ YTT203
5 | version_info[1] < 6
|
YTT203.py:5:1: YTT203 `sys.version_info[1]` compared to integer (python4), compare `sys.version_info` to tuple
|
4 | sys.version_info[1] >= 5
5 | version_info[1] < 6
| ^^^^^^^^^^^^^^^ YTT203
|

View File

@@ -1,20 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT204.py:4:1: YTT204 `sys.version_info.minor` compared to integer (python4), compare `sys.version_info` to tuple
|
2 | from sys import version_info
3 |
4 | sys.version_info.minor <= 7
| ^^^^^^^^^^^^^^^^^^^^^^ YTT204
5 | version_info.minor > 8
|
YTT204.py:5:1: YTT204 `sys.version_info.minor` compared to integer (python4), compare `sys.version_info` to tuple
|
4 | sys.version_info.minor <= 7
5 | version_info.minor > 8
| ^^^^^^^^^^^^^^^^^^ YTT204
|

View File

@@ -1,20 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT301.py:4:12: YTT301 `sys.version[0]` referenced (python10), use `sys.version_info`
|
2 | from sys import version
3 |
4 | py_major = sys.version[0]
| ^^^^^^^^^^^ YTT301
5 | py_major = version[0]
|
YTT301.py:5:12: YTT301 `sys.version[0]` referenced (python10), use `sys.version_info`
|
4 | py_major = sys.version[0]
5 | py_major = version[0]
| ^^^^^^^ YTT301
|

View File

@@ -1,50 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT302.py:4:1: YTT302 `sys.version` compared to string (python10), use `sys.version_info`
|
2 | from sys import version
3 |
4 | version < "3"
| ^^^^^^^ YTT302
5 | sys.version < "3"
6 | sys.version <= "3"
|
YTT302.py:5:1: YTT302 `sys.version` compared to string (python10), use `sys.version_info`
|
4 | version < "3"
5 | sys.version < "3"
| ^^^^^^^^^^^ YTT302
6 | sys.version <= "3"
7 | sys.version > "3"
|
YTT302.py:6:1: YTT302 `sys.version` compared to string (python10), use `sys.version_info`
|
4 | version < "3"
5 | sys.version < "3"
6 | sys.version <= "3"
| ^^^^^^^^^^^ YTT302
7 | sys.version > "3"
8 | sys.version >= "3"
|
YTT302.py:7:1: YTT302 `sys.version` compared to string (python10), use `sys.version_info`
|
5 | sys.version < "3"
6 | sys.version <= "3"
7 | sys.version > "3"
| ^^^^^^^^^^^ YTT302
8 | sys.version >= "3"
|
YTT302.py:8:1: YTT302 `sys.version` compared to string (python10), use `sys.version_info`
|
6 | sys.version <= "3"
7 | sys.version > "3"
8 | sys.version >= "3"
| ^^^^^^^^^^^ YTT302
|

View File

@@ -1,20 +0,0 @@
---
source: crates/ruff/src/rules/flake8_2020/mod.rs
---
YTT303.py:4:7: YTT303 `sys.version[:1]` referenced (python10), use `sys.version_info`
|
2 | from sys import version
3 |
4 | print(sys.version[:1])
| ^^^^^^^^^^^ YTT303
5 | print(version[:1])
|
YTT303.py:5:7: YTT303 `sys.version[:1]` referenced (python10), use `sys.version_info`
|
4 | print(sys.version[:1])
5 | print(version[:1])
| ^^^^^^^ YTT303
|

View File

@@ -1,202 +0,0 @@
//! Rules from [flake8-annotations](https://pypi.org/project/flake8-annotations/).
pub(crate) mod helpers;
pub(crate) mod rules;
pub mod settings;
#[cfg(test)]
mod tests {
use std::path::Path;
use anyhow::Result;
use crate::assert_messages;
use crate::registry::Rule;
use crate::settings::Settings;
use crate::test::test_path;
#[test]
fn defaults() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_annotations/annotation_presence.py"),
&Settings {
..Settings::for_rules(vec![
Rule::MissingTypeFunctionArgument,
Rule::MissingTypeArgs,
Rule::MissingTypeKwargs,
Rule::MissingTypeSelf,
Rule::MissingTypeCls,
Rule::MissingReturnTypeUndocumentedPublicFunction,
Rule::MissingReturnTypePrivateFunction,
Rule::MissingReturnTypeSpecialMethod,
Rule::MissingReturnTypeStaticMethod,
Rule::MissingReturnTypeClassMethod,
Rule::AnyType,
])
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn ignore_fully_untyped() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_annotations/ignore_fully_untyped.py"),
&Settings {
flake8_annotations: super::settings::Settings {
ignore_fully_untyped: true,
..Default::default()
},
..Settings::for_rules(vec![
Rule::MissingTypeFunctionArgument,
Rule::MissingTypeArgs,
Rule::MissingTypeKwargs,
Rule::MissingTypeSelf,
Rule::MissingTypeCls,
Rule::MissingReturnTypeUndocumentedPublicFunction,
Rule::MissingReturnTypePrivateFunction,
Rule::MissingReturnTypeSpecialMethod,
Rule::MissingReturnTypeStaticMethod,
Rule::MissingReturnTypeClassMethod,
Rule::AnyType,
])
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn suppress_dummy_args() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_annotations/suppress_dummy_args.py"),
&Settings {
flake8_annotations: super::settings::Settings {
suppress_dummy_args: true,
..Default::default()
},
..Settings::for_rules(vec![
Rule::MissingTypeFunctionArgument,
Rule::MissingTypeArgs,
Rule::MissingTypeKwargs,
Rule::MissingTypeSelf,
Rule::MissingTypeCls,
])
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn mypy_init_return() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_annotations/mypy_init_return.py"),
&Settings {
flake8_annotations: super::settings::Settings {
mypy_init_return: true,
..Default::default()
},
..Settings::for_rules(vec![
Rule::MissingReturnTypeUndocumentedPublicFunction,
Rule::MissingReturnTypePrivateFunction,
Rule::MissingReturnTypeSpecialMethod,
Rule::MissingReturnTypeStaticMethod,
Rule::MissingReturnTypeClassMethod,
])
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn suppress_none_returning() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_annotations/suppress_none_returning.py"),
&Settings {
flake8_annotations: super::settings::Settings {
suppress_none_returning: true,
..Default::default()
},
..Settings::for_rules(vec![
Rule::MissingTypeFunctionArgument,
Rule::MissingTypeArgs,
Rule::MissingTypeKwargs,
Rule::MissingTypeSelf,
Rule::MissingTypeCls,
Rule::MissingReturnTypeUndocumentedPublicFunction,
Rule::MissingReturnTypePrivateFunction,
Rule::MissingReturnTypeSpecialMethod,
Rule::MissingReturnTypeStaticMethod,
Rule::MissingReturnTypeClassMethod,
Rule::AnyType,
])
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn allow_star_arg_any() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_annotations/allow_star_arg_any.py"),
&Settings {
flake8_annotations: super::settings::Settings {
allow_star_arg_any: true,
..Default::default()
},
..Settings::for_rules(vec![Rule::AnyType])
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn allow_overload() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_annotations/allow_overload.py"),
&Settings {
..Settings::for_rules(vec![
Rule::MissingReturnTypeUndocumentedPublicFunction,
Rule::MissingReturnTypePrivateFunction,
Rule::MissingReturnTypeSpecialMethod,
Rule::MissingReturnTypeStaticMethod,
Rule::MissingReturnTypeClassMethod,
])
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn allow_nested_overload() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_annotations/allow_nested_overload.py"),
&Settings {
..Settings::for_rules(vec![
Rule::MissingReturnTypeUndocumentedPublicFunction,
Rule::MissingReturnTypePrivateFunction,
Rule::MissingReturnTypeSpecialMethod,
Rule::MissingReturnTypeStaticMethod,
Rule::MissingReturnTypeClassMethod,
])
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test]
fn simple_magic_methods() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_annotations/simple_magic_methods.py"),
&Settings::for_rule(Rule::MissingReturnTypeSpecialMethod),
)?;
assert_messages!(diagnostics);
Ok(())
}
}

View File

@@ -1,4 +0,0 @@
---
source: crates/ruff/src/rules/flake8_annotations/mod.rs
---

View File

@@ -1,12 +0,0 @@
---
source: crates/ruff/src/rules/flake8_annotations/mod.rs
---
allow_overload.py:29:9: ANN201 Missing return type annotation for public function `bar`
|
28 | class X:
29 | def bar(i):
| ^^^ ANN201
30 | return i
|

View File

@@ -1,36 +0,0 @@
---
source: crates/ruff/src/rules/flake8_annotations/mod.rs
---
allow_star_arg_any.py:10:12: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
9 | # ANN401
10 | def foo(a: Any, *args: str, **kwargs: str) -> int:
| ^^^ ANN401
11 | pass
|
allow_star_arg_any.py:15:47: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `foo`
|
14 | # ANN401
15 | def foo(a: int, *args: str, **kwargs: str) -> Any:
| ^^^ ANN401
16 | pass
|
allow_star_arg_any.py:40:29: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
39 | # ANN401
40 | def foo_method(self, a: Any, *params: str, **options: str) -> int:
| ^^^ ANN401
41 | pass
|
allow_star_arg_any.py:44:67: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `foo_method`
|
43 | # ANN401
44 | def foo_method(self, a: int, *params: str, **options: str) -> Any:
| ^^^ ANN401
45 | pass
|

View File

@@ -1,263 +0,0 @@
---
source: crates/ruff/src/rules/flake8_annotations/mod.rs
---
annotation_presence.py:5:5: ANN201 Missing return type annotation for public function `foo`
|
4 | # Error
5 | def foo(a, b):
| ^^^ ANN201
6 | pass
|
annotation_presence.py:5:9: ANN001 Missing type annotation for function argument `a`
|
4 | # Error
5 | def foo(a, b):
| ^ ANN001
6 | pass
|
annotation_presence.py:5:12: ANN001 Missing type annotation for function argument `b`
|
4 | # Error
5 | def foo(a, b):
| ^ ANN001
6 | pass
|
annotation_presence.py:10:5: ANN201 Missing return type annotation for public function `foo`
|
9 | # Error
10 | def foo(a: int, b):
| ^^^ ANN201
11 | pass
|
annotation_presence.py:10:17: ANN001 Missing type annotation for function argument `b`
|
9 | # Error
10 | def foo(a: int, b):
| ^ ANN001
11 | pass
|
annotation_presence.py:15:17: ANN001 Missing type annotation for function argument `b`
|
14 | # Error
15 | def foo(a: int, b) -> int:
| ^ ANN001
16 | pass
|
annotation_presence.py:20:5: ANN201 Missing return type annotation for public function `foo`
|
19 | # Error
20 | def foo(a: int, b: int):
| ^^^ ANN201
21 | pass
|
annotation_presence.py:25:5: ANN201 Missing return type annotation for public function `foo`
|
24 | # Error
25 | def foo():
| ^^^ ANN201
26 | pass
|
annotation_presence.py:45:12: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
44 | # ANN401
45 | def foo(a: Any, *args: str, **kwargs: str) -> int:
| ^^^ ANN401
46 | pass
|
annotation_presence.py:50:47: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `foo`
|
49 | # ANN401
50 | def foo(a: int, *args: str, **kwargs: str) -> Any:
| ^^^ ANN401
51 | pass
|
annotation_presence.py:55:24: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `*args`
|
54 | # ANN401
55 | def foo(a: int, *args: Any, **kwargs: Any) -> int:
| ^^^ ANN401
56 | pass
|
annotation_presence.py:55:39: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `**kwargs`
|
54 | # ANN401
55 | def foo(a: int, *args: Any, **kwargs: Any) -> int:
| ^^^ ANN401
56 | pass
|
annotation_presence.py:60:24: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `*args`
|
59 | # ANN401
60 | def foo(a: int, *args: Any, **kwargs: str) -> int:
| ^^^ ANN401
61 | pass
|
annotation_presence.py:65:39: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `**kwargs`
|
64 | # ANN401
65 | def foo(a: int, *args: str, **kwargs: Any) -> int:
| ^^^ ANN401
66 | pass
|
annotation_presence.py:75:13: ANN101 Missing type annotation for `self` in method
|
74 | # ANN101
75 | def foo(self, a: int, b: int) -> int:
| ^^^^ ANN101
76 | pass
|
annotation_presence.py:79:29: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
78 | # ANN401
79 | def foo(self: "Foo", a: Any, *params: str, **options: str) -> int:
| ^^^ ANN401
80 | pass
|
annotation_presence.py:83:67: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `foo`
|
82 | # ANN401
83 | def foo(self: "Foo", a: int, *params: str, **options: str) -> Any:
| ^^^ ANN401
84 | pass
|
annotation_presence.py:87:43: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `*params`
|
86 | # ANN401
87 | def foo(self: "Foo", a: int, *params: Any, **options: Any) -> int:
| ^^^ ANN401
88 | pass
|
annotation_presence.py:87:59: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `**options`
|
86 | # ANN401
87 | def foo(self: "Foo", a: int, *params: Any, **options: Any) -> int:
| ^^^ ANN401
88 | pass
|
annotation_presence.py:91:43: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `*params`
|
90 | # ANN401
91 | def foo(self: "Foo", a: int, *params: Any, **options: str) -> int:
| ^^^ ANN401
92 | pass
|
annotation_presence.py:95:59: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `**options`
|
94 | # ANN401
95 | def foo(self: "Foo", a: int, *params: str, **options: Any) -> int:
| ^^^ ANN401
96 | pass
|
annotation_presence.py:130:13: ANN102 Missing type annotation for `cls` in classmethod
|
128 | # ANN102
129 | @classmethod
130 | def foo(cls, a: int, b: int) -> int:
| ^^^ ANN102
131 | pass
|
annotation_presence.py:134:13: ANN101 Missing type annotation for `self` in method
|
133 | # ANN101
134 | def foo(self, /, a: int, b: int) -> int:
| ^^^^ ANN101
135 | pass
|
annotation_presence.py:149:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
148 | # ANN401
149 | def f(a: Any | int) -> None: ...
| ^^^^^^^^^ ANN401
150 | def f(a: int | Any) -> None: ...
151 | def f(a: Union[str, bytes, Any]) -> None: ...
|
annotation_presence.py:150:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
148 | # ANN401
149 | def f(a: Any | int) -> None: ...
150 | def f(a: int | Any) -> None: ...
| ^^^^^^^^^ ANN401
151 | def f(a: Union[str, bytes, Any]) -> None: ...
152 | def f(a: Optional[Any]) -> None: ...
|
annotation_presence.py:151:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
149 | def f(a: Any | int) -> None: ...
150 | def f(a: int | Any) -> None: ...
151 | def f(a: Union[str, bytes, Any]) -> None: ...
| ^^^^^^^^^^^^^^^^^^^^^^ ANN401
152 | def f(a: Optional[Any]) -> None: ...
153 | def f(a: Annotated[Any, ...]) -> None: ...
|
annotation_presence.py:152:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
150 | def f(a: int | Any) -> None: ...
151 | def f(a: Union[str, bytes, Any]) -> None: ...
152 | def f(a: Optional[Any]) -> None: ...
| ^^^^^^^^^^^^^ ANN401
153 | def f(a: Annotated[Any, ...]) -> None: ...
154 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
annotation_presence.py:153:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
151 | def f(a: Union[str, bytes, Any]) -> None: ...
152 | def f(a: Optional[Any]) -> None: ...
153 | def f(a: Annotated[Any, ...]) -> None: ...
| ^^^^^^^^^^^^^^^^^^^ ANN401
154 | def f(a: "Union[str, bytes, Any]") -> None: ...
|
annotation_presence.py:154:10: ANN401 Dynamically typed expressions (typing.Any) are disallowed in `a`
|
152 | def f(a: Optional[Any]) -> None: ...
153 | def f(a: Annotated[Any, ...]) -> None: ...
154 | def f(a: "Union[str, bytes, Any]") -> None: ...
| ^^^^^^^^^^^^^^^^^^^^^^^^ ANN401
|
annotation_presence.py:159:9: ANN204 [*] Missing return type annotation for special method `__init__`
|
157 | class Foo:
158 | @decorator()
159 | def __init__(self: "Foo", foo: int):
| ^^^^^^^^ ANN204
160 | ...
|
= help: Add `None` return type
Suggested fix
156 156 |
157 157 | class Foo:
158 158 | @decorator()
159 |- def __init__(self: "Foo", foo: int):
159 |+ def __init__(self: "Foo", foo: int) -> None:
160 160 | ...

View File

@@ -1,41 +0,0 @@
---
source: crates/ruff/src/rules/flake8_annotations/mod.rs
---
ignore_fully_untyped.py:24:5: ANN201 Missing return type annotation for public function `error_partially_typed_1`
|
24 | def error_partially_typed_1(a: int, b):
| ^^^^^^^^^^^^^^^^^^^^^^^ ANN201
25 | pass
|
ignore_fully_untyped.py:24:37: ANN001 Missing type annotation for function argument `b`
|
24 | def error_partially_typed_1(a: int, b):
| ^ ANN001
25 | pass
|
ignore_fully_untyped.py:28:37: ANN001 Missing type annotation for function argument `b`
|
28 | def error_partially_typed_2(a: int, b) -> int:
| ^ ANN001
29 | pass
|
ignore_fully_untyped.py:32:5: ANN201 Missing return type annotation for public function `error_partially_typed_3`
|
32 | def error_partially_typed_3(a: int, b: int):
| ^^^^^^^^^^^^^^^^^^^^^^^ ANN201
33 | pass
|
ignore_fully_untyped.py:43:9: ANN201 Missing return type annotation for public function `error_typed_self`
|
41 | pass
42 |
43 | def error_typed_self(self: X):
| ^^^^^^^^^^^^^^^^ ANN201
44 | pass
|

View File

@@ -1,70 +0,0 @@
---
source: crates/ruff/src/rules/flake8_annotations/mod.rs
---
mypy_init_return.py:5:9: ANN204 [*] Missing return type annotation for special method `__init__`
|
3 | # Error
4 | class Foo:
5 | def __init__(self):
| ^^^^^^^^ ANN204
6 | ...
|
= help: Add `None` return type
Suggested fix
2 2 |
3 3 | # Error
4 4 | class Foo:
5 |- def __init__(self):
5 |+ def __init__(self) -> None:
6 6 | ...
7 7 |
8 8 |
mypy_init_return.py:11:9: ANN204 [*] Missing return type annotation for special method `__init__`
|
9 | # Error
10 | class Foo:
11 | def __init__(self, foo):
| ^^^^^^^^ ANN204
12 | ...
|
= help: Add `None` return type
Suggested fix
8 8 |
9 9 | # Error
10 10 | class Foo:
11 |- def __init__(self, foo):
11 |+ def __init__(self, foo) -> None:
12 12 | ...
13 13 |
14 14 |
mypy_init_return.py:40:5: ANN202 Missing return type annotation for private function `__init__`
|
39 | # Error
40 | def __init__(self, foo: int):
| ^^^^^^^^ ANN202
41 | ...
|
mypy_init_return.py:47:9: ANN204 [*] Missing return type annotation for special method `__init__`
|
45 | # of a vararg falsely indicated that the function has a typed argument.
46 | class Foo:
47 | def __init__(self, *arg):
| ^^^^^^^^ ANN204
48 | ...
|
= help: Add `None` return type
Suggested fix
44 44 | # Error used to be ok for a moment since the mere presence
45 45 | # of a vararg falsely indicated that the function has a typed argument.
46 46 | class Foo:
47 |- def __init__(self, *arg):
47 |+ def __init__(self, *arg) -> None:
48 48 | ...

View File

@@ -1,279 +0,0 @@
---
source: crates/ruff/src/rules/flake8_annotations/mod.rs
---
simple_magic_methods.py:2:9: ANN204 [*] Missing return type annotation for special method `__str__`
|
1 | class Foo:
2 | def __str__(self):
| ^^^^^^^ ANN204
3 | ...
|
= help: Add `None` return type
Suggested fix
1 1 | class Foo:
2 |- def __str__(self):
2 |+ def __str__(self) -> str:
3 3 | ...
4 4 |
5 5 | def __repr__(self):
simple_magic_methods.py:5:9: ANN204 [*] Missing return type annotation for special method `__repr__`
|
3 | ...
4 |
5 | def __repr__(self):
| ^^^^^^^^ ANN204
6 | ...
|
= help: Add `None` return type
Suggested fix
2 2 | def __str__(self):
3 3 | ...
4 4 |
5 |- def __repr__(self):
5 |+ def __repr__(self) -> str:
6 6 | ...
7 7 |
8 8 | def __len__(self):
simple_magic_methods.py:8:9: ANN204 [*] Missing return type annotation for special method `__len__`
|
6 | ...
7 |
8 | def __len__(self):
| ^^^^^^^ ANN204
9 | ...
|
= help: Add `None` return type
Suggested fix
5 5 | def __repr__(self):
6 6 | ...
7 7 |
8 |- def __len__(self):
8 |+ def __len__(self) -> int:
9 9 | ...
10 10 |
11 11 | def __length_hint__(self):
simple_magic_methods.py:11:9: ANN204 [*] Missing return type annotation for special method `__length_hint__`
|
9 | ...
10 |
11 | def __length_hint__(self):
| ^^^^^^^^^^^^^^^ ANN204
12 | ...
|
= help: Add `None` return type
Suggested fix
8 8 | def __len__(self):
9 9 | ...
10 10 |
11 |- def __length_hint__(self):
11 |+ def __length_hint__(self) -> int:
12 12 | ...
13 13 |
14 14 | def __init__(self):
simple_magic_methods.py:14:9: ANN204 [*] Missing return type annotation for special method `__init__`
|
12 | ...
13 |
14 | def __init__(self):
| ^^^^^^^^ ANN204
15 | ...
|
= help: Add `None` return type
Suggested fix
11 11 | def __length_hint__(self):
12 12 | ...
13 13 |
14 |- def __init__(self):
14 |+ def __init__(self) -> None:
15 15 | ...
16 16 |
17 17 | def __del__(self):
simple_magic_methods.py:17:9: ANN204 [*] Missing return type annotation for special method `__del__`
|
15 | ...
16 |
17 | def __del__(self):
| ^^^^^^^ ANN204
18 | ...
|
= help: Add `None` return type
Suggested fix
14 14 | def __init__(self):
15 15 | ...
16 16 |
17 |- def __del__(self):
17 |+ def __del__(self) -> None:
18 18 | ...
19 19 |
20 20 | def __bool__(self):
simple_magic_methods.py:20:9: ANN204 [*] Missing return type annotation for special method `__bool__`
|
18 | ...
19 |
20 | def __bool__(self):
| ^^^^^^^^ ANN204
21 | ...
|
= help: Add `None` return type
Suggested fix
17 17 | def __del__(self):
18 18 | ...
19 19 |
20 |- def __bool__(self):
20 |+ def __bool__(self) -> bool:
21 21 | ...
22 22 |
23 23 | def __bytes__(self):
simple_magic_methods.py:23:9: ANN204 [*] Missing return type annotation for special method `__bytes__`
|
21 | ...
22 |
23 | def __bytes__(self):
| ^^^^^^^^^ ANN204
24 | ...
|
= help: Add `None` return type
Suggested fix
20 20 | def __bool__(self):
21 21 | ...
22 22 |
23 |- def __bytes__(self):
23 |+ def __bytes__(self) -> bytes:
24 24 | ...
25 25 |
26 26 | def __format__(self, format_spec):
simple_magic_methods.py:26:9: ANN204 [*] Missing return type annotation for special method `__format__`
|
24 | ...
25 |
26 | def __format__(self, format_spec):
| ^^^^^^^^^^ ANN204
27 | ...
|
= help: Add `None` return type
Suggested fix
23 23 | def __bytes__(self):
24 24 | ...
25 25 |
26 |- def __format__(self, format_spec):
26 |+ def __format__(self, format_spec) -> str:
27 27 | ...
28 28 |
29 29 | def __contains__(self, item):
simple_magic_methods.py:29:9: ANN204 [*] Missing return type annotation for special method `__contains__`
|
27 | ...
28 |
29 | def __contains__(self, item):
| ^^^^^^^^^^^^ ANN204
30 | ...
|
= help: Add `None` return type
Suggested fix
26 26 | def __format__(self, format_spec):
27 27 | ...
28 28 |
29 |- def __contains__(self, item):
29 |+ def __contains__(self, item) -> bool:
30 30 | ...
31 31 |
32 32 | def __complex__(self):
simple_magic_methods.py:32:9: ANN204 [*] Missing return type annotation for special method `__complex__`
|
30 | ...
31 |
32 | def __complex__(self):
| ^^^^^^^^^^^ ANN204
33 | ...
|
= help: Add `None` return type
Suggested fix
29 29 | def __contains__(self, item):
30 30 | ...
31 31 |
32 |- def __complex__(self):
32 |+ def __complex__(self) -> complex:
33 33 | ...
34 34 |
35 35 | def __int__(self):
simple_magic_methods.py:35:9: ANN204 [*] Missing return type annotation for special method `__int__`
|
33 | ...
34 |
35 | def __int__(self):
| ^^^^^^^ ANN204
36 | ...
|
= help: Add `None` return type
Suggested fix
32 32 | def __complex__(self):
33 33 | ...
34 34 |
35 |- def __int__(self):
35 |+ def __int__(self) -> int:
36 36 | ...
37 37 |
38 38 | def __float__(self):
simple_magic_methods.py:38:9: ANN204 [*] Missing return type annotation for special method `__float__`
|
36 | ...
37 |
38 | def __float__(self):
| ^^^^^^^^^ ANN204
39 | ...
|
= help: Add `None` return type
Suggested fix
35 35 | def __int__(self):
36 36 | ...
37 37 |
38 |- def __float__(self):
38 |+ def __float__(self) -> float:
39 39 | ...
40 40 |
41 41 | def __index__(self):
simple_magic_methods.py:41:9: ANN204 [*] Missing return type annotation for special method `__index__`
|
39 | ...
40 |
41 | def __index__(self):
| ^^^^^^^^^ ANN204
42 | ...
|
= help: Add `None` return type
Suggested fix
38 38 | def __float__(self):
39 39 | ...
40 40 |
41 |- def __index__(self):
41 |+ def __index__(self) -> int:
42 42 | ...

View File

@@ -1,4 +0,0 @@
---
source: crates/ruff/src/rules/flake8_annotations/mod.rs
---

View File

@@ -1,29 +0,0 @@
---
source: crates/ruff/src/rules/flake8_annotations/mod.rs
---
suppress_none_returning.py:45:5: ANN201 Missing return type annotation for public function `foo`
|
44 | # Error
45 | def foo():
| ^^^ ANN201
46 | return True
|
suppress_none_returning.py:50:5: ANN201 Missing return type annotation for public function `foo`
|
49 | # Error
50 | def foo():
| ^^^ ANN201
51 | a = 2 + 2
52 | if a == 4:
|
suppress_none_returning.py:59:9: ANN001 Missing type annotation for function argument `a`
|
58 | # Error (on the argument, but not the return type)
59 | def foo(a):
| ^ ANN001
60 | a = 2 + 2
|

View File

@@ -1,28 +0,0 @@
//! Rules from [flake8-async](https://pypi.org/project/flake8-async/).
pub(crate) mod rules;
#[cfg(test)]
mod tests {
use std::path::Path;
use anyhow::Result;
use test_case::test_case;
use crate::assert_messages;
use crate::registry::Rule;
use crate::settings::Settings;
use crate::test::test_path;
#[test_case(Rule::BlockingHttpCallInAsyncFunction, Path::new("ASYNC100.py"))]
#[test_case(Rule::OpenSleepOrSubprocessInAsyncFunction, Path::new("ASYNC101.py"))]
#[test_case(Rule::BlockingOsCallInAsyncFunction, Path::new("ASYNC102.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("flake8_async").join(path).as_path(),
&Settings::for_rule(rule_code),
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -1,39 +0,0 @@
---
source: crates/ruff/src/rules/flake8_async/mod.rs
---
ASYNC100.py:7:5: ASYNC100 Async functions should not call blocking HTTP methods
|
6 | async def foo():
7 | urllib.request.urlopen("http://example.com/foo/bar").read()
| ^^^^^^^^^^^^^^^^^^^^^^ ASYNC100
|
ASYNC100.py:11:5: ASYNC100 Async functions should not call blocking HTTP methods
|
10 | async def foo():
11 | requests.get()
| ^^^^^^^^^^^^ ASYNC100
|
ASYNC100.py:15:5: ASYNC100 Async functions should not call blocking HTTP methods
|
14 | async def foo():
15 | httpx.get()
| ^^^^^^^^^ ASYNC100
|
ASYNC100.py:19:5: ASYNC100 Async functions should not call blocking HTTP methods
|
18 | async def foo():
19 | requests.post()
| ^^^^^^^^^^^^^ ASYNC100
|
ASYNC100.py:23:5: ASYNC100 Async functions should not call blocking HTTP methods
|
22 | async def foo():
23 | httpx.post()
| ^^^^^^^^^^ ASYNC100
|

View File

@@ -1,46 +0,0 @@
---
source: crates/ruff/src/rules/flake8_async/mod.rs
---
ASYNC101.py:7:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
6 | async def foo():
7 | open("foo")
| ^^^^ ASYNC101
|
ASYNC101.py:11:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
10 | async def foo():
11 | time.sleep(1)
| ^^^^^^^^^^ ASYNC101
|
ASYNC101.py:15:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
14 | async def foo():
15 | subprocess.run("foo")
| ^^^^^^^^^^^^^^ ASYNC101
|
ASYNC101.py:19:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
18 | async def foo():
19 | subprocess.call("foo")
| ^^^^^^^^^^^^^^^ ASYNC101
|
ASYNC101.py:27:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
26 | async def foo():
27 | os.wait4(10)
| ^^^^^^^^ ASYNC101
|
ASYNC101.py:31:5: ASYNC101 Async functions should not call `open`, `time.sleep`, or `subprocess` methods
|
30 | async def foo():
31 | os.wait(12)
| ^^^^^^^ ASYNC101
|

View File

@@ -1,18 +0,0 @@
---
source: crates/ruff/src/rules/flake8_async/mod.rs
---
ASYNC102.py:5:5: ASYNC102 Async functions should not call synchronous `os` methods
|
4 | async def foo():
5 | os.popen()
| ^^^^^^^^ ASYNC102
|
ASYNC102.py:9:5: ASYNC102 Async functions should not call synchronous `os` methods
|
8 | async def foo():
9 | os.spawnl()
| ^^^^^^^^^ ASYNC102
|

View File

@@ -1,95 +0,0 @@
//! Rules from [flake8-bandit](https://pypi.org/project/flake8-bandit/).
mod helpers;
pub(crate) mod rules;
pub mod settings;
#[cfg(test)]
mod tests {
use std::path::Path;
use anyhow::Result;
use test_case::test_case;
use crate::assert_messages;
use crate::registry::Rule;
use crate::settings::Settings;
use crate::test::test_path;
#[test_case(Rule::Assert, Path::new("S101.py"))]
#[test_case(Rule::BadFilePermissions, Path::new("S103.py"))]
#[test_case(Rule::CallWithShellEqualsTrue, Path::new("S604.py"))]
#[test_case(Rule::ExecBuiltin, Path::new("S102.py"))]
#[test_case(Rule::FlaskDebugTrue, Path::new("S201.py"))]
#[test_case(Rule::HardcodedBindAllInterfaces, Path::new("S104.py"))]
#[test_case(Rule::HardcodedPasswordDefault, Path::new("S107.py"))]
#[test_case(Rule::HardcodedPasswordFuncArg, Path::new("S106.py"))]
#[test_case(Rule::HardcodedPasswordString, Path::new("S105.py"))]
#[test_case(Rule::HardcodedSQLExpression, Path::new("S608.py"))]
#[test_case(Rule::HardcodedTempFile, Path::new("S108.py"))]
#[test_case(Rule::HashlibInsecureHashFunction, Path::new("S324.py"))]
#[test_case(Rule::Jinja2AutoescapeFalse, Path::new("S701.py"))]
#[test_case(Rule::LoggingConfigInsecureListen, Path::new("S612.py"))]
#[test_case(Rule::ParamikoCall, Path::new("S601.py"))]
#[test_case(Rule::RequestWithNoCertValidation, Path::new("S501.py"))]
#[test_case(Rule::RequestWithoutTimeout, Path::new("S113.py"))]
#[test_case(Rule::SnmpInsecureVersion, Path::new("S508.py"))]
#[test_case(Rule::SnmpWeakCryptography, Path::new("S509.py"))]
#[test_case(Rule::StartProcessWithAShell, Path::new("S605.py"))]
#[test_case(Rule::StartProcessWithNoShell, Path::new("S606.py"))]
#[test_case(Rule::StartProcessWithPartialPath, Path::new("S607.py"))]
#[test_case(Rule::SubprocessPopenWithShellEqualsTrue, Path::new("S602.py"))]
#[test_case(Rule::SubprocessWithoutShellEqualsTrue, Path::new("S603.py"))]
#[test_case(Rule::SuspiciousPickleUsage, Path::new("S301.py"))]
#[test_case(Rule::SuspiciousEvalUsage, Path::new("S307.py"))]
#[test_case(Rule::SuspiciousTelnetUsage, Path::new("S312.py"))]
#[test_case(Rule::TryExceptContinue, Path::new("S112.py"))]
#[test_case(Rule::TryExceptPass, Path::new("S110.py"))]
#[test_case(Rule::UnixCommandWildcardInjection, Path::new("S609.py"))]
#[test_case(Rule::UnsafeYAMLLoad, Path::new("S506.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("flake8_bandit").join(path).as_path(),
&Settings::for_rule(rule_code),
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test]
fn check_hardcoded_tmp_additional_dirs() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_bandit/S108.py"),
&Settings {
flake8_bandit: super::settings::Settings {
hardcoded_tmp_directory: vec![
"/tmp".to_string(),
"/var/tmp".to_string(),
"/dev/shm".to_string(),
"/foo".to_string(),
],
check_typed_exception: false,
},
..Settings::for_rule(Rule::HardcodedTempFile)
},
)?;
assert_messages!("S108_extend", diagnostics);
Ok(())
}
#[test]
fn check_typed_exception() -> Result<()> {
let diagnostics = test_path(
Path::new("flake8_bandit/S110.py"),
&Settings {
flake8_bandit: super::settings::Settings {
check_typed_exception: true,
..Default::default()
},
..Settings::for_rule(Rule::TryExceptPass)
},
)?;
assert_messages!("S110_typed", diagnostics);
Ok(())
}
}

View File

@@ -1,89 +0,0 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::is_const_true;
use ruff_python_ast::{Expr, ExprAttribute, ExprCall, Stmt, StmtAssign};
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for uses of `debug=True` in Flask.
///
/// ## Why is this bad?
/// Enabling debug mode shows an interactive debugger in the browser if an
/// error occurs, and allows running arbitrary Python code from the browser.
/// This could leak sensitive information, or allow an attacker to run
/// arbitrary code.
///
/// ## Example
/// ```python
/// import flask
///
/// app = Flask()
///
/// app.run(debug=True)
/// ```
///
/// Use instead:
/// ```python
/// import flask
///
/// app = Flask()
///
/// app.run(debug=os.environ["ENV"] == "dev")
/// ```
///
/// ## References
/// - [Flask documentation: Debug Mode](https://flask.palletsprojects.com/en/latest/quickstart/#debug-mode)
#[violation]
pub struct FlaskDebugTrue;
impl Violation for FlaskDebugTrue {
#[derive_message_formats]
fn message(&self) -> String {
format!("Use of `debug=True` in Flask app detected")
}
}
/// S201
pub(crate) fn flask_debug_true(checker: &mut Checker, call: &ExprCall) {
let Expr::Attribute(ExprAttribute { attr, value, .. }) = call.func.as_ref() else {
return;
};
if attr.as_str() != "run" {
return;
}
let Some(debug_argument) = call.arguments.find_keyword("debug") else {
return;
};
if !is_const_true(&debug_argument.value) {
return;
}
let Expr::Name(name) = value.as_ref() else {
return;
};
if let Some(binding_id) = checker.semantic().resolve_name(name) {
if let Some(Stmt::Assign(StmtAssign { value, .. })) = checker
.semantic()
.binding(binding_id)
.statement(checker.semantic())
{
if let Expr::Call(ExprCall { func, .. }) = value.as_ref() {
if checker
.semantic()
.resolve_call_path(func)
.is_some_and(|call_path| matches!(call_path.as_slice(), ["flask", "Flask"]))
{
checker
.diagnostics
.push(Diagnostic::new(FlaskDebugTrue, debug_argument.range()));
}
}
}
};
}

View File

@@ -1,47 +0,0 @@
pub(crate) use assert_used::*;
pub(crate) use bad_file_permissions::*;
pub(crate) use exec_used::*;
pub(crate) use flask_debug_true::*;
pub(crate) use hardcoded_bind_all_interfaces::*;
pub(crate) use hardcoded_password_default::*;
pub(crate) use hardcoded_password_func_arg::*;
pub(crate) use hardcoded_password_string::*;
pub(crate) use hardcoded_sql_expression::*;
pub(crate) use hardcoded_tmp_directory::*;
pub(crate) use hashlib_insecure_hash_functions::*;
pub(crate) use jinja2_autoescape_false::*;
pub(crate) use logging_config_insecure_listen::*;
pub(crate) use paramiko_calls::*;
pub(crate) use request_with_no_cert_validation::*;
pub(crate) use request_without_timeout::*;
pub(crate) use shell_injection::*;
pub(crate) use snmp_insecure_version::*;
pub(crate) use snmp_weak_cryptography::*;
pub(crate) use suspicious_function_call::*;
pub(crate) use try_except_continue::*;
pub(crate) use try_except_pass::*;
pub(crate) use unsafe_yaml_load::*;
mod assert_used;
mod bad_file_permissions;
mod exec_used;
mod flask_debug_true;
mod hardcoded_bind_all_interfaces;
mod hardcoded_password_default;
mod hardcoded_password_func_arg;
mod hardcoded_password_string;
mod hardcoded_sql_expression;
mod hardcoded_tmp_directory;
mod hashlib_insecure_hash_functions;
mod jinja2_autoescape_false;
mod logging_config_insecure_listen;
mod paramiko_calls;
mod request_with_no_cert_validation;
mod request_without_timeout;
mod shell_injection;
mod snmp_insecure_version;
mod snmp_weak_cryptography;
mod suspicious_function_call;
mod try_except_continue;
mod try_except_pass;
mod unsafe_yaml_load;

View File

@@ -1,27 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S101.py:1:1: S101 Use of `assert` detected
|
1 | assert True # S101
| ^^^^^^ S101
|
S101.py:6:5: S101 Use of `assert` detected
|
4 | def fn():
5 | x = 1
6 | assert x == 1 # S101
| ^^^^^^ S101
7 | assert x == 2 # S101
|
S101.py:7:5: S101 Use of `assert` detected
|
5 | x = 1
6 | assert x == 1 # S101
7 | assert x == 2 # S101
| ^^^^^^ S101
|

View File

@@ -1,22 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S102.py:3:5: S102 Use of `exec` detected
|
1 | def fn():
2 | # Error
3 | exec('x = 2')
| ^^^^ S102
4 |
5 | exec('y = 3')
|
S102.py:5:1: S102 Use of `exec` detected
|
3 | exec('x = 2')
4 |
5 | exec('y = 3')
| ^^^^ S102
|

View File

@@ -1,131 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S103.py:6:25: S103 `os.chmod` setting a permissive mask `0o227` on file or directory
|
4 | keyfile = "foo"
5 |
6 | os.chmod("/etc/passwd", 0o227) # Error
| ^^^^^ S103
7 | os.chmod("/etc/passwd", 0o7) # Error
8 | os.chmod("/etc/passwd", 0o664) # OK
|
S103.py:7:25: S103 `os.chmod` setting a permissive mask `0o7` on file or directory
|
6 | os.chmod("/etc/passwd", 0o227) # Error
7 | os.chmod("/etc/passwd", 0o7) # Error
| ^^^ S103
8 | os.chmod("/etc/passwd", 0o664) # OK
9 | os.chmod("/etc/passwd", 0o777) # Error
|
S103.py:9:25: S103 `os.chmod` setting a permissive mask `0o777` on file or directory
|
7 | os.chmod("/etc/passwd", 0o7) # Error
8 | os.chmod("/etc/passwd", 0o664) # OK
9 | os.chmod("/etc/passwd", 0o777) # Error
| ^^^^^ S103
10 | os.chmod("/etc/passwd", 0o770) # Error
11 | os.chmod("/etc/passwd", 0o776) # Error
|
S103.py:10:25: S103 `os.chmod` setting a permissive mask `0o770` on file or directory
|
8 | os.chmod("/etc/passwd", 0o664) # OK
9 | os.chmod("/etc/passwd", 0o777) # Error
10 | os.chmod("/etc/passwd", 0o770) # Error
| ^^^^^ S103
11 | os.chmod("/etc/passwd", 0o776) # Error
12 | os.chmod("/etc/passwd", 0o760) # OK
|
S103.py:11:25: S103 `os.chmod` setting a permissive mask `0o776` on file or directory
|
9 | os.chmod("/etc/passwd", 0o777) # Error
10 | os.chmod("/etc/passwd", 0o770) # Error
11 | os.chmod("/etc/passwd", 0o776) # Error
| ^^^^^ S103
12 | os.chmod("/etc/passwd", 0o760) # OK
13 | os.chmod("~/.bashrc", 511) # Error
|
S103.py:13:23: S103 `os.chmod` setting a permissive mask `0o777` on file or directory
|
11 | os.chmod("/etc/passwd", 0o776) # Error
12 | os.chmod("/etc/passwd", 0o760) # OK
13 | os.chmod("~/.bashrc", 511) # Error
| ^^^ S103
14 | os.chmod("/etc/hosts", 0o777) # Error
15 | os.chmod("/tmp/oh_hai", 0x1FF) # Error
|
S103.py:14:24: S103 `os.chmod` setting a permissive mask `0o777` on file or directory
|
12 | os.chmod("/etc/passwd", 0o760) # OK
13 | os.chmod("~/.bashrc", 511) # Error
14 | os.chmod("/etc/hosts", 0o777) # Error
| ^^^^^ S103
15 | os.chmod("/tmp/oh_hai", 0x1FF) # Error
16 | os.chmod("/etc/passwd", stat.S_IRWXU) # OK
|
S103.py:15:25: S103 `os.chmod` setting a permissive mask `0o777` on file or directory
|
13 | os.chmod("~/.bashrc", 511) # Error
14 | os.chmod("/etc/hosts", 0o777) # Error
15 | os.chmod("/tmp/oh_hai", 0x1FF) # Error
| ^^^^^ S103
16 | os.chmod("/etc/passwd", stat.S_IRWXU) # OK
17 | os.chmod(keyfile, 0o777) # Error
|
S103.py:17:19: S103 `os.chmod` setting a permissive mask `0o777` on file or directory
|
15 | os.chmod("/tmp/oh_hai", 0x1FF) # Error
16 | os.chmod("/etc/passwd", stat.S_IRWXU) # OK
17 | os.chmod(keyfile, 0o777) # Error
| ^^^^^ S103
18 | os.chmod(keyfile, 0o7 | 0o70 | 0o700) # Error
19 | os.chmod(keyfile, stat.S_IRWXO | stat.S_IRWXG | stat.S_IRWXU) # Error
|
S103.py:18:19: S103 `os.chmod` setting a permissive mask `0o777` on file or directory
|
16 | os.chmod("/etc/passwd", stat.S_IRWXU) # OK
17 | os.chmod(keyfile, 0o777) # Error
18 | os.chmod(keyfile, 0o7 | 0o70 | 0o700) # Error
| ^^^^^^^^^^^^^^^^^^ S103
19 | os.chmod(keyfile, stat.S_IRWXO | stat.S_IRWXG | stat.S_IRWXU) # Error
20 | os.chmod("~/hidden_exec", stat.S_IXGRP) # Error
|
S103.py:19:19: S103 `os.chmod` setting a permissive mask `0o777` on file or directory
|
17 | os.chmod(keyfile, 0o777) # Error
18 | os.chmod(keyfile, 0o7 | 0o70 | 0o700) # Error
19 | os.chmod(keyfile, stat.S_IRWXO | stat.S_IRWXG | stat.S_IRWXU) # Error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S103
20 | os.chmod("~/hidden_exec", stat.S_IXGRP) # Error
21 | os.chmod("~/hidden_exec", stat.S_IXOTH) # OK
|
S103.py:20:27: S103 `os.chmod` setting a permissive mask `0o10` on file or directory
|
18 | os.chmod(keyfile, 0o7 | 0o70 | 0o700) # Error
19 | os.chmod(keyfile, stat.S_IRWXO | stat.S_IRWXG | stat.S_IRWXU) # Error
20 | os.chmod("~/hidden_exec", stat.S_IXGRP) # Error
| ^^^^^^^^^^^^ S103
21 | os.chmod("~/hidden_exec", stat.S_IXOTH) # OK
22 | os.chmod("/etc/passwd", stat.S_IWOTH) # Error
|
S103.py:22:25: S103 `os.chmod` setting a permissive mask `0o2` on file or directory
|
20 | os.chmod("~/hidden_exec", stat.S_IXGRP) # Error
21 | os.chmod("~/hidden_exec", stat.S_IXOTH) # OK
22 | os.chmod("/etc/passwd", stat.S_IWOTH) # Error
| ^^^^^^^^^^^^ S103
|

View File

@@ -1,35 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S104.py:9:1: S104 Possible binding to all interfaces
|
8 | # Error
9 | "0.0.0.0"
| ^^^^^^^^^ S104
10 | '0.0.0.0'
|
S104.py:10:1: S104 Possible binding to all interfaces
|
8 | # Error
9 | "0.0.0.0"
10 | '0.0.0.0'
| ^^^^^^^^^ S104
|
S104.py:14:6: S104 Possible binding to all interfaces
|
13 | # Error
14 | func("0.0.0.0")
| ^^^^^^^^^ S104
|
S104.py:18:9: S104 Possible binding to all interfaces
|
17 | def my_func():
18 | x = "0.0.0.0"
| ^^^^^^^^^ S104
19 | print(x)
|

View File

@@ -1,377 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S105.py:13:12: S105 Possible hardcoded password assigned to: "password"
|
12 | # Errors
13 | password = "s3cr3t"
| ^^^^^^^^ S105
14 | _pass = "s3cr3t"
15 | passwd = "s3cr3t"
|
S105.py:14:9: S105 Possible hardcoded password assigned to: "_pass"
|
12 | # Errors
13 | password = "s3cr3t"
14 | _pass = "s3cr3t"
| ^^^^^^^^ S105
15 | passwd = "s3cr3t"
16 | pwd = "s3cr3t"
|
S105.py:15:10: S105 Possible hardcoded password assigned to: "passwd"
|
13 | password = "s3cr3t"
14 | _pass = "s3cr3t"
15 | passwd = "s3cr3t"
| ^^^^^^^^ S105
16 | pwd = "s3cr3t"
17 | secret = "s3cr3t"
|
S105.py:16:7: S105 Possible hardcoded password assigned to: "pwd"
|
14 | _pass = "s3cr3t"
15 | passwd = "s3cr3t"
16 | pwd = "s3cr3t"
| ^^^^^^^^ S105
17 | secret = "s3cr3t"
18 | token = "s3cr3t"
|
S105.py:17:10: S105 Possible hardcoded password assigned to: "secret"
|
15 | passwd = "s3cr3t"
16 | pwd = "s3cr3t"
17 | secret = "s3cr3t"
| ^^^^^^^^ S105
18 | token = "s3cr3t"
19 | secrete = "s3cr3t"
|
S105.py:18:9: S105 Possible hardcoded password assigned to: "token"
|
16 | pwd = "s3cr3t"
17 | secret = "s3cr3t"
18 | token = "s3cr3t"
| ^^^^^^^^ S105
19 | secrete = "s3cr3t"
20 | safe = password = "s3cr3t"
|
S105.py:19:11: S105 Possible hardcoded password assigned to: "secrete"
|
17 | secret = "s3cr3t"
18 | token = "s3cr3t"
19 | secrete = "s3cr3t"
| ^^^^^^^^ S105
20 | safe = password = "s3cr3t"
21 | password = safe = "s3cr3t"
|
S105.py:20:19: S105 Possible hardcoded password assigned to: "password"
|
18 | token = "s3cr3t"
19 | secrete = "s3cr3t"
20 | safe = password = "s3cr3t"
| ^^^^^^^^ S105
21 | password = safe = "s3cr3t"
22 | PASSWORD = "s3cr3t"
|
S105.py:21:19: S105 Possible hardcoded password assigned to: "password"
|
19 | secrete = "s3cr3t"
20 | safe = password = "s3cr3t"
21 | password = safe = "s3cr3t"
| ^^^^^^^^ S105
22 | PASSWORD = "s3cr3t"
23 | PassWord = "s3cr3t"
|
S105.py:22:12: S105 Possible hardcoded password assigned to: "PASSWORD"
|
20 | safe = password = "s3cr3t"
21 | password = safe = "s3cr3t"
22 | PASSWORD = "s3cr3t"
| ^^^^^^^^ S105
23 | PassWord = "s3cr3t"
|
S105.py:23:12: S105 Possible hardcoded password assigned to: "PassWord"
|
21 | password = safe = "s3cr3t"
22 | PASSWORD = "s3cr3t"
23 | PassWord = "s3cr3t"
| ^^^^^^^^ S105
24 |
25 | d["password"] = "s3cr3t"
|
S105.py:25:17: S105 Possible hardcoded password assigned to: "password"
|
23 | PassWord = "s3cr3t"
24 |
25 | d["password"] = "s3cr3t"
| ^^^^^^^^ S105
26 | d["pass"] = "s3cr3t"
27 | d["passwd"] = "s3cr3t"
|
S105.py:26:13: S105 Possible hardcoded password assigned to: "pass"
|
25 | d["password"] = "s3cr3t"
26 | d["pass"] = "s3cr3t"
| ^^^^^^^^ S105
27 | d["passwd"] = "s3cr3t"
28 | d["pwd"] = "s3cr3t"
|
S105.py:27:15: S105 Possible hardcoded password assigned to: "passwd"
|
25 | d["password"] = "s3cr3t"
26 | d["pass"] = "s3cr3t"
27 | d["passwd"] = "s3cr3t"
| ^^^^^^^^ S105
28 | d["pwd"] = "s3cr3t"
29 | d["secret"] = "s3cr3t"
|
S105.py:28:12: S105 Possible hardcoded password assigned to: "pwd"
|
26 | d["pass"] = "s3cr3t"
27 | d["passwd"] = "s3cr3t"
28 | d["pwd"] = "s3cr3t"
| ^^^^^^^^ S105
29 | d["secret"] = "s3cr3t"
30 | d["token"] = "s3cr3t"
|
S105.py:29:15: S105 Possible hardcoded password assigned to: "secret"
|
27 | d["passwd"] = "s3cr3t"
28 | d["pwd"] = "s3cr3t"
29 | d["secret"] = "s3cr3t"
| ^^^^^^^^ S105
30 | d["token"] = "s3cr3t"
31 | d["secrete"] = "s3cr3t"
|
S105.py:30:14: S105 Possible hardcoded password assigned to: "token"
|
28 | d["pwd"] = "s3cr3t"
29 | d["secret"] = "s3cr3t"
30 | d["token"] = "s3cr3t"
| ^^^^^^^^ S105
31 | d["secrete"] = "s3cr3t"
32 | safe = d["password"] = "s3cr3t"
|
S105.py:31:16: S105 Possible hardcoded password assigned to: "secrete"
|
29 | d["secret"] = "s3cr3t"
30 | d["token"] = "s3cr3t"
31 | d["secrete"] = "s3cr3t"
| ^^^^^^^^ S105
32 | safe = d["password"] = "s3cr3t"
33 | d["password"] = safe = "s3cr3t"
|
S105.py:32:24: S105 Possible hardcoded password assigned to: "password"
|
30 | d["token"] = "s3cr3t"
31 | d["secrete"] = "s3cr3t"
32 | safe = d["password"] = "s3cr3t"
| ^^^^^^^^ S105
33 | d["password"] = safe = "s3cr3t"
|
S105.py:33:24: S105 Possible hardcoded password assigned to: "password"
|
31 | d["secrete"] = "s3cr3t"
32 | safe = d["password"] = "s3cr3t"
33 | d["password"] = safe = "s3cr3t"
| ^^^^^^^^ S105
|
S105.py:37:16: S105 Possible hardcoded password assigned to: "password"
|
36 | class MyClass:
37 | password = "s3cr3t"
| ^^^^^^^^ S105
38 | safe = password
|
S105.py:41:20: S105 Possible hardcoded password assigned to: "password"
|
41 | MyClass.password = "s3cr3t"
| ^^^^^^^^ S105
42 | MyClass._pass = "s3cr3t"
43 | MyClass.passwd = "s3cr3t"
|
S105.py:42:17: S105 Possible hardcoded password assigned to: "_pass"
|
41 | MyClass.password = "s3cr3t"
42 | MyClass._pass = "s3cr3t"
| ^^^^^^^^ S105
43 | MyClass.passwd = "s3cr3t"
44 | MyClass.pwd = "s3cr3t"
|
S105.py:43:18: S105 Possible hardcoded password assigned to: "passwd"
|
41 | MyClass.password = "s3cr3t"
42 | MyClass._pass = "s3cr3t"
43 | MyClass.passwd = "s3cr3t"
| ^^^^^^^^ S105
44 | MyClass.pwd = "s3cr3t"
45 | MyClass.secret = "s3cr3t"
|
S105.py:44:15: S105 Possible hardcoded password assigned to: "pwd"
|
42 | MyClass._pass = "s3cr3t"
43 | MyClass.passwd = "s3cr3t"
44 | MyClass.pwd = "s3cr3t"
| ^^^^^^^^ S105
45 | MyClass.secret = "s3cr3t"
46 | MyClass.token = "s3cr3t"
|
S105.py:45:18: S105 Possible hardcoded password assigned to: "secret"
|
43 | MyClass.passwd = "s3cr3t"
44 | MyClass.pwd = "s3cr3t"
45 | MyClass.secret = "s3cr3t"
| ^^^^^^^^ S105
46 | MyClass.token = "s3cr3t"
47 | MyClass.secrete = "s3cr3t"
|
S105.py:46:17: S105 Possible hardcoded password assigned to: "token"
|
44 | MyClass.pwd = "s3cr3t"
45 | MyClass.secret = "s3cr3t"
46 | MyClass.token = "s3cr3t"
| ^^^^^^^^ S105
47 | MyClass.secrete = "s3cr3t"
|
S105.py:47:19: S105 Possible hardcoded password assigned to: "secrete"
|
45 | MyClass.secret = "s3cr3t"
46 | MyClass.token = "s3cr3t"
47 | MyClass.secrete = "s3cr3t"
| ^^^^^^^^ S105
48 |
49 | password == "s3cr3t"
|
S105.py:49:13: S105 Possible hardcoded password assigned to: "password"
|
47 | MyClass.secrete = "s3cr3t"
48 |
49 | password == "s3cr3t"
| ^^^^^^^^ S105
50 | _pass == "s3cr3t"
51 | passwd == "s3cr3t"
|
S105.py:50:10: S105 Possible hardcoded password assigned to: "_pass"
|
49 | password == "s3cr3t"
50 | _pass == "s3cr3t"
| ^^^^^^^^ S105
51 | passwd == "s3cr3t"
52 | pwd == "s3cr3t"
|
S105.py:51:11: S105 Possible hardcoded password assigned to: "passwd"
|
49 | password == "s3cr3t"
50 | _pass == "s3cr3t"
51 | passwd == "s3cr3t"
| ^^^^^^^^ S105
52 | pwd == "s3cr3t"
53 | secret == "s3cr3t"
|
S105.py:52:8: S105 Possible hardcoded password assigned to: "pwd"
|
50 | _pass == "s3cr3t"
51 | passwd == "s3cr3t"
52 | pwd == "s3cr3t"
| ^^^^^^^^ S105
53 | secret == "s3cr3t"
54 | token == "s3cr3t"
|
S105.py:53:11: S105 Possible hardcoded password assigned to: "secret"
|
51 | passwd == "s3cr3t"
52 | pwd == "s3cr3t"
53 | secret == "s3cr3t"
| ^^^^^^^^ S105
54 | token == "s3cr3t"
55 | secrete == "s3cr3t"
|
S105.py:54:10: S105 Possible hardcoded password assigned to: "token"
|
52 | pwd == "s3cr3t"
53 | secret == "s3cr3t"
54 | token == "s3cr3t"
| ^^^^^^^^ S105
55 | secrete == "s3cr3t"
56 | password == safe == "s3cr3t"
|
S105.py:55:12: S105 Possible hardcoded password assigned to: "secrete"
|
53 | secret == "s3cr3t"
54 | token == "s3cr3t"
55 | secrete == "s3cr3t"
| ^^^^^^^^ S105
56 | password == safe == "s3cr3t"
|
S105.py:56:21: S105 Possible hardcoded password assigned to: "password"
|
54 | token == "s3cr3t"
55 | secrete == "s3cr3t"
56 | password == safe == "s3cr3t"
| ^^^^^^^^ S105
57 |
58 | if token == "1\n2":
|
S105.py:58:13: S105 Possible hardcoded password assigned to: "token"
|
56 | password == safe == "s3cr3t"
57 |
58 | if token == "1\n2":
| ^^^^^^ S105
59 | pass
|
S105.py:61:13: S105 Possible hardcoded password assigned to: "token"
|
59 | pass
60 |
61 | if token == "3\t4":
| ^^^^^^ S105
62 | pass
|
S105.py:64:13: S105 Possible hardcoded password assigned to: "token"
|
62 | pass
63 |
64 | if token == "5\r6":
| ^^^^^^ S105
65 | pass
|

View File

@@ -1,11 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S106.py:14:9: S106 Possible hardcoded password assigned to argument: "password"
|
13 | # Error
14 | func(1, password="s3cr3t")
| ^^^^^^^^^^^^^^^^^ S106
|

View File

@@ -1,39 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S107.py:5:29: S107 Possible hardcoded password assigned to function default: "password"
|
5 | def default(first, password="default"):
| ^^^^^^^^^ S107
6 | pass
|
S107.py:13:45: S107 Possible hardcoded password assigned to function default: "password"
|
13 | def default_posonly(first, /, pos, password="posonly"):
| ^^^^^^^^^ S107
14 | pass
|
S107.py:21:39: S107 Possible hardcoded password assigned to function default: "password"
|
21 | def default_kwonly(first, *, password="kwonly"):
| ^^^^^^^^ S107
22 | pass
|
S107.py:29:39: S107 Possible hardcoded password assigned to function default: "secret"
|
29 | def default_all(first, /, pos, secret="posonly", *, password="kwonly"):
| ^^^^^^^^^ S107
30 | pass
|
S107.py:29:62: S107 Possible hardcoded password assigned to function default: "password"
|
29 | def default_all(first, /, pos, secret="posonly", *, password="kwonly"):
| ^^^^^^^^ S107
30 | pass
|

View File

@@ -1,31 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S108.py:5:11: S108 Probable insecure usage of temporary file or directory: "/tmp/abc"
|
3 | f.write("def")
4 |
5 | with open("/tmp/abc", "w") as f:
| ^^^^^^^^^^ S108
6 | f.write("def")
|
S108.py:8:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123"
|
6 | f.write("def")
7 |
8 | with open("/var/tmp/123", "w") as f:
| ^^^^^^^^^^^^^^ S108
9 | f.write("def")
|
S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test"
|
9 | f.write("def")
10 |
11 | with open("/dev/shm/unit/test", "w") as f:
| ^^^^^^^^^^^^^^^^^^^^ S108
12 | f.write("def")
|

View File

@@ -1,39 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S108.py:5:11: S108 Probable insecure usage of temporary file or directory: "/tmp/abc"
|
3 | f.write("def")
4 |
5 | with open("/tmp/abc", "w") as f:
| ^^^^^^^^^^ S108
6 | f.write("def")
|
S108.py:8:11: S108 Probable insecure usage of temporary file or directory: "/var/tmp/123"
|
6 | f.write("def")
7 |
8 | with open("/var/tmp/123", "w") as f:
| ^^^^^^^^^^^^^^ S108
9 | f.write("def")
|
S108.py:11:11: S108 Probable insecure usage of temporary file or directory: "/dev/shm/unit/test"
|
9 | f.write("def")
10 |
11 | with open("/dev/shm/unit/test", "w") as f:
| ^^^^^^^^^^^^^^^^^^^^ S108
12 | f.write("def")
|
S108.py:15:11: S108 Probable insecure usage of temporary file or directory: "/foo/bar"
|
14 | # not ok by config
15 | with open("/foo/bar", "w") as f:
| ^^^^^^^^^^ S108
16 | f.write("def")
|

View File

@@ -1,26 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S110.py:3:1: S110 `try`-`except`-`pass` detected, consider logging the exception
|
1 | try:
2 | pass
3 | / except Exception:
4 | | pass
| |________^ S110
5 |
6 | try:
|
S110.py:8:1: S110 `try`-`except`-`pass` detected, consider logging the exception
|
6 | try:
7 | pass
8 | / except:
9 | | pass
| |________^ S110
10 |
11 | try:
|

View File

@@ -1,35 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S110.py:3:1: S110 `try`-`except`-`pass` detected, consider logging the exception
|
1 | try:
2 | pass
3 | / except Exception:
4 | | pass
| |________^ S110
5 |
6 | try:
|
S110.py:8:1: S110 `try`-`except`-`pass` detected, consider logging the exception
|
6 | try:
7 | pass
8 | / except:
9 | | pass
| |________^ S110
10 |
11 | try:
|
S110.py:13:1: S110 `try`-`except`-`pass` detected, consider logging the exception
|
11 | try:
12 | pass
13 | / except ValueError:
14 | | pass
| |________^ S110
|

View File

@@ -1,48 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S112.py:3:1: S112 `try`-`except`-`continue` detected, consider logging the exception
|
1 | try:
2 | pass
3 | / except Exception:
4 | | continue
| |____________^ S112
5 |
6 | try:
|
S112.py:8:1: S112 `try`-`except`-`continue` detected, consider logging the exception
|
6 | try:
7 | pass
8 | / except:
9 | | continue
| |____________^ S112
10 |
11 | try:
|
S112.py:13:1: S112 `try`-`except`-`continue` detected, consider logging the exception
|
11 | try:
12 | pass
13 | / except (Exception,):
14 | | continue
| |____________^ S112
15 |
16 | try:
|
S112.py:18:1: S112 `try`-`except`-`continue` detected, consider logging the exception
|
16 | try:
17 | pass
18 | / except (Exception, ValueError):
19 | | continue
| |____________^ S112
20 |
21 | try:
|

View File

@@ -1,142 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S113.py:3:1: S113 Probable use of requests call without timeout
|
1 | import requests
2 |
3 | requests.get('https://gmail.com')
| ^^^^^^^^^^^^ S113
4 | requests.get('https://gmail.com', timeout=None)
5 | requests.get('https://gmail.com', timeout=5)
|
S113.py:4:35: S113 Probable use of requests call with timeout set to `None`
|
3 | requests.get('https://gmail.com')
4 | requests.get('https://gmail.com', timeout=None)
| ^^^^^^^^^^^^ S113
5 | requests.get('https://gmail.com', timeout=5)
6 | requests.post('https://gmail.com')
|
S113.py:6:1: S113 Probable use of requests call without timeout
|
4 | requests.get('https://gmail.com', timeout=None)
5 | requests.get('https://gmail.com', timeout=5)
6 | requests.post('https://gmail.com')
| ^^^^^^^^^^^^^ S113
7 | requests.post('https://gmail.com', timeout=None)
8 | requests.post('https://gmail.com', timeout=5)
|
S113.py:7:36: S113 Probable use of requests call with timeout set to `None`
|
5 | requests.get('https://gmail.com', timeout=5)
6 | requests.post('https://gmail.com')
7 | requests.post('https://gmail.com', timeout=None)
| ^^^^^^^^^^^^ S113
8 | requests.post('https://gmail.com', timeout=5)
9 | requests.put('https://gmail.com')
|
S113.py:9:1: S113 Probable use of requests call without timeout
|
7 | requests.post('https://gmail.com', timeout=None)
8 | requests.post('https://gmail.com', timeout=5)
9 | requests.put('https://gmail.com')
| ^^^^^^^^^^^^ S113
10 | requests.put('https://gmail.com', timeout=None)
11 | requests.put('https://gmail.com', timeout=5)
|
S113.py:10:35: S113 Probable use of requests call with timeout set to `None`
|
8 | requests.post('https://gmail.com', timeout=5)
9 | requests.put('https://gmail.com')
10 | requests.put('https://gmail.com', timeout=None)
| ^^^^^^^^^^^^ S113
11 | requests.put('https://gmail.com', timeout=5)
12 | requests.delete('https://gmail.com')
|
S113.py:12:1: S113 Probable use of requests call without timeout
|
10 | requests.put('https://gmail.com', timeout=None)
11 | requests.put('https://gmail.com', timeout=5)
12 | requests.delete('https://gmail.com')
| ^^^^^^^^^^^^^^^ S113
13 | requests.delete('https://gmail.com', timeout=None)
14 | requests.delete('https://gmail.com', timeout=5)
|
S113.py:13:38: S113 Probable use of requests call with timeout set to `None`
|
11 | requests.put('https://gmail.com', timeout=5)
12 | requests.delete('https://gmail.com')
13 | requests.delete('https://gmail.com', timeout=None)
| ^^^^^^^^^^^^ S113
14 | requests.delete('https://gmail.com', timeout=5)
15 | requests.patch('https://gmail.com')
|
S113.py:15:1: S113 Probable use of requests call without timeout
|
13 | requests.delete('https://gmail.com', timeout=None)
14 | requests.delete('https://gmail.com', timeout=5)
15 | requests.patch('https://gmail.com')
| ^^^^^^^^^^^^^^ S113
16 | requests.patch('https://gmail.com', timeout=None)
17 | requests.patch('https://gmail.com', timeout=5)
|
S113.py:16:37: S113 Probable use of requests call with timeout set to `None`
|
14 | requests.delete('https://gmail.com', timeout=5)
15 | requests.patch('https://gmail.com')
16 | requests.patch('https://gmail.com', timeout=None)
| ^^^^^^^^^^^^ S113
17 | requests.patch('https://gmail.com', timeout=5)
18 | requests.options('https://gmail.com')
|
S113.py:18:1: S113 Probable use of requests call without timeout
|
16 | requests.patch('https://gmail.com', timeout=None)
17 | requests.patch('https://gmail.com', timeout=5)
18 | requests.options('https://gmail.com')
| ^^^^^^^^^^^^^^^^ S113
19 | requests.options('https://gmail.com', timeout=None)
20 | requests.options('https://gmail.com', timeout=5)
|
S113.py:19:39: S113 Probable use of requests call with timeout set to `None`
|
17 | requests.patch('https://gmail.com', timeout=5)
18 | requests.options('https://gmail.com')
19 | requests.options('https://gmail.com', timeout=None)
| ^^^^^^^^^^^^ S113
20 | requests.options('https://gmail.com', timeout=5)
21 | requests.head('https://gmail.com')
|
S113.py:21:1: S113 Probable use of requests call without timeout
|
19 | requests.options('https://gmail.com', timeout=None)
20 | requests.options('https://gmail.com', timeout=5)
21 | requests.head('https://gmail.com')
| ^^^^^^^^^^^^^ S113
22 | requests.head('https://gmail.com', timeout=None)
23 | requests.head('https://gmail.com', timeout=5)
|
S113.py:22:36: S113 Probable use of requests call with timeout set to `None`
|
20 | requests.options('https://gmail.com', timeout=5)
21 | requests.head('https://gmail.com')
22 | requests.head('https://gmail.com', timeout=None)
| ^^^^^^^^^^^^ S113
23 | requests.head('https://gmail.com', timeout=5)
|

View File

@@ -1,13 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S201.py:10:9: S201 Use of `debug=True` in Flask app detected
|
9 | # OK
10 | app.run(debug=True)
| ^^^^^^^^^^ S201
11 |
12 | # Errors
|

View File

@@ -1,12 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S301.py:3:1: S301 `pickle` and modules that wrap it can be unsafe when used to deserialize untrusted data, possible security issue
|
1 | import pickle
2 |
3 | pickle.loads()
| ^^^^^^^^^^^^^^ S301
|

View File

@@ -1,20 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S307.py:3:7: S307 Use of possibly insecure function; consider using `ast.literal_eval`
|
1 | import os
2 |
3 | print(eval("1+1")) # S307
| ^^^^^^^^^^^ S307
4 | print(eval("os.getcwd()")) # S307
|
S307.py:4:7: S307 Use of possibly insecure function; consider using `ast.literal_eval`
|
3 | print(eval("1+1")) # S307
4 | print(eval("os.getcwd()")) # S307
| ^^^^^^^^^^^^^^^^^^^ S307
|

View File

@@ -1,12 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S312.py:3:1: S312 Telnet-related functions are being called. Telnet is considered insecure. Use SSH or some other encrypted protocol.
|
1 | from telnetlib import Telnet
2 |
3 | Telnet("localhost", 23)
| ^^^^^^^^^^^^^^^^^^^^^^^ S312
|

View File

@@ -1,133 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S324.py:7:13: S324 Probable use of insecure hash functions in `hashlib`: `md5`
|
5 | # Invalid
6 |
7 | hashlib.new('md5')
| ^^^^^ S324
8 |
9 | hashlib.new('md4', b'test')
|
S324.py:9:13: S324 Probable use of insecure hash functions in `hashlib`: `md4`
|
7 | hashlib.new('md5')
8 |
9 | hashlib.new('md4', b'test')
| ^^^^^ S324
10 |
11 | hashlib.new(name='md5', data=b'test')
|
S324.py:11:18: S324 Probable use of insecure hash functions in `hashlib`: `md5`
|
9 | hashlib.new('md4', b'test')
10 |
11 | hashlib.new(name='md5', data=b'test')
| ^^^^^ S324
12 |
13 | hashlib.new('MD4', data=b'test')
|
S324.py:13:13: S324 Probable use of insecure hash functions in `hashlib`: `MD4`
|
11 | hashlib.new(name='md5', data=b'test')
12 |
13 | hashlib.new('MD4', data=b'test')
| ^^^^^ S324
14 |
15 | hashlib.new('sha1')
|
S324.py:15:13: S324 Probable use of insecure hash functions in `hashlib`: `sha1`
|
13 | hashlib.new('MD4', data=b'test')
14 |
15 | hashlib.new('sha1')
| ^^^^^^ S324
16 |
17 | hashlib.new('sha1', data=b'test')
|
S324.py:17:13: S324 Probable use of insecure hash functions in `hashlib`: `sha1`
|
15 | hashlib.new('sha1')
16 |
17 | hashlib.new('sha1', data=b'test')
| ^^^^^^ S324
18 |
19 | hashlib.new('sha', data=b'test')
|
S324.py:19:13: S324 Probable use of insecure hash functions in `hashlib`: `sha`
|
17 | hashlib.new('sha1', data=b'test')
18 |
19 | hashlib.new('sha', data=b'test')
| ^^^^^ S324
20 |
21 | hashlib.new(name='SHA', data=b'test')
|
S324.py:21:18: S324 Probable use of insecure hash functions in `hashlib`: `SHA`
|
19 | hashlib.new('sha', data=b'test')
20 |
21 | hashlib.new(name='SHA', data=b'test')
| ^^^^^ S324
22 |
23 | hashlib.sha(data=b'test')
|
S324.py:23:1: S324 Probable use of insecure hash functions in `hashlib`: `sha`
|
21 | hashlib.new(name='SHA', data=b'test')
22 |
23 | hashlib.sha(data=b'test')
| ^^^^^^^^^^^ S324
24 |
25 | hashlib.md5()
|
S324.py:25:1: S324 Probable use of insecure hash functions in `hashlib`: `md5`
|
23 | hashlib.sha(data=b'test')
24 |
25 | hashlib.md5()
| ^^^^^^^^^^^ S324
26 |
27 | hashlib_new('sha1')
|
S324.py:27:13: S324 Probable use of insecure hash functions in `hashlib`: `sha1`
|
25 | hashlib.md5()
26 |
27 | hashlib_new('sha1')
| ^^^^^^ S324
28 |
29 | hashlib_sha1('sha1')
|
S324.py:29:1: S324 Probable use of insecure hash functions in `hashlib`: `sha1`
|
27 | hashlib_new('sha1')
28 |
29 | hashlib_sha1('sha1')
| ^^^^^^^^^^^^ S324
30 |
31 | # usedforsecurity arg only available in Python 3.9+
|
S324.py:32:13: S324 Probable use of insecure hash functions in `hashlib`: `sha1`
|
31 | # usedforsecurity arg only available in Python 3.9+
32 | hashlib.new('sha1', usedforsecurity=True)
| ^^^^^^ S324
33 |
34 | # Valid
|

View File

@@ -1,180 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S501.py:5:47: S501 Probable use of `requests` call with `verify=False` disabling SSL certificate checks
|
4 | requests.get('https://gmail.com', timeout=30, verify=True)
5 | requests.get('https://gmail.com', timeout=30, verify=False)
| ^^^^^^^^^^^^ S501
6 | requests.post('https://gmail.com', timeout=30, verify=True)
7 | requests.post('https://gmail.com', timeout=30, verify=False)
|
S501.py:7:48: S501 Probable use of `requests` call with `verify=False` disabling SSL certificate checks
|
5 | requests.get('https://gmail.com', timeout=30, verify=False)
6 | requests.post('https://gmail.com', timeout=30, verify=True)
7 | requests.post('https://gmail.com', timeout=30, verify=False)
| ^^^^^^^^^^^^ S501
8 | requests.put('https://gmail.com', timeout=30, verify=True)
9 | requests.put('https://gmail.com', timeout=30, verify=False)
|
S501.py:9:47: S501 Probable use of `requests` call with `verify=False` disabling SSL certificate checks
|
7 | requests.post('https://gmail.com', timeout=30, verify=False)
8 | requests.put('https://gmail.com', timeout=30, verify=True)
9 | requests.put('https://gmail.com', timeout=30, verify=False)
| ^^^^^^^^^^^^ S501
10 | requests.delete('https://gmail.com', timeout=30, verify=True)
11 | requests.delete('https://gmail.com', timeout=30, verify=False)
|
S501.py:11:50: S501 Probable use of `requests` call with `verify=False` disabling SSL certificate checks
|
9 | requests.put('https://gmail.com', timeout=30, verify=False)
10 | requests.delete('https://gmail.com', timeout=30, verify=True)
11 | requests.delete('https://gmail.com', timeout=30, verify=False)
| ^^^^^^^^^^^^ S501
12 | requests.patch('https://gmail.com', timeout=30, verify=True)
13 | requests.patch('https://gmail.com', timeout=30, verify=False)
|
S501.py:13:49: S501 Probable use of `requests` call with `verify=False` disabling SSL certificate checks
|
11 | requests.delete('https://gmail.com', timeout=30, verify=False)
12 | requests.patch('https://gmail.com', timeout=30, verify=True)
13 | requests.patch('https://gmail.com', timeout=30, verify=False)
| ^^^^^^^^^^^^ S501
14 | requests.options('https://gmail.com', timeout=30, verify=True)
15 | requests.options('https://gmail.com', timeout=30, verify=False)
|
S501.py:15:51: S501 Probable use of `requests` call with `verify=False` disabling SSL certificate checks
|
13 | requests.patch('https://gmail.com', timeout=30, verify=False)
14 | requests.options('https://gmail.com', timeout=30, verify=True)
15 | requests.options('https://gmail.com', timeout=30, verify=False)
| ^^^^^^^^^^^^ S501
16 | requests.head('https://gmail.com', timeout=30, verify=True)
17 | requests.head('https://gmail.com', timeout=30, verify=False)
|
S501.py:17:48: S501 Probable use of `requests` call with `verify=False` disabling SSL certificate checks
|
15 | requests.options('https://gmail.com', timeout=30, verify=False)
16 | requests.head('https://gmail.com', timeout=30, verify=True)
17 | requests.head('https://gmail.com', timeout=30, verify=False)
| ^^^^^^^^^^^^ S501
18 |
19 | httpx.request('GET', 'https://gmail.com', verify=True)
|
S501.py:20:43: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
19 | httpx.request('GET', 'https://gmail.com', verify=True)
20 | httpx.request('GET', 'https://gmail.com', verify=False)
| ^^^^^^^^^^^^ S501
21 | httpx.get('https://gmail.com', verify=True)
22 | httpx.get('https://gmail.com', verify=False)
|
S501.py:22:32: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
20 | httpx.request('GET', 'https://gmail.com', verify=False)
21 | httpx.get('https://gmail.com', verify=True)
22 | httpx.get('https://gmail.com', verify=False)
| ^^^^^^^^^^^^ S501
23 | httpx.options('https://gmail.com', verify=True)
24 | httpx.options('https://gmail.com', verify=False)
|
S501.py:24:36: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
22 | httpx.get('https://gmail.com', verify=False)
23 | httpx.options('https://gmail.com', verify=True)
24 | httpx.options('https://gmail.com', verify=False)
| ^^^^^^^^^^^^ S501
25 | httpx.head('https://gmail.com', verify=True)
26 | httpx.head('https://gmail.com', verify=False)
|
S501.py:26:33: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
24 | httpx.options('https://gmail.com', verify=False)
25 | httpx.head('https://gmail.com', verify=True)
26 | httpx.head('https://gmail.com', verify=False)
| ^^^^^^^^^^^^ S501
27 | httpx.post('https://gmail.com', verify=True)
28 | httpx.post('https://gmail.com', verify=False)
|
S501.py:28:33: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
26 | httpx.head('https://gmail.com', verify=False)
27 | httpx.post('https://gmail.com', verify=True)
28 | httpx.post('https://gmail.com', verify=False)
| ^^^^^^^^^^^^ S501
29 | httpx.put('https://gmail.com', verify=True)
30 | httpx.put('https://gmail.com', verify=False)
|
S501.py:30:32: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
28 | httpx.post('https://gmail.com', verify=False)
29 | httpx.put('https://gmail.com', verify=True)
30 | httpx.put('https://gmail.com', verify=False)
| ^^^^^^^^^^^^ S501
31 | httpx.patch('https://gmail.com', verify=True)
32 | httpx.patch('https://gmail.com', verify=False)
|
S501.py:32:34: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
30 | httpx.put('https://gmail.com', verify=False)
31 | httpx.patch('https://gmail.com', verify=True)
32 | httpx.patch('https://gmail.com', verify=False)
| ^^^^^^^^^^^^ S501
33 | httpx.delete('https://gmail.com', verify=True)
34 | httpx.delete('https://gmail.com', verify=False)
|
S501.py:34:35: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
32 | httpx.patch('https://gmail.com', verify=False)
33 | httpx.delete('https://gmail.com', verify=True)
34 | httpx.delete('https://gmail.com', verify=False)
| ^^^^^^^^^^^^ S501
35 | httpx.stream('https://gmail.com', verify=True)
36 | httpx.stream('https://gmail.com', verify=False)
|
S501.py:36:35: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
34 | httpx.delete('https://gmail.com', verify=False)
35 | httpx.stream('https://gmail.com', verify=True)
36 | httpx.stream('https://gmail.com', verify=False)
| ^^^^^^^^^^^^ S501
37 | httpx.Client()
38 | httpx.Client(verify=False)
|
S501.py:38:14: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
36 | httpx.stream('https://gmail.com', verify=False)
37 | httpx.Client()
38 | httpx.Client(verify=False)
| ^^^^^^^^^^^^ S501
39 | httpx.AsyncClient()
40 | httpx.AsyncClient(verify=False)
|
S501.py:40:19: S501 Probable use of `httpx` call with `verify=False` disabling SSL certificate checks
|
38 | httpx.Client(verify=False)
39 | httpx.AsyncClient()
40 | httpx.AsyncClient(verify=False)
| ^^^^^^^^^^^^ S501
|

View File

@@ -1,22 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S506.py:10:9: S506 Probable use of unsafe `yaml.load`. Allows instantiation of arbitrary objects. Consider `yaml.safe_load`.
|
8 | def test_yaml_load():
9 | ystr = yaml.dump({"a": 1, "b": 2, "c": 3})
10 | y = yaml.load(ystr)
| ^^^^^^^^^ S506
11 | yaml.dump(y)
12 | try:
|
S506.py:24:24: S506 Probable use of unsafe loader `Loader` with `yaml.load`. Allows instantiation of arbitrary objects. Consider `yaml.safe_load`.
|
24 | yaml.load("{}", Loader=yaml.Loader)
| ^^^^^^^^^^^ S506
25 |
26 | # no issue should be found
|

View File

@@ -1,22 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S508.py:3:25: S508 The use of SNMPv1 and SNMPv2 is insecure. Use SNMPv3 if able.
|
1 | from pysnmp.hlapi import CommunityData
2 |
3 | CommunityData("public", mpModel=0) # S508
| ^^^^^^^^^ S508
4 | CommunityData("public", mpModel=1) # S508
|
S508.py:4:25: S508 The use of SNMPv1 and SNMPv2 is insecure. Use SNMPv3 if able.
|
3 | CommunityData("public", mpModel=0) # S508
4 | CommunityData("public", mpModel=1) # S508
| ^^^^^^^^^ S508
5 |
6 | CommunityData("public", mpModel=2) # OK
|

View File

@@ -1,20 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S509.py:4:12: S509 You should not use SNMPv3 without encryption. `noAuthNoPriv` & `authNoPriv` is insecure.
|
4 | insecure = UsmUserData("securityName") # S509
| ^^^^^^^^^^^ S509
5 | auth_no_priv = UsmUserData("securityName", "authName") # S509
|
S509.py:5:16: S509 You should not use SNMPv3 without encryption. `noAuthNoPriv` & `authNoPriv` is insecure.
|
4 | insecure = UsmUserData("securityName") # S509
5 | auth_no_priv = UsmUserData("securityName", "authName") # S509
| ^^^^^^^^^^^ S509
6 |
7 | less_insecure = UsmUserData("securityName", "authName", "privName") # OK
|

View File

@@ -1,12 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S601.py:3:1: S601 Possible shell injection via Paramiko call; check inputs are properly sanitized
|
1 | import paramiko
2 |
3 | paramiko.exec_command('something; really; unsafe')
| ^^^^^^^^^^^^^^^^^^^^^ S601
|

View File

@@ -1,117 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S602.py:4:15: S602 `subprocess` call with `shell=True` seems safe, but may be changed in the future; consider rewriting without `shell`
|
3 | # Check different Popen wrappers are checked.
4 | Popen("true", shell=True)
| ^^^^^^^^^^ S602
5 | call("true", shell=True)
6 | check_call("true", shell=True)
|
S602.py:5:14: S602 `subprocess` call with `shell=True` seems safe, but may be changed in the future; consider rewriting without `shell`
|
3 | # Check different Popen wrappers are checked.
4 | Popen("true", shell=True)
5 | call("true", shell=True)
| ^^^^^^^^^^ S602
6 | check_call("true", shell=True)
7 | check_output("true", shell=True)
|
S602.py:6:20: S602 `subprocess` call with `shell=True` seems safe, but may be changed in the future; consider rewriting without `shell`
|
4 | Popen("true", shell=True)
5 | call("true", shell=True)
6 | check_call("true", shell=True)
| ^^^^^^^^^^ S602
7 | check_output("true", shell=True)
8 | run("true", shell=True)
|
S602.py:7:22: S602 `subprocess` call with `shell=True` seems safe, but may be changed in the future; consider rewriting without `shell`
|
5 | call("true", shell=True)
6 | check_call("true", shell=True)
7 | check_output("true", shell=True)
| ^^^^^^^^^^ S602
8 | run("true", shell=True)
|
S602.py:8:13: S602 `subprocess` call with `shell=True` seems safe, but may be changed in the future; consider rewriting without `shell`
|
6 | check_call("true", shell=True)
7 | check_output("true", shell=True)
8 | run("true", shell=True)
| ^^^^^^^^^^ S602
9 |
10 | # Check values that truthy values are treated as true.
|
S602.py:11:15: S602 `subprocess` call with `shell=True` seems safe, but may be changed in the future; consider rewriting without `shell`
|
10 | # Check values that truthy values are treated as true.
11 | Popen("true", shell=1)
| ^^^^^^^ S602
12 | Popen("true", shell=[1])
13 | Popen("true", shell={1: 1})
|
S602.py:12:15: S602 `subprocess` call with `shell=True` seems safe, but may be changed in the future; consider rewriting without `shell`
|
10 | # Check values that truthy values are treated as true.
11 | Popen("true", shell=1)
12 | Popen("true", shell=[1])
| ^^^^^^^^^ S602
13 | Popen("true", shell={1: 1})
14 | Popen("true", shell=(1,))
|
S602.py:13:15: S602 `subprocess` call with `shell=True` seems safe, but may be changed in the future; consider rewriting without `shell`
|
11 | Popen("true", shell=1)
12 | Popen("true", shell=[1])
13 | Popen("true", shell={1: 1})
| ^^^^^^^^^^^^ S602
14 | Popen("true", shell=(1,))
|
S602.py:14:15: S602 `subprocess` call with `shell=True` seems safe, but may be changed in the future; consider rewriting without `shell`
|
12 | Popen("true", shell=[1])
13 | Popen("true", shell={1: 1})
14 | Popen("true", shell=(1,))
| ^^^^^^^^^^ S602
15 |
16 | # Check command argument looks unsafe.
|
S602.py:18:19: S602 `subprocess` call with `shell=True` identified, security issue
|
16 | # Check command argument looks unsafe.
17 | var_string = "true"
18 | Popen(var_string, shell=True)
| ^^^^^^^^^^ S602
19 | Popen([var_string], shell=True)
20 | Popen([var_string, ""], shell=True)
|
S602.py:19:21: S602 `subprocess` call with `shell=True` identified, security issue
|
17 | var_string = "true"
18 | Popen(var_string, shell=True)
19 | Popen([var_string], shell=True)
| ^^^^^^^^^^ S602
20 | Popen([var_string, ""], shell=True)
|
S602.py:20:25: S602 `subprocess` call with `shell=True` identified, security issue
|
18 | Popen(var_string, shell=True)
19 | Popen([var_string], shell=True)
20 | Popen([var_string, ""], shell=True)
| ^^^^^^^^^^ S602
|

View File

@@ -1,106 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S603.py:4:15: S603 `subprocess` call: check for execution of untrusted input
|
3 | # Different Popen wrappers are checked.
4 | Popen("true", shell=False)
| ^^^^^^^^^^^ S603
5 | call("true", shell=False)
6 | check_call("true", shell=False)
|
S603.py:5:14: S603 `subprocess` call: check for execution of untrusted input
|
3 | # Different Popen wrappers are checked.
4 | Popen("true", shell=False)
5 | call("true", shell=False)
| ^^^^^^^^^^^ S603
6 | check_call("true", shell=False)
7 | check_output("true", shell=False)
|
S603.py:6:20: S603 `subprocess` call: check for execution of untrusted input
|
4 | Popen("true", shell=False)
5 | call("true", shell=False)
6 | check_call("true", shell=False)
| ^^^^^^^^^^^ S603
7 | check_output("true", shell=False)
8 | run("true", shell=False)
|
S603.py:7:22: S603 `subprocess` call: check for execution of untrusted input
|
5 | call("true", shell=False)
6 | check_call("true", shell=False)
7 | check_output("true", shell=False)
| ^^^^^^^^^^^ S603
8 | run("true", shell=False)
|
S603.py:8:13: S603 `subprocess` call: check for execution of untrusted input
|
6 | check_call("true", shell=False)
7 | check_output("true", shell=False)
8 | run("true", shell=False)
| ^^^^^^^^^^^ S603
9 |
10 | # Values that falsey values are treated as false.
|
S603.py:11:15: S603 `subprocess` call: check for execution of untrusted input
|
10 | # Values that falsey values are treated as false.
11 | Popen("true", shell=0)
| ^^^^^^^ S603
12 | Popen("true", shell=[])
13 | Popen("true", shell={})
|
S603.py:12:15: S603 `subprocess` call: check for execution of untrusted input
|
10 | # Values that falsey values are treated as false.
11 | Popen("true", shell=0)
12 | Popen("true", shell=[])
| ^^^^^^^^ S603
13 | Popen("true", shell={})
14 | Popen("true", shell=None)
|
S603.py:13:15: S603 `subprocess` call: check for execution of untrusted input
|
11 | Popen("true", shell=0)
12 | Popen("true", shell=[])
13 | Popen("true", shell={})
| ^^^^^^^^ S603
14 | Popen("true", shell=None)
|
S603.py:14:15: S603 `subprocess` call: check for execution of untrusted input
|
12 | Popen("true", shell=[])
13 | Popen("true", shell={})
14 | Popen("true", shell=None)
| ^^^^^^^^^^ S603
15 |
16 | # Unknown values are treated as falsey.
|
S603.py:17:15: S603 `subprocess` call: check for execution of untrusted input
|
16 | # Unknown values are treated as falsey.
17 | Popen("true", shell=True if True else False)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S603
18 |
19 | # No value is also caught.
|
S603.py:20:7: S603 `subprocess` call: check for execution of untrusted input
|
19 | # No value is also caught.
20 | Popen("true")
| ^^^^^^ S603
|

View File

@@ -1,10 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S604.py:5:5: S604 Function call with `shell=True` parameter identified, security issue
|
5 | foo(shell=True)
| ^^^^^^^^^^ S604
|

View File

@@ -1,147 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S605.py:7:11: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
6 | # Check all shell functions.
7 | os.system("true")
| ^^^^^^ S605
8 | os.popen("true")
9 | os.popen2("true")
|
S605.py:8:10: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
6 | # Check all shell functions.
7 | os.system("true")
8 | os.popen("true")
| ^^^^^^ S605
9 | os.popen2("true")
10 | os.popen3("true")
|
S605.py:9:11: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
7 | os.system("true")
8 | os.popen("true")
9 | os.popen2("true")
| ^^^^^^ S605
10 | os.popen3("true")
11 | os.popen4("true")
|
S605.py:10:11: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
8 | os.popen("true")
9 | os.popen2("true")
10 | os.popen3("true")
| ^^^^^^ S605
11 | os.popen4("true")
12 | popen2.popen2("true")
|
S605.py:11:11: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
9 | os.popen2("true")
10 | os.popen3("true")
11 | os.popen4("true")
| ^^^^^^ S605
12 | popen2.popen2("true")
13 | popen2.popen3("true")
|
S605.py:12:15: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
10 | os.popen3("true")
11 | os.popen4("true")
12 | popen2.popen2("true")
| ^^^^^^ S605
13 | popen2.popen3("true")
14 | popen2.popen4("true")
|
S605.py:13:15: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
11 | os.popen4("true")
12 | popen2.popen2("true")
13 | popen2.popen3("true")
| ^^^^^^ S605
14 | popen2.popen4("true")
15 | popen2.Popen3("true")
|
S605.py:14:15: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
12 | popen2.popen2("true")
13 | popen2.popen3("true")
14 | popen2.popen4("true")
| ^^^^^^ S605
15 | popen2.Popen3("true")
16 | popen2.Popen4("true")
|
S605.py:15:15: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
13 | popen2.popen3("true")
14 | popen2.popen4("true")
15 | popen2.Popen3("true")
| ^^^^^^ S605
16 | popen2.Popen4("true")
17 | commands.getoutput("true")
|
S605.py:16:15: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
14 | popen2.popen4("true")
15 | popen2.Popen3("true")
16 | popen2.Popen4("true")
| ^^^^^^ S605
17 | commands.getoutput("true")
18 | commands.getstatusoutput("true")
|
S605.py:17:20: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
15 | popen2.Popen3("true")
16 | popen2.Popen4("true")
17 | commands.getoutput("true")
| ^^^^^^ S605
18 | commands.getstatusoutput("true")
|
S605.py:18:26: S605 Starting a process with a shell: seems safe, but may be changed in the future; consider rewriting without `shell`
|
16 | popen2.Popen4("true")
17 | commands.getoutput("true")
18 | commands.getstatusoutput("true")
| ^^^^^^ S605
|
S605.py:23:11: S605 Starting a process with a shell, possible injection detected
|
21 | # Check command argument looks unsafe.
22 | var_string = "true"
23 | os.system(var_string)
| ^^^^^^^^^^ S605
24 | os.system([var_string])
25 | os.system([var_string, ""])
|
S605.py:24:11: S605 Starting a process with a shell, possible injection detected
|
22 | var_string = "true"
23 | os.system(var_string)
24 | os.system([var_string])
| ^^^^^^^^^^^^ S605
25 | os.system([var_string, ""])
|
S605.py:25:11: S605 Starting a process with a shell, possible injection detected
|
23 | os.system(var_string)
24 | os.system([var_string])
25 | os.system([var_string, ""])
| ^^^^^^^^^^^^^^^^ S605
|

View File

@@ -1,170 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S606.py:4:1: S606 Starting a process without a shell
|
3 | # Check all shell functions.
4 | os.execl("true")
| ^^^^^^^^ S606
5 | os.execle("true")
6 | os.execlp("true")
|
S606.py:5:1: S606 Starting a process without a shell
|
3 | # Check all shell functions.
4 | os.execl("true")
5 | os.execle("true")
| ^^^^^^^^^ S606
6 | os.execlp("true")
7 | os.execlpe("true")
|
S606.py:6:1: S606 Starting a process without a shell
|
4 | os.execl("true")
5 | os.execle("true")
6 | os.execlp("true")
| ^^^^^^^^^ S606
7 | os.execlpe("true")
8 | os.execv("true")
|
S606.py:7:1: S606 Starting a process without a shell
|
5 | os.execle("true")
6 | os.execlp("true")
7 | os.execlpe("true")
| ^^^^^^^^^^ S606
8 | os.execv("true")
9 | os.execve("true")
|
S606.py:8:1: S606 Starting a process without a shell
|
6 | os.execlp("true")
7 | os.execlpe("true")
8 | os.execv("true")
| ^^^^^^^^ S606
9 | os.execve("true")
10 | os.execvp("true")
|
S606.py:9:1: S606 Starting a process without a shell
|
7 | os.execlpe("true")
8 | os.execv("true")
9 | os.execve("true")
| ^^^^^^^^^ S606
10 | os.execvp("true")
11 | os.execvpe("true")
|
S606.py:10:1: S606 Starting a process without a shell
|
8 | os.execv("true")
9 | os.execve("true")
10 | os.execvp("true")
| ^^^^^^^^^ S606
11 | os.execvpe("true")
12 | os.spawnl("true")
|
S606.py:11:1: S606 Starting a process without a shell
|
9 | os.execve("true")
10 | os.execvp("true")
11 | os.execvpe("true")
| ^^^^^^^^^^ S606
12 | os.spawnl("true")
13 | os.spawnle("true")
|
S606.py:12:1: S606 Starting a process without a shell
|
10 | os.execvp("true")
11 | os.execvpe("true")
12 | os.spawnl("true")
| ^^^^^^^^^ S606
13 | os.spawnle("true")
14 | os.spawnlp("true")
|
S606.py:13:1: S606 Starting a process without a shell
|
11 | os.execvpe("true")
12 | os.spawnl("true")
13 | os.spawnle("true")
| ^^^^^^^^^^ S606
14 | os.spawnlp("true")
15 | os.spawnlpe("true")
|
S606.py:14:1: S606 Starting a process without a shell
|
12 | os.spawnl("true")
13 | os.spawnle("true")
14 | os.spawnlp("true")
| ^^^^^^^^^^ S606
15 | os.spawnlpe("true")
16 | os.spawnv("true")
|
S606.py:15:1: S606 Starting a process without a shell
|
13 | os.spawnle("true")
14 | os.spawnlp("true")
15 | os.spawnlpe("true")
| ^^^^^^^^^^^ S606
16 | os.spawnv("true")
17 | os.spawnve("true")
|
S606.py:16:1: S606 Starting a process without a shell
|
14 | os.spawnlp("true")
15 | os.spawnlpe("true")
16 | os.spawnv("true")
| ^^^^^^^^^ S606
17 | os.spawnve("true")
18 | os.spawnvp("true")
|
S606.py:17:1: S606 Starting a process without a shell
|
15 | os.spawnlpe("true")
16 | os.spawnv("true")
17 | os.spawnve("true")
| ^^^^^^^^^^ S606
18 | os.spawnvp("true")
19 | os.spawnvpe("true")
|
S606.py:18:1: S606 Starting a process without a shell
|
16 | os.spawnv("true")
17 | os.spawnve("true")
18 | os.spawnvp("true")
| ^^^^^^^^^^ S606
19 | os.spawnvpe("true")
20 | os.startfile("true")
|
S606.py:19:1: S606 Starting a process without a shell
|
17 | os.spawnve("true")
18 | os.spawnvp("true")
19 | os.spawnvpe("true")
| ^^^^^^^^^^^ S606
20 | os.startfile("true")
|
S606.py:20:1: S606 Starting a process without a shell
|
18 | os.spawnvp("true")
19 | os.spawnvpe("true")
20 | os.startfile("true")
| ^^^^^^^^^^^^ S606
|

View File

@@ -1,223 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S607.py:9:11: S607 Starting a process with a partial executable path
|
7 | subprocess.check_output("true")
8 | subprocess.run("true")
9 | os.system("true")
| ^^^^^^ S607
10 | os.popen("true")
11 | os.popen2("true")
|
S607.py:10:10: S607 Starting a process with a partial executable path
|
8 | subprocess.run("true")
9 | os.system("true")
10 | os.popen("true")
| ^^^^^^ S607
11 | os.popen2("true")
12 | os.popen3("true")
|
S607.py:11:11: S607 Starting a process with a partial executable path
|
9 | os.system("true")
10 | os.popen("true")
11 | os.popen2("true")
| ^^^^^^ S607
12 | os.popen3("true")
13 | os.popen4("true")
|
S607.py:12:11: S607 Starting a process with a partial executable path
|
10 | os.popen("true")
11 | os.popen2("true")
12 | os.popen3("true")
| ^^^^^^ S607
13 | os.popen4("true")
14 | popen2.popen2("true")
|
S607.py:13:11: S607 Starting a process with a partial executable path
|
11 | os.popen2("true")
12 | os.popen3("true")
13 | os.popen4("true")
| ^^^^^^ S607
14 | popen2.popen2("true")
15 | popen2.popen3("true")
|
S607.py:21:10: S607 Starting a process with a partial executable path
|
19 | commands.getoutput("true")
20 | commands.getstatusoutput("true")
21 | os.execl("true")
| ^^^^^^ S607
22 | os.execle("true")
23 | os.execlp("true")
|
S607.py:22:11: S607 Starting a process with a partial executable path
|
20 | commands.getstatusoutput("true")
21 | os.execl("true")
22 | os.execle("true")
| ^^^^^^ S607
23 | os.execlp("true")
24 | os.execlpe("true")
|
S607.py:23:11: S607 Starting a process with a partial executable path
|
21 | os.execl("true")
22 | os.execle("true")
23 | os.execlp("true")
| ^^^^^^ S607
24 | os.execlpe("true")
25 | os.execv("true")
|
S607.py:24:12: S607 Starting a process with a partial executable path
|
22 | os.execle("true")
23 | os.execlp("true")
24 | os.execlpe("true")
| ^^^^^^ S607
25 | os.execv("true")
26 | os.execve("true")
|
S607.py:25:10: S607 Starting a process with a partial executable path
|
23 | os.execlp("true")
24 | os.execlpe("true")
25 | os.execv("true")
| ^^^^^^ S607
26 | os.execve("true")
27 | os.execvp("true")
|
S607.py:26:11: S607 Starting a process with a partial executable path
|
24 | os.execlpe("true")
25 | os.execv("true")
26 | os.execve("true")
| ^^^^^^ S607
27 | os.execvp("true")
28 | os.execvpe("true")
|
S607.py:27:11: S607 Starting a process with a partial executable path
|
25 | os.execv("true")
26 | os.execve("true")
27 | os.execvp("true")
| ^^^^^^ S607
28 | os.execvpe("true")
29 | os.spawnl("true")
|
S607.py:28:12: S607 Starting a process with a partial executable path
|
26 | os.execve("true")
27 | os.execvp("true")
28 | os.execvpe("true")
| ^^^^^^ S607
29 | os.spawnl("true")
30 | os.spawnle("true")
|
S607.py:29:11: S607 Starting a process with a partial executable path
|
27 | os.execvp("true")
28 | os.execvpe("true")
29 | os.spawnl("true")
| ^^^^^^ S607
30 | os.spawnle("true")
31 | os.spawnlp("true")
|
S607.py:30:12: S607 Starting a process with a partial executable path
|
28 | os.execvpe("true")
29 | os.spawnl("true")
30 | os.spawnle("true")
| ^^^^^^ S607
31 | os.spawnlp("true")
32 | os.spawnlpe("true")
|
S607.py:31:12: S607 Starting a process with a partial executable path
|
29 | os.spawnl("true")
30 | os.spawnle("true")
31 | os.spawnlp("true")
| ^^^^^^ S607
32 | os.spawnlpe("true")
33 | os.spawnv("true")
|
S607.py:32:13: S607 Starting a process with a partial executable path
|
30 | os.spawnle("true")
31 | os.spawnlp("true")
32 | os.spawnlpe("true")
| ^^^^^^ S607
33 | os.spawnv("true")
34 | os.spawnve("true")
|
S607.py:33:11: S607 Starting a process with a partial executable path
|
31 | os.spawnlp("true")
32 | os.spawnlpe("true")
33 | os.spawnv("true")
| ^^^^^^ S607
34 | os.spawnve("true")
35 | os.spawnvp("true")
|
S607.py:34:12: S607 Starting a process with a partial executable path
|
32 | os.spawnlpe("true")
33 | os.spawnv("true")
34 | os.spawnve("true")
| ^^^^^^ S607
35 | os.spawnvp("true")
36 | os.spawnvpe("true")
|
S607.py:35:12: S607 Starting a process with a partial executable path
|
33 | os.spawnv("true")
34 | os.spawnve("true")
35 | os.spawnvp("true")
| ^^^^^^ S607
36 | os.spawnvpe("true")
37 | os.startfile("true")
|
S607.py:36:13: S607 Starting a process with a partial executable path
|
34 | os.spawnve("true")
35 | os.spawnvp("true")
36 | os.spawnvpe("true")
| ^^^^^^ S607
37 | os.startfile("true")
|
S607.py:37:14: S607 Starting a process with a partial executable path
|
35 | os.spawnvp("true")
36 | os.spawnvpe("true")
37 | os.startfile("true")
| ^^^^^^ S607
38 |
39 | # Check it does not fail for full paths.
|

View File

@@ -1,482 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S608.py:2:10: S608 Possible SQL injection vector through string-based query construction
|
1 | # single-line failures
2 | query1 = "SELECT %s FROM table" % (var,) # bad
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
3 | query2 = "SELECT var FROM " + table
4 | query3 = "SELECT " + val + " FROM " + table
|
S608.py:3:10: S608 Possible SQL injection vector through string-based query construction
|
1 | # single-line failures
2 | query1 = "SELECT %s FROM table" % (var,) # bad
3 | query2 = "SELECT var FROM " + table
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
4 | query3 = "SELECT " + val + " FROM " + table
5 | query4 = "SELECT {} FROM table;".format(var)
|
S608.py:4:10: S608 Possible SQL injection vector through string-based query construction
|
2 | query1 = "SELECT %s FROM table" % (var,) # bad
3 | query2 = "SELECT var FROM " + table
4 | query3 = "SELECT " + val + " FROM " + table
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
5 | query4 = "SELECT {} FROM table;".format(var)
6 | query5 = f"SELECT * FROM table WHERE var = {var}"
|
S608.py:5:10: S608 Possible SQL injection vector through string-based query construction
|
3 | query2 = "SELECT var FROM " + table
4 | query3 = "SELECT " + val + " FROM " + table
5 | query4 = "SELECT {} FROM table;".format(var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
6 | query5 = f"SELECT * FROM table WHERE var = {var}"
|
S608.py:6:10: S608 Possible SQL injection vector through string-based query construction
|
4 | query3 = "SELECT " + val + " FROM " + table
5 | query4 = "SELECT {} FROM table;".format(var)
6 | query5 = f"SELECT * FROM table WHERE var = {var}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
7 |
8 | query6 = "DELETE FROM table WHERE var = %s" % (var,)
|
S608.py:8:10: S608 Possible SQL injection vector through string-based query construction
|
6 | query5 = f"SELECT * FROM table WHERE var = {var}"
7 |
8 | query6 = "DELETE FROM table WHERE var = %s" % (var,)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
9 | query7 = "DELETE FROM table WHERE VAR = " + var
10 | query8 = "DELETE FROM " + table + "WHERE var = " + var
|
S608.py:9:10: S608 Possible SQL injection vector through string-based query construction
|
8 | query6 = "DELETE FROM table WHERE var = %s" % (var,)
9 | query7 = "DELETE FROM table WHERE VAR = " + var
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
10 | query8 = "DELETE FROM " + table + "WHERE var = " + var
11 | query9 = "DELETE FROM table WHERE var = {}".format(var)
|
S608.py:10:10: S608 Possible SQL injection vector through string-based query construction
|
8 | query6 = "DELETE FROM table WHERE var = %s" % (var,)
9 | query7 = "DELETE FROM table WHERE VAR = " + var
10 | query8 = "DELETE FROM " + table + "WHERE var = " + var
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
11 | query9 = "DELETE FROM table WHERE var = {}".format(var)
12 | query10 = f"DELETE FROM table WHERE var = {var}"
|
S608.py:11:10: S608 Possible SQL injection vector through string-based query construction
|
9 | query7 = "DELETE FROM table WHERE VAR = " + var
10 | query8 = "DELETE FROM " + table + "WHERE var = " + var
11 | query9 = "DELETE FROM table WHERE var = {}".format(var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
12 | query10 = f"DELETE FROM table WHERE var = {var}"
|
S608.py:12:11: S608 Possible SQL injection vector through string-based query construction
|
10 | query8 = "DELETE FROM " + table + "WHERE var = " + var
11 | query9 = "DELETE FROM table WHERE var = {}".format(var)
12 | query10 = f"DELETE FROM table WHERE var = {var}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
13 |
14 | query11 = "INSERT INTO table VALUES (%s)" % (var,)
|
S608.py:14:11: S608 Possible SQL injection vector through string-based query construction
|
12 | query10 = f"DELETE FROM table WHERE var = {var}"
13 |
14 | query11 = "INSERT INTO table VALUES (%s)" % (var,)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
15 | query12 = "INSERT INTO TABLE VALUES (" + var + ")"
16 | query13 = "INSERT INTO {} VALUES ({})".format(table, var)
|
S608.py:15:11: S608 Possible SQL injection vector through string-based query construction
|
14 | query11 = "INSERT INTO table VALUES (%s)" % (var,)
15 | query12 = "INSERT INTO TABLE VALUES (" + var + ")"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
16 | query13 = "INSERT INTO {} VALUES ({})".format(table, var)
17 | query14 = f"INSERT INTO {table} VALUES var = {var}"
|
S608.py:16:11: S608 Possible SQL injection vector through string-based query construction
|
14 | query11 = "INSERT INTO table VALUES (%s)" % (var,)
15 | query12 = "INSERT INTO TABLE VALUES (" + var + ")"
16 | query13 = "INSERT INTO {} VALUES ({})".format(table, var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
17 | query14 = f"INSERT INTO {table} VALUES var = {var}"
|
S608.py:17:11: S608 Possible SQL injection vector through string-based query construction
|
15 | query12 = "INSERT INTO TABLE VALUES (" + var + ")"
16 | query13 = "INSERT INTO {} VALUES ({})".format(table, var)
17 | query14 = f"INSERT INTO {table} VALUES var = {var}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
18 |
19 | query15 = "UPDATE %s SET var = %s" % (table, var)
|
S608.py:19:11: S608 Possible SQL injection vector through string-based query construction
|
17 | query14 = f"INSERT INTO {table} VALUES var = {var}"
18 |
19 | query15 = "UPDATE %s SET var = %s" % (table, var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
20 | query16 = "UPDATE " + table + " SET var = " + var
21 | query17 = "UPDATE {} SET var = {}".format(table, var)
|
S608.py:20:11: S608 Possible SQL injection vector through string-based query construction
|
19 | query15 = "UPDATE %s SET var = %s" % (table, var)
20 | query16 = "UPDATE " + table + " SET var = " + var
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
21 | query17 = "UPDATE {} SET var = {}".format(table, var)
22 | query18 = f"UPDATE {table} SET var = {var}"
|
S608.py:21:11: S608 Possible SQL injection vector through string-based query construction
|
19 | query15 = "UPDATE %s SET var = %s" % (table, var)
20 | query16 = "UPDATE " + table + " SET var = " + var
21 | query17 = "UPDATE {} SET var = {}".format(table, var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
22 | query18 = f"UPDATE {table} SET var = {var}"
|
S608.py:22:11: S608 Possible SQL injection vector through string-based query construction
|
20 | query16 = "UPDATE " + table + " SET var = " + var
21 | query17 = "UPDATE {} SET var = {}".format(table, var)
22 | query18 = f"UPDATE {table} SET var = {var}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
23 |
24 | query19 = "select %s from table" % (var,)
|
S608.py:24:11: S608 Possible SQL injection vector through string-based query construction
|
22 | query18 = f"UPDATE {table} SET var = {var}"
23 |
24 | query19 = "select %s from table" % (var,)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
25 | query20 = "select var from " + table
26 | query21 = "select " + val + " from " + table
|
S608.py:25:11: S608 Possible SQL injection vector through string-based query construction
|
24 | query19 = "select %s from table" % (var,)
25 | query20 = "select var from " + table
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
26 | query21 = "select " + val + " from " + table
27 | query22 = "select {} from table;".format(var)
|
S608.py:26:11: S608 Possible SQL injection vector through string-based query construction
|
24 | query19 = "select %s from table" % (var,)
25 | query20 = "select var from " + table
26 | query21 = "select " + val + " from " + table
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
27 | query22 = "select {} from table;".format(var)
28 | query23 = f"select * from table where var = {var}"
|
S608.py:27:11: S608 Possible SQL injection vector through string-based query construction
|
25 | query20 = "select var from " + table
26 | query21 = "select " + val + " from " + table
27 | query22 = "select {} from table;".format(var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
28 | query23 = f"select * from table where var = {var}"
|
S608.py:28:11: S608 Possible SQL injection vector through string-based query construction
|
26 | query21 = "select " + val + " from " + table
27 | query22 = "select {} from table;".format(var)
28 | query23 = f"select * from table where var = {var}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
29 |
30 | query24 = "delete from table where var = %s" % (var,)
|
S608.py:30:11: S608 Possible SQL injection vector through string-based query construction
|
28 | query23 = f"select * from table where var = {var}"
29 |
30 | query24 = "delete from table where var = %s" % (var,)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
31 | query25 = "delete from table where var = " + var
32 | query26 = "delete from " + table + "where var = " + var
|
S608.py:31:11: S608 Possible SQL injection vector through string-based query construction
|
30 | query24 = "delete from table where var = %s" % (var,)
31 | query25 = "delete from table where var = " + var
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
32 | query26 = "delete from " + table + "where var = " + var
33 | query27 = "delete from table where var = {}".format(var)
|
S608.py:32:11: S608 Possible SQL injection vector through string-based query construction
|
30 | query24 = "delete from table where var = %s" % (var,)
31 | query25 = "delete from table where var = " + var
32 | query26 = "delete from " + table + "where var = " + var
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
33 | query27 = "delete from table where var = {}".format(var)
34 | query28 = f"delete from table where var = {var}"
|
S608.py:33:11: S608 Possible SQL injection vector through string-based query construction
|
31 | query25 = "delete from table where var = " + var
32 | query26 = "delete from " + table + "where var = " + var
33 | query27 = "delete from table where var = {}".format(var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
34 | query28 = f"delete from table where var = {var}"
|
S608.py:34:11: S608 Possible SQL injection vector through string-based query construction
|
32 | query26 = "delete from " + table + "where var = " + var
33 | query27 = "delete from table where var = {}".format(var)
34 | query28 = f"delete from table where var = {var}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
35 |
36 | query29 = "insert into table values (%s)" % (var,)
|
S608.py:36:11: S608 Possible SQL injection vector through string-based query construction
|
34 | query28 = f"delete from table where var = {var}"
35 |
36 | query29 = "insert into table values (%s)" % (var,)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
37 | query30 = "insert into table values (" + var + ")"
38 | query31 = "insert into {} values ({})".format(table, var)
|
S608.py:37:11: S608 Possible SQL injection vector through string-based query construction
|
36 | query29 = "insert into table values (%s)" % (var,)
37 | query30 = "insert into table values (" + var + ")"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
38 | query31 = "insert into {} values ({})".format(table, var)
39 | query32 = f"insert into {table} values var = {var}"
|
S608.py:38:11: S608 Possible SQL injection vector through string-based query construction
|
36 | query29 = "insert into table values (%s)" % (var,)
37 | query30 = "insert into table values (" + var + ")"
38 | query31 = "insert into {} values ({})".format(table, var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
39 | query32 = f"insert into {table} values var = {var}"
|
S608.py:39:11: S608 Possible SQL injection vector through string-based query construction
|
37 | query30 = "insert into table values (" + var + ")"
38 | query31 = "insert into {} values ({})".format(table, var)
39 | query32 = f"insert into {table} values var = {var}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
40 |
41 | query33 = "update %s set var = %s" % (table, var)
|
S608.py:41:11: S608 Possible SQL injection vector through string-based query construction
|
39 | query32 = f"insert into {table} values var = {var}"
40 |
41 | query33 = "update %s set var = %s" % (table, var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
42 | query34 = "update " + table + " set var = " + var
43 | query35 = "update {} set var = {}".format(table, var)
|
S608.py:42:11: S608 Possible SQL injection vector through string-based query construction
|
41 | query33 = "update %s set var = %s" % (table, var)
42 | query34 = "update " + table + " set var = " + var
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
43 | query35 = "update {} set var = {}".format(table, var)
44 | query36 = f"update {table} set var = {var}"
|
S608.py:43:11: S608 Possible SQL injection vector through string-based query construction
|
41 | query33 = "update %s set var = %s" % (table, var)
42 | query34 = "update " + table + " set var = " + var
43 | query35 = "update {} set var = {}".format(table, var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
44 | query36 = f"update {table} set var = {var}"
|
S608.py:44:11: S608 Possible SQL injection vector through string-based query construction
|
42 | query34 = "update " + table + " set var = " + var
43 | query35 = "update {} set var = {}".format(table, var)
44 | query36 = f"update {table} set var = {var}"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
45 |
46 | # multi-line failures
|
S608.py:48:12: S608 Possible SQL injection vector through string-based query construction
|
46 | # multi-line failures
47 | def query37():
48 | return """
| ____________^
49 | | SELECT *
50 | | FROM table
51 | | WHERE var = %s
52 | | """ % var
| |_____________^ S608
53 |
54 | def query38():
|
S608.py:55:12: S608 Possible SQL injection vector through string-based query construction
|
54 | def query38():
55 | return """
| ____________^
56 | | SELECT *
57 | | FROM TABLE
58 | | WHERE var =
59 | | """ + var
| |_____________^ S608
60 |
61 | def query39():
|
S608.py:62:12: S608 Possible SQL injection vector through string-based query construction
|
61 | def query39():
62 | return """
| ____________^
63 | | SELECT *
64 | | FROM table
65 | | WHERE var = {}
66 | | """.format(var)
| |___________________^ S608
67 |
68 | def query40():
|
S608.py:69:12: S608 Possible SQL injection vector through string-based query construction
|
68 | def query40():
69 | return f"""
| ____________^
70 | | SELECT *
71 | | FROM table
72 | | WHERE var = {var}
73 | | """
| |_______^ S608
74 |
75 | def query41():
|
S608.py:77:9: S608 Possible SQL injection vector through string-based query construction
|
75 | def query41():
76 | return (
77 | "SELECT * "
| _________^
78 | | "FROM table "
79 | | f"WHERE var = {var}"
| |____________________________^ S608
80 | )
|
S608.py:83:26: S608 Possible SQL injection vector through string-based query construction
|
82 | # # cursor-wrapped failures
83 | query42 = cursor.execute("SELECT * FROM table WHERE var = %s" % var)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
84 | query43 = cursor.execute(f"SELECT * FROM table WHERE var = {var}")
85 | query44 = cursor.execute("SELECT * FROM table WHERE var = {}".format(var))
|
S608.py:84:26: S608 Possible SQL injection vector through string-based query construction
|
82 | # # cursor-wrapped failures
83 | query42 = cursor.execute("SELECT * FROM table WHERE var = %s" % var)
84 | query43 = cursor.execute(f"SELECT * FROM table WHERE var = {var}")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
85 | query44 = cursor.execute("SELECT * FROM table WHERE var = {}".format(var))
86 | query45 = cursor.executemany("SELECT * FROM table WHERE var = %s" % var, [])
|
S608.py:85:26: S608 Possible SQL injection vector through string-based query construction
|
83 | query42 = cursor.execute("SELECT * FROM table WHERE var = %s" % var)
84 | query43 = cursor.execute(f"SELECT * FROM table WHERE var = {var}")
85 | query44 = cursor.execute("SELECT * FROM table WHERE var = {}".format(var))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
86 | query45 = cursor.executemany("SELECT * FROM table WHERE var = %s" % var, [])
|
S608.py:86:30: S608 Possible SQL injection vector through string-based query construction
|
84 | query43 = cursor.execute(f"SELECT * FROM table WHERE var = {var}")
85 | query44 = cursor.execute("SELECT * FROM table WHERE var = {}".format(var))
86 | query45 = cursor.executemany("SELECT * FROM table WHERE var = %s" % var, [])
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
87 |
88 | # # pass
|
S608.py:98:9: S608 Possible SQL injection vector through string-based query construction
|
97 | # # INSERT without INTO (e.g. MySQL and derivatives)
98 | query = "INSERT table VALUES (%s)" % (var,)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
99 |
100 | # # REPLACE (e.g. MySQL and derivatives, SQLite)
|
S608.py:101:9: S608 Possible SQL injection vector through string-based query construction
|
100 | # # REPLACE (e.g. MySQL and derivatives, SQLite)
101 | query = "REPLACE INTO table VALUES (%s)" % (var,)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
102 | query = "REPLACE table VALUES (%s)" % (var,)
|
S608.py:102:9: S608 Possible SQL injection vector through string-based query construction
|
100 | # # REPLACE (e.g. MySQL and derivatives, SQLite)
101 | query = "REPLACE INTO table VALUES (%s)" % (var,)
102 | query = "REPLACE table VALUES (%s)" % (var,)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ S608
103 |
104 | query = "Deselect something that is not SQL even though it has a ' from ' somewhere in %s." % "there"
|

View File

@@ -1,41 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S609.py:4:1: S609 Possible wildcard injection in call due to `*` usage
|
2 | import subprocess
3 |
4 | os.popen("chmod +w foo*")
| ^^^^^^^^ S609
5 | subprocess.Popen("/bin/chown root: *", shell=True)
6 | subprocess.Popen(["/usr/local/bin/rsync", "*", "some_where:"], shell=True)
|
S609.py:5:1: S609 Possible wildcard injection in call due to `*` usage
|
4 | os.popen("chmod +w foo*")
5 | subprocess.Popen("/bin/chown root: *", shell=True)
| ^^^^^^^^^^^^^^^^ S609
6 | subprocess.Popen(["/usr/local/bin/rsync", "*", "some_where:"], shell=True)
7 | subprocess.Popen("/usr/local/bin/rsync * no_injection_here:")
|
S609.py:6:1: S609 Possible wildcard injection in call due to `*` usage
|
4 | os.popen("chmod +w foo*")
5 | subprocess.Popen("/bin/chown root: *", shell=True)
6 | subprocess.Popen(["/usr/local/bin/rsync", "*", "some_where:"], shell=True)
| ^^^^^^^^^^^^^^^^ S609
7 | subprocess.Popen("/usr/local/bin/rsync * no_injection_here:")
8 | os.system("tar cf foo.tar bar/*")
|
S609.py:8:1: S609 Possible wildcard injection in call due to `*` usage
|
6 | subprocess.Popen(["/usr/local/bin/rsync", "*", "some_where:"], shell=True)
7 | subprocess.Popen("/usr/local/bin/rsync * no_injection_here:")
8 | os.system("tar cf foo.tar bar/*")
| ^^^^^^^^^ S609
|

View File

@@ -1,14 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S612.py:3:5: S612 Use of insecure `logging.config.listen` detected
|
1 | import logging.config
2 |
3 | t = logging.config.listen(9999)
| ^^^^^^^^^^^^^^^^^^^^^ S612
4 |
5 | def verify_func():
|

View File

@@ -1,51 +0,0 @@
---
source: crates/ruff/src/rules/flake8_bandit/mod.rs
---
S701.py:9:57: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function.
|
7 | templateEnv = jinja2.Environment(autoescape=True,
8 | loader=templateLoader )
9 | Environment(loader=templateLoader, load=templateLoader, autoescape=something) # S701
| ^^^^^^^^^^^^^^^^^^^^ S701
10 | templateEnv = jinja2.Environment(autoescape=False, loader=templateLoader ) # S701
11 | Environment(loader=templateLoader,
|
S701.py:10:34: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function.
|
8 | loader=templateLoader )
9 | Environment(loader=templateLoader, load=templateLoader, autoescape=something) # S701
10 | templateEnv = jinja2.Environment(autoescape=False, loader=templateLoader ) # S701
| ^^^^^^^^^^^^^^^^ S701
11 | Environment(loader=templateLoader,
12 | load=templateLoader,
|
S701.py:13:13: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function.
|
11 | Environment(loader=templateLoader,
12 | load=templateLoader,
13 | autoescape=False) # S701
| ^^^^^^^^^^^^^^^^ S701
14 |
15 | Environment(loader=templateLoader, # S701
|
S701.py:15:1: S701 By default, jinja2 sets `autoescape` to `False`. Consider using `autoescape=True` or the `select_autoescape` function to mitigate XSS vulnerabilities.
|
13 | autoescape=False) # S701
14 |
15 | Environment(loader=templateLoader, # S701
| ^^^^^^^^^^^ S701
16 | load=templateLoader)
|
S701.py:29:36: S701 Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function.
|
27 | def fake_func():
28 | return 'foobar'
29 | Environment(loader=templateLoader, autoescape=fake_func()) # S701
| ^^^^^^^^^^^^^^^^^^^^^^ S701
|

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