Compare commits

..

125 Commits

Author SHA1 Message Date
Charlie Marsh
add7fefeb5 Bump version to 0.0.237 2023-01-28 10:52:14 -05:00
Charlie Marsh
ec24947865 Fix version shorthand detection to use -V instead of -v (#2301)
Fixes a regression introduced in eda2be6350 (but not yet released to users). (`-v` is a real flag, but it's an alias for `--verbose`, not `--version`.)

Closes #2299.
2023-01-28 10:47:47 -05:00
Charlie Marsh
8038d32649 Deploy under docs subdirectory 2023-01-28 10:28:40 -05:00
Charlie Marsh
0362cc1098 Allow manual trigger for docs 2023-01-28 10:24:52 -05:00
Charlie Marsh
860e3110c0 Serve docs under /docs subdirectory 2023-01-28 10:22:35 -05:00
Jonxslays
0fa8c578cb Fix typo in typing_extensions (#2298) 2023-01-28 10:03:54 -05:00
Charlie Marsh
861df12269 Preserve global binding kind during reassignments (#2297) 2023-01-28 08:40:09 -05:00
Charlie Marsh
071e3fd196 Split MkDocs site into multiple pages (#2296) 2023-01-28 08:31:16 -05:00
Martin Fischer
dd79ec293a Rename new explain subcommand to rule
We probably want to introduce multiple explain subcommands and
overloading `explain` to explain it all seems like a bad idea.
We may want to introduce a subcommand to explain config options and
config options may end up having the same name as their rules, e.g. the
current `banned-api` is both a rule name (although not yet exposed to
the user) and a config option.

The idea is:

* `ruff rule` lists all rules supported by ruff
* `ruff rule <code>` explains a specific rule
* `ruff linter` lists all linters supported by ruff
* `ruff linter <name>` lists all rules/options supported by a specific linter

(After this commit only the 2nd case is implemented.)
2023-01-28 07:26:20 -05:00
Martin Fischer
5d331e43bf fix: help text and env for --format option of explain subcommand
The doc comment and the env attribute were copied by mistake.
2023-01-28 07:26:20 -05:00
Martin Fischer
ff3563b8ce Remove --check alias introduced in eda2be63
We do not want to support the --{subcommand} legacy format for new
subcommands ... only for subcommands that used this format previously.
2023-01-28 07:26:20 -05:00
Matt Morris
caada2f8bb add missing backticks to flake8 plugin urls in README (#2291) 2023-01-28 07:16:23 -05:00
messense
0b4cc5ac12 Add readme field to pyproject.toml (#2293) 2023-01-28 07:14:58 -05:00
Charlie Marsh
8c70247188 Switch to red MkDocs theme 2023-01-27 23:15:49 -05:00
Charlie Marsh
eaac3cae5e Add MkDocs version of README (#2287)
Co-authored-by: Justin Flannery <juftin@juftin.com>
2023-01-27 22:57:42 -05:00
Charlie Marsh
fd56414b2f Re-add ALL disclaimer 2023-01-27 22:18:20 -05:00
Martin Fischer
9731f96fb4 fix: typo in BREAKING_CHANGES.md & improve wrapping 2023-01-27 21:35:41 -05:00
Charlie Marsh
1a0191f1ac Add release to breaking changes 2023-01-27 20:34:24 -05:00
Charlie Marsh
249cf73d4e Tweak some wording in CLI help (#2285) 2023-01-27 20:25:58 -05:00
Martin Fischer
eda2be6350 Use subcommands for CLI instead of incompatible boolean flags
This commit greatly simplifies the implementation of the CLI,
as well as the user expierence (since --help no longer lists all
options even though many of them are in fact incompatible).

To preserve backwards-compatability as much as possible aliases have
been added for the new subcommands, so for example the following two
commands are equivalent:

    ruff explain E402 --format json
    ruff --explain E402 --format json

However for this to work the legacy-format double-dash command has to
come first, i.e. the following no longer works:

    ruff --format json --explain E402

Since ruff previously had an implicitly default subcommand,
this is preserved for backwards compatibility, i.e. the following two
commands are equivalent:

    ruff .
    ruff check .

Previously ruff didn't complain about several argument combinations that
should have never been allowed, e.g:

    ruff --explain RUF001 --line-length 33

previously worked but now rightfully fails since the explain command
doesn't support a `--line-length` option.
2023-01-27 19:38:17 -05:00
Charlie Marsh
57a68f7c7d Document the location of the personal config file (#2283) 2023-01-27 19:25:55 -05:00
Charlie Marsh
a19dd9237b Add comparison to type checkers (#2282) 2023-01-27 19:18:40 -05:00
Simon Brugman
4f067d806e add clippy and rust_dev to pre-commit (#2256)
I presume the reasoning for not including clippy in `pre-commit` was that it passes all files. This can be turned off with `pass_filenames`, in which case it only runs once.

`cargo +nightly dev generate-all` is also added (when excluding `target` is does not give false positives).

(The overhead of these commands is not much when the build is there. People can always choose to run only certain hooks with `pre-commit run [hook] --all-files`)
2023-01-27 18:53:44 -05:00
Samuel Cormier-Iijima
dd15c69181 [flake8-bandit] Add Rule S110 (try/except/pass) (#2197) 2023-01-27 18:52:55 -05:00
Charlie Marsh
b692921160 Use rustup show in lieu of actions-rs/toolchain (#2280) 2023-01-27 18:51:41 -05:00
Charlie Marsh
b3e8b1b787 Expand heuristic for detecting logging calls (#2279) 2023-01-27 18:41:16 -05:00
Charlie Marsh
0b34ca7107 Move off nightly Rust for dev workflows (#2278) 2023-01-27 18:35:19 -05:00
Charlie Marsh
df44c5124e Add missing autofix levels to sometimes-fixable rules 2023-01-27 18:25:23 -05:00
Simon Brugman
0e27f78b3f feat: include os.getcwdb (bytes) into flake8-use-pathlib (#2276) 2023-01-27 18:25:02 -05:00
Florian Best
cd8ad1df08 mark some fixers as sometimes-fixable (#2271) 2023-01-27 18:23:32 -05:00
Charlie Marsh
d1aaf16e40 Omit typing module from flake8-type-checking by default (#2277) 2023-01-27 18:19:45 -05:00
Ville Skyttä
7320058ce2 Incompatiblity warning updates (#2272) 2023-01-27 18:17:23 -05:00
Aarni Koskela
3a8b367b1c flake8-annotations: Move has_any_typed_arg into correct nested if (#2269) 2023-01-27 18:15:46 -05:00
Ville Skyttä
221b87332c feat: add more DTZ fix suggestions in messages (#2274) 2023-01-27 18:14:17 -05:00
Franck Nijhof
8149c8cbc4 Treat attribute constants as constant for yoda-conditions (#2266)
Accessed attributes that are Python constants should be considered for yoda-conditions


```py
## Error
JediOrder.YODA == age  # SIM300

## OK
age == JediOrder.YODA
```

~~PS: This PR will fail CI, as the `main` branch currently failing.~~
2023-01-27 12:55:12 -05:00
Charlie Marsh
2c415016a6 Update F401 snapshots 2023-01-27 12:43:42 -05:00
Sladyn
bb85119ba8 Convert UnusedImport violation to struct fields (#2141) 2023-01-27 11:31:39 -05:00
Simon Brugman
94551a203e feat: pylint PLE0604 and PLE0605 (#2241) 2023-01-27 11:26:33 -05:00
Charlie Marsh
64c4e4c6c7 Treat constant tuples as constants for yoda-conditions (#2265) 2023-01-27 11:25:57 -05:00
Charlie Marsh
84e4b7c96f Treat builtins as synthetically used (#2251) 2023-01-27 11:25:45 -05:00
Franck Nijhof
ca26f664ec Fix SIM300 to take Python constants into account (#2255)
SIM300 currently doesn't take Python constants into account when looking for Yoda conditions, this PR fixes that behavior.

```python
# Errors
YODA == age  # SIM300
YODA > age  # SIM300
YODA >= age  # SIM300

# OK
age == YODA
age < YODA
age <= YODA
```

Ref: <https://github.com/home-assistant/core/pull/86793>
2023-01-27 11:20:21 -05:00
Aarni Koskela
779b232db9 Fix typo: RelatveImportsOrder (#2264) 2023-01-27 11:15:43 -05:00
Charlie Marsh
a316b26b49 Rewrite some string-format violation messages (#2242) 2023-01-26 19:42:16 -05:00
Charlie Marsh
685d9ab848 Bump version to 0.0.236 2023-01-26 18:47:00 -05:00
Charlie Marsh
093f9156e1 Wrap return-bool-condition-directly fixes in bool() (#2240) 2023-01-26 18:22:34 -05:00
Charlie Marsh
615e62ae24 Clarify E-category rule support (#2239) 2023-01-26 18:12:28 -05:00
Charlie Marsh
76a0c45773 Track type-checking blocks during tree traversal (#2238) 2023-01-26 18:09:28 -05:00
Charlie Marsh
3ec46f0936 Allow pytest in shebang (#2237) 2023-01-26 17:32:23 -05:00
Charlie Marsh
a6ec2eb044 Avoid removing trailing comments on pass statements (#2235)
This isn't super consistent with some other rules, but... if you have a lone body, with a `pass`, followed by a comment, it's probably surprising if it gets removed. Let's retain the comment.

Closes #2231.
2023-01-26 17:29:13 -05:00
Simon Brugman
9d3a5530af refactor: move violations to linters (#2234) 2023-01-26 17:28:14 -05:00
Simon Brugman
8766e6a666 docs(readme): add featuretools (#2236) 2023-01-26 17:24:45 -05:00
Charlie Marsh
b08367b5a8 Avoid flagging blind exceptions with valid logging (#2232) 2023-01-26 17:05:01 -05:00
Charlie Marsh
98a8330124 Add stylist settings to all LibCST invocations (#2225) 2023-01-26 16:59:33 -05:00
Charlie Marsh
4d52ea87ef Implement exempt-modules setting from flake8-type-checking (#2230) 2023-01-26 16:55:32 -05:00
Charlie Marsh
291239b9f1 Fix range for try-consider-else (#2228) 2023-01-26 16:36:18 -05:00
Charlie Marsh
224334b6d1 Avoid erroneous class autofixes in indented blocks (#2226) 2023-01-26 16:24:21 -05:00
Charlie Marsh
0cab3f8437 Preserve indentation when fixing via LibCST (#2223) 2023-01-26 16:09:35 -05:00
Charlie Marsh
5f8810e987 Add strictness setting for flake8-typing-imports (#2221) 2023-01-26 16:04:21 -05:00
Charlie Marsh
f15c562a1c Remove unused overridden property (#2217) 2023-01-26 14:46:46 -05:00
Martin Fischer
4f3b63edd4 fix: --explain reporting the wrong linter
Fixes a regression introduced in 4e4643aa5d.

We want the longest prefixes to be checked first so we of course
have to reverse the sorting when sorting by prefix length.

Fixes #2210.
2023-01-26 13:53:35 -05:00
Simon Brugman
bab8691132 chore: fix script indent (#2213) 2023-01-26 13:53:22 -05:00
Charlie Marsh
50c85fd192 Add a fixable and unfixable example to the docs (#2211) 2023-01-26 13:23:21 -05:00
Martin Fischer
23819ae338 Group options in --help output and sort them by importance
`ruff --help` previously listed 37 options in no particular order
(with niche options like --isolated being listed before before essential
options such as --select).  This commit remedies that and additionally
groups the options by making use of the Clap help_heading feature.

Note that while the source code has previously also referred to
--add-noqa, --show-settings, and --show-files as "subcommands"
this commit intentionally does not list them under the new
Subcommands section since contrary to --explain and --clean
combining them with most of the other options makes sense.
2023-01-26 13:06:29 -05:00
Martin Fischer
4bf2879067 refactor: Move add_noqa if branch up 2023-01-26 13:06:29 -05:00
Martin Fischer
b359f3a9ff refactor: Get rid of ruff::resolver::FileDiscovery 2023-01-26 13:06:29 -05:00
Martin Fischer
73d0461d55 refactor: Check required_version in Settings::from_configuration
The idiomatic way in Rust is to make invalid types unrepresentable
instead of paranoidly calling a validate method everywhere.
2023-01-26 13:06:29 -05:00
Martin Fischer
55bb36fb8b refactor: Introduce LogLevelArgs 2023-01-26 13:06:29 -05:00
Martin Fischer
cebea16fe4 refactor: Move Args::partition call after panic::set_hook 2023-01-26 13:06:29 -05:00
Charlie Marsh
f7be192f8b Alphabetize Flake8 plugins in the README (#2209) 2023-01-26 13:05:30 -05:00
Edgar R. M
e88275280b Implement some rules from flake8-logging-format (#2150) 2023-01-26 12:58:10 -05:00
Samuel Cormier-Iijima
7370a27c09 Don't flag B009/B010 if identifiers would be mangled (#2204) 2023-01-26 12:56:18 -05:00
jvstme
0ad6b8224d Fix typo in src option docs (#2201) 2023-01-26 12:23:09 -05:00
Henry Schreiner
f3aa409d9a docs(readme): add pypa's build (#2200) 2023-01-26 12:18:04 -05:00
Charlie Marsh
adb5c5b150 Fix respect_gitignore reference (#2196) 2023-01-26 09:53:17 -05:00
Martin Fischer
b69b6a7ec8 refactor: Move comments before if conditions 2023-01-25 22:08:35 -05:00
Martin Fischer
a7d2def9cd refactor: Move ruff_cli::resolve to own module 2023-01-25 22:08:35 -05:00
Martin Fischer
d9ead4e6df refactor: Rename CLI arg structs from Cli to Args
Technically the command-line interface (CLI) encompasses both input and
output, so naming the input structs 'Args' is more accurate than 'Cli'.
2023-01-25 22:08:35 -05:00
Charlie Marsh
b346f74915 Run cargo update (#2185) 2023-01-25 21:32:44 -05:00
Eric Roberts
708295f4c9 Move violations for pycodestyle rules to rules files (#2138) 2023-01-25 20:11:36 -05:00
Charlie Marsh
4190f1045e Remove manual newline from autofix helpers (#2184) 2023-01-25 19:53:26 -05:00
Florian Stasse
353857e2a5 Implement TRY400 (#2115) 2023-01-25 19:42:19 -05:00
Denis Gavrilyuk
55b43c8ea7 feat: implement TRY002 and TRY003 (#2135) 2023-01-25 19:22:43 -05:00
Anders Kaseorg
6036d1bbe2 flake8_executable: Only match shebang at beginning of line (#2183)
The Python implementation uses `re.match` for this, which only matches
at the beginning of a line.

https://github.com/xuhdev/flake8-executable/blob/v2.1.3/flake8_executable/__init__.py#L124

We could use `Regex::captures_read_at`, but that’s a more complicated
API; it’s easier to anchor the regex with `^`.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2023-01-25 18:57:09 -05:00
Charlie Marsh
edd0e16a02 Bump version to 0.0.235 2023-01-25 18:28:27 -05:00
Charlie Marsh
fdccb6ec1c Fix conflicting error message warning (#2182) 2023-01-25 18:26:43 -05:00
Anders Kaseorg
c00b8b6d2d Remove stray parenthesis from fixed errors message (#2181)
Signed-off-by: Anders Kaseorg <andersk@mit.edu>

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2023-01-25 18:15:12 -05:00
Simon Brugman
52201422ae fix: platform-independent newlines 2023-01-25 18:00:39 -05:00
Simon Brugman
d7fe1eeba0 fix: platform-independent paths 2023-01-25 18:00:39 -05:00
Simon Brugman
5835d719c4 ci: enable windows testing in Github Actions 2023-01-25 18:00:39 -05:00
Simon Brugman
c859ac4933 refactor: test ground truth update for new macro 2023-01-25 18:00:39 -05:00
Simon Brugman
e9c1089ddc refactor: tests use new marco 2023-01-25 18:00:39 -05:00
Simon Brugman
413acdf83c feat: introduce macro for testing snap files across platforms 2023-01-25 18:00:39 -05:00
Charlie Marsh
16d2ece87d Restore single-file license (#2180)
These were split into per-project licenses in #1648, but I don't like that they're no longer included in the distribution (due to current limitations in the `pyproject.toml` spec).
2023-01-25 17:59:12 -05:00
Anders Kaseorg
823f1c5b6a Avoid duplicate CI runs triggered by pushes to pull requests (#2178)
https://github.com/charliermarsh/ruff/pull/2157#discussion_r1087179996

Signed-off-by: Anders Kaseorg <andersk@mit.edu>

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2023-01-25 17:45:07 -05:00
Charlie Marsh
9b07d0bd92 Bump version to 0.0.234 2023-01-25 16:55:57 -05:00
Charlie Marsh
23525a8ea0 Actually, rename TYP rules to TCH (#2176) 2023-01-25 16:52:49 -05:00
Charlie Marsh
6ede030700 Allow manual releases for pre-release testing 2023-01-25 16:37:04 -05:00
Charlie Marsh
44f3e5013d Add flake8-type-checking license 2023-01-25 16:27:18 -05:00
Charlie Marsh
35cf9e242e Rename TYP rules to TYC (#2175) 2023-01-25 16:26:22 -05:00
Charlie Marsh
d5dff11d4b Avoid reraise-no-cause for explicit reraises (#2174) 2023-01-25 15:51:24 -05:00
Charlie Marsh
8e1fac620e Add flake8-builtins options to README (#2173) 2023-01-25 15:43:26 -05:00
Aarni Koskela
0da691c0d5 Add Babel to readme (#2170) 2023-01-25 15:21:26 -05:00
Hugo van Kemenade
233415921b Add colour to CI for readability 2023-01-25 15:21:10 -05:00
Hugo van Kemenade
81141e2a73 Bump GitHub Actions 2023-01-25 15:21:10 -05:00
Hugo van Kemenade
6e255ad53c Allow testing feature branches 2023-01-25 15:21:10 -05:00
Hugo van Kemenade
6d87adbcc0 Fix singular and plural for error(s) 2023-01-25 15:21:10 -05:00
Florian Best
43a8ce6c89 fix: avoid flagging unused loop variable (B007) with globals(), vars() or eval() (#2166) 2023-01-25 15:18:58 -05:00
Charlie Marsh
a978706dce Re-add error wrapper in main.rs (#2168) 2023-01-25 15:11:24 -05:00
Florian Best
dc1aa8dd1d Suggest input format in error case (#2167) 2023-01-25 14:55:04 -05:00
Charlie Marsh
662e29b1ce Avoid re-resolving settings for repeated paths (#2165)
After this change:

```shell
> time cargo run -- -n $(find ../django -type f -name '*.py')`
8.85s user 0.20s system 498% cpu 1.814 total
> time cargo run -- -n ../django
8.95s user 0.23s system 507% cpu 1.811 total
```

I also verified that we only hit the creation path once via some manual logging.

Closes #2154.
2023-01-25 13:38:33 -05:00
Charlie Marsh
6978dcf035 Add an FAQ on autofix (#2163) 2023-01-25 13:09:16 -05:00
Charlie Marsh
0e6f513607 Avoid prefer-type-error (TRY004) with intermediary control flow (#2162) 2023-01-25 13:00:59 -05:00
Charlie Marsh
02421d02f5 Avoid flagging unused loop variable (B007) with locals() (#2161) 2023-01-25 12:53:35 -05:00
Charlie Marsh
38de46ae3c Treat Python 3.7 as minimum supported version (#2159) 2023-01-25 12:36:50 -05:00
Martin Fischer
f6fd702d41 Add #![warn(clippy::pedantic)] to lib.rs and main.rs files
We already enforced pedantic clippy lints via the
following command in .github/workflows/ci.yaml:

    cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic

Additionally adding #![warn(clippy::pedantic)] to all main.rs and lib.rs
has the benefit that violations of pedantic clippy lints are also
reported when just running `cargo clippy` without any arguments and
are thereby also picked up by LSP[1] servers such as rust-analyzer[2].
However for rust-analyzer to run clippy you'll have to configure:

    "rust-analyzer.check.command": "clippy",

in your editor.[3]

[1]: https://microsoft.github.io/language-server-protocol/
[2]: https://rust-analyzer.github.io/
[3]: https://rust-analyzer.github.io/manual.html#configuration
2023-01-25 00:40:29 -05:00
Martin Fischer
2125d0bb54 refactor: Move #![forbid(unsafe_code)] attributes up
What's forbidden is more important than which clippy lints are
ignored and more important directives should come first.
2023-01-25 00:40:29 -05:00
Charlie Marsh
63b4f60ba4 Implement typing-only import detection (TYP001, TYP002, TYP003) (#2147) 2023-01-24 23:48:11 -05:00
Charlie Marsh
9eb13bc9da Downgrade recommended pre-commit version to v0.0.231 2023-01-24 23:47:13 -05:00
Charlie Marsh
0758049e49 Implement runtime-import-in-type-checking-block (TYP004) (#2146) 2023-01-24 23:33:26 -05:00
Charlie Marsh
deff503932 Avoid generating dirty call paths (#2144) 2023-01-24 20:40:38 -05:00
Jonathan Plasse
82d7814101 Update .pre-commit-config.yml (#2139) 2023-01-24 19:45:34 -05:00
Eric Roberts
0cac1a0d21 Move is_overlong to helpers (#2137) 2023-01-24 12:45:35 -05:00
Charlie Marsh
605416922d Bump version to 0.0.233 2023-01-24 10:46:49 -05:00
Charlie Marsh
7b81f36e54 Enable executable checks on Windows (#2133) 2023-01-24 10:46:27 -05:00
Eric Roberts
ff63da9f52 Move compare to helpers file (#2131)
From discussion on https://github.com/charliermarsh/ruff/pull/2123

I didn't originally have a helpers file so I put the function in both
places but now that a helpers file exists it seems logical for it to be
there.
2023-01-24 10:30:56 -05:00
571 changed files with 11081 additions and 4459 deletions

View File

@@ -4,7 +4,7 @@ on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
@@ -13,6 +13,7 @@ concurrency:
env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
jobs:
@@ -21,16 +22,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-11-01
override: true
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- run: cargo build --all
- run: ./target/debug/ruff_dev generate-all
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. Run 'cargo dev generate-all'."
- run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. Run 'cargo dev generate-all'."
- run: git diff --exit-code -- README.md ruff.schema.json
cargo-fmt:
@@ -38,12 +36,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-11-01
override: true
components: rustfmt
- name: "Install Rust toolchain"
run: rustup component add rustfmt
- run: cargo fmt --all --check
cargo_clippy:
@@ -51,48 +45,52 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-11-01
override: true
components: clippy
target: wasm32-unknown-unknown
- name: "Install Rust toolchain"
run: |
rustup component add clippy
rustup target add wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v1
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic
- run: cargo clippy -p ruff --target wasm32-unknown-unknown --all-features -- -D warnings -W clippy::pedantic
cargo-test:
name: "cargo test"
runs-on: ubuntu-latest
strategy:
matrix:
os: [ ubuntu-latest, windows-latest ]
runs-on: ${{ matrix.os }}
name: "cargo test | ${{ matrix.os }}"
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: 1.65.0
override: true
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- run: cargo install cargo-insta
- run: pip install black[d]==22.12.0
- name: Run tests
- name: "Run tests (Ubuntu)"
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
cargo insta test --all --delete-unreferenced-snapshots
git diff --exit-code
- name: "Run tests (Windows)"
if: ${{ matrix.os == 'windows-latest' }}
shell: bash
run: |
cargo insta test --all
git diff --exit-code
- run: cargo test --package ruff_cli --test black_compatibility_test -- --ignored
# Check for broken links in the documentation.
# Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025).
- run: RUSTDOCFLAGS="-D warnings" cargo doc --all --no-deps
- run: cargo doc --all --no-deps
env:
# Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025).
RUSTDOCFLAGS: "-D warnings"
scripts:
name: "test scripts"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
override: true
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- run: ./scripts/add_rule.py --name DoTheThing --code PLC999 --linter pylint
- run: cargo check
@@ -101,61 +99,26 @@ jobs:
./scripts/add_rule.py --name FirstRule --code TST001 --linter test
- run: cargo check
# TODO(charlie): Re-enable the `wasm-pack` tests.
# See: https://github.com/charliermarsh/ruff/issues/1425
# wasm-pack-test:
# name: "wasm-pack test"
# runs-on: ubuntu-latest
# env:
# WASM_BINDGEN_TEST_TIMEOUT: 60
# steps:
# - uses: actions/checkout@v3
# - uses: actions-rs/toolchain@v1
# with:
# profile: minimal
# toolchain: nightly-2022-11-01
# override: true
# - uses: actions/cache@v3
# env:
# cache-name: cache-cargo
# with:
# path: |
# ~/.cargo/registry
# ~/.cargo/git
# key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
# restore-keys: |
# ${{ runner.os }}-build-${{ env.cache-name }}-
# ${{ runner.os }}-build-
# ${{ runner.os }}-
# - uses: jetli/wasm-pack-action@v0.4.0
# - uses: jetli/wasm-bindgen-action@v0.2.0
# - run: wasm-pack test --node
maturin-build:
name: "maturin build"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: 1.65.0
override: true
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- uses: actions/setup-python@v4
with:
python-version: "3.11"
- run: pip install maturin
- run: maturin build -b bin
- run: python scripts/transform_readme.py --target pypi
typos:
name: Spell Check with Typos
name: "spell check"
runs-on: ubuntu-latest
steps:
- name: Checkout Actions Repository
uses: actions/checkout@v2
- name: Check spelling of file.txt
uses: crate-ci/typos@master
- uses: actions/checkout@v3
- uses: crate-ci/typos@master
with:
files: .

35
.github/workflows/docs.yaml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: mkdocs
on:
push:
paths:
- README.md
- mkdocs.template.yml
- .github/workflows/docs.yaml
branches: [ main ]
workflow_dispatch:
jobs:
mkdocs:
runs-on: ubuntu-latest
env:
CF_API_TOKEN_EXISTS: ${{ secrets.CF_API_TOKEN != '' }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- name: "Install dependencies"
run: |
pip install "mkdocs~=1.4.2" "mkdocs-material~=9.0.6"
- name: "Copy README File"
run: |
python scripts/transform_readme.py --target mkdocs
python scripts/generate_mkdocs.py
mkdocs build --strict
- name: "Deploy to Cloudflare Pages"
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
uses: cloudflare/wrangler-action@2.0.0
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CF_ACCOUNT_ID }}
command: pages publish site --project-name=ruff-docs --branch ${GITHUB_HEAD_REF} --commit-hash ${GITHUB_SHA}

View File

@@ -12,6 +12,7 @@ env:
PYTHON_VERSION: "3.7" # to build abi3 wheels
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
jobs:
@@ -23,22 +24,18 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
default: true
- name: Build wheels - x86_64
- name: "Install Rust toolchain"
run: rustup show
- name: "Build wheels - x86_64"
uses: messense/maturin-action@v1
with:
target: x86_64
args: --release --out dist --sdist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- name: Install built wheel - x86_64
- name: "Install built wheel - x86_64"
run: |
pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -50,21 +47,17 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
default: true
- name: Build wheels - universal2
- name: "Install Rust toolchain"
run: rustup show
- name: "Build wheels - universal2"
uses: messense/maturin-action@v1
with:
args: --release --universal2 --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- name: Install built wheel - universal2
- name: "Install built wheel - universal2"
run: |
pip install dist/${{ env.CRATE_NAME }}-*universal2.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -80,23 +73,19 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: ${{ matrix.target }}
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
default: true
- name: Build wheels
- name: "Install Rust toolchain"
run: rustup show
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- name: Install built wheel
- name: "Install built wheel"
shell: bash
run: |
python -m pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -112,18 +101,18 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Build wheels
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: auto
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- name: Install built wheel
- name: "Install built wheel"
if: matrix.target == 'x86_64'
run: |
pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -138,13 +127,13 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Build wheels
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: auto
args: --no-default-features --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- uses: uraimo/run-on-arch-action@v2.0.5
- uses: uraimo/run-on-arch-action@v2.5.0
if: matrix.target != 'ppc64'
name: Install built wheel
with:
@@ -157,8 +146,8 @@ jobs:
pip3 install -U pip
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -176,13 +165,13 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Build wheels
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: musllinux_1_2
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
- name: Install built wheel
- name: "Install built wheel"
if: matrix.target == 'x86_64-unknown-linux-musl'
uses: addnab/docker-run-action@v3
with:
@@ -191,8 +180,8 @@ jobs:
run: |
apk add py3-pip
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links /io/dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -211,7 +200,7 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Build wheels
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
@@ -227,8 +216,8 @@ jobs:
apk add py3-pip
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -251,18 +240,18 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: pypy${{ matrix.python-version }}
- name: Build wheels
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: auto
args: --release --out dist -i pypy${{ matrix.python-version }} -m ./${{ env.CRATE_NAME }}/Cargo.toml
- name: Install built wheel
- name: "Install built wheel"
if: matrix.target == 'x86_64'
run: |
pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -280,11 +269,11 @@ jobs:
- musllinux-cross
- pypy
steps:
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
name: wheels
- uses: actions/setup-python@v4
- name: Publish to PyPi
- name: "Publish to PyPi"
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.FLAKE8_TO_RUFF_TOKEN }}

View File

@@ -8,6 +8,7 @@ on:
env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
jobs:
@@ -17,12 +18,8 @@ jobs:
CF_API_TOKEN_EXISTS: ${{ secrets.CF_API_TOKEN != '' }}
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly-2022-11-01
override: true
target: wasm32-unknown-unknown
- name: "Install Rust toolchain"
run: rustup target add wasm32-unknown-unknown
- uses: actions/setup-node@v3
with:
node-version: 18

View File

@@ -1,6 +1,7 @@
name: "[ruff] Release"
on:
workflow_dispatch:
release:
types: [published]
@@ -13,6 +14,7 @@ env:
PYTHON_VERSION: "3.7" # to build abi3 wheels
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
CARGO_TERM_COLOR: always
RUSTUP_MAX_RETRIES: 10
jobs:
@@ -24,22 +26,18 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
default: true
- name: Build wheels - x86_64
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels - x86_64"
uses: messense/maturin-action@v1
with:
target: x86_64
args: --release --out dist --sdist
- name: Install built wheel - x86_64
- name: "Install built wheel - x86_64"
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -51,21 +49,17 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
default: true
- name: Build wheels - universal2
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels - universal2"
uses: messense/maturin-action@v1
with:
args: --release --universal2 --out dist
- name: Install built wheel - universal2
- name: "Install built wheel - universal2"
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*universal2.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -81,23 +75,19 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: ${{ matrix.target }}
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
default: true
- name: Build wheels
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist
- name: Install built wheel
- name: "Install built wheel"
shell: bash
run: |
python -m pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -113,18 +103,20 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Build wheels
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: auto
args: --release --out dist
- name: Install built wheel
- name: "Install built wheel"
if: matrix.target == 'x86_64'
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -139,13 +131,15 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Build wheels
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: auto
args: --no-default-features --release --out dist
- uses: uraimo/run-on-arch-action@v2.0.5
- uses: uraimo/run-on-arch-action@v2.5.0
if: matrix.target != 'ppc64'
name: Install built wheel
with:
@@ -158,8 +152,8 @@ jobs:
pip3 install -U pip
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -177,13 +171,15 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
architecture: x64
- name: Build wheels
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: musllinux_1_2
args: --release --out dist
- name: Install built wheel
- name: "Install built wheel"
if: matrix.target == 'x86_64-unknown-linux-musl'
uses: addnab/docker-run-action@v3
with:
@@ -192,8 +188,8 @@ jobs:
run: |
apk add py3-pip
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links /io/dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -212,7 +208,9 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Build wheels
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
@@ -228,8 +226,8 @@ jobs:
apk add py3-pip
run: |
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -252,18 +250,20 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: pypy${{ matrix.python-version }}
- name: Build wheels
- name: "Prep README.md"
run: python scripts/transform_readme.py --target pypi
- name: "Build wheels"
uses: messense/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: auto
args: --release --out dist -i pypy${{ matrix.python-version }}
- name: Install built wheel
- name: "Install built wheel"
if: matrix.target == 'x86_64'
run: |
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
- name: Upload wheels
uses: actions/upload-artifact@v2
- name: "Upload wheels"
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
@@ -282,17 +282,17 @@ jobs:
- pypy
if: "startsWith(github.ref, 'refs/tags/')"
steps:
- uses: actions/download-artifact@v2
- uses: actions/download-artifact@v3
with:
name: wheels
- uses: actions/setup-python@v4
- name: Publish to PyPi
- name: "Publish to PyPi"
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.RUFF_TOKEN }}
run: |
pip install --upgrade twine
twine upload --skip-existing *
- name: Update pre-commit mirror
- name: "Update pre-commit mirror"
run: |
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.RUFF_PRE_COMMIT_PAT }}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/charliermarsh/ruff-pre-commit/dispatches --data '{"event_type": "pypi_release"}'

2
.gitignore vendored
View File

@@ -1,6 +1,8 @@
# Local cache
.ruff_cache
resources/test/cpython
docs/
mkdocs.yml
###
# Rust.gitignore

View File

@@ -1,8 +1,10 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.232
rev: v0.0.237
hooks:
- id: ruff
args: [--fix]
exclude: ^resources
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.10.1
@@ -16,3 +18,14 @@ repos:
entry: cargo fmt --
language: rust
types: [rust]
- id: clippy
name: clippy
entry: cargo clippy --workspace --all-targets --all-features
language: rust
pass_filenames: false
- id: dev-generate-all
name: dev-generate-all
entry: cargo dev generate-all
language: rust
pass_filenames: false
exclude: target

View File

@@ -1,5 +1,44 @@
# Breaking Changes
## 0.0.237
### `--explain`, `--clean`, and `--generate-shell-completion` are now subcommands ([#2190](https://github.com/charliermarsh/ruff/pull/2190))
`--explain`, `--clean`, and `--generate-shell-completion` are now implemented as subcommands:
ruff . # Still works! And will always work.
ruff check . # New! Also works.
ruff --explain E402 # Still works.
ruff rule E402 # New! Also works. (And preferred.)
# Oops! The command has to come first.
ruff --format json --explain E402 # No longer works.
ruff --explain E402 --format json # Still works!
ruff rule E402 --format json # Works! (And preferred.)
This change is largely backwards compatible -- most users should experience
no change in behavior. However, please note the following exceptions:
* Subcommands will now fail when invoked with unsupported arguments, instead
of silently ignoring them. For example, the following will now fail:
ruff --clean --respect-gitignore
(the `clean` command doesn't support `--respect-gitignore`.)
* The semantics of `ruff <arg>` have changed slightly when `<arg>` is a valid subcommand.
For example, prior to this release, running `ruff rule` would run `ruff` over a file or
directory called `rule`. Now, `ruff rule` would invoke the `rule` subcommand. This should
only impact projects with files or directories named `rule`, `check`, `explain`, `clean`,
or `generate-shell-completion`.
* Scripts that invoke ruff should supply `--` before any positional arguments.
(The semantics of `ruff -- <arg>` have not changed.)
* `--explain` previously treated `--format grouped` as a synonym for `--format text`.
This is no longer supported; instead, use `--format text`.
## 0.0.226
### `misplaced-comparison-constant` (`PLC2201`) was deprecated in favor of `SIM300` ([#1980](https://github.com/charliermarsh/ruff/pull/1980))

View File

@@ -39,20 +39,24 @@ cargo run resources/test/fixtures --no-cache
```
Prior to opening a pull request, ensure that your code has been auto-formatted,
and that it passes both the lint and test validation checks.
For rustfmt and Clippy, we use [nightly Rust][nightly], as it is stricter than stable Rust.
(However, tests and builds use stable Rust.)
and that it passes both the lint and test validation checks:
```shell
cargo +nightly fmt --all # Auto-formatting...
cargo +nightly clippy --fix --workspace --all-targets --all-features -- -W clippy::pedantic # Linting...
cargo fmt --all # Auto-formatting...
cargo clippy --fix --workspace --all-targets --all-features # Linting...
cargo test --all # Testing...
```
These checks will run on GitHub Actions when you open your Pull Request, but running them locally
will save you time and expedite the merge process.
If you have `pre-commit` [installed](https://pre-commit.com/#installation) then you can use it to
assist with formatting and linting. The following command will run the `pre-commit` hooks:
```shell
pre-commit run --all-files
```
Your Pull Request will be reviewed by a maintainer, which may involve a few rounds of iteration
prior to merging.
@@ -79,7 +83,7 @@ To trigger the violation, you'll likely want to augment the logic in `src/checke
defines the Python AST visitor, responsible for iterating over the abstract syntax tree and
collecting diagnostics as it goes.
If you need to inspect the AST, you can run `cargo +nightly dev print-ast` with a Python file. Grep
If you need to inspect the AST, you can run `cargo dev print-ast` with a Python file. Grep
for the `Check::new` invocations to understand how other, similar rules are implemented.
To add a test fixture, create a file under `resources/test/fixtures/[linter]`, named to match
@@ -87,7 +91,7 @@ the code you defined earlier (e.g., `resources/test/fixtures/pycodestyle/E402.py
contain a variety of violations and non-violations designed to evaluate and demonstrate the behavior
of your lint rule.
Run `cargo +nightly dev generate-all` to generate the code for your new fixture. Then run Ruff
Run `cargo dev generate-all` to generate the code for your new fixture. Then run Ruff
locally with (e.g.) `cargo run resources/test/fixtures/pycodestyle/E402.py --no-cache --select E402`.
Once you're satisfied with the output, codify the behavior as a snapshot test by adding a new
@@ -95,7 +99,7 @@ Once you're satisfied with the output, codify the behavior as a snapshot test by
Your test will fail, but you'll be prompted to follow-up with `cargo insta review`. Accept the
generated snapshot, then commit the snapshot file alongside the rest of your changes.
Finally, regenerate the documentation and generated code with `cargo +nightly dev generate-all`.
Finally, regenerate the documentation and generated code with `cargo dev generate-all`.
### Example: Adding a new configuration option
@@ -121,7 +125,7 @@ You may also want to add the new configuration option to the `flake8-to-ruff` to
responsible for converting `flake8` configuration files to Ruff's TOML format. This logic
lives in `flake8_to_ruff/src/converter.rs`.
Finally, regenerate the documentation and generated code with `cargo +nightly dev generate-all`.
Finally, regenerate the documentation and generated code with `cargo dev generate-all`.
## Release process
@@ -131,5 +135,3 @@ them to [PyPI](https://pypi.org/project/ruff/).
Ruff follows the [semver](https://semver.org/) versioning standard. However, as pre-1.0 software,
even patch releases may contain [non-backwards-compatible changes](https://semver.org/#spec-item-4).
[nightly]: https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust

366
Cargo.lock generated
View File

@@ -82,9 +82,9 @@ dependencies = [
[[package]]
name = "assert_cmd"
version = "2.0.7"
version = "2.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3"
checksum = "9834fcc22e0874394a010230586367d4a3e9f11b560f469262678547e1d2575e"
dependencies = [
"bstr 1.1.0",
"doc-comment",
@@ -147,6 +147,15 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-buffer"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [
"generic-array",
]
[[package]]
name = "bstr"
version = "0.2.17"
@@ -172,9 +181,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.11.1"
version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
[[package]]
name = "cachedir"
@@ -227,12 +236,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "chunked_transfer"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
[[package]]
name = "ciborium"
version = "0.2.0"
@@ -274,13 +277,13 @@ dependencies = [
[[package]]
name = "clap"
version = "4.0.32"
version = "4.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
dependencies = [
"bitflags",
"clap_derive",
"clap_lex 0.3.0",
"clap_lex 0.3.1",
"is-terminal",
"once_cell",
"strsim",
@@ -289,11 +292,11 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.0.7"
version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75"
dependencies = [
"clap 4.0.32",
"clap 4.1.4",
]
[[package]]
@@ -302,26 +305,26 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4160b4a4f72ef58bd766bad27c09e6ef1cc9d82a22f6a0f55d152985a4a48e31"
dependencies = [
"clap 4.0.32",
"clap 4.1.4",
"clap_complete",
"clap_complete_fig",
]
[[package]]
name = "clap_complete_fig"
version = "4.0.2"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46b30e010e669cd021e5004f3be26cff6b7c08d2a8a0d65b48d43a8cc0efd6c3"
checksum = "cf0c76d8fcf782a1102ccfcd10ca8246e7fdd609c1cd6deddbb96cb638e9bb5c"
dependencies = [
"clap 4.0.32",
"clap 4.1.4",
"clap_complete",
]
[[package]]
name = "clap_derive"
version = "4.0.21"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
dependencies = [
"heck",
"proc-macro-error",
@@ -341,9 +344,9 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
dependencies = [
"os_str_bytes",
]
@@ -390,15 +393,14 @@ checksum = "5458d9d1a587efaf5091602c59d299696a3877a439c8f6d461a2d3cce11df87a"
[[package]]
name = "console"
version = "0.15.2"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"terminal_size",
"winapi",
"windows-sys",
]
[[package]]
@@ -427,6 +429,15 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "cpufeatures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
@@ -522,10 +533,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "cxx"
version = "1.0.85"
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "cxx"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b61a7545f753a88bcbe0a70de1fcc0221e10bfc752f576754fa91e663db1622e"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -535,9 +556,9 @@ dependencies = [
[[package]]
name = "cxx-build"
version = "1.0.85"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0"
checksum = "f464457d494b5ed6905c63b0c4704842aba319084a0a3561cdc1359536b53200"
dependencies = [
"cc",
"codespan-reporting",
@@ -550,15 +571,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
version = "1.0.85"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59"
checksum = "43c7119ce3a3701ed81aca8410b9acf6fc399d2629d057b87e2efa4e63a3aaea"
[[package]]
name = "cxxbridge-macro"
version = "1.0.85"
version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
checksum = "65e07508b90551e610910fa648a1878991d367064997a596135b86df30daf07e"
dependencies = [
"proc-macro2",
"quote",
@@ -577,6 +598,16 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "digest"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "directories"
version = "4.0.1"
@@ -719,10 +750,10 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.0.232"
version = "0.0.237"
dependencies = [
"anyhow",
"clap 4.0.32",
"clap 4.1.4",
"colored",
"configparser",
"once_cell",
@@ -733,7 +764,7 @@ dependencies = [
"serde_json",
"strum",
"strum_macros",
"toml 0.6.0",
"toml",
]
[[package]]
@@ -770,6 +801,16 @@ dependencies = [
"libc",
]
[[package]]
name = "generic-array"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.8"
@@ -785,18 +826,18 @@ dependencies = [
[[package]]
name = "glob"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "globset"
version = "0.4.9"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
dependencies = [
"aho-corasick",
"bstr 0.2.17",
"bstr 1.1.0",
"fnv",
"log",
"regex",
@@ -883,11 +924,10 @@ dependencies = [
[[package]]
name = "ignore"
version = "0.4.18"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
dependencies = [
"crossbeam-utils",
"globset",
"lazy_static",
"log",
@@ -941,13 +981,15 @@ dependencies = [
[[package]]
name = "insta"
version = "1.23.0"
version = "1.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48b08a091dfe5b09a6a9688c468fdd5b4396e92ce09e2eb932f0884b02788a4"
checksum = "f6f0f08b46e4379744de2ab67aa8f7de3ffd1da3e275adc41fcc82053ede46ff"
dependencies = [
"console",
"lazy_static",
"linked-hash-map",
"pest",
"pest_derive",
"serde",
"similar",
"yaml-rust",
@@ -964,9 +1006,9 @@ dependencies = [
[[package]]
name = "io-lifetimes"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
dependencies = [
"libc",
"windows-sys",
@@ -984,6 +1026,15 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "is_executable"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8"
dependencies = [
"winapi",
]
[[package]]
name = "itertools"
version = "0.10.5"
@@ -1183,9 +1234,9 @@ dependencies = [
[[package]]
name = "matches"
version = "0.1.9"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]]
name = "memchr"
@@ -1243,9 +1294,9 @@ checksum = "d906846a98739ed9d73d66e62c2641eef8321f1734b7a1156ab045a0248fb2b3"
[[package]]
name = "nix"
version = "0.26.1"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694"
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
dependencies = [
"bitflags",
"cfg-if",
@@ -1310,9 +1361,9 @@ dependencies = [
[[package]]
name = "num-complex"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
dependencies = [
"num-traits",
"serde",
@@ -1349,18 +1400,18 @@ dependencies = [
[[package]]
name = "num_enum"
version = "0.5.7"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.7"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -1398,9 +1449,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.5"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
dependencies = [
"cfg-if",
"libc",
@@ -1466,6 +1517,50 @@ version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pest"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f"
dependencies = [
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bf026e2d0581559db66d837fe5242320f525d85c76283c61f4d51a1238d65ea"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b27bd18aa01d91c8ed2b61ea23406a676b42d82609c6e2581fba42f0c15f17f"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f02b677c1859756359fc9983c2e56a0237f18624a3789528804406b7e915e5d"
dependencies = [
"once_cell",
"pest",
"sha2",
]
[[package]]
name = "petgraph"
version = "0.6.2"
@@ -1600,9 +1695,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "predicates"
version = "2.1.4"
version = "2.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f54fc5dc63ed3bbf19494623db4f3af16842c0d975818e469022d09e53f0aa05"
checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd"
dependencies = [
"difflib",
"itertools",
@@ -1627,13 +1722,12 @@ dependencies = [
[[package]]
name = "proc-macro-crate"
version = "1.2.1"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
dependencies = [
"once_cell",
"thiserror",
"toml 0.5.11",
"toml_edit",
]
[[package]]
@@ -1662,9 +1756,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.49"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
dependencies = [
"unicode-ident",
]
@@ -1749,9 +1843,9 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.10.1"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
@@ -1781,9 +1875,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.7.0"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
dependencies = [
"aho-corasick",
"memchr",
@@ -1828,13 +1922,13 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.232"
version = "0.0.237"
dependencies = [
"anyhow",
"bitflags",
"cfg-if",
"chrono",
"clap 4.0.32",
"clap 4.1.4",
"colored",
"console_error_panic_hook",
"console_log",
@@ -1847,6 +1941,7 @@ dependencies = [
"ignore",
"imperative",
"insta",
"is_executable",
"itertools",
"js-sys",
"libcst",
@@ -1875,14 +1970,14 @@ dependencies = [
"textwrap",
"thiserror",
"titlecase",
"toml 0.6.0",
"toml",
"wasm-bindgen",
"wasm-bindgen-test",
]
[[package]]
name = "ruff_cli"
version = "0.0.232"
version = "0.0.237"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -1891,7 +1986,7 @@ dependencies = [
"bincode",
"cachedir",
"chrono",
"clap 4.0.32",
"clap 4.1.4",
"clap_complete_command",
"clearscreen",
"colored",
@@ -1919,10 +2014,10 @@ dependencies = [
[[package]]
name = "ruff_dev"
version = "0.0.232"
version = "0.0.237"
dependencies = [
"anyhow",
"clap 4.0.32",
"clap 4.1.4",
"itertools",
"libcst",
"once_cell",
@@ -1940,7 +2035,7 @@ dependencies = [
[[package]]
name = "ruff_macros"
version = "0.0.232"
version = "0.0.237"
dependencies = [
"once_cell",
"proc-macro2",
@@ -1967,9 +2062,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.36.5"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
dependencies = [
"bitflags",
"errno",
@@ -1981,9 +2076,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.20.7"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c"
checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
dependencies = [
"log",
"ring",
@@ -2149,9 +2244,9 @@ checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]]
name = "serde"
version = "1.0.151"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
@@ -2169,9 +2264,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.151"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
@@ -2209,6 +2304,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "shellexpand"
version = "3.0.0"
@@ -2333,23 +2439,13 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.1.3"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "terminfo"
version = "0.7.5"
@@ -2487,15 +2583,6 @@ dependencies = [
"regex",
]
[[package]]
name = "toml"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
name = "toml"
version = "0.6.0"
@@ -2540,6 +2627,18 @@ dependencies = [
"static_assertions",
]
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ucd-trie"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "unic-char-property"
version = "0.9.0"
@@ -2606,9 +2705,9 @@ dependencies = [
[[package]]
name = "unicode-bidi"
version = "0.3.8"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58"
[[package]]
name = "unicode-ident"
@@ -2674,12 +2773,11 @@ dependencies = [
[[package]]
name = "ureq"
version = "2.5.0"
version = "2.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f"
checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d"
dependencies = [
"base64",
"chunked_transfer",
"flate2",
"log",
"once_cell",
@@ -2873,9 +2971,9 @@ dependencies = [
[[package]]
name = "which"
version = "4.3.0"
version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
dependencies = [
"either",
"libc",
@@ -2936,45 +3034,45 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "yaml-rust"

View File

@@ -8,7 +8,7 @@ default-members = [".", "ruff_cli"]
[package]
name = "ruff"
version = "0.0.232"
version = "0.0.237"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
edition = "2021"
rust-version = "1.65.0"
@@ -46,7 +46,7 @@ num-traits = "0.2.15"
once_cell = { version = "1.16.0" }
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
regex = { version = "1.6.0" }
ruff_macros = { version = "0.0.232", path = "ruff_macros" }
ruff_macros = { version = "0.0.237", path = "ruff_macros" }
rustc-hash = { version = "1.1.0" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "4f38cb68e4a97aeea9eb19673803a0bd5f655383" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "4f38cb68e4a97aeea9eb19673803a0bd5f655383" }
@@ -61,7 +61,7 @@ strum_macros = { version = "0.24.3" }
textwrap = { version = "0.16.0" }
thiserror = { version = "1.0" }
titlecase = { version = "2.2.1" }
toml = { version = "0.6.0", features= ["parse"] }
toml = { version = "0.6.0" }
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
# For (future) wasm-pack support
@@ -73,8 +73,11 @@ serde-wasm-bindgen = { version = "0.4" }
js-sys = { version = "0.3.60" }
wasm-bindgen = { version = "0.2.83" }
[target.'cfg(not(target_family = "wasm"))'.dependencies]
is_executable = "1.0.1"
[dev-dependencies]
insta = { version = "1.19.1", features = ["yaml"] }
insta = { version = "1.19.1", features = ["yaml", "redactions"] }
test-case = { version = "2.2.2" }
wasm-bindgen-test = { version = "0.3.33" }

986
LICENSE
View File

@@ -19,3 +19,989 @@ 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.
end of terms and conditions
The externally maintained libraries from which parts of the Software is derived
are:
- flake8-comprehensions, licensed as follows:
"""
MIT License
Copyright (c) 2017 Adam Johnson
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-no-pep420, licensed as follows:
"""
MIT License
Copyright (c) 2020 Adam Johnson
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-tidy-imports, licensed as follows:
"""
MIT License
Copyright (c) 2017 Adam Johnson
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-return, licensed as follows:
"""
MIT License
Copyright (c) 2019 Afonasev Evgeniy
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-2020, licensed as follows:
"""
Copyright (c) 2019 Anthony Sottile
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.
"""
- pyupgrade, licensed as follows:
"""
Copyright (c) 2017 Anthony Sottile
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-blind-except, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2014 Elijah Andrews
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-implicit-str-concat, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2019 Dylan Turner
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-debugger, licensed as follows:
"""
MIT License
Copyright (c) 2016 Joseph Kahn
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-print, licensed as follows:
"""
MIT License
Copyright (c) 2016 Joseph Kahn
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-import-conventions, licensed as follows:
"""
MIT License
Copyright (c) 2021 João Palmeiro
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-simplify, licensed as follows:
"""
MIT License
Copyright (c) 2020 Martin Thoma
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-unused-arguments, licensed as follows:
"""
MIT License
Copyright (c) 2019 Nathan Hoad
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.
"""
- pygrep-hooks, licensed as follows:
"""
Copyright (c) 2018 Anthony Sottile
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.
"""
- autoflake, licensed as follows:
"""
Copyright (C) 2012-2018 Steven Myint
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, licensed as follows:
"""
== Flake8 License (MIT) ==
Copyright (C) 2011-2013 Tarek Ziade <tarek@ziade.org>
Copyright (C) 2012-2016 Ian Cordasco <graffatcolmingov@gmail.com>
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-bugbear, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2016 Łukasz Langa
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-commas, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2017 Thomas Grainger.
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.
Portions of this flake8-commas Software may utilize the following
copyrighted material, the use of which is hereby acknowledged.
Original flake8-commas: https://github.com/trevorcreech/flake8-commas/commit/e8563b71b1d5442e102c8734c11cb5202284293d
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.
"""
- isort, licensed as follows:
"""
The MIT License (MIT)
Copyright (c) 2013 Timothy Edmund Crosley
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.
"""
- pep8-naming, licensed as follows:
"""
Copyright © 2013 Florent Xicluna <florent.xicluna@gmail.com>
Licensed under the terms of the Expat License
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.
"""
- pycodestyle, licensed as follows:
"""
Copyright © 2006-2009 Johann C. Rocholl <johann@rocholl.net>
Copyright © 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
Copyright © 2014-2020 Ian Lee <IanLee1521@gmail.com>
Licensed under the terms of the Expat License
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.
"""
- pydocstyle, licensed as follows:
"""
Copyright (c) 2012 GreenSteam, <http://greensteam.dk/>
Copyright (c) 2014-2020 Amir Rachum, <http://amir.rachum.com/>
Copyright (c) 2020 Sambhav Kothari, <https://github.com/samj1912>
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.
"""
- Pyflakes, licensed as follows:
"""
Copyright 2005-2011 Divmod, Inc.
Copyright 2013-2014 Florent Xicluna
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-use-pathlib, licensed as follows:
"""
MIT License
Copyright (c) 2021 Rodolphe Pelloux-Prayer
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.
"""
- RustPython, licensed as follows:
"""
MIT License
Copyright (c) 2020 RustPython Team
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-annotations, licensed as follows:
"""
MIT License
Copyright (c) 2019 - Present S. Co1
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-type-checking, licensed as follows:
"""
Copyright (c) 2021, Sondre Lillebø Gundersen
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of pytest-{{ cookiecutter.plugin_name }} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
- flake8-bandit, licensed as follows:
"""
Copyright (c) 2017 Tyler Wince
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-eradicate, licensed as follows:
"""
MIT License
Copyright (c) 2018 Nikita Sobolev
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-quotes, licensed as follows:
"""
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-logging-format, licensed as follows:
"""
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

650
README.md
View File

@@ -1,3 +1,5 @@
<!-- Begin section: Overview -->
# Ruff
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v1.json)](https://github.com/charliermarsh/ruff)
@@ -67,6 +69,9 @@ Ruff is extremely actively developed and used in major open-source projects like
- [Home Assistant](https://github.com/home-assistant/core)
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
- [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel)
- [build (PyPA)](https://github.com/pypa/build)
- [Babel](https://github.com/python-babel/babel)
- [featuretools](https://github.com/alteryx/featuretools)
Read the [launch blog post](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster).
@@ -103,6 +108,8 @@ developer of [Zulip](https://github.com/zulip/zulip):
> This is just ridiculously fast... `ruff` is amazing.
<!-- End section: Overview -->
## Table of Contents
1. [Installation and Usage](#installation-and-usage)
@@ -112,9 +119,9 @@ developer of [Zulip](https://github.com/zulip/zulip):
1. [pycodestyle (E, W)](#pycodestyle-e-w)
1. [mccabe (C90)](#mccabe-c90)
1. [isort (I)](#isort-i)
1. [pep8-naming (N)](#pep8-naming-n)
1. [pydocstyle (D)](#pydocstyle-d)
1. [pyupgrade (UP)](#pyupgrade-up)
1. [pep8-naming (N)](#pep8-naming-n)
1. [flake8-2020 (YTT)](#flake8-2020-ytt)
1. [flake8-annotations (ANN)](#flake8-annotations-ann)
1. [flake8-bandit (S)](#flake8-bandit-s)
@@ -122,30 +129,31 @@ developer of [Zulip](https://github.com/zulip/zulip):
1. [flake8-boolean-trap (FBT)](#flake8-boolean-trap-fbt)
1. [flake8-bugbear (B)](#flake8-bugbear-b)
1. [flake8-builtins (A)](#flake8-builtins-a)
1. [flake8-commas (COM)](#flake8-commas-com)
1. [flake8-comprehensions (C4)](#flake8-comprehensions-c4)
1. [flake8-datetimez (DTZ)](#flake8-datetimez-dtz)
1. [flake8-debugger (T10)](#flake8-debugger-t10)
1. [flake8-errmsg (EM)](#flake8-errmsg-em)
1. [flake8-executable (EXE)](#flake8-executable-exe)
1. [flake8-implicit-str-concat (ISC)](#flake8-implicit-str-concat-isc)
1. [flake8-import-conventions (ICN)](#flake8-import-conventions-icn)
1. [flake8-logging-format (G)](#flake8-logging-format-g)
1. [flake8-no-pep420 (INP)](#flake8-no-pep420-inp)
1. [flake8-pie (PIE)](#flake8-pie-pie)
1. [flake8-print (T20)](#flake8-print-t20)
1. [flake8-pytest-style (PT)](#flake8-pytest-style-pt)
1. [flake8-quotes (Q)](#flake8-quotes-q)
1. [flake8-return (RET)](#flake8-return-ret)
1. [flake8-simplify (SIM)](#flake8-simplify-sim)
1. [flake8-tidy-imports (TID)](#flake8-tidy-imports-tid)
1. [flake8-type-checking (TCH)](#flake8-type-checking-tch)
1. [flake8-unused-arguments (ARG)](#flake8-unused-arguments-arg)
1. [flake8-datetimez (DTZ)](#flake8-datetimez-dtz)
1. [flake8-use-pathlib (PTH)](#flake8-use-pathlib-pth)
1. [eradicate (ERA)](#eradicate-era)
1. [pandas-vet (PD)](#pandas-vet-pd)
1. [pygrep-hooks (PGH)](#pygrep-hooks-pgh)
1. [Pylint (PL)](#pylint-pl)
1. [flake8-pie (PIE)](#flake8-pie-pie)
1. [flake8-commas (COM)](#flake8-commas-com)
1. [flake8-no-pep420 (INP)](#flake8-no-pep420-inp)
1. [flake8-executable (EXE)](#flake8-executable-exe)
1. [flake8-type-checking (TYP)](#flake8-type-checking-typ)
1. [tryceratops (TRY)](#tryceratops-try)
1. [flake8-use-pathlib (PTH)](#flake8-use-pathlib-pth)
1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. -->
1. [Editor Integrations](#editor-integrations)
1. [FAQ](#faq)
@@ -157,6 +165,8 @@ developer of [Zulip](https://github.com/zulip/zulip):
## Installation and Usage
<!-- Begin section: Installation and Usage -->
### Installation
Ruff is available as [`ruff`](https://pypi.org/project/ruff/) on PyPI:
@@ -212,13 +222,17 @@ Ruff also works with [pre-commit](https://pre-commit.com):
```yaml
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.232'
rev: 'v0.0.237'
hooks:
- id: ruff
```
<!-- End section: Installation and Usage -->
## Configuration
<!-- Begin section: Configuration -->
Ruff is configurable both via `pyproject.toml` and the command line. For a full list of configurable
options, see the [API reference](#reference).
@@ -226,12 +240,14 @@ If left unspecified, the default configuration is equivalent to:
```toml
[tool.ruff]
line-length = 88
# Enable Pyflakes `E` and `F` codes by default.
select = ["E", "F"]
ignore = []
# Allow autofix for all enabled rules (when `--fix`) is provided.
fixable = ["A", "B", "C", "D", "E", "F", "..."]
unfixable = []
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
@@ -256,6 +272,9 @@ exclude = [
]
per-file-ignores = {}
# Same as Black.
line-length = 88
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
@@ -267,20 +286,21 @@ target-version = "py310"
max-complexity = 10
```
As an example, the following would configure Ruff to: (1) avoid enforcing line-length violations
(`E501`); (2) never remove unused imports (`F401`); and (3) ignore import-at-top-of-file violations
(`E402`) in `__init__.py` files:
As an example, the following would configure Ruff to: (1) enforce flake8-bugbear rules, in addition
to the defaults; (2) avoid enforcing line-length violations (`E501`); (3) avoid attempting to fix
flake8-bugbear (`B`) violations; and (3) ignore import-at-top-of-file violations (`E402`) in
`__init__.py` files:
```toml
[tool.ruff]
# Enable Pyflakes and pycodestyle rules.
select = ["E", "F"]
# Enable flake8-bugbear (`B`) rules.
select = ["E", "F", "B"]
# Never enforce `E501` (line length violations).
ignore = ["E501"]
# Never try to fix `F401` (unused imports).
unfixable = ["F401"]
# Avoid trying to fix flake8-bugbear (`B`) violations.
unfixable = ["B"]
# Ignore `E402` (import violations) in all `__init__.py` files, and in `path/to/file.py`.
[tool.ruff.per-file-ignores]
@@ -310,6 +330,17 @@ As a special-case, Ruff also supports the `ALL` code, which enables all rules. N
formats. Enabling `ALL` without further configuration may result in suboptimal behavior, especially
for the `pydocstyle` plugin.
If you're wondering how to configure Ruff, here are some **recommended guidelines**:
- Prefer `select` and `ignore` over `extend-select` and `extend-ignore`, to make your rule set
explicit.
- Use `ALL` with discretion. Enabling `ALL` will implicitly enable new rules whenever you upgrade.
- Start with a small set of rules (`select = ["E", "F"]`) and add a category at-a-time. For example,
you might consider expanding to `select = ["E", "F", "B"]` to enable the popular `flake8-bugbear`
extension.
- By default, Ruff's autofix is aggressive. If you find that it's too aggressive for your liking,
consider turning off autofix for specific rules or categories (see: [FAQ](#ruff-tried-to-fix-something-but-it-broke-my-code-what-should-i-do)).
As an alternative to `pyproject.toml`, Ruff will also respect a `ruff.toml` file, which implements
an equivalent schema (though the `[tool.ruff]` hierarchy can be omitted). For example, the
`pyproject.toml` described above would be represented via the following `ruff.toml`:
@@ -345,86 +376,24 @@ See `ruff --help` for more:
```
Ruff: An extremely fast Python linter.
Usage: ruff [OPTIONS] [FILES]...
Usage: ruff [OPTIONS] <COMMAND>
Arguments:
[FILES]...
Commands:
check Run Ruff on the given files or directories (default)
rule Explain a rule
clean Clear any caches in the current directory and any subdirectories
help Print this message or the help of the given subcommand(s)
Options:
--config <CONFIG>
Path to the `pyproject.toml` or `ruff.toml` file to use for configuration
-v, --verbose
Enable verbose logging
-q, --quiet
Print lint violations, but nothing else
-s, --silent
Disable all logging (but still exit with status code "1" upon detecting lint violations)
-e, --exit-zero
Exit with status code "0", even upon detecting lint violations
-w, --watch
Run in watch mode by re-running whenever files change
--fix
Attempt to automatically fix lint violations
--fix-only
Fix any fixable lint violations, but don't report on leftover violations. Implies `--fix`
--diff
Avoid writing any fixed files back; instead, output a diff for each changed file to stdout
-n, --no-cache
Disable cache reads
--isolated
Ignore all configuration files
--select <RULE_CODE>
Comma-separated list of rule codes to enable (or ALL, to enable all rules)
--extend-select <RULE_CODE>
Like --select, but adds additional rule codes on top of the selected ones
--ignore <RULE_CODE>
Comma-separated list of rule codes to disable
--extend-ignore <RULE_CODE>
Like --ignore, but adds additional rule codes on top of the ignored ones
--exclude <FILE_PATTERN>
List of paths, used to omit files and/or directories from analysis
--extend-exclude <FILE_PATTERN>
Like --exclude, but adds additional files and directories on top of those already excluded
--fixable <RULE_CODE>
List of rule codes to treat as eligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
--unfixable <RULE_CODE>
List of rule codes to treat as ineligible for autofix. Only applicable when autofix itself is enabled (e.g., via `--fix`)
--per-file-ignores <PER_FILE_IGNORES>
List of mappings from file pattern to code to exclude
--format <FORMAT>
Output serialization format for violations [env: RUFF_FORMAT=] [possible values: text, json, junit, grouped, github, gitlab, pylint]
--stdin-filename <STDIN_FILENAME>
The name of the file when passing it through stdin
--cache-dir <CACHE_DIR>
Path to the cache directory [env: RUFF_CACHE_DIR=]
--show-source
Show violations with source code
--respect-gitignore
Respect file exclusions via `.gitignore` and other standard ignore files
--force-exclude
Enforce exclusions, even for paths passed to Ruff directly on the command-line
--update-check
Enable or disable automatic update checks
--dummy-variable-rgx <DUMMY_VARIABLE_RGX>
Regular expression matching the name of dummy variables
--target-version <TARGET_VERSION>
The minimum Python version that should be supported
--line-length <LINE_LENGTH>
Set the line-length for length-associated rules and automatic formatting
--add-noqa
Enable automatic additions of `noqa` directives to failing lines
--clean
Clear any caches in the current directory or any subdirectories
--explain <EXPLAIN>
Explain a rule
--show-files
See the files Ruff will be run against with the current settings
--show-settings
See the settings Ruff will use to lint a given Python file
-h, --help
Print help information
-V, --version
Print version information
-h, --help Print help
-V, --version Print version
Log levels:
-v, --verbose Enable verbose logging
-q, --quiet Print lint violations, but nothing else
-s, --silent Disable all logging (but still exit with status code "1" upon detecting lint violations)
For help with a specific command, see: `ruff help <command>`.
```
<!-- End auto-generated cli help. -->
@@ -445,10 +414,9 @@ There are a few exceptions to these rules:
resolved relative to the _current working directory_.
3. If no `pyproject.toml` file is found in the filesystem hierarchy, Ruff will fall back to using
a default configuration. If a user-specific configuration file exists
at `${config_dir}/ruff/pyproject.toml`,
that file will be used instead of the default configuration, with `${config_dir}` being
determined via the [`dirs`](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) crate, and all
relative paths being again resolved relative to the _current working directory_.
at `${config_dir}/ruff/pyproject.toml`, that file will be used instead of the default
configuration, with `${config_dir}` being determined via the [`dirs`](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html)
crate, and all relative paths being again resolved relative to the _current working directory_.
4. Any `pyproject.toml`-supported settings that are provided on the command-line (e.g., via
`--select`) will override the settings in _every_ resolved configuration file.
@@ -543,11 +511,17 @@ Third, Ruff can _automatically add_ `noqa` directives to all failing lines. This
migrating a new codebase to Ruff. You can run `ruff /path/to/file.py --add-noqa` to automatically
add `noqa` directives to all failing lines, with the appropriate rule codes.
<!-- End section: Configuration -->
## Supported Rules
<!-- Begin section: Rules -->
Regardless of the rule's origin, Ruff re-implements every rule in Rust as a first-party feature.
By default, Ruff enables all `E` and `F` rule codes, which correspond to those built-in to Flake8.
By default, Ruff enables Flake8's `E` and `F` rules. Ruff supports all rules from the `F` category,
and a [subset](#error-e) of the `E` category, omitting those stylistic rules made obsolete by the
use of an autoformatter, like [Black](https://github.com/psf/black).
The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` command-line option.
@@ -566,20 +540,20 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/) on PyPI.
| F405 | import-star-usage | `{name}` may be undefined, or defined from star imports: {sources} | |
| F406 | import-star-not-permitted | `from {name} import *` only allowed at module level | |
| F407 | future-feature-not-defined | Future feature `{name}` is not defined | |
| F501 | percent-format-invalid-format | '...' % ... has invalid format string: {message} | |
| F502 | percent-format-expected-mapping | '...' % ... expected mapping but got sequence | |
| F503 | percent-format-expected-sequence | '...' % ... expected sequence but got mapping | |
| F504 | percent-format-extra-named-arguments | '...' % ... has unused named argument(s): {message} | 🛠 |
| F505 | percent-format-missing-argument | '...' % ... is missing argument(s) for placeholder(s): {message} | |
| F506 | percent-format-mixed-positional-and-named | '...' % ... has mixed positional and named placeholders | |
| F507 | percent-format-positional-count-mismatch | '...' % ... has {wanted} placeholder(s) but {got} substitution(s) | |
| F508 | percent-format-star-requires-sequence | '...' % ... `*` specifier requires sequence | |
| F509 | percent-format-unsupported-format-character | '...' % ... has unsupported format character '{char}' | |
| F521 | string-dot-format-invalid-format | '...'.format(...) has invalid format string: {message} | |
| F522 | string-dot-format-extra-named-arguments | '...'.format(...) has unused named argument(s): {message} | 🛠 |
| F523 | string-dot-format-extra-positional-arguments | '...'.format(...) has unused arguments at position(s): {message} | |
| F524 | string-dot-format-missing-arguments | '...'.format(...) is missing argument(s) for placeholder(s): {message} | |
| F525 | string-dot-format-mixing-automatic | '...'.format(...) mixes automatic and manual numbering | |
| F501 | percent-format-invalid-format | `%`-format string has invalid format string: {message} | |
| F502 | percent-format-expected-mapping | `%`-format string expected mapping but got sequence | |
| F503 | percent-format-expected-sequence | `%`-format string expected sequence but got mapping | |
| F504 | percent-format-extra-named-arguments | `%`-format string has unused named argument(s): {message} | 🛠 |
| F505 | percent-format-missing-argument | `%`-format string is missing argument(s) for placeholder(s): {message} | |
| F506 | percent-format-mixed-positional-and-named | `%`-format string has mixed positional and named placeholders | |
| F507 | percent-format-positional-count-mismatch | `%`-format string has {wanted} placeholder(s) but {got} substitution(s) | |
| F508 | percent-format-star-requires-sequence | `%`-format string `*` specifier requires sequence | |
| F509 | percent-format-unsupported-format-character | `%`-format string has unsupported format character '{char}' | |
| F521 | string-dot-format-invalid-format | `.format` call has invalid format string: {message} | |
| F522 | string-dot-format-extra-named-arguments | `.format` call has unused named argument(s): {message} | 🛠 |
| F523 | string-dot-format-extra-positional-arguments | `.format` call has unused arguments at position(s): {message} | |
| F524 | string-dot-format-missing-arguments | `.format` call is missing argument(s) for placeholder(s): {message} | |
| F525 | string-dot-format-mixing-automatic | `.format` string mixes automatic and manual numbering | |
| F541 | f-string-missing-placeholders | f-string without any placeholders | 🛠 |
| F601 | multi-value-repeated-key-literal | Dictionary key literal `{name}` repeated | 🛠 |
| F602 | multi-value-repeated-key-variable | Dictionary key `{name}` repeated | 🛠 |
@@ -651,6 +625,28 @@ For more, see [isort](https://pypi.org/project/isort/) on PyPI.
| I001 | unsorted-imports | Import block is un-sorted or un-formatted | 🛠 |
| I002 | missing-required-import | Missing required import: `{name}` | 🛠 |
### pep8-naming (N)
For more, see [pep8-naming](https://pypi.org/project/pep8-naming/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| N801 | invalid-class-name | Class name `{name}` should use CapWords convention | |
| N802 | invalid-function-name | Function name `{name}` should be lowercase | |
| N803 | invalid-argument-name | Argument name `{name}` should be lowercase | |
| N804 | invalid-first-argument-name-for-class-method | First argument of a class method should be named `cls` | |
| N805 | invalid-first-argument-name-for-method | First argument of a method should be named `self` | |
| N806 | non-lowercase-variable-in-function | Variable `{name}` in function should be lowercase | |
| N807 | dunder-function-name | Function name should not start and end with `__` | |
| N811 | constant-imported-as-non-constant | Constant `{name}` imported as non-constant `{asname}` | |
| N812 | lowercase-imported-as-non-lowercase | Lowercase `{name}` imported as non-lowercase `{asname}` | |
| N813 | camelcase-imported-as-lowercase | Camelcase `{name}` imported as lowercase `{asname}` | |
| N814 | camelcase-imported-as-constant | Camelcase `{name}` imported as constant `{asname}` | |
| N815 | mixed-case-variable-in-class-scope | Variable `{name}` in class scope should not be mixedCase | |
| N816 | mixed-case-variable-in-global-scope | Variable `{name}` in global scope should not be mixedCase | |
| N817 | camelcase-imported-as-acronym | Camelcase `{name}` imported as acronym `{asname}` | |
| N818 | error-suffix-on-exception-name | Exception name `{name}` should be named with an Error suffix | |
### pydocstyle (D)
For more, see [pydocstyle](https://pypi.org/project/pydocstyle/) on PyPI.
@@ -744,28 +740,6 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/) on PyPI.
| UP033 | functools-cache | Use `@functools.cache` instead of `@functools.lru_cache(maxsize=None)` | 🛠 |
| UP034 | extraneous-parentheses | Avoid extraneous parentheses | 🛠 |
### pep8-naming (N)
For more, see [pep8-naming](https://pypi.org/project/pep8-naming/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| N801 | invalid-class-name | Class name `{name}` should use CapWords convention | |
| N802 | invalid-function-name | Function name `{name}` should be lowercase | |
| N803 | invalid-argument-name | Argument name `{name}` should be lowercase | |
| N804 | invalid-first-argument-name-for-class-method | First argument of a class method should be named `cls` | |
| N805 | invalid-first-argument-name-for-method | First argument of a method should be named `self` | |
| N806 | non-lowercase-variable-in-function | Variable `{name}` in function should be lowercase | |
| N807 | dunder-function-name | Function name should not start and end with `__` | |
| N811 | constant-imported-as-non-constant | Constant `{name}` imported as non-constant `{asname}` | |
| N812 | lowercase-imported-as-non-lowercase | Lowercase `{name}` imported as non-lowercase `{asname}` | |
| N813 | camelcase-imported-as-lowercase | Camelcase `{name}` imported as lowercase `{asname}` | |
| N814 | camelcase-imported-as-constant | Camelcase `{name}` imported as constant `{asname}` | |
| N815 | mixed-case-variable-in-class-scope | Variable `{name}` in class scope should not be mixedCase | |
| N816 | mixed-case-variable-in-global-scope | Variable `{name}` in global scope should not be mixedCase | |
| N817 | camelcase-imported-as-acronym | Camelcase `{name}` imported as acronym `{asname}` | |
| N818 | error-suffix-on-exception-name | Exception name `{name}` should be named with an Error suffix | |
### flake8-2020 (YTT)
For more, see [flake8-2020](https://pypi.org/project/flake8-2020/) on PyPI.
@@ -815,6 +789,7 @@ For more, see [flake8-bandit](https://pypi.org/project/flake8-bandit/) on PyPI.
| S106 | hardcoded-password-func-arg | Possible hardcoded password: "{}" | |
| S107 | hardcoded-password-default | Possible hardcoded password: "{}" | |
| S108 | hardcoded-temp-file | Probable insecure usage of temporary file or directory: "{}" | |
| S110 | try-except-pass | `try`-`except`-`pass` detected, consider logging the exception | |
| S113 | request-without-timeout | Probable use of requests call with timeout set to `{value}` | |
| S324 | hashlib-insecure-hash-function | Probable use of insecure hash functions in `hashlib`: "{}" | |
| S501 | request-with-no-cert-validation | Probable use of `{string}` call with `verify=False` disabling SSL certificate checks | |
@@ -853,12 +828,12 @@ For more, see [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) on PyPI
| B004 | unreliable-callable-check | Using `hasattr(x, '__call__')` to test if x is callable is unreliable. Use `callable(x)` for consistent results. | |
| B005 | strip-with-multi-characters | Using `.strip()` with multi-character strings is misleading the reader | |
| B006 | mutable-argument-default | Do not use mutable data structures for argument defaults | |
| B007 | unused-loop-control-variable | Loop control variable `{name}` not used within the loop body | 🛠 |
| B007 | unused-loop-control-variable | Loop control variable `{name}` not used within loop body | 🛠 |
| B008 | function-call-argument-default | Do not perform function call `{name}` in argument defaults | |
| B009 | get-attr-with-constant | Do not call `getattr` with a constant attribute value. It is not any safer than normal property access. | 🛠 |
| B010 | set-attr-with-constant | Do not call `setattr` with a constant attribute value. It is not any safer than normal property access. | 🛠 |
| B011 | do-not-assert-false | Do not `assert False` (`python -O` removes these calls), raise `AssertionError()` | 🛠 |
| B012 | jump-statement-in-finally | `{name}` inside finally blocks cause exceptions to be silenced | |
| B012 | jump-statement-in-finally | `{name}` inside `finally` blocks cause exceptions to be silenced | |
| B013 | redundant-tuple-in-exception-handler | A length-one tuple literal is redundant. Write `except {name}` instead of `except ({name},)`. | 🛠 |
| B014 | duplicate-handler-exception | Exception handler with duplicate exception: `{name}` | 🛠 |
| B015 | useless-comparison | Pointless comparison. This comparison does nothing but waste CPU instructions. Either prepend `assert` or remove it. | |
@@ -887,6 +862,16 @@ For more, see [flake8-builtins](https://pypi.org/project/flake8-builtins/) on Py
| A002 | builtin-argument-shadowing | Argument `{name}` is shadowing a python builtin | |
| A003 | builtin-attribute-shadowing | Class attribute `{name}` is shadowing a python builtin | |
### flake8-commas (COM)
For more, see [flake8-commas](https://pypi.org/project/flake8-commas/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| COM812 | trailing-comma-missing | Trailing comma missing | 🛠 |
| COM818 | trailing-comma-on-bare-tuple-prohibited | Trailing comma on bare tuple prohibited | |
| COM819 | trailing-comma-prohibited | Trailing comma prohibited | 🛠 |
### flake8-comprehensions (C4)
For more, see [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/) on PyPI.
@@ -910,6 +895,22 @@ For more, see [flake8-comprehensions](https://pypi.org/project/flake8-comprehens
| C416 | unnecessary-comprehension | Unnecessary `{obj_type}` comprehension (rewrite using `{obj_type}()`) | 🛠 |
| C417 | unnecessary-map | Unnecessary `map` usage (rewrite using a generator expression) | |
### flake8-datetimez (DTZ)
For more, see [flake8-datetimez](https://pypi.org/project/flake8-datetimez/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| DTZ001 | call-datetime-without-tzinfo | The use of `datetime.datetime()` without `tzinfo` argument is not allowed | |
| DTZ002 | call-datetime-today | The use of `datetime.datetime.today()` is not allowed, use `datetime.datetime.now(tz=)` instead | |
| DTZ003 | call-datetime-utcnow | The use of `datetime.datetime.utcnow()` is not allowed, use `datetime.datetime.now(tz=)` instead | |
| DTZ004 | call-datetime-utcfromtimestamp | The use of `datetime.datetime.utcfromtimestamp()` is not allowed, use `datetime.datetime.fromtimestamp(ts, tz=)` instead | |
| DTZ005 | call-datetime-now-without-tzinfo | The use of `datetime.datetime.now()` without `tz` argument is not allowed | |
| DTZ006 | call-datetime-fromtimestamp | The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed | |
| DTZ007 | call-datetime-strptime-without-zone | The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` or `.astimezone()` | |
| DTZ011 | call-date-today | The use of `datetime.date.today()` is not allowed, use `datetime.datetime.now(tz=).date()` instead | |
| DTZ012 | call-date-fromtimestamp | The use of `datetime.date.fromtimestamp()` is not allowed, use `datetime.datetime.fromtimestamp(ts, tz=).date()` instead | |
### flake8-debugger (T10)
For more, see [flake8-debugger](https://pypi.org/project/flake8-debugger/) on PyPI.
@@ -928,6 +929,18 @@ For more, see [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) on PyPI.
| EM102 | f-string-in-exception | Exception must not use an f-string literal, assign to variable first | |
| EM103 | dot-format-in-exception | Exception must not use a `.format()` string directly, assign to variable first | |
### flake8-executable (EXE)
For more, see [flake8-executable](https://pypi.org/project/flake8-executable/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| EXE001 | shebang-not-executable | Shebang is present but file is not executable | |
| EXE002 | shebang-missing-executable-file | The file is executable but no shebang is present | |
| EXE003 | shebang-python | Shebang should contain "python" | |
| EXE004 | shebang-whitespace | Avoid whitespace before shebang | 🛠 |
| EXE005 | shebang-newline | Shebang should be at the beginning of the file | |
### flake8-implicit-str-concat (ISC)
For more, see [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/) on PyPI.
@@ -946,6 +959,42 @@ For more, see [flake8-import-conventions](https://github.com/joaopalmeiro/flake8
| ---- | ---- | ------- | --- |
| ICN001 | import-alias-is-not-conventional | `{name}` should be imported as `{asname}` | |
### flake8-logging-format (G)
For more, see [flake8-logging-format](https://pypi.org/project/flake8-logging-format/0.9.0/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| G001 | logging-string-format | Logging statement uses `string.format()` | |
| G002 | logging-percent-format | Logging statement uses `%` | |
| G003 | logging-string-concat | Logging statement uses `+` | |
| G004 | logging-f-string | Logging statement uses f-string | |
| G010 | logging-warn | Logging statement uses `warn` instead of `warning` | 🛠 |
| G101 | logging-extra-attr-clash | Logging statement uses an extra field that clashes with a LogRecord field: `{key}` | |
| G201 | logging-exc-info | Logging `.exception(...)` should be used instead of `.error(..., exc_info=True)` | |
| G202 | logging-redundant-exc-info | Logging statement has redundant `exc_info` | |
### flake8-no-pep420 (INP)
For more, see [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| INP001 | implicit-namespace-package | File `{filename}` is part of an implicit namespace package. Add an `__init__.py`. | |
### flake8-pie (PIE)
For more, see [flake8-pie](https://pypi.org/project/flake8-pie/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PIE790 | no-unnecessary-pass | Unnecessary `pass` statement | 🛠 |
| PIE794 | dupe-class-field-definitions | Class field `{name}` is defined multiple times | 🛠 |
| PIE796 | prefer-unique-enums | Enum contains duplicate value: `{value}` | |
| PIE800 | no-unnecessary-spread | Unnecessary spread `**` | |
| PIE804 | no-unnecessary-dict-kwargs | Unnecessary `dict` kwargs | |
| PIE807 | prefer-list-builtin | Prefer `list` over useless lambda | 🛠 |
### flake8-print (T20)
For more, see [flake8-print](https://pypi.org/project/flake8-print/) on PyPI.
@@ -1054,6 +1103,18 @@ For more, see [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports
| TID251 | banned-api | `{name}` is banned: {message} | |
| TID252 | relative-imports | Relative imports from parent modules are banned | |
### flake8-type-checking (TCH)
For more, see [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| TCH001 | typing-only-first-party-import | Move application import `{}` into a type-checking block | |
| TCH002 | typing-only-third-party-import | Move third-party import `{}` into a type-checking block | |
| TCH003 | typing-only-standard-library-import | Move standard library import `{}` into a type-checking block | |
| TCH004 | runtime-import-in-type-checking-block | Move import `{}` out of type-checking block. Import is used for more than type hinting. | |
| TCH005 | empty-type-checking-block | Found empty type-checking block | |
### flake8-unused-arguments (ARG)
For more, see [flake8-unused-arguments](https://pypi.org/project/flake8-unused-arguments/) on PyPI.
@@ -1066,21 +1127,37 @@ For more, see [flake8-unused-arguments](https://pypi.org/project/flake8-unused-a
| ARG004 | unused-static-method-argument | Unused static method argument: `{name}` | |
| ARG005 | unused-lambda-argument | Unused lambda argument: `{name}` | |
### flake8-datetimez (DTZ)
### flake8-use-pathlib (PTH)
For more, see [flake8-datetimez](https://pypi.org/project/flake8-datetimez/) on PyPI.
For more, see [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| DTZ001 | call-datetime-without-tzinfo | The use of `datetime.datetime()` without `tzinfo` argument is not allowed | |
| DTZ002 | call-datetime-today | The use of `datetime.datetime.today()` is not allowed | |
| DTZ003 | call-datetime-utcnow | The use of `datetime.datetime.utcnow()` is not allowed | |
| DTZ004 | call-datetime-utcfromtimestamp | The use of `datetime.datetime.utcfromtimestamp()` is not allowed | |
| DTZ005 | call-datetime-now-without-tzinfo | The use of `datetime.datetime.now()` without `tz` argument is not allowed | |
| DTZ006 | call-datetime-fromtimestamp | The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed | |
| DTZ007 | call-datetime-strptime-without-zone | The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` or `.astimezone()` | |
| DTZ011 | call-date-today | The use of `datetime.date.today()` is not allowed. | |
| DTZ012 | call-date-fromtimestamp | The use of `datetime.date.fromtimestamp()` is not allowed | |
| PTH100 | pathlib-abspath | `os.path.abspath` should be replaced by `.resolve()` | |
| PTH101 | pathlib-chmod | `os.chmod` should be replaced by `.chmod()` | |
| PTH102 | pathlib-mkdir | `os.mkdir` should be replaced by `.mkdir()` | |
| PTH103 | pathlib-makedirs | `os.makedirs` should be replaced by `.mkdir(parents=True)` | |
| PTH104 | pathlib-rename | `os.rename` should be replaced by `.rename()` | |
| PTH105 | pathlib-replace | `os.replace`should be replaced by `.replace()` | |
| PTH106 | pathlib-rmdir | `os.rmdir` should be replaced by `.rmdir()` | |
| PTH107 | pathlib-remove | `os.remove` should be replaced by `.unlink()` | |
| PTH108 | pathlib-unlink | `os.unlink` should be replaced by `.unlink()` | |
| PTH109 | pathlib-getcwd | `os.getcwd()` should be replaced by `Path.cwd()` | |
| PTH110 | pathlib-exists | `os.path.exists` should be replaced by `.exists()` | |
| PTH111 | pathlib-expanduser | `os.path.expanduser` should be replaced by `.expanduser()` | |
| PTH112 | pathlib-is-dir | `os.path.isdir` should be replaced by `.is_dir()` | |
| PTH113 | pathlib-is-file | `os.path.isfile` should be replaced by `.is_file()` | |
| PTH114 | pathlib-is-link | `os.path.islink` should be replaced by `.is_symlink()` | |
| PTH115 | pathlib-readlink | `os.readlink(` should be replaced by `.readlink()` | |
| PTH116 | pathlib-stat | `os.stat` should be replaced by `.stat()` or `.owner()` or `.group()` | |
| PTH117 | pathlib-is-abs | `os.path.isabs` should be replaced by `.is_absolute()` | |
| PTH118 | pathlib-join | `os.path.join` should be replaced by foo_path / "bar" | |
| PTH119 | pathlib-basename | `os.path.basename` should be replaced by `.name` | |
| PTH120 | pathlib-dirname | `os.path.dirname` should be replaced by `.parent` | |
| PTH121 | pathlib-samefile | `os.path.samefile` should be replaced by `.samefile()` | |
| PTH122 | pathlib-splitext | `os.path.splitext` should be replaced by `.suffix` | |
| PTH123 | pathlib-open | `open("foo")` should be replaced by`Path("foo").open()` | |
| PTH124 | pathlib-py-path | `py.path` is in maintenance mode, use `pathlib` instead | |
### eradicate (ERA)
@@ -1135,6 +1212,8 @@ For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI.
| ---- | ---- | ------- | --- |
| PLE0117 | nonlocal-without-binding | Nonlocal name `{name}` found without binding | |
| PLE0118 | used-prior-global-declaration | Name `{name}` is used prior to global declaration on line {line} | |
| PLE0604 | invalid-all-object | Invalid object in `__all__`, must contain only strings | |
| PLE0605 | invalid-all-format | Invalid format for `__all__`, must be `tuple` or `list` | |
| PLE1142 | await-outside-async | `await` should be used within an async function | |
#### Refactor (PLR)
@@ -1153,100 +1232,20 @@ For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI.
| PLW0120 | useless-else-on-loop | Else clause on loop without a break statement, remove the else and de-indent all the code inside it | |
| PLW0602 | global-variable-not-assigned | Using global for `{name}` but no assignment is done | |
### flake8-pie (PIE)
For more, see [flake8-pie](https://pypi.org/project/flake8-pie/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PIE790 | no-unnecessary-pass | Unnecessary `pass` statement | 🛠 |
| PIE794 | dupe-class-field-definitions | Class field `{name}` is defined multiple times | 🛠 |
| PIE796 | prefer-unique-enums | Enum contains duplicate value: `{value}` | |
| PIE800 | no-unnecessary-spread | Unnecessary spread `**` | |
| PIE804 | no-unnecessary-dict-kwargs | Unnecessary `dict` kwargs | |
| PIE807 | prefer-list-builtin | Prefer `list` over useless lambda | 🛠 |
### flake8-commas (COM)
For more, see [flake8-commas](https://pypi.org/project/flake8-commas/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| COM812 | trailing-comma-missing | Trailing comma missing | 🛠 |
| COM818 | trailing-comma-on-bare-tuple-prohibited | Trailing comma on bare tuple prohibited | |
| COM819 | trailing-comma-prohibited | Trailing comma prohibited | 🛠 |
### flake8-no-pep420 (INP)
For more, see [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| INP001 | implicit-namespace-package | File `{filename}` is part of an implicit namespace package. Add an `__init__.py`. | |
### flake8-executable (EXE)
For more, see [flake8-executable](https://pypi.org/project/flake8-executable/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| EXE001 | shebang-not-executable | Shebang is present but file is not executable | |
| EXE002 | shebang-missing-executable-file | The file is executable but no shebang is present | |
| EXE003 | shebang-python | Shebang should contain "python" | |
| EXE004 | shebang-whitespace | Avoid whitespace before shebang | 🛠 |
| EXE005 | shebang-newline | Shebang should be at the beginning of the file | |
### flake8-type-checking (TYP)
For more, see [flake8-type-checking](https://pypi.org/project/flake8-type-checking/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| TYP005 | empty-type-checking-block | Found empty type-checking block | |
### tryceratops (TRY)
For more, see [tryceratops](https://pypi.org/project/tryceratops/1.1.0/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| TRY002 | raise-vanilla-class | Create your own exception | |
| TRY003 | raise-vanilla-args | Avoid specifying long messages outside the exception class | |
| TRY004 | prefer-type-error | Prefer `TypeError` exception for invalid type | 🛠 |
| TRY200 | reraise-no-cause | Use `raise from` to specify exception cause | |
| TRY201 | verbose-raise | Use `raise` without specifying exception name | |
| TRY300 | try-consider-else | Consider `else` block | |
| TRY300 | try-consider-else | Consider moving this statement to an `else` block | |
| TRY301 | raise-within-try | Abstract `raise` to an inner function | |
### flake8-use-pathlib (PTH)
For more, see [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/) on PyPI.
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PTH100 | pathlib-abspath | `os.path.abspath` should be replaced by `.resolve()` | |
| PTH101 | pathlib-chmod | `os.chmod` should be replaced by `.chmod()` | |
| PTH102 | pathlib-mkdir | `os.mkdir` should be replaced by `.mkdir()` | |
| PTH103 | pathlib-makedirs | `os.makedirs` should be replaced by `.mkdir(parents=True)` | |
| PTH104 | pathlib-rename | `os.rename` should be replaced by `.rename()` | |
| PTH105 | pathlib-replace | `os.replace`should be replaced by `.replace()` | |
| PTH106 | pathlib-rmdir | `os.rmdir` should be replaced by `.rmdir()` | |
| PTH107 | pathlib-remove | `os.remove` should be replaced by `.unlink()` | |
| PTH108 | pathlib-unlink | `os.unlink` should be replaced by `.unlink()` | |
| PTH109 | pathlib-getcwd | `os.getcwd()` should be replaced by `Path.cwd()` | |
| PTH110 | pathlib-exists | `os.path.exists` should be replaced by `.exists()` | |
| PTH111 | pathlib-expanduser | `os.path.expanduser` should be replaced by `.expanduser()` | |
| PTH112 | pathlib-is-dir | `os.path.isdir` should be replaced by `.is_dir()` | |
| PTH113 | pathlib-is-file | `os.path.isfile` should be replaced by `.is_file()` | |
| PTH114 | pathlib-is-link | `os.path.islink` should be replaced by `.is_symlink()` | |
| PTH115 | pathlib-readlink | `os.readlink(` should be replaced by `.readlink()` | |
| PTH116 | pathlib-stat | `os.stat` should be replaced by `.stat()` or `.owner()` or `.group()` | |
| PTH117 | pathlib-is-abs | `os.path.isabs` should be replaced by `.is_absolute()` | |
| PTH118 | pathlib-join | `os.path.join` should be replaced by foo_path / "bar" | |
| PTH119 | pathlib-basename | `os.path.basename` should be replaced by `.name` | |
| PTH120 | pathlib-dirname | `os.path.dirname` should be replaced by `.parent` | |
| PTH121 | pathlib-samefile | `os.path.samefile` should be replaced by `.samefile()` | |
| PTH122 | pathlib-splitext | `os.path.splitext` should be replaced by `.suffix` | |
| PTH123 | pathlib-open | `open("foo")` should be replaced by`Path("foo").open()` | |
| PTH124 | pathlib-py-path | `py.path` is in maintenance mode, use `pathlib` instead | |
| TRY400 | error-instead-of-exception | Use `logging.exception` instead of `logging.error` | |
### Ruff-specific rules (RUF)
@@ -1261,8 +1260,12 @@ For more, see [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
<!-- End auto-generated sections. -->
<!-- End section: Rules -->
## Editor Integrations
<!-- Begin section: Editor Integrations -->
### VS Code (Official)
Download the [Ruff VS Code extension](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff),
@@ -1501,8 +1504,12 @@ jobs:
run: ruff --format=github .
```
<!-- End section: Editor Integrations -->
## FAQ
<!-- Begin section: FAQ -->
### Is Ruff compatible with Black?
Yes. Ruff is compatible with [Black](https://github.com/psf/black) out-of-the-box, as long as
@@ -1519,7 +1526,9 @@ automatically convert your existing configuration.)
Ruff can be used as a drop-in replacement for Flake8 when used (1) without or with a small number of
plugins, (2) alongside Black, and (3) on Python 3 code.
Under those conditions, Ruff implements every rule in Flake8.
Under those conditions, Ruff implements every rule in Flake8. In practice, that means Ruff
implements all of the `F` rules (which originate from Pyflakes), along with a subset of the `E` and
`W` rules (which originate from pycodestyle).
Ruff also re-implements some of the most popular Flake8 plugins and related code quality tools
natively, including:
@@ -1543,8 +1552,9 @@ natively, including:
- [`flake8-executable`](https://pypi.org/project/flake8-executable/)
- [`flake8-implicit-str-concat`](https://pypi.org/project/flake8-implicit-str-concat/)
- [`flake8-import-conventions`](https://github.com/joaopalmeiro/flake8-import-conventions)
- [`flake8-logging-format`](https://pypi.org/project/flake8-logging-format/)
- [`flake8-no-pep420`](https://pypi.org/project/flake8-no-pep420)
- [`flake8-pie`](https://pypi.org/project/flake8-pie/) ([#1543](https://github.com/charliermarsh/ruff/issues/1543))
- [`flake8-pie`](https://pypi.org/project/flake8-pie/)
- [`flake8-print`](https://pypi.org/project/flake8-print/)
- [`flake8-pytest-style`](https://pypi.org/project/flake8-pytest-style/)
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
@@ -1552,6 +1562,8 @@ natively, including:
- [`flake8-simplify`](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998))
- [`flake8-super`](https://pypi.org/project/flake8-super/)
- [`flake8-tidy-imports`](https://pypi.org/project/flake8-tidy-imports/)
- [`flake8-type-checking`](https://pypi.org/project/flake8-type-checking/)
- [`flake8-use-pathlib`](https://pypi.org/project/flake8-use-pathlib/)
- [`isort`](https://pypi.org/project/isort/)
- [`mccabe`](https://pypi.org/project/mccabe/)
- [`pandas-vet`](https://pypi.org/project/pandas-vet/)
@@ -1592,6 +1604,21 @@ Unlike Pylint, Ruff is capable of automatically fixing its own lint violations.
Pylint parity is being tracked in [#970](https://github.com/charliermarsh/ruff/issues/970).
### How does Ruff compare to Mypy, or Pyright, or Pyre?
Ruff is a linter, not a type checker. It can detect some of the same problems that a type checker
can, but a type checker will catch certain errors that Ruff would miss. The opposite is also true:
Ruff will catch certain errors that a type checker would typically ignore.
For example, unlike a type checker, Ruff will notify you if an import is unused, by looking for
references to that import in the source code; on the other hand, a type checker could flag that you
passed an integer argument to a function that expects a string, which Ruff would miss. The
tools are complementary.
It's recommended that you use Ruff in conjunction with a type checker, like Mypy, Pyright, or Pyre,
with Ruff providing faster feedback on lint violations and the type checker providing more detailed
feedback on type errors.
### Which tools does Ruff replace?
Today, Ruff can be used to replace Flake8 when used with any of the following plugins:
@@ -1613,8 +1640,9 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
- [`flake8-executable`](https://pypi.org/project/flake8-executable/)
- [`flake8-implicit-str-concat`](https://pypi.org/project/flake8-implicit-str-concat/)
- [`flake8-import-conventions`](https://github.com/joaopalmeiro/flake8-import-conventions)
- [`flake8-logging-format`](https://pypi.org/project/flake8-logging-format/)
- [`flake8-no-pep420`](https://pypi.org/project/flake8-no-pep420)
- [`flake8-pie`](https://pypi.org/project/flake8-pie/) ([#1543](https://github.com/charliermarsh/ruff/issues/1543))
- [`flake8-pie`](https://pypi.org/project/flake8-pie/)
- [`flake8-print`](https://pypi.org/project/flake8-print/)
- [`flake8-pytest-style`](https://pypi.org/project/flake8-pytest-style/)
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
@@ -1622,6 +1650,8 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
- [`flake8-simplify`](https://pypi.org/project/flake8-simplify/) ([#998](https://github.com/charliermarsh/ruff/issues/998))
- [`flake8-super`](https://pypi.org/project/flake8-super/)
- [`flake8-tidy-imports`](https://pypi.org/project/flake8-tidy-imports/)
- [`flake8-type-checking`](https://pypi.org/project/flake8-type-checking/)
- [`flake8-use-pathlib`](https://pypi.org/project/flake8-use-pathlib/)
- [`mccabe`](https://pypi.org/project/mccabe/)
- [`pandas-vet`](https://pypi.org/project/pandas-vet/)
- [`pep8-naming`](https://pypi.org/project/pep8-naming/)
@@ -1692,7 +1722,7 @@ After installing `ruff` and `nbqa`, you can run Ruff over a notebook like so:
Untitled.ipynb:cell_1:2:5: F841 Local variable `x` is assigned to but never used
Untitled.ipynb:cell_2:1:1: E402 Module level import not at top of file
Untitled.ipynb:cell_2:1:8: F401 `os` imported but unused
Found 3 error(s).
Found 3 errors.
1 potentially fixable with the --fix option.
```
@@ -1728,6 +1758,66 @@ matter how they're provided, which avoids accidental incompatibilities and simpl
Run `ruff /path/to/code.py --show-settings` to view the resolved settings for a given file.
### I want to use Ruff, but I don't want to use `pyproject.toml`. Is that possible?
Yes! In lieu of a `pyproject.toml` file, you can use a `ruff.toml` file for configuration. The two
files are functionally equivalent and have an identical schema, with the exception that a `ruff.toml`
file can omit the `[tool.ruff]` section header.
For example, given this `pyproject.toml`:
```toml
[tool.ruff]
line-length = 88
[tool.ruff.pydocstyle]
convention = "google"
```
You could instead use a `ruff.toml` file like so:
```toml
line-length = 88
[pydocstyle]
convention = "google"
```
Ruff doesn't currently support INI files, like `setup.cfg` or `tox.ini`.
### How can I change Ruff's default configuration?
When no configuration file is found, Ruff will look for a user-specific `pyproject.toml` or
`ruff.toml` file as a last resort. This behavior is similar to Flake8's `~/.config/flake8`.
On macOS, Ruff expects that file to be located at `/Users/Alice/Library/Application Support/ruff/ruff.toml`.
On Linux, Ruff expects that file to be located at `/home/alice/.config/ruff/ruff.toml`.
On Windows, Ruff expects that file to be located at `C:\Users\Alice\AppData\Roaming\ruff\ruff.toml`.
For more, see the [`dirs`](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) crate.
### Ruff tried to fix something, but it broke my code. What should I do?
Ruff's autofix is a best-effort mechanism. Given the dynamic nature of Python, it's difficult to
have _complete_ certainty when making changes to code, even for the seemingly trivial fixes.
In the future, Ruff will support enabling autofix behavior based on the safety of the patch.
In the meantime, if you find that the autofix is too aggressive, you can disable it on a per-rule or
per-category basis using the [`unfixable`](#unfixable) mechanic. For example, to disable autofix
for some possibly-unsafe rules, you could add the following to your `pyproject.toml`:
```toml
[tool.ruff]
unfixable = ["B", "SIM", "TRY", "RUF"]
```
If you find a case where Ruff's autofix breaks your code, please file an Issue!
<!-- End section: FAQ -->
## Contributing
Contributions are welcome and hugely appreciated. To get started, check out the
@@ -1864,7 +1954,9 @@ Benchmark 1: find . -type f -name "*.py" | xargs -P 0 pyupgrade --py311-plus
## Reference
### Options
<!-- Begin section: Settings -->
### Top-level
<!-- Sections automatically generated by `cargo dev generate-options`. -->
<!-- Begin auto-generated options sections. -->
@@ -2350,7 +2442,7 @@ Enabled by default.
```toml
[tool.ruff]
respect_gitignore = false
respect-gitignore = false
```
---
@@ -2415,7 +2507,7 @@ my_package/
bar.py
```
The `src` directory should be included in `source` (e.g., `source =
The `src` directory should be included in the `src` option (e.g., `src =
["src"]`), such that when resolving imports, `my_package.foo` is
considered a first-party import.
@@ -2621,6 +2713,24 @@ suppress-none-returning = true
### `flake8-bandit`
#### [`check-typed-exception`](#check-typed-exception)
Whether to disallow `try`-`except`-`pass` (`S110`) for specific exception types. By default,
`try`-`except`-`pass` is only disallowed for `Exception` and `BaseException`.
**Default value**: `false`
**Type**: `bool`
**Example usage**:
```toml
[tool.ruff.flake8-bandit]
check-typed-exception = true
```
---
#### [`hardcoded-tmp-directory`](#hardcoded-tmp-directory)
A list of directories to consider temporary.
@@ -2677,6 +2787,25 @@ extend-immutable-calls = ["fastapi.Depends", "fastapi.Query"]
---
### `flake8-builtins`
#### [`builtins-ignorelist`](#builtins-ignorelist)
Ignore list of builtins.
**Default value**: `[]`
**Type**: `Vec<String>`
**Example usage**:
```toml
[tool.ruff.flake8-builtins]
builtins-ignorelist = ["id"]
```
---
### `flake8-errmsg`
#### [`max-string-length`](#max-string-length)
@@ -3033,6 +3162,45 @@ and can be circumvented via `eval` or `importlib`.
---
### `flake8-type-checking`
#### [`exempt-modules`](#exempt-modules)
Exempt certain modules from needing to be moved into type-checking
blocks.
**Default value**: `["typing"]`
**Type**: `Vec<String>`
**Example usage**:
```toml
[tool.ruff.flake8-type-checking]
exempt-modules = ["typing", "typing_extensions"]
```
---
#### [`strict`](#strict)
Enforce TC001, TC002, and TC003 rules even when valid runtime imports
are present for the same module.
See: https://github.com/snok/flake8-type-checking#strict.
**Default value**: `false`
**Type**: `bool`
**Example usage**:
```toml
[tool.ruff.flake8-type-checking]
strict = true
```
---
### `flake8-unused-arguments`
#### [`ignore-variadic-names`](#ignore-variadic-names)
@@ -3549,6 +3717,8 @@ keep-runtime-typing = true
<!-- End auto-generated options sections. -->
<!-- End section: Settings -->
## License
MIT

View File

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

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.0.232"
version = "0.0.237"
edition = "2021"
[dependencies]
@@ -16,7 +16,7 @@ serde = { version = "1.0.147", features = ["derive"] }
serde_json = { version = "1.0.87" }
strum = { version = "0.24.1", features = ["strum_macros"] }
strum_macros = { version = "0.24.3" }
toml = { version = "0.6.0", features = ["parse"] }
toml = { version = "0.6.0" }
[dev-dependencies]

View File

@@ -1,4 +1,6 @@
//! Utility to generate Ruff's `pyproject.toml` section from a Flake8 INI file.
#![forbid(unsafe_code)]
#![warn(clippy::pedantic)]
#![allow(
clippy::collapsible_else_if,
clippy::collapsible_if,
@@ -11,7 +13,6 @@
clippy::similar_names,
clippy::too_many_lines
)]
#![forbid(unsafe_code)]
use std::path::PathBuf;
@@ -25,7 +26,7 @@ use ruff::flake8_to_ruff::{self, ExternalConfig};
about = "Convert existing Flake8 configuration to Ruff.",
long_about = None
)]
struct Cli {
struct Args {
/// Path to the Flake8 configuration file (e.g., `setup.cfg`, `tox.ini`, or
/// `.flake8`).
#[arg(required = true)]
@@ -40,15 +41,15 @@ struct Cli {
}
fn main() -> Result<()> {
let cli = Cli::parse();
let args = Args::parse();
// Read the INI file.
let mut ini = Ini::new_cs();
ini.set_multiline(true);
let config = ini.load(cli.file).map_err(|msg| anyhow::anyhow!(msg))?;
let config = ini.load(args.file).map_err(|msg| anyhow::anyhow!(msg))?;
// Read the pyproject.toml file.
let pyproject = cli.pyproject.map(flake8_to_ruff::parse).transpose()?;
let pyproject = args.pyproject.map(flake8_to_ruff::parse).transpose()?;
let external_config = pyproject
.as_ref()
.and_then(|pyproject| pyproject.tool.as_ref())
@@ -59,7 +60,7 @@ fn main() -> Result<()> {
.unwrap_or_default();
// Create Ruff's pyproject.toml section.
let pyproject = flake8_to_ruff::convert(&config, &external_config, cli.plugin)?;
let pyproject = flake8_to_ruff::convert(&config, &external_config, args.plugin)?;
println!("{}", toml::to_string_pretty(&pyproject)?);
Ok(())

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016 Joseph Kahn
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Martin Thoma
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.

View File

@@ -1,19 +0,0 @@
Copyright (C) 2012-2018 Steven Myint
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.

View File

@@ -1,22 +0,0 @@
== Flake8 License (MIT) ==
Copyright (C) 2011-2013 Tarek Ziade <tarek@ziade.org>
Copyright (C) 2012-2016 Ian Cordasco <graffatcolmingov@gmail.com>
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.

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2016 Łukasz Langa
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.

View File

@@ -1,45 +0,0 @@
The MIT License (MIT)
Copyright (c) 2017 Thomas Grainger.
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.
Portions of this flake8-commas Software may utilize the following
copyrighted material, the use of which is hereby acknowledged.
Original flake8-commas: https://github.com/trevorcreech/flake8-commas/commit/e8563b71b1d5442e102c8734c11cb5202284293d
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.

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 Timothy Edmund Crosley
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.

View File

@@ -1,23 +0,0 @@
Copyright © 2013 Florent Xicluna <florent.xicluna@gmail.com>
Licensed under the terms of the Expat License
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.

View File

@@ -1,25 +0,0 @@
Copyright © 2006-2009 Johann C. Rocholl <johann@rocholl.net>
Copyright © 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
Copyright © 2014-2020 Ian Lee <IanLee1521@gmail.com>
Licensed under the terms of the Expat License
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.

View File

@@ -1,23 +0,0 @@
Copyright (c) 2012 GreenSteam, <http://greensteam.dk/>
Copyright (c) 2014-2020 Amir Rachum, <http://amir.rachum.com/>
Copyright (c) 2020 Sambhav Kothari, <https://github.com/samj1912>
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.

View File

@@ -1,21 +0,0 @@
Copyright 2005-2011 Divmod, Inc.
Copyright 2013-2014 Florent Xicluna
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.

View File

@@ -1,22 +0,0 @@
MIT License
Copyright (c) 2021 Rodolphe Pelloux-Prayer
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 RustPython Team
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Adam Johnson
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020 Adam Johnson
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Adam Johnson
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 Afonasev Evgeniy
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.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2019 Anthony Sottile
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.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2017 Anthony Sottile
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.

View File

@@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 Elijah Andrews
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.

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2019 Dylan Turner
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016 Joseph Kahn
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2021 João Palmeiro
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 Nathan Hoad
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.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2018 Anthony Sottile
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 - Present S. Co1
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.

View File

@@ -1,19 +0,0 @@
Copyright (c) 2017 Tyler Wince
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.

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 Nikita Sobolev
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.

View File

@@ -1,17 +0,0 @@
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.

49
mkdocs.template.yml Normal file
View File

@@ -0,0 +1,49 @@
site_name: Ruff
theme:
name: material
features:
- navigation.instant
- navigation.tracking
- content.code.annotate
- toc.integrate
- toc.follow
- navigation.path
- navigation.top
- content.code.copy
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: red
toggle:
icon: material/weather-sunny
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: red
toggle:
icon: material/weather-night
name: Switch to light mode
repo_url: https://github.com/charliermarsh/ruff
repo_name: ruff
site_author: charliermarsh
site_url: https://beta.ruff.rs/docs/
site_dir: site/docs
markdown_extensions:
- toc:
permalink: "#"
- pymdownx.snippets:
- pymdownx.magiclink:
- attr_list:
- md_in_html:
- pymdownx.highlight:
anchor_linenums: true
- pymdownx.inlinehilite:
- pymdownx.superfences:
- markdown.extensions.attr_list:
- pymdownx.keys:
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.highlight:
anchor_linenums: true
plugins:
- search

View File

@@ -7,7 +7,7 @@ build-backend = "maturin"
[project]
name = "ruff"
version = "0.0.232"
version = "0.0.237"
description = "An extremely fast Python linter, written in Rust."
authors = [
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
@@ -15,6 +15,7 @@ authors = [
maintainers = [
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
]
readme = "README.md"
requires-python = ">=3.7"
license = { file = "LICENSE" }
keywords = ["automation", "flake8", "pycodestyle", "pyflakes", "pylint", "clippy"]

View File

@@ -39,3 +39,10 @@ class Foo:
# Error
def __init__(self, foo: int):
...
# Error used to be ok for a moment since the mere presence
# of a vararg falsely indicated that the function has a typed argument.
class Foo:
def __init__(self, *arg):
...

View File

@@ -0,0 +1,14 @@
try:
pass
except Exception:
pass
try:
pass
except:
pass
try:
pass
except ValueError:
pass

View File

@@ -61,3 +61,34 @@ except Exception as e:
raise bad
except BaseException:
pass
import logging
try:
pass
except Exception:
logging.error("...")
try:
pass
except Exception:
logging.error("...", exc_info=False)
try:
pass
except Exception:
logging.error("...", exc_info=None)
try:
pass
except Exception:
logging.exception("...")
try:
pass
except Exception:
logging.error("...", exc_info=True)

View File

@@ -29,3 +29,19 @@ def strange_generator():
for i, (j, (k, l)) in strange_generator(): # i, k not used
print(j, l)
FMT = "{foo} {bar}"
for foo, bar in [(1, 2)]:
if foo:
print(FMT.format(**locals()))
for foo, bar in [(1, 2)]:
if foo:
print(FMT.format(**globals()))
for foo, bar in [(1, 2)]:
if foo:
print(FMT.format(**vars()))
for foo, bar in [(1, 2)]:
print(FMT.format(foo=foo, bar=eval('bar')))

View File

@@ -1,7 +1,7 @@
"""
Should emit:
B009 - Line 18, 19, 20, 21, 22
B010 - Line 33, 34, 35, 36
B009 - Line 19, 20, 21, 22, 23, 24
B010 - Line 40, 41, 42, 43, 44, 45
"""
# Valid getattr usage
@@ -13,10 +13,12 @@ getattr(foo, bar, None)
getattr(foo, "123abc")
getattr(foo, r"123\abc")
getattr(foo, "except")
getattr(foo, "__123abc")
# Invalid usage
getattr(foo, "bar")
getattr(foo, "_123abc")
getattr(foo, "__123abc__")
getattr(foo, "abc123")
getattr(foo, r"abc123")
_ = lambda x: getattr(x, "bar")
@@ -27,6 +29,7 @@ if getattr(x, "bar"):
setattr(foo, bar, None)
setattr(foo, "bar{foo}".format(foo="a"), None)
setattr(foo, "123abc", None)
setattr(foo, "__123abc", None)
setattr(foo, r"123\abc", None)
setattr(foo, "except", None)
_ = lambda x: setattr(x, "bar", 1)
@@ -36,6 +39,7 @@ if setattr(x, "bar", 1):
# Invalid usage
setattr(foo, "bar", None)
setattr(foo, "_123abc", None)
setattr(foo, "__123abc__", None)
setattr(foo, "abc123", None)
setattr(foo, r"abc123", None)
setattr(foo.bar, r"baz", None)

View File

@@ -0,0 +1,3 @@
import logging
logging.info("Hello {}".format("World!"))

View File

@@ -0,0 +1,3 @@
import logging
logging.info("Hello %s" % "World!")

View File

@@ -0,0 +1,3 @@
import logging
logging.info("Hello" + " " + "World!")

View File

@@ -0,0 +1,4 @@
import logging
name = "world"
logging.info(f"Hello {name}")

View File

@@ -0,0 +1,3 @@
import logging
logging.warn("Hello World!")

View File

@@ -0,0 +1,8 @@
import logging
logging.info(
"Hello world!",
extra={
"name": "foobar",
},
)

View File

@@ -0,0 +1,8 @@
import logging
logging.info(
"Hello world!",
extra=dict(
name="foobar",
),
)

View File

@@ -0,0 +1,3 @@
import logging
logging.error('Hello World', exc_info=True)

View File

@@ -0,0 +1,3 @@
import logging
logging.exception('Hello World', exc_info=True)

View File

@@ -0,0 +1,7 @@
import argparse
from pathlib import Path
parser = argparse.ArgumentParser()
parser.add_argument("target_dir", type=Path)
args = parser.parse_args()
parser.error(f"Target directory {args.target_dir} does not exist")

View File

@@ -0,0 +1,8 @@
import logging
logging.info(
"Hello {world}!",
extra=dict(
world="World",
),
)

View File

@@ -0,0 +1,8 @@
import logging
logging.info(
"Hello {world}!",
extra=dict(
world="{}".format("World"),
),
)

View File

@@ -0,0 +1,3 @@
import logging
logging.info("Hello World!")

View File

@@ -0,0 +1,3 @@
import warnings
warnings.warn("Hello World!")

View File

@@ -1,12 +1,12 @@
class Foo:
"""buzz"""
pass # PIE790
pass
if foo:
"""foo"""
pass # PIE790
pass
def multi_statement() -> None:
@@ -18,28 +18,28 @@ if foo:
pass
else:
"""bar"""
pass # PIE790
pass
while True:
pass
else:
"""bar"""
pass # PIE790
pass
for _ in range(10):
pass
else:
"""bar"""
pass # PIE790
pass
async for _ in range(10):
pass
else:
"""bar"""
pass # PIE790
pass
def foo() -> None:
@@ -47,7 +47,7 @@ def foo() -> None:
buzz
"""
pass # PIE790
pass
async def foo():
@@ -55,14 +55,14 @@ async def foo():
buzz
"""
pass # PIE790
pass
try:
"""
buzz
"""
pass # PIE790
pass
except ValueError:
pass
@@ -71,29 +71,34 @@ try:
bar()
except ValueError:
"""bar"""
pass # PIE790
pass
for _ in range(10):
"""buzz"""
pass # PIE790
pass
async for _ in range(10):
"""buzz"""
pass # PIE790
pass
while cond:
"""buzz"""
pass # PIE790
pass
with bar:
"""buzz"""
pass # PIE790
pass
async with bar:
"""buzz"""
pass # PIE790
pass
def foo() -> None:
"""buzz"""
pass # bar
class Foo:

View File

@@ -1,15 +1,26 @@
# Errors
"yoda" == compare # SIM300
'yoda' == compare # SIM300
"yoda" == compare # SIM300
42 == age # SIM300
("a", "b") == compare # SIM300
"yoda" <= compare # SIM300
'yoda' < compare # SIM300
"yoda" < compare # SIM300
42 > age # SIM300
YODA == age # SIM300
YODA > age # SIM300
YODA >= age # SIM300
JediOrder.YODA == age # SIM300
# OK
compare == "yoda"
age == 42
compare == ("a", "b")
x == y
"yoda" == compare == 1
"yoda" == compare == someothervar
"yoda" == "yoda"
age == YODA
age < YODA
age <= YODA
YODA == YODA
age == JediOrder.YODA

View File

@@ -0,0 +1,28 @@
"""Tests to determine first-party import classification.
For typing-only import detection tests, see `TCH002.py`.
"""
def f():
import TYP001
x: TYP001
def f():
import TYP001
print(TYP001)
def f():
from . import TYP001
x: TYP001
def f():
from . import TYP001
print(TYP001)

View File

@@ -0,0 +1,148 @@
"""Tests to determine accurate detection of typing-only imports."""
def f():
import pandas as pd # TCH002
x: pd.DataFrame
def f():
from pandas import DataFrame # TCH002
x: DataFrame
def f():
from pandas import DataFrame as df # TCH002
x: df
def f():
import pandas as pd # TCH002
x: pd.DataFrame = 1
def f():
from pandas import DataFrame # TCH002
x: DataFrame = 2
def f():
from pandas import DataFrame as df # TCH002
x: df = 3
def f():
import pandas as pd # TCH002
x: "pd.DataFrame" = 1
def f():
import pandas as pd
x = dict["pd.DataFrame", "pd.DataFrame"] # TCH002
def f():
import pandas as pd
print(pd)
def f():
from pandas import DataFrame
print(DataFrame)
def f():
from pandas import DataFrame
def f():
print(DataFrame)
def f():
from typing import Dict, Any
def example() -> Any:
return 1
x: Dict[int] = 20
def f():
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Dict
x: Dict[int] = 20
def f():
from pathlib import Path
class ImportVisitor(ast.NodeTransformer):
def __init__(self, cwd: Path) -> None:
self.cwd = cwd
origin = Path(spec.origin)
class ExampleClass:
def __init__(self):
self.cwd = Path(pandas.getcwd())
def f():
import pandas
class Migration:
enum = pandas
def f():
import pandas
class Migration:
enum = pandas.EnumClass
def f():
from typing import TYPE_CHECKING
from pandas import y
if TYPE_CHECKING:
_type = x
else:
_type = y
def f():
from typing import TYPE_CHECKING
from pandas import y
if TYPE_CHECKING:
_type = x
elif True:
_type = y
def f():
from typing import cast
import pandas as pd
x = cast(pd.DataFrame, 2)
def f():
import pandas as pd
x = dict[pd.DataFrame, pd.DataFrame]

View File

@@ -0,0 +1,16 @@
"""Tests to determine standard library import classification.
For typing-only import detection tests, see `TCH002.py`.
"""
def f():
import os
x: os
def f():
import os
print(os)

View File

@@ -0,0 +1,5 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from datetime import datetime
x = datetime

View File

@@ -0,0 +1,8 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from datetime import date
def example():
return date()

View File

@@ -0,0 +1,6 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Any
CustomType = Any

View File

@@ -0,0 +1,11 @@
from typing import TYPE_CHECKING, Type
if TYPE_CHECKING:
from typing import Any
def example(*args: Any, **kwargs: Any):
return
my_type: Type[Any] | Any

View File

@@ -0,0 +1,8 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import List, Sequence, Set
def example(a: List[int], /, b: Sequence[int], *, c: Set[int]):
return

View File

@@ -0,0 +1,10 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from pandas import DataFrame
def example():
from pandas import DataFrame
x = DataFrame

View File

@@ -0,0 +1,10 @@
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import AsyncIterator, List
class Example:
async def example(self) -> AsyncIterator[List[str]]:
yield 0

View File

@@ -0,0 +1,7 @@
from typing import TYPE_CHECKING
from weakref import WeakKeyDictionary
if TYPE_CHECKING:
from typing import Any
d = WeakKeyDictionary["Any", "Any"]()

View File

@@ -1,7 +1,7 @@
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
pass # TYP005
pass # TCH005
def example():

View File

@@ -0,0 +1,16 @@
def f():
import pandas as pd
x: pd.DataFrame
def f():
import pandas.core.frame as pd
x: pd.DataFrame
def f():
import flask
x: flask

View File

@@ -0,0 +1,54 @@
def f():
# Even in strict mode, this shouldn't rase an error, since `pkg` is used at runtime,
# and implicitly imports `pkg.bar`.
import pkg
import pkg.bar
def test(value: pkg.bar.A):
return pkg.B()
def f():
# Even in strict mode, this shouldn't rase an error, since `pkg.bar` is used at
# runtime, and implicitly imports `pkg`.
import pkg
import pkg.bar
def test(value: pkg.A):
return pkg.bar.B()
def f():
# In un-strict mode, this shouldn't rase an error, since `pkg` is used at runtime.
import pkg
from pkg import A
def test(value: A):
return pkg.B()
def f():
# In un-strict mode, this shouldn't rase an error, since `pkg` is used at runtime.
from pkg import A, B
def test(value: A):
return B()
def f():
# Even in strict mode, this shouldn't rase an error, since `pkg.baz` is used at
# runtime, and implicitly imports `pkg.bar`.
import pkg.bar
import pkg.baz
def test(value: pkg.bar.A):
return pkg.baz.B()
def f():
# In un-strict mode, this _should_ rase an error, since `pkg` is used at runtime.
import pkg
from pkg.bar import A
def test(value: A):
return pkg.B()

View File

@@ -29,3 +29,4 @@ os.path.splitext(p)
with open(p) as fp:
fp.read()
open(p).close()
os.getcwdb(p)

View File

@@ -0,0 +1,3 @@
from pathlib import Path
(Path("") / "").open()

View File

@@ -6,7 +6,7 @@ from typing import NewType
GLOBAL: str = "foo"
def f():
def assign():
global GLOBAL
GLOBAL = "bar"
lower = 0
@@ -18,4 +18,18 @@ def f():
MyObj2 = namedtuple("MyObj12", ["a", "b"])
T = TypeVar("T")
UserId = NewType('UserId', int)
UserId = NewType("UserId", int)
def aug_assign(rank, world_size):
global CURRENT_PORT
CURRENT_PORT += 1
if CURRENT_PORT > MAX_PORT:
CURRENT_PORT = START_PORT
def loop_assign():
global CURRENT_PORT
for CURRENT_PORT in range(5):
pass

View File

@@ -0,0 +1,6 @@
"""Test: explicit re-export of shadowed builtins."""
from concurrent.futures import (
CancelledError as CancelledError,
TimeoutError as TimeoutError,
)

View File

@@ -0,0 +1,11 @@
__all__ = (
None, # [invalid-all-object]
Fruit,
Worm,
)
class Fruit:
pass
class Worm:
pass

View File

@@ -0,0 +1,7 @@
__all__ = ("CONST") # [invalid-all-format]
__all__ = ["Hello"] + {"world"} # [invalid-all-format]
__all__ += {"world"} # [invalid-all-format]
__all__ = {"world"} + ["Hello"] # [invalid-all-format]

View File

@@ -2,31 +2,37 @@
# Errors.
###
def f():
global x
global X
def f():
global x
global X
print(x)
print(X)
###
# Non-errors.
###
def f():
global x
global X
x = 1
X = 1
def f():
global x
global X
(x, y) = (1, 2)
(X, y) = (1, 2)
def f():
global x
global X
del x
del X
def f():
global X
X += 1

View File

@@ -0,0 +1,31 @@
"""
Violation:
Raising vanilla exception with custom message means it should be customized.
"""
from somewhere import exceptions
def func():
a = 1
if a == 1:
raise Exception("Custom message")
b = 1
if b == 1:
raise Exception
def ignore():
try:
a = 1
except Exception as ex:
# This is another violation, but this specific analyzer shouldn't care
raise ex
def anotherfunc():
a = 1
if a == 1:
raise exceptions.Exception("Another except") # That's fine

View File

@@ -0,0 +1,54 @@
class CustomException(Exception):
pass
def func():
a = 1
if a == 1:
raise CustomException("Long message")
elif a == 2:
raise CustomException("Short") # This is acceptable
elif a == 3:
raise CustomException("its_code_not_message") # This is acceptable
def ignore():
try:
a = 1
except Exception as ex:
# This is another violation, but this specific analyzer shouldn't care
raise ex
class BadArgCantBeEven(Exception):
pass
class GoodArgCantBeEven(Exception):
def __init__(self, arg):
super().__init__(f"The argument '{arg}' should be even")
def bad(a):
if a % 2 == 0:
raise BadArgCantBeEven(f"The argument '{a}' should be even")
def another_bad(a):
if a % 2 == 0:
raise BadArgCantBeEven(f"The argument {a} should not be odd.")
def and_another_bad(a):
if a % 2 == 0:
raise BadArgCantBeEven("The argument `a` should not be odd.")
def good(a: int):
if a % 2 == 0:
raise GoodArgCantBeEven(a)
def another_good(a):
if a % 2 == 0:
raise GoodArgCantBeEven(a)

View File

@@ -94,7 +94,7 @@ def incorrect_MemoryError(some_arg):
# not multiline is on purpose for fix
raise MemoryError(
"..."
)
)
def incorrect_NameError(some_arg):
@@ -294,3 +294,39 @@ def multiple_ifs(some_args):
raise ValueError("...") # this is ok if we don't simplify
else:
pass
def early_return():
if isinstance(this, some_type):
if x in this:
return
raise ValueError(f"{this} has a problem") # this is ok
def early_break():
for x in this:
if isinstance(this, some_type):
if x in this:
break
raise ValueError(f"{this} has a problem") # this is ok
def early_continue():
for x in this:
if isinstance(this, some_type):
if x in this:
continue
raise ValueError(f"{this} has a problem") # this is ok
def early_return_else():
if isinstance(this, some_type):
pass
else:
if x in this:
return
raise ValueError(f"{this} has a problem") # this is ok

View File

@@ -1,27 +1,32 @@
"""
Violation:
Reraise without using 'from'
"""
class MyException(Exception):
pass
class MainFunctionFailed(Exception):
pass
def process():
raise MyException
def bad():
def func():
try:
process()
except MyException:
raise MainFunctionFailed()
a = 1
except Exception:
raise MyException()
def func():
try:
a = 1
except Exception:
if True:
raise MainFunctionFailed()
raise MyException()
def good():
try:
process()
except MyException as ex:
raise MainFunctionFailed() from ex
a = 1
except MyException as e:
raise e # This is verbose violation, shouldn't trigger no cause
except Exception:
raise # Just re-raising don't need 'from'

View File

@@ -0,0 +1,62 @@
"""
Violation:
Use '.exception' over '.error' inside except blocks
"""
import logging
logger = logging.getLogger(__name__)
def bad():
try:
a = 1
except Exception:
logging.error("Context message here")
if True:
logging.error("Context message here")
def bad():
try:
a = 1
except Exception:
logger.error("Context message here")
if True:
logger.error("Context message here")
def bad():
try:
a = 1
except Exception:
log.error("Context message here")
if True:
log.error("Context message here")
def bad():
try:
a = 1
except Exception:
self.logger.error("Context message here")
if True:
self.logger.error("Context message here")
def good():
try:
a = 1
except Exception:
logger.exception("Context message here")
def good():
try:
a = 1
except Exception:
foo.exception("Context message here")

View File

@@ -16,7 +16,7 @@ resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-s
resources/test/project/examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
resources/test/project/project/file.py:1:8: F401 `os` imported but unused
resources/test/project/project/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
Found 7 error(s).
Found 7 errors.
7 potentially fixable with the --fix option.
```
@@ -31,7 +31,7 @@ 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 error(s).
Found 7 errors.
7 potentially fixable with the --fix option.
```
@@ -42,7 +42,7 @@ files:
∴ (cd resources/test/project/examples/docs && cargo run .)
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 error(s).
Found 2 errors.
2 potentially fixable with the --fix option.
```
@@ -60,7 +60,7 @@ resources/test/project/examples/docs/docs/file.py:3:8: F401 `numpy` imported but
resources/test/project/examples/docs/docs/file.py:4:27: F401 `docs.concepts.file` imported but unused
resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
resources/test/project/project/file.py:1:8: F401 `os` imported but unused
Found 9 error(s).
Found 9 errors.
9 potentially fixable with the --fix option.
```
@@ -73,7 +73,7 @@ docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never
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 error(s).
Found 4 errors.
4 potentially fixable with the --fix option.
```
@@ -82,7 +82,7 @@ Passing an excluded directory directly should report errors in the contained fil
```
∴ cargo run resources/test/project/examples/excluded/
resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
Found 1 error(s).
Found 1 error.
1 potentially fixable with the --fix option.
```

View File

@@ -230,6 +230,17 @@
}
]
},
"flake8-type-checking": {
"description": "Options for the `flake8-type-checking` plugin.",
"anyOf": [
{
"$ref": "#/definitions/Flake8TypeCheckingOptions"
},
{
"type": "null"
}
]
},
"flake8-unused-arguments": {
"description": "Options for the `flake8-unused-arguments` plugin.",
"anyOf": [
@@ -421,7 +432,7 @@
]
},
"src": {
"description": "The source code paths to consider, e.g., when resolving first- vs. third-party imports.\n\nAs an example: given a Python package structure like:\n\n```text my_package/ pyproject.toml src/ my_package/ __init__.py foo.py bar.py ```\n\nThe `src` directory should be included in `source` (e.g., `source = [\"src\"]`), such that when resolving imports, `my_package.foo` is considered a first-party import.\n\nThis field supports globs. For example, if you have a series of Python packages in a `python_modules` directory, `src = [\"python_modules/*\"]` would expand to incorporate all of the packages in that directory. User home directory and environment variables will also be expanded.",
"description": "The source code paths to consider, e.g., when resolving first- vs. third-party imports.\n\nAs an example: given a Python package structure like:\n\n```text my_package/ pyproject.toml src/ my_package/ __init__.py foo.py bar.py ```\n\nThe `src` directory should be included in the `src` option (e.g., `src = [\"src\"]`), such that when resolving imports, `my_package.foo` is considered a first-party import.\n\nThis field supports globs. For example, if you have a series of Python packages in a `python_modules` directory, `src = [\"python_modules/*\"]` would expand to incorporate all of the packages in that directory. User home directory and environment variables will also be expanded.",
"type": [
"array",
"null"
@@ -567,6 +578,13 @@
"Flake8BanditOptions": {
"type": "object",
"properties": {
"check-typed-exception": {
"description": "Whether to disallow `try`-`except`-`pass` (`S110`) for specific exception types. By default, `try`-`except`-`pass` is only disallowed for `Exception` and `BaseException`.",
"type": [
"boolean",
"null"
]
},
"hardcoded-tmp-directory": {
"description": "A list of directories to consider temporary.",
"type": [
@@ -822,6 +840,29 @@
},
"additionalProperties": false
},
"Flake8TypeCheckingOptions": {
"type": "object",
"properties": {
"exempt-modules": {
"description": "Exempt certain modules from needing to be moved into type-checking blocks.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"strict": {
"description": "Enforce TC001, TC002, and TC003 rules even when valid runtime imports are present for the same module. See: https://github.com/snok/flake8-type-checking#strict.",
"type": [
"boolean",
"null"
]
}
},
"additionalProperties": false
},
"Flake8UnusedArgumentsOptions": {
"type": "object",
"properties": {
@@ -947,7 +988,7 @@
"description": "Whether to place \"closer\" imports (fewer `.` characters, most local) before \"further\" imports (more `.` characters, least local), or vice versa.\n\nThe default (\"furthest-to-closest\") is equivalent to isort's `reverse-relative` default (`reverse-relative = false`); setting this to \"closest-to-furthest\" is equivalent to isort's `reverse-relative = true`.",
"anyOf": [
{
"$ref": "#/definitions/RelatveImportsOrder"
"$ref": "#/definitions/RelativeImportsOrder"
},
{
"type": "null"
@@ -1138,10 +1179,6 @@
"PythonVersion": {
"type": "string",
"enum": [
"py33",
"py34",
"py35",
"py36",
"py37",
"py38",
"py39",
@@ -1167,7 +1204,7 @@
}
]
},
"RelatveImportsOrder": {
"RelativeImportsOrder": {
"oneOf": [
{
"description": "Place \"closer\" imports (fewer `.` characters, most local) before \"further\" imports (more `.` characters, least local).",
@@ -1479,6 +1516,22 @@
"FBT001",
"FBT002",
"FBT003",
"G",
"G0",
"G00",
"G001",
"G002",
"G003",
"G004",
"G01",
"G010",
"G1",
"G10",
"G101",
"G2",
"G20",
"G201",
"G202",
"I",
"I0",
"I00",
@@ -1569,6 +1622,10 @@
"PLE011",
"PLE0117",
"PLE0118",
"PLE06",
"PLE060",
"PLE0604",
"PLE0605",
"PLE1",
"PLE11",
"PLE114",
@@ -1703,6 +1760,7 @@
"S107",
"S108",
"S11",
"S110",
"S113",
"S3",
"S32",
@@ -1764,6 +1822,14 @@
"T20",
"T201",
"T203",
"TCH",
"TCH0",
"TCH00",
"TCH001",
"TCH002",
"TCH003",
"TCH004",
"TCH005",
"TID",
"TID2",
"TID25",
@@ -1772,6 +1838,8 @@
"TRY",
"TRY0",
"TRY00",
"TRY002",
"TRY003",
"TRY004",
"TRY2",
"TRY20",
@@ -1781,10 +1849,9 @@
"TRY30",
"TRY300",
"TRY301",
"TYP",
"TYP0",
"TYP00",
"TYP005",
"TRY4",
"TRY40",
"TRY400",
"UP",
"UP0",
"UP00",

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_cli"
version = "0.0.232"
version = "0.0.237"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
edition = "2021"
rust-version = "1.65.0"

View File

@@ -15,135 +15,206 @@ use rustc_hash::FxHashMap;
#[command(
author,
name = "ruff",
about = "Ruff: An extremely fast Python linter."
about = "Ruff: An extremely fast Python linter.",
after_help = "For help with a specific command, see: `ruff help <command>`."
)]
#[command(version)]
#[allow(clippy::struct_excessive_bools)]
pub struct Cli {
#[arg(required_unless_present_any = ["clean", "explain", "generate_shell_completion"])]
pub struct Args {
#[command(subcommand)]
pub command: Command,
#[clap(flatten)]
pub log_level_args: LogLevelArgs,
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, clap::Subcommand)]
pub enum Command {
/// Run Ruff on the given files or directories (default).
Check(CheckArgs),
/// Explain a rule.
#[clap(alias = "--explain")]
Rule {
#[arg(value_parser=Rule::from_code)]
rule: &'static Rule,
/// Output format
#[arg(long, value_enum, default_value = "text")]
format: HelpFormat,
},
/// Clear any caches in the current directory and any subdirectories.
#[clap(alias = "--clean")]
Clean,
/// Generate shell completion.
#[clap(alias = "--generate-shell-completion", hide = true)]
GenerateShellCompletion { shell: clap_complete_command::Shell },
}
#[derive(Debug, clap::Args)]
#[allow(clippy::struct_excessive_bools, clippy::module_name_repetitions)]
pub struct CheckArgs {
/// List of files or directories to check.
pub files: Vec<PathBuf>,
/// Path to the `pyproject.toml` or `ruff.toml` file to use for
/// configuration.
#[arg(long, conflicts_with = "isolated")]
pub config: Option<PathBuf>,
/// Enable verbose logging.
#[arg(short, long, group = "verbosity")]
pub verbose: bool,
/// Print lint violations, but nothing else.
#[arg(short, long, group = "verbosity")]
pub quiet: bool,
/// Disable all logging (but still exit with status code "1" upon detecting
/// lint violations).
#[arg(short, long, group = "verbosity")]
pub silent: bool,
/// Exit with status code "0", even upon detecting lint violations.
#[arg(short, long)]
pub exit_zero: bool,
/// Run in watch mode by re-running whenever files change.
#[arg(short, long)]
pub watch: bool,
/// Attempt to automatically fix lint violations.
#[arg(long, overrides_with("no_fix"))]
fix: bool,
#[clap(long, overrides_with("fix"), hide = true)]
no_fix: bool,
/// Show violations with source code.
#[arg(long, overrides_with("no_show_source"))]
show_source: bool,
#[clap(long, overrides_with("show_source"), hide = true)]
no_show_source: bool,
/// Avoid writing any fixed files back; instead, output a diff for each
/// changed file to stdout.
#[arg(long)]
pub diff: bool,
/// Run in watch mode by re-running whenever files change.
#[arg(short, long)]
pub watch: bool,
/// Fix any fixable lint violations, but don't report on leftover
/// violations. Implies `--fix`.
#[arg(long, overrides_with("no_fix_only"))]
fix_only: bool,
#[clap(long, overrides_with("fix_only"), hide = true)]
no_fix_only: bool,
/// Avoid writing any fixed files back; instead, output a diff for each
/// changed file to stdout.
#[arg(long)]
pub diff: bool,
/// Disable cache reads.
#[arg(short, long)]
pub no_cache: bool,
/// Ignore all configuration files.
#[arg(long, conflicts_with = "config")]
pub isolated: bool,
/// Comma-separated list of rule codes to enable (or ALL, to enable all
/// rules).
#[arg(long, value_delimiter = ',', value_name = "RULE_CODE")]
pub select: Option<Vec<RuleSelector>>,
/// Like --select, but adds additional rule codes on top of the selected
/// ones.
#[arg(long, value_delimiter = ',', value_name = "RULE_CODE")]
pub extend_select: Option<Vec<RuleSelector>>,
/// Comma-separated list of rule codes to disable.
#[arg(long, value_delimiter = ',', value_name = "RULE_CODE")]
pub ignore: Option<Vec<RuleSelector>>,
/// Like --ignore, but adds additional rule codes on top of the ignored
/// ones.
#[arg(long, value_delimiter = ',', value_name = "RULE_CODE")]
pub extend_ignore: Option<Vec<RuleSelector>>,
/// List of paths, used to omit files and/or directories from analysis.
#[arg(long, value_delimiter = ',', value_name = "FILE_PATTERN")]
pub exclude: Option<Vec<FilePattern>>,
/// Like --exclude, but adds additional files and directories on top of
/// those already excluded.
#[arg(long, value_delimiter = ',', value_name = "FILE_PATTERN")]
pub extend_exclude: Option<Vec<FilePattern>>,
/// List of rule codes to treat as eligible for autofix. Only applicable
/// when autofix itself is enabled (e.g., via `--fix`).
#[arg(long, value_delimiter = ',', value_name = "RULE_CODE")]
pub fixable: Option<Vec<RuleSelector>>,
/// List of rule codes to treat as ineligible for autofix. Only applicable
/// when autofix itself is enabled (e.g., via `--fix`).
#[arg(long, value_delimiter = ',', value_name = "RULE_CODE")]
pub unfixable: Option<Vec<RuleSelector>>,
/// List of mappings from file pattern to code to exclude
#[arg(long, value_delimiter = ',')]
pub per_file_ignores: Option<Vec<PatternPrefixPair>>,
/// Output serialization format for violations.
#[arg(long, value_enum, env = "RUFF_FORMAT")]
pub format: Option<SerializationFormat>,
/// The name of the file when passing it through stdin.
#[arg(long)]
pub stdin_filename: Option<PathBuf>,
/// Path to the cache directory.
#[arg(long, env = "RUFF_CACHE_DIR")]
pub cache_dir: Option<PathBuf>,
/// Show violations with source code.
#[arg(long, overrides_with("no_show_source"))]
show_source: bool,
#[clap(long, overrides_with("show_source"), hide = true)]
no_show_source: bool,
/// Path to the `pyproject.toml` or `ruff.toml` file to use for
/// configuration.
#[arg(long, conflicts_with = "isolated")]
pub config: Option<PathBuf>,
/// Comma-separated list of rule codes to enable (or ALL, to enable all
/// rules).
#[arg(
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
)]
pub select: Option<Vec<RuleSelector>>,
/// Comma-separated list of rule codes to disable.
#[arg(
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
)]
pub ignore: Option<Vec<RuleSelector>>,
/// Like --select, but adds additional rule codes on top of the selected
/// ones.
#[arg(
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
)]
pub extend_select: Option<Vec<RuleSelector>>,
/// Like --ignore, but adds additional rule codes on top of the ignored
/// ones.
#[arg(
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
)]
pub extend_ignore: Option<Vec<RuleSelector>>,
/// List of mappings from file pattern to code to exclude
#[arg(long, value_delimiter = ',', help_heading = "Rule selection")]
pub per_file_ignores: Option<Vec<PatternPrefixPair>>,
/// List of paths, used to omit files and/or directories from analysis.
#[arg(
long,
value_delimiter = ',',
value_name = "FILE_PATTERN",
help_heading = "File selection"
)]
pub exclude: Option<Vec<FilePattern>>,
/// Like --exclude, but adds additional files and directories on top of
/// those already excluded.
#[arg(
long,
value_delimiter = ',',
value_name = "FILE_PATTERN",
help_heading = "File selection"
)]
pub extend_exclude: Option<Vec<FilePattern>>,
/// List of rule codes to treat as eligible for autofix. Only applicable
/// when autofix itself is enabled (e.g., via `--fix`).
#[arg(
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
)]
pub fixable: Option<Vec<RuleSelector>>,
/// List of rule codes to treat as ineligible for autofix. Only applicable
/// when autofix itself is enabled (e.g., via `--fix`).
#[arg(
long,
value_delimiter = ',',
value_name = "RULE_CODE",
help_heading = "Rule selection"
)]
pub unfixable: Option<Vec<RuleSelector>>,
/// Respect file exclusions via `.gitignore` and other standard ignore
/// files.
#[arg(long, overrides_with("no_respect_gitignore"))]
#[arg(
long,
overrides_with("no_respect_gitignore"),
help_heading = "File selection"
)]
respect_gitignore: bool,
#[clap(long, overrides_with("respect_gitignore"), hide = true)]
no_respect_gitignore: bool,
/// Enforce exclusions, even for paths passed to Ruff directly on the
/// command-line.
#[arg(long, overrides_with("no_force_exclude"))]
#[arg(
long,
overrides_with("no_force_exclude"),
help_heading = "File selection"
)]
force_exclude: bool,
#[clap(long, overrides_with("force_exclude"), hide = true)]
no_force_exclude: bool,
/// Enable or disable automatic update checks.
#[arg(long, overrides_with("no_update_check"))]
update_check: bool,
#[clap(long, overrides_with("update_check"), hide = true)]
no_update_check: bool,
/// Regular expression matching the name of dummy variables.
#[arg(long)]
pub dummy_variable_rgx: Option<Regex>,
/// The minimum Python version that should be supported.
#[arg(long)]
#[arg(long, help_heading = "Rule configuration")]
pub target_version: Option<PythonVersion>,
/// Set the line-length for length-associated rules and automatic
/// formatting.
#[arg(long)]
#[arg(long, help_heading = "Rule configuration")]
pub line_length: Option<usize>,
/// Regular expression matching the name of dummy variables.
#[arg(long, help_heading = "Rule configuration")]
pub dummy_variable_rgx: Option<Regex>,
/// Disable cache reads.
#[arg(short, long, help_heading = "Miscellaneous")]
pub no_cache: bool,
/// Ignore all configuration files.
#[arg(long, conflicts_with = "config", help_heading = "Miscellaneous")]
pub isolated: bool,
/// Path to the cache directory.
#[arg(long, env = "RUFF_CACHE_DIR", help_heading = "Miscellaneous")]
pub cache_dir: Option<PathBuf>,
/// The name of the file when passing it through stdin.
#[arg(long, help_heading = "Miscellaneous")]
pub stdin_filename: Option<PathBuf>,
/// Exit with status code "0", even upon detecting lint violations.
#[arg(short, long, help_heading = "Miscellaneous")]
pub exit_zero: bool,
/// Enable or disable automatic update checks.
#[arg(
long,
overrides_with("no_update_check"),
help_heading = "Miscellaneous"
)]
update_check: bool,
#[clap(long, overrides_with("update_check"), hide = true)]
no_update_check: bool,
/// Enable automatic additions of `noqa` directives to failing lines.
#[arg(
long,
// conflicts_with = "add_noqa",
conflicts_with = "clean",
conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
@@ -151,62 +222,11 @@ pub struct Cli {
conflicts_with = "watch",
)]
pub add_noqa: bool,
/// Clear any caches in the current directory or any subdirectories.
#[arg(
long,
// Fake subcommands.
conflicts_with = "add_noqa",
// conflicts_with = "clean",
conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
conflicts_with = "stdin_filename",
conflicts_with = "watch",
)]
pub clean: bool,
/// Explain a rule.
#[arg(
long,
value_parser=Rule::from_code,
// Fake subcommands.
conflicts_with = "add_noqa",
conflicts_with = "clean",
// conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
conflicts_with = "stdin_filename",
conflicts_with = "watch",
)]
pub explain: Option<&'static Rule>,
/// Generate shell completion
#[arg(
long,
hide = true,
value_name = "SHELL",
// Fake subcommands.
conflicts_with = "add_noqa",
conflicts_with = "clean",
conflicts_with = "explain",
// conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
conflicts_with = "stdin_filename",
conflicts_with = "watch",
)]
pub generate_shell_completion: Option<clap_complete_command::Shell>,
/// See the files Ruff will be run against with the current settings.
#[arg(
long,
// Fake subcommands.
conflicts_with = "add_noqa",
conflicts_with = "clean",
conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
// conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
@@ -219,9 +239,6 @@ pub struct Cli {
long,
// Fake subcommands.
conflicts_with = "add_noqa",
conflicts_with = "clean",
conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
// conflicts_with = "show_settings",
// Unsupported default-command arguments.
@@ -231,28 +248,75 @@ pub struct Cli {
pub show_settings: bool,
}
impl Cli {
#[derive(Debug, Clone, Copy, clap::ValueEnum)]
pub enum HelpFormat {
Text,
Json,
}
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, clap::Args)]
pub struct LogLevelArgs {
/// Enable verbose logging.
#[arg(
short,
long,
global = true,
group = "verbosity",
help_heading = "Log levels"
)]
pub verbose: bool,
/// Print lint violations, but nothing else.
#[arg(
short,
long,
global = true,
group = "verbosity",
help_heading = "Log levels"
)]
pub quiet: bool,
/// Disable all logging (but still exit with status code "1" upon detecting
/// lint violations).
#[arg(
short,
long,
global = true,
group = "verbosity",
help_heading = "Log levels"
)]
pub silent: bool,
}
impl From<&LogLevelArgs> for LogLevel {
fn from(args: &LogLevelArgs) -> Self {
if args.silent {
LogLevel::Silent
} else if args.quiet {
LogLevel::Quiet
} else if args.verbose {
LogLevel::Verbose
} else {
LogLevel::Default
}
}
}
impl CheckArgs {
/// Partition the CLI into command-line arguments and configuration
/// overrides.
pub fn partition(self) -> (Arguments, Overrides) {
(
Arguments {
add_noqa: self.add_noqa,
clean: self.clean,
config: self.config,
diff: self.diff,
exit_zero: self.exit_zero,
explain: self.explain,
files: self.files,
generate_shell_completion: self.generate_shell_completion,
isolated: self.isolated,
no_cache: self.no_cache,
quiet: self.quiet,
show_files: self.show_files,
show_settings: self.show_settings,
silent: self.silent,
stdin_filename: self.stdin_filename,
verbose: self.verbose,
watch: self.watch,
},
Overrides {
@@ -299,21 +363,15 @@ fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
#[allow(clippy::struct_excessive_bools)]
pub struct Arguments {
pub add_noqa: bool,
pub clean: bool,
pub config: Option<PathBuf>,
pub diff: bool,
pub exit_zero: bool,
pub explain: Option<&'static Rule>,
pub files: Vec<PathBuf>,
pub generate_shell_completion: Option<clap_complete_command::Shell>,
pub isolated: bool,
pub no_cache: bool,
pub quiet: bool,
pub show_files: bool,
pub show_settings: bool,
pub silent: bool,
pub stdin_filename: Option<PathBuf>,
pub verbose: bool,
pub watch: bool,
}
@@ -420,19 +478,6 @@ impl ConfigProcessor for &Overrides {
}
}
/// Map the CLI settings to a `LogLevel`.
pub fn extract_log_level(cli: &Arguments) -> LogLevel {
if cli.silent {
LogLevel::Silent
} else if cli.quiet {
LogLevel::Quiet
} else if cli.verbose {
LogLevel::Verbose
} else {
LogLevel::Default
}
}
/// Convert a list of `PatternPrefixPair` structs to `PerFileIgnore`.
pub fn collect_per_file_ignores(pairs: Vec<PatternPrefixPair>) -> Vec<PerFileIgnore> {
let mut per_file_ignores: FxHashMap<String, Vec<RuleSelector>> = FxHashMap::default();

View File

@@ -16,15 +16,14 @@ use ruff::linter::add_noqa_to_path;
use ruff::logging::LogLevel;
use ruff::message::{Location, Message};
use ruff::registry::{Linter, Rule, RuleNamespace};
use ruff::resolver::{FileDiscovery, PyprojectDiscovery};
use ruff::resolver::PyprojectDiscovery;
use ruff::settings::flags;
use ruff::settings::types::SerializationFormat;
use ruff::{fix, fs, packaging, resolver, warn_user_once, AutofixAvailability, IOError};
use serde::Serialize;
use walkdir::WalkDir;
use crate::args::{HelpFormat, Overrides};
use crate::cache;
use crate::cli::Overrides;
use crate::diagnostics::{lint_path, lint_stdin, Diagnostics};
use crate::iterators::par_iter;
@@ -32,15 +31,13 @@ use crate::iterators::par_iter;
pub fn run(
files: &[PathBuf],
pyproject_strategy: &PyprojectDiscovery,
file_strategy: &FileDiscovery,
overrides: &Overrides,
cache: flags::Cache,
autofix: fix::FixMode,
) -> Result<Diagnostics> {
// Collect all the Python files to check.
let start = Instant::now();
let (paths, resolver) =
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
let (paths, resolver) = resolver::python_files_in_path(files, pyproject_strategy, overrides)?;
let duration = start.elapsed();
debug!("Identified files to lint in: {:?}", duration);
@@ -49,9 +46,6 @@ pub fn run(
return Ok(Diagnostics::default());
}
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
// Initialize the cache.
if matches!(cache, flags::Cache::Enabled) {
match &pyproject_strategy {
@@ -120,7 +114,7 @@ pub fn run(
location: Location::default(),
end_location: Location::default(),
fix: None,
filename: path.to_string_lossy().to_string(),
filename: format!("{}", path.display()),
source: None,
}])
} else {
@@ -156,12 +150,11 @@ fn read_from_stdin() -> Result<String> {
pub fn run_stdin(
filename: Option<&Path>,
pyproject_strategy: &PyprojectDiscovery,
file_strategy: &FileDiscovery,
overrides: &Overrides,
autofix: fix::FixMode,
) -> Result<Diagnostics> {
if let Some(filename) = filename {
if !resolver::python_file_at_path(filename, pyproject_strategy, file_strategy, overrides)? {
if !resolver::python_file_at_path(filename, pyproject_strategy, overrides)? {
return Ok(Diagnostics::default());
}
}
@@ -182,13 +175,11 @@ pub fn run_stdin(
pub fn add_noqa(
files: &[PathBuf],
pyproject_strategy: &PyprojectDiscovery,
file_strategy: &FileDiscovery,
overrides: &Overrides,
) -> Result<usize> {
// Collect all the files to check.
let start = Instant::now();
let (paths, resolver) =
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
let (paths, resolver) = resolver::python_files_in_path(files, pyproject_strategy, overrides)?;
let duration = start.elapsed();
debug!("Identified files to lint in: {:?}", duration);
@@ -197,9 +188,6 @@ pub fn add_noqa(
return Ok(0);
}
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
let start = Instant::now();
let modifications: usize = par_iter(&paths)
.flatten()
@@ -226,15 +214,10 @@ pub fn add_noqa(
pub fn show_settings(
files: &[PathBuf],
pyproject_strategy: &PyprojectDiscovery,
file_strategy: &FileDiscovery,
overrides: &Overrides,
) -> Result<()> {
// Collect all files in the hierarchy.
let (paths, resolver) =
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
let (paths, resolver) = resolver::python_files_in_path(files, pyproject_strategy, overrides)?;
// Print the list of files.
let Some(entry) = paths
@@ -255,21 +238,16 @@ pub fn show_settings(
pub fn show_files(
files: &[PathBuf],
pyproject_strategy: &PyprojectDiscovery,
file_strategy: &FileDiscovery,
overrides: &Overrides,
) -> Result<()> {
// Collect all files in the hierarchy.
let (paths, resolver) =
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
let (paths, _resolver) = resolver::python_files_in_path(files, pyproject_strategy, overrides)?;
if paths.is_empty() {
warn_user_once!("No Python files found under the given path(s)");
return Ok(());
}
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
// Print the list of files.
for entry in paths
.iter()
@@ -290,10 +268,10 @@ struct Explanation<'a> {
}
/// Explain a `Rule` to the user.
pub fn explain(rule: &Rule, format: SerializationFormat) -> Result<()> {
pub fn rule(rule: &Rule, format: HelpFormat) -> Result<()> {
let (linter, _) = Linter::parse_code(rule.code()).unwrap();
match format {
SerializationFormat::Text | SerializationFormat::Grouped => {
HelpFormat::Text => {
println!("{}\n", rule.as_ref());
println!("Code: {} ({})\n", rule.code(), linter.name());
@@ -311,7 +289,7 @@ pub fn explain(rule: &Rule, format: SerializationFormat) -> Result<()> {
println!("* {format}");
}
}
SerializationFormat::Json => {
HelpFormat::Json => {
println!(
"{}",
serde_json::to_string_pretty(&Explanation {
@@ -321,24 +299,12 @@ pub fn explain(rule: &Rule, format: SerializationFormat) -> Result<()> {
})?
);
}
SerializationFormat::Junit => {
bail!("`--explain` does not support junit format")
}
SerializationFormat::Github => {
bail!("`--explain` does not support GitHub format")
}
SerializationFormat::Gitlab => {
bail!("`--explain` does not support GitLab format")
}
SerializationFormat::Pylint => {
bail!("`--explain` does not support pylint format")
}
};
Ok(())
}
/// Clear any caches in the current directory or any subdirectories.
pub fn clean(level: &LogLevel) -> Result<()> {
pub fn clean(level: LogLevel) -> Result<()> {
for entry in WalkDir::new(&*path_dedot::CWD)
.into_iter()
.filter_map(Result::ok)
@@ -346,7 +312,7 @@ pub fn clean(level: &LogLevel) -> Result<()> {
{
let cache = entry.path().join(CACHE_DIR_NAME);
if cache.is_dir() {
if level >= &LogLevel::Default {
if level >= LogLevel::Default {
eprintln!("Removing cache at: {}", fs::relativize_path(&cache).bold());
}
remove_dir_all(&cache)?;

View File

@@ -42,9 +42,6 @@ pub fn lint_path(
cache: flags::Cache,
autofix: fix::FixMode,
) -> Result<Diagnostics> {
// Validate the `Settings` and return any errors.
settings.lib.validate()?;
// Check the cache.
// TODO(charlie): `fixer::Mode::Apply` and `fixer::Mode::Diff` both have
// side-effects that aren't captured in the cache. (In practice, it's fine
@@ -116,9 +113,6 @@ pub fn lint_stdin(
settings: &Settings,
autofix: fix::FixMode,
) -> Result<Diagnostics> {
// Validate the `Settings` and return any errors.
settings.validate()?;
// Lint the inputs.
let (messages, fixed) = if matches!(autofix, fix::FixMode::Apply | fix::FixMode::Diff) {
let (transformed, fixed, messages) = lint_fix(

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