Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20234c6156 | ||
|
|
de767cc026 | ||
|
|
ce1663d302 | ||
|
|
f40e4bcd14 | ||
|
|
e7d40d435f | ||
|
|
ef8fe31c0c | ||
|
|
226f682c99 | ||
|
|
468ffd29fb | ||
|
|
a61126ab23 | ||
|
|
54c7c25861 | ||
|
|
eff7700d92 | ||
|
|
8934f6938d | ||
|
|
8f0fc3033a | ||
|
|
4107bc828d | ||
|
|
706d28cabc | ||
|
|
4da2264722 | ||
|
|
bf88c815aa | ||
|
|
8a4831dd5b | ||
|
|
b5ab492a70 | ||
|
|
1fc09ebd5c | ||
|
|
6cf047976c | ||
|
|
87465daacc | ||
|
|
a52bed7101 | ||
|
|
20ac823778 | ||
|
|
1028ed3565 | ||
|
|
98897db6ac | ||
|
|
5ce4262112 | ||
|
|
6b2359384d | ||
|
|
d3443d7c19 | ||
|
|
04b1e1de6f | ||
|
|
c93c85300f | ||
|
|
73ed6f8654 | ||
|
|
eb183645f3 | ||
|
|
ef17aa93da | ||
|
|
f366b0147f | ||
|
|
fc88fa35ff | ||
|
|
a2806eb8ef | ||
|
|
89d919eac5 | ||
|
|
5ad77fbc8d | ||
|
|
9cb18a481b | ||
|
|
2393e270ed | ||
|
|
f36e6035c8 | ||
|
|
ecf0dd05d6 | ||
|
|
5f67ee93f7 | ||
|
|
1e19142d0e | ||
|
|
6a95dade6d | ||
|
|
d6e765877e | ||
|
|
e4d36bae57 | ||
|
|
e3531276a7 | ||
|
|
634553f188 | ||
|
|
4ff0b75045 | ||
|
|
481d668511 |
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
- run: ./target/release/ruff_dev generate-rules-table
|
||||
- run: ./target/release/ruff_dev generate-options
|
||||
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. You may have to rerun 'cargo dev generate-options' and/or 'cargo dev generate-rules-table'."
|
||||
- run: ./target/release/ruff_dev generate-check-code-prefix && cargo fmt -- src/checks_gen.rs
|
||||
- run: ./target/release/ruff_dev generate-check-code-prefix
|
||||
- run: git diff --quiet src/checks_gen.rs || echo "::error file=src/checks_gen.rs::This file is outdated. You may have to rerun 'cargo dev generate-check-code-prefix'."
|
||||
- run: git diff --exit-code -- README.md src/checks_gen.rs
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.183
|
||||
rev: v0.0.190
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
16
Cargo.lock
generated
16
Cargo.lock
generated
@@ -724,7 +724,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.183-dev.0"
|
||||
version = "0.0.190-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.29",
|
||||
@@ -1845,7 +1845,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.183"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1901,7 +1901,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.183"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.29",
|
||||
@@ -1919,7 +1919,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.183"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1962,7 +1962,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=8d879a53197f9c73062f6160410bdba796a71cbf#8d879a53197f9c73062f6160410bdba796a71cbf"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-common",
|
||||
@@ -1972,7 +1972,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=8d879a53197f9c73062f6160410bdba796a71cbf#8d879a53197f9c73062f6160410bdba796a71cbf"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -1995,7 +1995,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=8d879a53197f9c73062f6160410bdba796a71cbf#8d879a53197f9c73062f6160410bdba796a71cbf"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
@@ -2012,7 +2012,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=8d879a53197f9c73062f6160410bdba796a71cbf#8d879a53197f9c73062f6160410bdba796a71cbf"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
|
||||
10
Cargo.toml
10
Cargo.toml
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.183"
|
||||
version = "0.0.190"
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
@@ -43,11 +43,11 @@ quick-junit = { version = "0.3.2" }
|
||||
rayon = { version = "1.5.3" }
|
||||
regex = { version = "1.6.0" }
|
||||
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
|
||||
ruff_macros = { version = "0.0.183", path = "ruff_macros" }
|
||||
ruff_macros = { version = "0.0.190", path = "ruff_macros" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "8d879a53197f9c73062f6160410bdba796a71cbf" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "8d879a53197f9c73062f6160410bdba796a71cbf" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "8d879a53197f9c73062f6160410bdba796a71cbf" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
|
||||
219
README.md
219
README.md
@@ -94,8 +94,9 @@ of [Conda](https://docs.conda.io/en/latest/):
|
||||
1. [flake8-simplify (SIM)](#flake8-simplify-sim)
|
||||
1. [flake8-tidy-imports (TID)](#flake8-tidy-imports-tid)
|
||||
1. [flake8-unused-arguments (ARG)](#flake8-unused-arguments-arg)
|
||||
1. [flake8-datetimez (DTZ)](#flake8-datetimez-dtz)
|
||||
1. [eradicate (ERA)](#eradicate-era)
|
||||
1. [pandas-vet (PDV)](#pandas-vet-pdv)
|
||||
1. [pandas-vet (PD)](#pandas-vet-pd)
|
||||
1. [pygrep-hooks (PGH)](#pygrep-hooks-pgh)
|
||||
1. [Pylint (PLC, PLE, PLR, PLW)](#pylint-plc-ple-plr-plw)
|
||||
1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. -->
|
||||
@@ -118,6 +119,8 @@ Ruff is available as [`ruff`](https://pypi.org/project/ruff/) on PyPI:
|
||||
pip install ruff
|
||||
```
|
||||
|
||||
[](https://repology.org/project/ruff-python-linter/versions)
|
||||
|
||||
For **macOS Homebrew** and **Linuxbrew** users, Ruff is also available as [`ruff`](https://formulae.brew.sh/formula/ruff) on Homebrew:
|
||||
|
||||
```shell
|
||||
@@ -157,7 +160,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.183
|
||||
rev: v0.0.190
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -354,7 +357,7 @@ There are a few exceptions to these rules:
|
||||
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
|
||||
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.
|
||||
@@ -673,7 +676,7 @@ For more, see [flake8-annotations](https://pypi.org/project/flake8-annotations/2
|
||||
| ANN102 | MissingTypeCls | Missing type annotation for `...` in classmethod | |
|
||||
| ANN201 | MissingReturnTypePublicFunction | Missing return type annotation for public function `...` | |
|
||||
| ANN202 | MissingReturnTypePrivateFunction | Missing return type annotation for private function `...` | |
|
||||
| ANN204 | MissingReturnTypeMagicMethod | Missing return type annotation for magic method `...` | |
|
||||
| ANN204 | MissingReturnTypeSpecialMethod | Missing return type annotation for special method `...` | 🛠 |
|
||||
| ANN205 | MissingReturnTypeStaticMethod | Missing return type annotation for staticmethod `...` | |
|
||||
| ANN206 | MissingReturnTypeClassMethod | Missing return type annotation for classmethod `...` | |
|
||||
| ANN401 | DynamicallyTypedExpression | Dynamically typed expressions (typing.Any) are disallowed in `...` | |
|
||||
@@ -864,6 +867,22 @@ For more, see [flake8-unused-arguments](https://pypi.org/project/flake8-unused-a
|
||||
| ARG004 | UnusedStaticMethodArgument | Unused static method argument: `...` | |
|
||||
| ARG005 | UnusedLambdaArgument | Unused lambda argument: `...` | |
|
||||
|
||||
### flake8-datetimez (DTZ)
|
||||
|
||||
For more, see [flake8-datetimez](https://pypi.org/project/flake8-datetimez/20.10.0/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| DTZ001 | CallDatetimeWithoutTzinfo | The use of `datetime.datetime()` without `tzinfo` argument is not allowed | |
|
||||
| DTZ002 | CallDatetimeToday | The use of `datetime.datetime.today()` is not allowed | |
|
||||
| DTZ003 | CallDatetimeUtcnow | The use of `datetime.datetime.utcnow()` is not allowed | |
|
||||
| DTZ004 | CallDatetimeUtcfromtimestamp | The use of `datetime.datetime.utcfromtimestamp()` is not allowed | |
|
||||
| DTZ005 | CallDatetimeNowWithoutTzinfo | The use of `datetime.datetime.now()` without `tz` argument is not allowed | |
|
||||
| DTZ006 | CallDatetimeFromtimestamp | The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed | |
|
||||
| DTZ007 | CallDatetimeStrptimeWithoutZone | The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` | |
|
||||
| DTZ011 | CallDateToday | The use of `datetime.date.today()` is not allowed. | |
|
||||
| DTZ012 | CallDateFromtimestamp | The use of `datetime.date.fromtimestamp()` is not allowed | |
|
||||
|
||||
### eradicate (ERA)
|
||||
|
||||
For more, see [eradicate](https://pypi.org/project/eradicate/2.1.0/) on PyPI.
|
||||
@@ -872,24 +891,24 @@ For more, see [eradicate](https://pypi.org/project/eradicate/2.1.0/) on PyPI.
|
||||
| ---- | ---- | ------- | --- |
|
||||
| ERA001 | CommentedOutCode | Found commented-out code | 🛠 |
|
||||
|
||||
### pandas-vet (PDV)
|
||||
### pandas-vet (PD)
|
||||
|
||||
For more, see [pandas-vet](https://pypi.org/project/pandas-vet/0.2.3/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PDV002 | UseOfInplaceArgument | `inplace=True` should be avoided; it has inconsistent behavior | |
|
||||
| PDV003 | UseOfDotIsNull | `.isna` is preferred to `.isnull`; functionality is equivalent | |
|
||||
| PDV004 | UseOfDotNotNull | `.notna` is preferred to `.notnull`; functionality is equivalent | |
|
||||
| PDV007 | UseOfDotIx | ``ix` i` deprecated; use more explicit `.loc` o` `.iloc` | |
|
||||
| PDV008 | UseOfDotAt | Use `.loc` instead of `.at`. If speed is important, use numpy. | |
|
||||
| PDV009 | UseOfDotIat | Use `.iloc` instea` of `.iat`. If speed is important, use numpy. | |
|
||||
| PDV010 | UseOfDotPivotOrUnstack | `.pivot_table` is preferred to `.pivot` or `.unstack`; provides same functionality | |
|
||||
| PDV011 | UseOfDotValues | Use `.to_numpy()` instead of `.values` | |
|
||||
| PDV012 | UseOfDotReadTable | `.read_csv` is preferred to `.read_table`; provides same functionality | |
|
||||
| PDV013 | UseOfDotStack | `.melt` is preferred to `.stack`; provides same functionality | |
|
||||
| PDV015 | UseOfPdMerge | Use `.merge` method instead of `pd.merge` function. They have equivalent functionality. | |
|
||||
| PDV901 | DfIsABadVariableName | `df` is a bad variable name. Be kinder to your future self. | |
|
||||
| PD002 | UseOfInplaceArgument | `inplace=True` should be avoided; it has inconsistent behavior | |
|
||||
| PD003 | UseOfDotIsNull | `.isna` is preferred to `.isnull`; functionality is equivalent | |
|
||||
| PD004 | UseOfDotNotNull | `.notna` is preferred to `.notnull`; functionality is equivalent | |
|
||||
| PD007 | UseOfDotIx | `.ix` is deprecated; use more explicit `.loc` or `.iloc` | |
|
||||
| PD008 | UseOfDotAt | Use `.loc` instead of `.at`. If speed is important, use numpy. | |
|
||||
| PD009 | UseOfDotIat | Use `.iloc` instead of `.iat`. If speed is important, use numpy. | |
|
||||
| PD010 | UseOfDotPivotOrUnstack | `.pivot_table` is preferred to `.pivot` or `.unstack`; provides same functionality | |
|
||||
| PD011 | UseOfDotValues | Use `.to_numpy()` instead of `.values` | |
|
||||
| PD012 | UseOfDotReadTable | `.read_csv` is preferred to `.read_table`; provides same functionality | |
|
||||
| PD013 | UseOfDotStack | `.melt` is preferred to `.stack`; provides same functionality | |
|
||||
| PD015 | UseOfPdMerge | Use `.merge` method instead of `pd.merge` function. They have equivalent functionality. | |
|
||||
| PD901 | DfIsABadVariableName | `df` is a bad variable name. Be kinder to your future self. | |
|
||||
|
||||
### pygrep-hooks (PGH)
|
||||
|
||||
@@ -898,6 +917,8 @@ For more, see [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) on GitH
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PGH001 | NoEval | No builtin `eval()` allowed | |
|
||||
| PGH002 | DeprecatedLogWarn | `warn` is deprecated in favor of `warning` | |
|
||||
| PGH003 | BlanketTypeIgnore | Use specific error codes when ignoring type issues | |
|
||||
|
||||
### Pylint (PLC, PLE, PLR, PLW)
|
||||
|
||||
@@ -933,21 +954,100 @@ For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI.
|
||||
|
||||
### VS Code (Official)
|
||||
|
||||
Download the [Ruff VS Code extension](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff).
|
||||
Download the [Ruff VS Code extension](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff),
|
||||
which supports autofix actions, import sorting, and more.
|
||||
|
||||
### Language Server Protocol
|
||||

|
||||
|
||||
Ruff is available as a [Language Server Protocol (LSP)](https://microsoft.github.io/language-server-protocol/)
|
||||
server, distributed as the [`python-lsp-ruff`](https://github.com/python-lsp/python-lsp-ruff) plugin
|
||||
for [`python-lsp-server`](https://github.com/python-lsp/python-lsp-server), both of which are
|
||||
installable via [PyPI](https://pypi.org/project/python-lsp-ruff/):
|
||||
### Language Server Protocol (Official)
|
||||
|
||||
Ruff supports the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/)
|
||||
via the [`ruff-lsp`](https://github.com/charliermarsh/ruff-lsp) Python package, available on
|
||||
[PyPI](https://pypi.org/project/ruff-lsp/).
|
||||
|
||||
[`ruff-lsp`](https://github.com/charliermarsh/ruff-lsp) enables Ruff to be used with any editor that
|
||||
supports the Language Server Protocol, including [Neovim](https://github.com/charliermarsh/ruff-lsp#example-neovim),
|
||||
[Sublime Text](https://github.com/charliermarsh/ruff-lsp#example-sublime-text), Emacs, and more.
|
||||
|
||||
For example, to use `ruff-lsp` with Neovim, install `ruff-lsp` from PyPI along with
|
||||
[`nvim-lspconfig`](https://github.com/neovim/nvim-lspconfig). Then, add something like the following
|
||||
to your `init.lua`:
|
||||
|
||||
```lua
|
||||
-- See: https://github.com/neovim/nvim-lspconfig/tree/54eb2a070a4f389b1be0f98070f81d23e2b1a715#suggested-configuration
|
||||
local opts = { noremap=true, silent=true }
|
||||
vim.keymap.set('n', '<space>e', vim.diagnostic.open_float, opts)
|
||||
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts)
|
||||
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts)
|
||||
vim.keymap.set('n', '<space>q', vim.diagnostic.setloclist, opts)
|
||||
|
||||
-- Use an on_attach function to only map the following keys
|
||||
-- after the language server attaches to the current buffer
|
||||
local on_attach = function(client, bufnr)
|
||||
-- Enable completion triggered by <c-x><c-o>
|
||||
vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
|
||||
|
||||
-- Mappings.
|
||||
-- See `:help vim.lsp.*` for documentation on any of the below functions
|
||||
local bufopts = { noremap=true, silent=true, buffer=bufnr }
|
||||
vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts)
|
||||
vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts)
|
||||
vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts)
|
||||
vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, bufopts)
|
||||
vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, bufopts)
|
||||
vim.keymap.set('n', '<space>wa', vim.lsp.buf.add_workspace_folder, bufopts)
|
||||
vim.keymap.set('n', '<space>wr', vim.lsp.buf.remove_workspace_folder, bufopts)
|
||||
vim.keymap.set('n', '<space>wl', function()
|
||||
print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
|
||||
end, bufopts)
|
||||
vim.keymap.set('n', '<space>D', vim.lsp.buf.type_definition, bufopts)
|
||||
vim.keymap.set('n', '<space>rn', vim.lsp.buf.rename, bufopts)
|
||||
vim.keymap.set('n', '<space>ca', vim.lsp.buf.code_action, bufopts)
|
||||
vim.keymap.set('n', 'gr', vim.lsp.buf.references, bufopts)
|
||||
vim.keymap.set('n', '<space>f', function() vim.lsp.buf.format { async = true } end, bufopts)
|
||||
end
|
||||
|
||||
-- Configure `ruff-lsp`.
|
||||
local configs = require 'lspconfig.configs'
|
||||
if not configs.ruff_lsp then
|
||||
configs.ruff_lsp = {
|
||||
default_config = {
|
||||
cmd = { "ruff-lsp" },
|
||||
filetypes = {'python'},
|
||||
root_dir = require('lspconfig').util.find_git_ancestor,
|
||||
settings = {
|
||||
ruff_lsp = {
|
||||
-- Any extra CLI arguments for `ruff` go here.
|
||||
args = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
require('lspconfig').ruff_lsp.setup {
|
||||
on_attach = on_attach,
|
||||
}
|
||||
```
|
||||
|
||||
Upon successful installation, you should see Ruff's diagnostics surfaced directly in your editor:
|
||||
|
||||

|
||||
|
||||
### Language Server Protocol (Unofficial)
|
||||
|
||||
Ruff is also available as the [`python-lsp-ruff`](https://github.com/python-lsp/python-lsp-ruff)
|
||||
plugin for [`python-lsp-server`](https://github.com/python-lsp/python-lsp-ruff), both of which are
|
||||
installable from PyPI:
|
||||
|
||||
```shell
|
||||
pip install python-lsp-server python-lsp-ruff
|
||||
```
|
||||
|
||||
The LSP server can be used with any editor that supports the Language Server Protocol. For example,
|
||||
to use it with Neovim, you would add something like the following to your `init.lua`:
|
||||
The LSP server can then be used with any editor that supports the Language Server Protocol.
|
||||
|
||||
For example, to use `python-lsp-ruff` with Neovim, add something like the following to your
|
||||
`init.lua`:
|
||||
|
||||
```lua
|
||||
require'lspconfig'.pylsp.setup {
|
||||
@@ -956,6 +1056,15 @@ require'lspconfig'.pylsp.setup {
|
||||
plugins = {
|
||||
ruff = {
|
||||
enabled = true
|
||||
},
|
||||
pycodestyle = {
|
||||
enabled = false
|
||||
},
|
||||
pyflakes = {
|
||||
enabled = false
|
||||
},
|
||||
mccabe = {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -963,9 +1072,6 @@ require'lspconfig'.pylsp.setup {
|
||||
}
|
||||
```
|
||||
|
||||
[`ruffd`](https://github.com/Seamooo/ruffd) is another implementation of the Language Server
|
||||
Protocol (LSP) for Ruff, written in Rust.
|
||||
|
||||
### PyCharm
|
||||
|
||||
Ruff can be installed as an [External Tool](https://www.jetbrains.com/help/pycharm/configuring-third-party-tools.html)
|
||||
@@ -980,8 +1086,8 @@ Ruff should then appear as a runnable action:
|
||||
|
||||
### Vim & Neovim
|
||||
|
||||
Ruff can be integrated into any editor that supports the Language Server Protocol (LSP) (see:
|
||||
[Language Server Protocol](#language-server-protocol)).
|
||||
Ruff can be integrated into any editor that supports the Language Server Protocol via [`ruff-lsp`](https://github.com/charliermarsh/ruff-lsp)
|
||||
(see: [Language Server Protocol](#language-server-protocol-official)).
|
||||
|
||||
Ruff is also available as part of the [coc-pyright](https://github.com/fannheyward/coc-pyright)
|
||||
extension for `coc.nvim`.
|
||||
@@ -1097,9 +1203,11 @@ natively, including:
|
||||
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/)
|
||||
- [`flake8-builtins`](https://pypi.org/project/flake8-builtins/)
|
||||
- [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/)
|
||||
- [`flake8-datetimez`](https://pypi.org/project/flake8-datetimez/)
|
||||
- [`flake8-debugger`](https://pypi.org/project/flake8-debugger/)
|
||||
- [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/)
|
||||
- [`flake8-eradicate`](https://pypi.org/project/flake8-eradicate/)
|
||||
- [`flake8-errmsg`](https://pypi.org/project/flake8-errmsg/)
|
||||
- [`flake8-import-conventions`](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
|
||||
@@ -1110,7 +1218,7 @@ natively, including:
|
||||
- [`mccabe`](https://pypi.org/project/mccabe/)
|
||||
- [`pep8-naming`](https://pypi.org/project/pep8-naming/)
|
||||
- [`pydocstyle`](https://pypi.org/project/pydocstyle/)
|
||||
- [`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (1/10)
|
||||
- [`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (3/10)
|
||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (16/33)
|
||||
- [`yesqa`](https://github.com/asottile/yesqa)
|
||||
|
||||
@@ -1150,9 +1258,11 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/)
|
||||
- [`flake8-builtins`](https://pypi.org/project/flake8-builtins/)
|
||||
- [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/)
|
||||
- [`flake8-datetimez`](https://pypi.org/project/flake8-datetimez/)
|
||||
- [`flake8-debugger`](https://pypi.org/project/flake8-debugger/)
|
||||
- [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/)
|
||||
- [`flake8-eradicate`](https://pypi.org/project/flake8-eradicate/)
|
||||
- [`flake8-errmsg`](https://pypi.org/project/flake8-errmsg/)
|
||||
- [`flake8-import-conventions`](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
|
||||
@@ -1165,7 +1275,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
|
||||
Ruff can also replace [`isort`](https://pypi.org/project/isort/),
|
||||
[`yesqa`](https://github.com/asottile/yesqa), [`eradicate`](https://pypi.org/project/eradicate/),
|
||||
[`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (1/10), and a subset of the rules
|
||||
[`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (3/10), and a subset of the rules
|
||||
implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (16/33).
|
||||
|
||||
If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, free to file an Issue.
|
||||
@@ -1486,7 +1596,7 @@ ignored when evaluating (e.g.) unused-variable checks. The default expression ma
|
||||
```toml
|
||||
[tool.ruff]
|
||||
# Only ignore variables named "_".
|
||||
dummy_variable_rgx = "^_$"
|
||||
dummy-variable-rgx = "^_$"
|
||||
```
|
||||
|
||||
---
|
||||
@@ -1655,6 +1765,30 @@ fixable = ["E", "F"]
|
||||
|
||||
---
|
||||
|
||||
#### [`force-exclude`](#force-exclude)
|
||||
|
||||
Whether to enforce `exclude` and `extend-exclude` patterns, even for paths that are
|
||||
passed to Ruff explicitly. Typically, Ruff will lint any paths passed in directly, even
|
||||
if they would typically be excluded. Setting `force-exclude = true` will cause Ruff to
|
||||
respect these exclusions unequivocally.
|
||||
|
||||
This is useful for [`pre-commit`](https://pre-commit.com/), which explicitly passes all
|
||||
changed files to the [`ruff-pre-commit`](https://github.com/charliermarsh/ruff-pre-commit)
|
||||
plugin, regardless of whether they're marked as excluded by Ruff's own settings.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
force-exclude = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`format`](#format)
|
||||
|
||||
The style in which violation messages should be formatted: `"text"` (default),
|
||||
@@ -2142,6 +2276,25 @@ ban-relative-imports = "all"
|
||||
|
||||
---
|
||||
|
||||
### `flake8-unused-arguments`
|
||||
|
||||
#### [`ignore-variadic-names`](#ignore-variadic-names)
|
||||
|
||||
Whether to allow unused variadic arguments, like `*args` and `**kwargs`.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.flake8-unused-arguments]
|
||||
ignore-variadic-names = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `isort`
|
||||
|
||||
#### [`combine-as-imports`](#combine-as-imports)
|
||||
|
||||
12
flake8_to_ruff/Cargo.lock
generated
12
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.183"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.183"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -2028,7 +2028,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=8d879a53197f9c73062f6160410bdba796a71cbf#8d879a53197f9c73062f6160410bdba796a71cbf"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-common",
|
||||
@@ -2038,7 +2038,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=8d879a53197f9c73062f6160410bdba796a71cbf#8d879a53197f9c73062f6160410bdba796a71cbf"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -2061,7 +2061,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=8d879a53197f9c73062f6160410bdba796a71cbf#8d879a53197f9c73062f6160410bdba796a71cbf"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
@@ -2078,7 +2078,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=8d879a53197f9c73062f6160410bdba796a71cbf#8d879a53197f9c73062f6160410bdba796a71cbf"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c01f014b1269eedcf4bdb45d5fbc62ae2beecf31#c01f014b1269eedcf4bdb45d5fbc62ae2beecf31"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.183-dev.0"
|
||||
version = "0.0.190-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -268,6 +268,7 @@ mod tests {
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
force_exclude: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
@@ -288,6 +289,7 @@ mod tests {
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
flake8_unused_arguments: None,
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
@@ -316,6 +318,7 @@ mod tests {
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
force_exclude: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: Some(100),
|
||||
@@ -336,6 +339,7 @@ mod tests {
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
flake8_unused_arguments: None,
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
@@ -364,6 +368,7 @@ mod tests {
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
force_exclude: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: Some(100),
|
||||
@@ -384,6 +389,7 @@ mod tests {
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
flake8_unused_arguments: None,
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
@@ -412,6 +418,7 @@ mod tests {
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
force_exclude: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
@@ -432,6 +439,7 @@ mod tests {
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
flake8_unused_arguments: None,
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
@@ -460,6 +468,7 @@ mod tests {
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
force_exclude: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
@@ -485,6 +494,7 @@ mod tests {
|
||||
}),
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
flake8_unused_arguments: None,
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
@@ -516,6 +526,7 @@ mod tests {
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
force_exclude: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
@@ -572,6 +583,7 @@ mod tests {
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
flake8_unused_arguments: None,
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
@@ -600,6 +612,7 @@ mod tests {
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
force_exclude: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
@@ -626,6 +639,7 @@ mod tests {
|
||||
}),
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
flake8_unused_arguments: None,
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
|
||||
@@ -12,6 +12,7 @@ pub enum Plugin {
|
||||
Flake8Bugbear,
|
||||
Flake8Builtins,
|
||||
Flake8Comprehensions,
|
||||
Flake8Datetimez,
|
||||
Flake8Debugger,
|
||||
Flake8Docstrings,
|
||||
Flake8ErrMsg,
|
||||
@@ -38,6 +39,7 @@ impl FromStr for Plugin {
|
||||
"flake8-bugbear" => Ok(Plugin::Flake8Bugbear),
|
||||
"flake8-builtins" => Ok(Plugin::Flake8Builtins),
|
||||
"flake8-comprehensions" => Ok(Plugin::Flake8Comprehensions),
|
||||
"flake8-datetimez" => Ok(Plugin::Flake8Datetimez),
|
||||
"flake8-debugger" => Ok(Plugin::Flake8Debugger),
|
||||
"flake8-docstrings" => Ok(Plugin::Flake8Docstrings),
|
||||
"flake8-eradicate" => Ok(Plugin::Flake8BlindExcept),
|
||||
@@ -66,6 +68,7 @@ impl Plugin {
|
||||
Plugin::Flake8Bugbear => CheckCodePrefix::B,
|
||||
Plugin::Flake8Builtins => CheckCodePrefix::A,
|
||||
Plugin::Flake8Comprehensions => CheckCodePrefix::C4,
|
||||
Plugin::Flake8Datetimez => CheckCodePrefix::DTZ,
|
||||
Plugin::Flake8Debugger => CheckCodePrefix::T1,
|
||||
Plugin::Flake8Docstrings => CheckCodePrefix::D,
|
||||
// TODO(charlie): Handle rename of `E` to `ERA`.
|
||||
@@ -77,8 +80,7 @@ impl Plugin {
|
||||
Plugin::Flake8Simplify => CheckCodePrefix::SIM,
|
||||
Plugin::Flake8TidyImports => CheckCodePrefix::I25,
|
||||
Plugin::McCabe => CheckCodePrefix::C9,
|
||||
// TODO(charlie): Handle rename of `PD` to `PDV`.
|
||||
Plugin::PandasVet => CheckCodePrefix::PDV,
|
||||
Plugin::PandasVet => CheckCodePrefix::PD,
|
||||
Plugin::PEP8Naming => CheckCodePrefix::N,
|
||||
Plugin::Pyupgrade => CheckCodePrefix::U,
|
||||
}
|
||||
@@ -92,6 +94,7 @@ impl Plugin {
|
||||
Plugin::Flake8Bugbear => vec![CheckCodePrefix::B],
|
||||
Plugin::Flake8Builtins => vec![CheckCodePrefix::A],
|
||||
Plugin::Flake8Comprehensions => vec![CheckCodePrefix::C4],
|
||||
Plugin::Flake8Datetimez => vec![CheckCodePrefix::DTZ],
|
||||
Plugin::Flake8Debugger => vec![CheckCodePrefix::T1],
|
||||
Plugin::Flake8Docstrings => {
|
||||
// Use the user-provided docstring.
|
||||
@@ -117,7 +120,7 @@ impl Plugin {
|
||||
Plugin::Flake8Simplify => vec![CheckCodePrefix::SIM],
|
||||
Plugin::Flake8TidyImports => vec![CheckCodePrefix::TID],
|
||||
Plugin::McCabe => vec![CheckCodePrefix::C9],
|
||||
Plugin::PandasVet => vec![CheckCodePrefix::PDV],
|
||||
Plugin::PandasVet => vec![CheckCodePrefix::PD],
|
||||
Plugin::PEP8Naming => vec![CheckCodePrefix::N],
|
||||
Plugin::Pyupgrade => vec![CheckCodePrefix::UP],
|
||||
}
|
||||
@@ -409,6 +412,7 @@ pub fn infer_plugins_from_codes(codes: &BTreeSet<CheckCodePrefix>) -> Vec<Plugin
|
||||
Plugin::Flake8Bugbear,
|
||||
Plugin::Flake8Builtins,
|
||||
Plugin::Flake8Comprehensions,
|
||||
Plugin::Flake8Datetimez,
|
||||
Plugin::Flake8Debugger,
|
||||
Plugin::Flake8Docstrings,
|
||||
Plugin::Flake8Eradicate,
|
||||
|
||||
@@ -32,6 +32,8 @@ build-backend = "maturin"
|
||||
bindings = "bin"
|
||||
strip = true
|
||||
|
||||
[tool.ruff]
|
||||
|
||||
[tool.ruff.isort]
|
||||
force-wrap-aliases = true
|
||||
combine-as-imports = true
|
||||
|
||||
18
resources/test/fixtures/flake8_datetimez/DTZ001.py
vendored
Normal file
18
resources/test/fixtures/flake8_datetimez/DTZ001.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import datetime
|
||||
|
||||
# no args
|
||||
datetime.datetime(2000, 1, 1, 0, 0, 0)
|
||||
|
||||
# none args
|
||||
datetime.datetime(2000, 1, 1, 0, 0, 0, 0, None)
|
||||
|
||||
# no kwargs
|
||||
datetime.datetime(2000, 1, 1, fold=1)
|
||||
|
||||
# none kwargs
|
||||
datetime.datetime(2000, 1, 1, tzinfo=None)
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# no args unqualified
|
||||
datetime(2000, 1, 1, 0, 0, 0)
|
||||
9
resources/test/fixtures/flake8_datetimez/DTZ002.py
vendored
Normal file
9
resources/test/fixtures/flake8_datetimez/DTZ002.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import datetime
|
||||
|
||||
# qualified
|
||||
datetime.datetime.today()
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# unqualified
|
||||
datetime.today()
|
||||
9
resources/test/fixtures/flake8_datetimez/DTZ003.py
vendored
Normal file
9
resources/test/fixtures/flake8_datetimez/DTZ003.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import datetime
|
||||
|
||||
# qualified
|
||||
datetime.datetime.utcnow()
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# unqualified
|
||||
datetime.utcnow()
|
||||
9
resources/test/fixtures/flake8_datetimez/DTZ004.py
vendored
Normal file
9
resources/test/fixtures/flake8_datetimez/DTZ004.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import datetime
|
||||
|
||||
# qualified
|
||||
datetime.datetime.utcfromtimestamp(1234)
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# unqualified
|
||||
datetime.utcfromtimestamp(1234)
|
||||
18
resources/test/fixtures/flake8_datetimez/DTZ005.py
vendored
Normal file
18
resources/test/fixtures/flake8_datetimez/DTZ005.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import datetime
|
||||
|
||||
# no args
|
||||
datetime.datetime.now()
|
||||
|
||||
# wrong keywords
|
||||
datetime.datetime.now(bad=datetime.timezone.utc)
|
||||
|
||||
# none args
|
||||
datetime.datetime.now(None)
|
||||
|
||||
# none keywords
|
||||
datetime.datetime.now(tz=None)
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# no args unqualified
|
||||
datetime.now()
|
||||
18
resources/test/fixtures/flake8_datetimez/DTZ006.py
vendored
Normal file
18
resources/test/fixtures/flake8_datetimez/DTZ006.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import datetime
|
||||
|
||||
# no args
|
||||
datetime.datetime.fromtimestamp(1234)
|
||||
|
||||
# wrong keywords
|
||||
datetime.datetime.fromtimestamp(1234, bad=datetime.timezone.utc)
|
||||
|
||||
# none args
|
||||
datetime.datetime.fromtimestamp(1234, None)
|
||||
|
||||
# none keywords
|
||||
datetime.datetime.fromtimestamp(1234, tz=None)
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# no args unqualified
|
||||
datetime.fromtimestamp(1234)
|
||||
35
resources/test/fixtures/flake8_datetimez/DTZ007.py
vendored
Normal file
35
resources/test/fixtures/flake8_datetimez/DTZ007.py
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import datetime
|
||||
|
||||
# bad format
|
||||
datetime.datetime.strptime("something", "%H:%M:%S%Z")
|
||||
|
||||
# no replace or astimezone
|
||||
datetime.datetime.strptime("something", "something")
|
||||
|
||||
# wrong replace
|
||||
datetime.datetime.strptime("something", "something").replace(hour=1)
|
||||
|
||||
# none replace
|
||||
datetime.datetime.strptime("something", "something").replace(tzinfo=None)
|
||||
|
||||
# OK
|
||||
datetime.datetime.strptime("something", "something").replace(
|
||||
tzinfo=datetime.timezone.utc
|
||||
)
|
||||
|
||||
# OK
|
||||
datetime.datetime.strptime("something", "something").astimezone()
|
||||
|
||||
# OK
|
||||
datetime.datetime.strptime("something", "%H:%M:%S%z")
|
||||
|
||||
# OK
|
||||
datetime.datetime.strptime("something", something).astimezone()
|
||||
|
||||
# OK
|
||||
datetime.datetime.strptime("something", something).replace(tzinfo=datetime.timezone.utc)
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
# no replace orastimezone unqualified
|
||||
datetime.strptime("something", "something")
|
||||
9
resources/test/fixtures/flake8_datetimez/DTZ011.py
vendored
Normal file
9
resources/test/fixtures/flake8_datetimez/DTZ011.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import datetime
|
||||
|
||||
# qualified
|
||||
datetime.date.today()
|
||||
|
||||
from datetime import date
|
||||
|
||||
# unqualified
|
||||
date.today()
|
||||
9
resources/test/fixtures/flake8_datetimez/DTZ012.py
vendored
Normal file
9
resources/test/fixtures/flake8_datetimez/DTZ012.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import datetime
|
||||
|
||||
# qualified
|
||||
datetime.date.fromtimestamp(1234)
|
||||
|
||||
from datetime import date
|
||||
|
||||
# unqualified
|
||||
date.fromtimestamp(1234)
|
||||
@@ -1,6 +1,5 @@
|
||||
breakpoint()
|
||||
|
||||
|
||||
import pdb
|
||||
import builtins
|
||||
from builtins import breakpoint
|
||||
@@ -9,7 +8,6 @@ from celery.contrib.rdb import set_trace
|
||||
from celery.contrib import rdb
|
||||
import celery.contrib.rdb
|
||||
|
||||
|
||||
breakpoint()
|
||||
st()
|
||||
set_trace()
|
||||
4
resources/test/fixtures/flake8_errmsg/EM.py
vendored
4
resources/test/fixtures/flake8_errmsg/EM.py
vendored
@@ -5,6 +5,10 @@ def f_a():
|
||||
raise RuntimeError("This is an example exception")
|
||||
|
||||
|
||||
def f_a_short():
|
||||
raise RuntimeError("Error")
|
||||
|
||||
|
||||
def f_b():
|
||||
example = "example"
|
||||
raise RuntimeError(f"This is an {example} exception")
|
||||
|
||||
9
resources/test/fixtures/flake8_print/T201.py
vendored
9
resources/test/fixtures/flake8_print/T201.py
vendored
@@ -1 +1,10 @@
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
print("Hello, world!") # T201
|
||||
print("Hello, world!", file=None) # T201
|
||||
print("Hello, world!", file=sys.stdout) # T201
|
||||
print("Hello, world!", file=sys.stderr) # T201
|
||||
|
||||
with tempfile.NamedTemporaryFile() as fp:
|
||||
print("Hello, world!", file=fp) # OK
|
||||
|
||||
1
resources/test/fixtures/flake8_print/T203.py
vendored
1
resources/test/fixtures/flake8_print/T203.py
vendored
@@ -2,7 +2,6 @@ from pprint import pprint
|
||||
|
||||
pprint("Hello, world!") # T203
|
||||
|
||||
|
||||
import pprint
|
||||
|
||||
pprint.pprint("Hello, world!") # T203
|
||||
|
||||
27
resources/test/fixtures/flake8_return/RET504.py
vendored
27
resources/test/fixtures/flake8_return/RET504.py
vendored
@@ -6,18 +6,6 @@ def x():
|
||||
return a # error
|
||||
|
||||
|
||||
def x():
|
||||
b, a = 1, 2
|
||||
print(b)
|
||||
return a # error
|
||||
|
||||
|
||||
def x():
|
||||
a = 1
|
||||
print()
|
||||
return a # error
|
||||
|
||||
|
||||
def x():
|
||||
a = 1
|
||||
print(a)
|
||||
@@ -53,7 +41,6 @@ def x():
|
||||
|
||||
# https://github.com/afonasev/flake8-return/issues/47#issue-641117366
|
||||
def user_agent_username(username=None):
|
||||
|
||||
if not username:
|
||||
return ""
|
||||
|
||||
@@ -136,6 +123,20 @@ def x():
|
||||
return a
|
||||
|
||||
|
||||
# Considered OK, since functions can have side effects.
|
||||
def x():
|
||||
b, a = 1, 2
|
||||
print(b)
|
||||
return a
|
||||
|
||||
|
||||
# Considered OK, since functions can have side effects.
|
||||
def x():
|
||||
a = 1
|
||||
print()
|
||||
return a
|
||||
|
||||
|
||||
# Test cases for using value for assignment then returning it
|
||||
# See:https://github.com/afonasev/flake8-return/issues/47
|
||||
def resolve_from_url(self, url: str) -> dict:
|
||||
|
||||
@@ -27,7 +27,7 @@ def f(cls, x):
|
||||
lambda x: print("Hello, world!")
|
||||
|
||||
|
||||
class X:
|
||||
class C:
|
||||
###
|
||||
# Unused arguments.
|
||||
###
|
||||
|
||||
14
resources/test/fixtures/flake8_unused_arguments/ignore_variadic_names.py
vendored
Normal file
14
resources/test/fixtures/flake8_unused_arguments/ignore_variadic_names.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
def f(a, b):
|
||||
print("Hello, world!")
|
||||
|
||||
|
||||
def f(a, b, *args, **kwargs):
|
||||
print("Hello, world!")
|
||||
|
||||
|
||||
class C:
|
||||
def f(self, a, b):
|
||||
print("Hello, world!")
|
||||
|
||||
def f(self, a, b, *args, **kwargs):
|
||||
print("Hello, world!")
|
||||
5
resources/test/fixtures/pycodestyle/E501.py
vendored
5
resources/test/fixtures/pycodestyle/E501.py
vendored
@@ -55,3 +55,8 @@ sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labor
|
||||
|
||||
# OK
|
||||
# https://loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong.url.com
|
||||
|
||||
# Not OK
|
||||
_ = """
|
||||
Source: https://github.com/PyCQA/pycodestyle/pull/258/files#diff-841c622497a8033d10152bfdfb15b20b92437ecdea21a260944ea86b77b51533
|
||||
"""
|
||||
|
||||
13
resources/test/fixtures/pyflakes/F821_7.py
vendored
Normal file
13
resources/test/fixtures/pyflakes/F821_7.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
"""Test: Mypy extensions."""
|
||||
|
||||
from mypy_extensions import DefaultNamedArg
|
||||
|
||||
# OK
|
||||
_ = DefaultNamedArg(bool | None, name="some_prop_name")
|
||||
_ = DefaultNamedArg(type=bool | None, name="some_prop_name")
|
||||
_ = DefaultNamedArg(bool | None, "some_prop_name")
|
||||
|
||||
# Not OK
|
||||
_ = DefaultNamedArg("Undefined", name="some_prop_name")
|
||||
_ = DefaultNamedArg(type="Undefined", name="some_prop_name")
|
||||
_ = DefaultNamedArg("Undefined", "some_prop_name")
|
||||
8
resources/test/fixtures/pygrep-hooks/PGH002_0.py
vendored
Normal file
8
resources/test/fixtures/pygrep-hooks/PGH002_0.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import logging
|
||||
import warnings
|
||||
from warnings import warn
|
||||
|
||||
warnings.warn("this is ok")
|
||||
warn("by itself is also ok")
|
||||
logging.warning("this is fine")
|
||||
log.warning("this is ok")
|
||||
15
resources/test/fixtures/pygrep-hooks/PGH002_1.py
vendored
Normal file
15
resources/test/fixtures/pygrep-hooks/PGH002_1.py
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import logging
|
||||
from logging import warn
|
||||
|
||||
logging.warn("this is not ok")
|
||||
log.warn("this is also not ok")
|
||||
warn("not ok")
|
||||
|
||||
|
||||
def foo():
|
||||
from logging import warn
|
||||
|
||||
def warn():
|
||||
pass
|
||||
|
||||
warn("has been redefined, but we will still report it")
|
||||
11
resources/test/fixtures/pygrep-hooks/PGH003_0.py
vendored
Normal file
11
resources/test/fixtures/pygrep-hooks/PGH003_0.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
x = 1 # type: ignore
|
||||
x = 1 # type ignore
|
||||
x = 1 # type:ignore
|
||||
|
||||
x = 1
|
||||
x = 1 # type ignore # noqa
|
||||
x = 1 # type: ignore[attr-defined]
|
||||
x = 1 # type: ignore[attr-defined, name-defined]
|
||||
x = 1 # type: ignore[type-mismatch] # noqa
|
||||
x = 1 # type: Union[int, str]
|
||||
x = 1 # type: ignoreme
|
||||
@@ -109,6 +109,11 @@ def f():
|
||||
del x
|
||||
|
||||
|
||||
def f():
|
||||
print(f"{x=}")
|
||||
global x
|
||||
|
||||
|
||||
###
|
||||
# Non-errors.
|
||||
###
|
||||
@@ -146,3 +151,8 @@ def f():
|
||||
global x, y
|
||||
|
||||
del x
|
||||
|
||||
|
||||
def f():
|
||||
global x
|
||||
print(f"{x=}")
|
||||
|
||||
17
resources/test/fixtures/ruff/RUF100.py
vendored
17
resources/test/fixtures/ruff/RUF100.py
vendored
@@ -69,3 +69,20 @@ _ = """Lorem ipsum dolor sit amet.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.
|
||||
""" # noqa
|
||||
|
||||
# Valid
|
||||
# this is a veryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy long comment # noqa: E501
|
||||
|
||||
# Valid
|
||||
_ = """Here's a source: https://github.com/ethereum/web3.py/blob/ffe59daf10edc19ee5f05227b25bac8d090e8aa4/web3/_utils/events.py#L201
|
||||
|
||||
May raise:
|
||||
- DeserializationError if the abi string is invalid or abi or log topics/data do not match
|
||||
""" # noqa: E501
|
||||
|
||||
import collections # noqa
|
||||
import os # noqa: F401, RUF100
|
||||
import shelve # noqa: RUF100
|
||||
import sys # noqa: F401, RUF100
|
||||
|
||||
print(sys.path)
|
||||
|
||||
2
resources/test/package/pyproject.toml
Normal file
2
resources/test/package/pyproject.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[tool.ruff]
|
||||
src = ["."]
|
||||
4
resources/test/package/src/package/app.py
Normal file
4
resources/test/package/src/package/app.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from package.core import method
|
||||
|
||||
if __name__ == "__main__":
|
||||
method()
|
||||
0
resources/test/package/src/package/core.py
Normal file
0
resources/test/package/src/package/core.py
Normal file
0
resources/test/project/project/__init__.py
Normal file
0
resources/test/project/project/__init__.py
Normal file
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.183"
|
||||
version = "0.0.190"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -11,8 +11,8 @@ itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
ruff = { path = ".." }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "8d879a53197f9c73062f6160410bdba796a71cbf" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "8d879a53197f9c73062f6160410bdba796a71cbf" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "8d879a53197f9c73062f6160410bdba796a71cbf" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
//! Generate the `CheckCodePrefix` enum.
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fs::OpenOptions;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Output, Stdio};
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{ensure, Result};
|
||||
use clap::Parser;
|
||||
use codegen::{Scope, Type, Variant};
|
||||
use itertools::Itertools;
|
||||
use ruff::checks::{CheckCode, CODE_REDIRECTS, PREFIX_REDIRECTS};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
const FILE: &str = "src/checks_gen.rs";
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
@@ -107,7 +107,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
for (prefix, codes) in &prefix_to_codes {
|
||||
if let Some(target) = CODE_REDIRECTS.get(&prefix.as_str()) {
|
||||
gen = gen.line(format!(
|
||||
"CheckCodePrefix::{prefix} => {{ eprintln!(\"{{}}{{}} {{}}\", \
|
||||
"CheckCodePrefix::{prefix} => {{ one_time_warning!(\"{{}}{{}} {{}}\", \
|
||||
\"warning\".yellow().bold(), \":\".bold(), \"`{}` has been remapped to \
|
||||
`{}`\".bold()); \n vec![{}] }}",
|
||||
prefix,
|
||||
@@ -119,7 +119,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
));
|
||||
} else if let Some(target) = PREFIX_REDIRECTS.get(&prefix.as_str()) {
|
||||
gen = gen.line(format!(
|
||||
"CheckCodePrefix::{prefix} => {{ eprintln!(\"{{}}{{}} {{}}\", \
|
||||
"CheckCodePrefix::{prefix} => {{ one_time_warning!(\"{{}}{{}} {{}}\", \
|
||||
\"warning\".yellow().bold(), \":\".bold(), \"`{}` has been remapped to \
|
||||
`{}`\".bold()); \n vec![{}] }}",
|
||||
prefix,
|
||||
@@ -182,6 +182,8 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
output.push('\n');
|
||||
output.push_str("use crate::checks::CheckCode;");
|
||||
output.push('\n');
|
||||
output.push_str("use crate::one_time_warning;");
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
output.push_str(&scope.to_string());
|
||||
output.push('\n');
|
||||
@@ -202,12 +204,25 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
|
||||
let rustfmt = Command::new("rustfmt")
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?;
|
||||
write!(rustfmt.stdin.as_ref().unwrap(), "{output}")?;
|
||||
let Output { status, stdout, .. } = rustfmt.wait_with_output()?;
|
||||
ensure!(status.success(), "rustfmt failed with {status}");
|
||||
|
||||
// Write the output to `src/checks_gen.rs` (or stdout).
|
||||
if cli.dry_run {
|
||||
println!("{output}");
|
||||
println!("{}", String::from_utf8(stdout)?);
|
||||
} else {
|
||||
let mut f = OpenOptions::new().write(true).truncate(true).open(FILE)?;
|
||||
write!(f, "{output}")?;
|
||||
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.expect("Failed to find root directory")
|
||||
.join("src/checks_gen.rs");
|
||||
if fs::read(&file).map_or(true, |old| old != stdout) {
|
||||
fs::write(&file, stdout)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.183"
|
||||
version = "0.0.190"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -3,7 +3,8 @@ use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_ast::{
|
||||
Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprKind, Location, Stmt, StmtKind,
|
||||
Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprKind, Keyword, KeywordData,
|
||||
Location, Stmt, StmtKind,
|
||||
};
|
||||
use rustpython_parser::lexer;
|
||||
use rustpython_parser::lexer::Tok;
|
||||
@@ -210,6 +211,34 @@ pub fn is_constant_non_singleton(expr: &Expr) -> bool {
|
||||
is_constant(expr) && !is_singleton(expr)
|
||||
}
|
||||
|
||||
/// Return the `Keyword` with the given name, if it's present in the list of
|
||||
/// `Keyword` arguments.
|
||||
pub fn find_keyword<'a>(keywords: &'a [Keyword], keyword_name: &str) -> Option<&'a Keyword> {
|
||||
keywords.iter().find(|keyword| {
|
||||
let KeywordData { arg, .. } = &keyword.node;
|
||||
arg.as_ref().map_or(false, |arg| arg == keyword_name)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return `true` if an `Expr` is `None`.
|
||||
pub fn is_const_none(expr: &Expr) -> bool {
|
||||
matches!(
|
||||
&expr.node,
|
||||
ExprKind::Constant {
|
||||
value: Constant::None,
|
||||
kind: None
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Return `true` if a keyword argument is present with a non-`None` value.
|
||||
pub fn has_non_none_keyword(keywords: &[Keyword], keyword: &str) -> bool {
|
||||
find_keyword(keywords, keyword).map_or(false, |keyword| {
|
||||
let KeywordData { value, .. } = &keyword.node;
|
||||
!is_const_none(value)
|
||||
})
|
||||
}
|
||||
|
||||
/// Extract the names of all handled exceptions.
|
||||
pub fn extract_handler_names(handlers: &[Excepthandler]) -> Vec<Vec<&str>> {
|
||||
let mut handler_names = vec![];
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::str::Lines;
|
||||
use rustpython_ast::{Located, Location};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
/// Extract the leading indentation from a line.
|
||||
pub fn indentation<'a, T>(checker: &'a Checker, located: &'a Located<T>) -> Cow<'a, str> {
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::autofix::Fix;
|
||||
use crate::checks::Check;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
#[derive(Debug, Hash)]
|
||||
#[derive(Debug, Copy, Clone, Hash)]
|
||||
pub enum Mode {
|
||||
Generate,
|
||||
Apply,
|
||||
@@ -27,15 +27,6 @@ impl From<bool> for Mode {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Mode> for bool {
|
||||
fn from(value: &Mode) -> Self {
|
||||
match value {
|
||||
Mode::Generate | Mode::Apply => true,
|
||||
Mode::None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Auto-fix errors in a file, and write the fixed source code to disk.
|
||||
pub fn fix_file<'a>(
|
||||
checks: &'a [Check],
|
||||
|
||||
85
src/cache.rs
85
src/cache.rs
@@ -8,13 +8,15 @@ use std::path::Path;
|
||||
use anyhow::Result;
|
||||
use filetime::FileTime;
|
||||
use log::error;
|
||||
use once_cell::sync::Lazy;
|
||||
use path_absolutize::Absolutize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::autofix::fixer;
|
||||
use crate::message::Message;
|
||||
use crate::settings::Settings;
|
||||
use crate::settings::{flags, Settings};
|
||||
|
||||
static CACHE_DIR: Lazy<Option<String>> = Lazy::new(|| std::env::var("RUFF_CACHE_DIR").ok());
|
||||
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -34,55 +36,18 @@ struct CheckResult {
|
||||
messages: Vec<Message>,
|
||||
}
|
||||
|
||||
pub enum Mode {
|
||||
ReadWrite,
|
||||
ReadOnly,
|
||||
WriteOnly,
|
||||
None,
|
||||
fn cache_dir() -> &'static Path {
|
||||
Path::new(CACHE_DIR.as_ref().map_or(".ruff_cache", String::as_str))
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
fn allow_read(&self) -> bool {
|
||||
match self {
|
||||
Mode::ReadWrite => true,
|
||||
Mode::ReadOnly => true,
|
||||
Mode::WriteOnly => false,
|
||||
Mode::None => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn allow_write(&self) -> bool {
|
||||
match self {
|
||||
Mode::ReadWrite => true,
|
||||
Mode::ReadOnly => false,
|
||||
Mode::WriteOnly => true,
|
||||
Mode::None => false,
|
||||
}
|
||||
}
|
||||
fn content_dir() -> &'static Path {
|
||||
Path::new("content")
|
||||
}
|
||||
|
||||
impl From<bool> for Mode {
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
Mode::ReadWrite
|
||||
} else {
|
||||
Mode::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cache_dir() -> &'static str {
|
||||
"./.ruff_cache"
|
||||
}
|
||||
|
||||
fn content_dir() -> &'static str {
|
||||
"content"
|
||||
}
|
||||
|
||||
fn cache_key(path: &Path, settings: &Settings, autofix: &fixer::Mode) -> u64 {
|
||||
fn cache_key<P: AsRef<Path>>(path: P, settings: &Settings, autofix: fixer::Mode) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
CARGO_PKG_VERSION.hash(&mut hasher);
|
||||
path.absolutize().unwrap().hash(&mut hasher);
|
||||
path.as_ref().absolutize().unwrap().hash(&mut hasher);
|
||||
settings.hash(&mut hasher);
|
||||
autofix.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
@@ -90,7 +55,7 @@ fn cache_key(path: &Path, settings: &Settings, autofix: &fixer::Mode) -> u64 {
|
||||
|
||||
/// Initialize the cache directory.
|
||||
pub fn init() -> Result<()> {
|
||||
let path = Path::new(cache_dir());
|
||||
let path = cache_dir();
|
||||
|
||||
// Create the cache directories.
|
||||
create_dir_all(path.join(content_dir()))?;
|
||||
@@ -112,30 +77,24 @@ pub fn init() -> Result<()> {
|
||||
|
||||
fn write_sync(key: u64, value: &[u8]) -> Result<(), std::io::Error> {
|
||||
fs::write(
|
||||
Path::new(cache_dir())
|
||||
.join(content_dir())
|
||||
.join(format!("{key:x}")),
|
||||
cache_dir().join(content_dir()).join(format!("{key:x}")),
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
fn read_sync(key: u64) -> Result<Vec<u8>, std::io::Error> {
|
||||
fs::read(
|
||||
Path::new(cache_dir())
|
||||
.join(content_dir())
|
||||
.join(format!("{key:x}")),
|
||||
)
|
||||
fs::read(cache_dir().join(content_dir()).join(format!("{key:x}")))
|
||||
}
|
||||
|
||||
/// Get a value from the cache.
|
||||
pub fn get(
|
||||
path: &Path,
|
||||
pub fn get<P: AsRef<Path>>(
|
||||
path: P,
|
||||
metadata: &Metadata,
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
mode: &Mode,
|
||||
autofix: fixer::Mode,
|
||||
cache: flags::Cache,
|
||||
) -> Option<Vec<Message>> {
|
||||
if !mode.allow_read() {
|
||||
if matches!(cache, flags::Cache::Disabled) {
|
||||
return None;
|
||||
};
|
||||
|
||||
@@ -157,15 +116,15 @@ pub fn get(
|
||||
}
|
||||
|
||||
/// Set a value in the cache.
|
||||
pub fn set(
|
||||
path: &Path,
|
||||
pub fn set<P: AsRef<Path>>(
|
||||
path: P,
|
||||
metadata: &Metadata,
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
autofix: fixer::Mode,
|
||||
messages: &[Message],
|
||||
mode: &Mode,
|
||||
cache: flags::Cache,
|
||||
) {
|
||||
if !mode.allow_write() {
|
||||
if matches!(cache, flags::Cache::Disabled) {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
//! Lint rules based on checking raw physical lines.
|
||||
|
||||
use nohash_hasher::IntMap;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::checks::{Check, CheckCode, CheckKind, CODE_REDIRECTS};
|
||||
use crate::noqa;
|
||||
use crate::noqa::{is_file_exempt, Directive};
|
||||
use crate::settings::Settings;
|
||||
|
||||
// Regex from PEP263.
|
||||
static CODING_COMMENT_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^[ \t\f]*#.*?coding[:=][ \t]*utf-?8").unwrap());
|
||||
|
||||
static URL_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^https?://\S+$").unwrap());
|
||||
|
||||
/// Whether the given line is too long and should be reported.
|
||||
fn should_enforce_line_length(line: &str, length: usize, limit: usize) -> bool {
|
||||
if length <= limit {
|
||||
return false;
|
||||
}
|
||||
let mut chunks = line.split_whitespace();
|
||||
let (Some(first), Some(_)) = (chunks.next(), chunks.next()) else {
|
||||
// Single word / no printable chars - no way to make the line shorter
|
||||
return false;
|
||||
};
|
||||
|
||||
// Do not enforce the line length for commented lines that end with a URL
|
||||
// or contain only a single word.
|
||||
!(first == "#" && chunks.last().map_or(true, |c| URL_REGEX.is_match(c)))
|
||||
}
|
||||
|
||||
pub fn check_lines(
|
||||
checks: &mut Vec<Check>,
|
||||
contents: &str,
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
settings: &Settings,
|
||||
autofix: bool,
|
||||
ignore_noqa: bool,
|
||||
) {
|
||||
let enforce_unnecessary_coding_comment = settings.enabled.contains(&CheckCode::UP009);
|
||||
let enforce_line_too_long = settings.enabled.contains(&CheckCode::E501);
|
||||
let enforce_noqa = settings.enabled.contains(&CheckCode::RUF100);
|
||||
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<&str>)> = IntMap::default();
|
||||
let mut line_checks = vec![];
|
||||
let mut ignored = vec![];
|
||||
|
||||
checks.sort_by_key(|check| check.location);
|
||||
let mut checks_iter = checks.iter().enumerate().peekable();
|
||||
if let Some((_index, check)) = checks_iter.peek() {
|
||||
assert!(check.location.row() >= 1);
|
||||
}
|
||||
|
||||
macro_rules! add_if {
|
||||
($check:expr, $noqa_lineno:expr, $line:expr) => {{
|
||||
match noqa_directives
|
||||
.entry($noqa_lineno)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive($line), vec![]))
|
||||
{
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push($check.kind.code().as_ref());
|
||||
if ignore_noqa {
|
||||
line_checks.push($check);
|
||||
}
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if noqa::includes($check.kind.code(), codes) {
|
||||
matches.push($check.kind.code().as_ref());
|
||||
if ignore_noqa {
|
||||
line_checks.push($check);
|
||||
}
|
||||
} else {
|
||||
line_checks.push($check);
|
||||
}
|
||||
}
|
||||
(Directive::None, ..) => line_checks.push($check),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
for (lineno, line) in lines.iter().enumerate() {
|
||||
// If we hit an exemption for the entire file, bail.
|
||||
if is_file_exempt(line) {
|
||||
checks.drain(..);
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the noqa (logical) line number for the current (physical) line.
|
||||
// If there are newlines at the end of the file, they won't be represented in
|
||||
// `noqa_line_for`, so fallback to the current line.
|
||||
let noqa_lineno = noqa_line_for.get(&(lineno + 1)).unwrap_or(&(lineno + 1)) - 1;
|
||||
|
||||
// Enforce unnecessary coding comments (UP009).
|
||||
if enforce_unnecessary_coding_comment {
|
||||
if lineno < 2 {
|
||||
// PEP3120 makes utf-8 the default encoding.
|
||||
if CODING_COMMENT_REGEX.is_match(line) {
|
||||
let mut check = Check::new(
|
||||
CheckKind::PEP3120UnnecessaryCodingComment,
|
||||
Range {
|
||||
location: Location::new(lineno + 1, 0),
|
||||
end_location: Location::new(lineno + 2, 0),
|
||||
},
|
||||
);
|
||||
if autofix && settings.fixable.contains(check.kind.code()) {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(lineno + 1, 0),
|
||||
Location::new(lineno + 2, 0),
|
||||
));
|
||||
}
|
||||
add_if!(check, noqa_lineno, lines[noqa_lineno]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_noqa {
|
||||
noqa_directives
|
||||
.entry(noqa_lineno)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[noqa_lineno]), vec![]));
|
||||
}
|
||||
|
||||
// Remove any ignored checks.
|
||||
while let Some((index, check)) =
|
||||
checks_iter.next_if(|(_index, check)| check.location.row() == lineno + 1)
|
||||
{
|
||||
let noqa = noqa_directives
|
||||
.entry(noqa_lineno)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[noqa_lineno]), vec![]));
|
||||
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
ignored.push(index);
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if noqa::includes(check.kind.code(), codes) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
ignored.push(index);
|
||||
}
|
||||
}
|
||||
(Directive::None, ..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce line length violations (E501).
|
||||
if enforce_line_too_long {
|
||||
let line_length = line.chars().count();
|
||||
if should_enforce_line_length(line, line_length, settings.line_length) {
|
||||
let check = Check::new(
|
||||
CheckKind::LineTooLong(line_length, settings.line_length),
|
||||
Range {
|
||||
location: Location::new(lineno + 1, 0),
|
||||
end_location: Location::new(lineno + 1, line_length),
|
||||
},
|
||||
);
|
||||
add_if!(check, noqa_lineno, lines[noqa_lineno]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce newlines at end of files (W292).
|
||||
if settings.enabled.contains(&CheckCode::W292) && !contents.ends_with('\n') {
|
||||
// Note: if `lines.last()` is `None`, then `contents` is empty (and so we don't
|
||||
// want to raise W292 anyway).
|
||||
if let Some(line) = lines.last() {
|
||||
let check = Check::new(
|
||||
CheckKind::NoNewLineAtEndOfFile,
|
||||
Range {
|
||||
location: Location::new(lines.len(), line.len() + 1),
|
||||
end_location: Location::new(lines.len(), line.len() + 1),
|
||||
},
|
||||
);
|
||||
|
||||
let lineno = lines.len() - 1;
|
||||
let noqa_lineno = noqa_line_for.get(&(lineno + 1)).unwrap_or(&(lineno + 1)) - 1;
|
||||
add_if!(check, noqa_lineno, lines[noqa_lineno]);
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce that the noqa directive was actually used (RUF100).
|
||||
if enforce_noqa {
|
||||
for (row, (directive, matches)) in noqa_directives {
|
||||
match directive {
|
||||
Directive::All(spaces, start, end) => {
|
||||
if matches.is_empty() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnusedNOQA(None),
|
||||
Range {
|
||||
location: Location::new(row + 1, start),
|
||||
end_location: Location::new(row + 1, end),
|
||||
},
|
||||
);
|
||||
if autofix && settings.fixable.contains(check.kind.code()) {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
}
|
||||
line_checks.push(check);
|
||||
}
|
||||
}
|
||||
Directive::Codes(spaces, start, end, codes) => {
|
||||
let mut invalid_codes = vec![];
|
||||
let mut valid_codes = vec![];
|
||||
for code in codes {
|
||||
let code = CODE_REDIRECTS.get(code).map_or(code, AsRef::as_ref);
|
||||
if matches.contains(&code) || settings.external.contains(code) {
|
||||
valid_codes.push(code.to_string());
|
||||
} else {
|
||||
invalid_codes.push(code.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
if !invalid_codes.is_empty() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnusedNOQA(Some(invalid_codes)),
|
||||
Range {
|
||||
location: Location::new(row + 1, start),
|
||||
end_location: Location::new(row + 1, end),
|
||||
},
|
||||
);
|
||||
if autofix && settings.fixable.contains(check.kind.code()) {
|
||||
if valid_codes.is_empty() {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
} else {
|
||||
check.amend(Fix::replacement(
|
||||
format!("# noqa: {}", valid_codes.join(", ")),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
}
|
||||
}
|
||||
line_checks.push(check);
|
||||
}
|
||||
}
|
||||
Directive::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !ignore_noqa {
|
||||
ignored.sort_unstable();
|
||||
for index in ignored.iter().rev() {
|
||||
checks.swap_remove(*index);
|
||||
}
|
||||
}
|
||||
checks.extend(line_checks);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nohash_hasher::IntMap;
|
||||
|
||||
use super::check_lines;
|
||||
use crate::checks::{Check, CheckCode};
|
||||
use crate::settings::Settings;
|
||||
|
||||
#[test]
|
||||
fn e501_non_ascii_char() {
|
||||
let line = "'\u{4e9c}' * 2"; // 7 in UTF-32, 9 in UTF-8.
|
||||
let check_with_max_line_length = |line_length: usize| {
|
||||
let mut checks: Vec<Check> = vec![];
|
||||
check_lines(
|
||||
&mut checks,
|
||||
line,
|
||||
&IntMap::default(),
|
||||
&Settings {
|
||||
line_length,
|
||||
..Settings::for_rule(CheckCode::E501)
|
||||
},
|
||||
true,
|
||||
false,
|
||||
);
|
||||
checks
|
||||
};
|
||||
assert!(!check_with_max_line_length(6).is_empty());
|
||||
assert!(check_with_max_line_length(7).is_empty());
|
||||
}
|
||||
}
|
||||
@@ -31,16 +31,16 @@ use crate::python::future::ALL_FEATURE_NAMES;
|
||||
use crate::python::typing;
|
||||
use crate::python::typing::SubscriptKind;
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::settings::Settings;
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
use crate::vendored::cformat::{CFormatError, CFormatErrorType};
|
||||
use crate::visibility::{module_visibility, transition_scope, Modifier, Visibility, VisibleScope};
|
||||
use crate::{
|
||||
docstrings, flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except,
|
||||
flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_debugger,
|
||||
flake8_errmsg, flake8_import_conventions, flake8_print, flake8_return, flake8_simplify,
|
||||
flake8_tidy_imports, flake8_unused_arguments, mccabe, noqa, pandas_vet, pep8_naming,
|
||||
pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, visibility,
|
||||
flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez,
|
||||
flake8_debugger, flake8_errmsg, flake8_import_conventions, flake8_print, flake8_return,
|
||||
flake8_simplify, flake8_tidy_imports, flake8_unused_arguments, mccabe, noqa, pandas_vet,
|
||||
pep8_naming, pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, visibility,
|
||||
};
|
||||
|
||||
const GLOBAL_SCOPE_INDEX: usize = 0;
|
||||
@@ -51,8 +51,8 @@ type DeferralContext<'a> = (Vec<usize>, Vec<RefEquality<'a, Stmt>>);
|
||||
pub struct Checker<'a> {
|
||||
// Input data.
|
||||
path: &'a Path,
|
||||
autofix: bool,
|
||||
ignore_noqa: bool,
|
||||
autofix: flags::Autofix,
|
||||
noqa: flags::Noqa,
|
||||
pub(crate) settings: &'a Settings,
|
||||
pub(crate) noqa_line_for: &'a IntMap<usize, usize>,
|
||||
pub(crate) locator: &'a SourceCodeLocator<'a>,
|
||||
@@ -73,6 +73,7 @@ pub struct Checker<'a> {
|
||||
pub(crate) child_to_parent: FxHashMap<RefEquality<'a, Stmt>, RefEquality<'a, Stmt>>,
|
||||
pub(crate) bindings: Vec<Binding<'a>>,
|
||||
pub(crate) redefinitions: IntMap<usize, Vec<usize>>,
|
||||
exprs: Vec<RefEquality<'a, Expr>>,
|
||||
scopes: Vec<Scope<'a>>,
|
||||
scope_stack: Vec<usize>,
|
||||
dead_scopes: Vec<usize>,
|
||||
@@ -95,15 +96,15 @@ pub struct Checker<'a> {
|
||||
annotations_future_enabled: bool,
|
||||
except_handlers: Vec<Vec<Vec<&'a str>>>,
|
||||
// Check-specific state.
|
||||
pub(crate) seen_b023: Vec<&'a Expr>,
|
||||
pub(crate) flake8_bugbear_seen: Vec<&'a Expr>,
|
||||
}
|
||||
|
||||
impl<'a> Checker<'a> {
|
||||
pub fn new(
|
||||
settings: &'a Settings,
|
||||
noqa_line_for: &'a IntMap<usize, usize>,
|
||||
autofix: bool,
|
||||
ignore_noqa: bool,
|
||||
autofix: flags::Autofix,
|
||||
noqa: flags::Noqa,
|
||||
path: &'a Path,
|
||||
locator: &'a SourceCodeLocator,
|
||||
) -> Checker<'a> {
|
||||
@@ -111,7 +112,7 @@ impl<'a> Checker<'a> {
|
||||
settings,
|
||||
noqa_line_for,
|
||||
autofix,
|
||||
ignore_noqa,
|
||||
noqa,
|
||||
path,
|
||||
locator,
|
||||
checks: vec![],
|
||||
@@ -124,6 +125,7 @@ impl<'a> Checker<'a> {
|
||||
child_to_parent: FxHashMap::default(),
|
||||
bindings: vec![],
|
||||
redefinitions: IntMap::default(),
|
||||
exprs: vec![],
|
||||
scopes: vec![],
|
||||
scope_stack: vec![],
|
||||
dead_scopes: vec![],
|
||||
@@ -149,24 +151,19 @@ impl<'a> Checker<'a> {
|
||||
annotations_future_enabled: false,
|
||||
except_handlers: vec![],
|
||||
// Check-specific state.
|
||||
seen_b023: vec![],
|
||||
flake8_bugbear_seen: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a `Check` to the `Checker`.
|
||||
pub(crate) fn add_check(&mut self, check: Check) {
|
||||
pub(crate) fn add_check(&mut self, mut check: Check) {
|
||||
// If we're in an f-string, override the location. RustPython doesn't produce
|
||||
// reliable locations for expressions within f-strings, so we use the
|
||||
// span of the f-string itself as a best-effort default.
|
||||
let check = if let Some(range) = self.in_f_string {
|
||||
Check {
|
||||
location: range.location,
|
||||
end_location: range.end_location,
|
||||
..check
|
||||
}
|
||||
} else {
|
||||
check
|
||||
};
|
||||
if let Some(range) = self.in_f_string {
|
||||
check.location = range.location;
|
||||
check.end_location = range.end_location;
|
||||
}
|
||||
self.checks.push(check);
|
||||
}
|
||||
|
||||
@@ -182,7 +179,16 @@ impl<'a> Checker<'a> {
|
||||
pub fn patch(&self, code: &CheckCode) -> bool {
|
||||
// TODO(charlie): We can't fix errors in f-strings until RustPython adds
|
||||
// location data.
|
||||
self.autofix && self.in_f_string.is_none() && self.settings.fixable.contains(code)
|
||||
matches!(self.autofix, flags::Autofix::Enabled)
|
||||
&& self.in_f_string.is_none()
|
||||
&& self.settings.fixable.contains(code)
|
||||
}
|
||||
|
||||
/// Return the amended `Range` from a `Located`.
|
||||
pub fn range_for<T>(&self, located: &Located<T>) -> Range {
|
||||
// If we're in an f-string, override the location.
|
||||
self.in_f_string
|
||||
.unwrap_or_else(|| Range::from_located(located))
|
||||
}
|
||||
|
||||
/// Return `true` if the `Expr` is a reference to `typing.${target}`.
|
||||
@@ -216,7 +222,7 @@ impl<'a> Checker<'a> {
|
||||
// members from the fix that will eventually be excluded by a `noqa`.
|
||||
// Unfortunately, we _do_ want to register a `Check` for each eventually-ignored
|
||||
// import, so that our `noqa` counts are accurate.
|
||||
if self.ignore_noqa {
|
||||
if matches!(self.noqa, flags::Noqa::Disabled) {
|
||||
return false;
|
||||
}
|
||||
let noqa_lineno = self.noqa_line_for.get(&lineno).unwrap_or(&lineno);
|
||||
@@ -541,7 +547,7 @@ where
|
||||
kind: BindingKind::FunctionDefinition,
|
||||
used: None,
|
||||
range: Range::from_located(stmt),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -646,7 +652,7 @@ where
|
||||
),
|
||||
used: None,
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
@@ -686,7 +692,7 @@ where
|
||||
None
|
||||
},
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -845,7 +851,7 @@ where
|
||||
Range::from_located(alias),
|
||||
)),
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -876,7 +882,7 @@ where
|
||||
kind: BindingKind::StarImportation(*level, module.clone()),
|
||||
used: None,
|
||||
range: Range::from_located(stmt),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -945,7 +951,7 @@ where
|
||||
None
|
||||
},
|
||||
range,
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1177,7 +1183,7 @@ where
|
||||
self, stmt, targets, value,
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::PDV901) {
|
||||
if self.settings.enabled.contains(&CheckCode::PD901) {
|
||||
if let Some(check) = pandas_vet::checks::assignment_to_df(targets) {
|
||||
self.add_check(check);
|
||||
}
|
||||
@@ -1380,7 +1386,7 @@ where
|
||||
kind: BindingKind::ClassDefinition,
|
||||
used: None,
|
||||
range: Range::from_located(stmt),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1401,10 +1407,6 @@ where
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'b Expr) {
|
||||
let prev_in_f_string = self.in_f_string;
|
||||
let prev_in_literal = self.in_literal;
|
||||
let prev_in_type_definition = self.in_type_definition;
|
||||
|
||||
if !(self.in_deferred_type_definition || self.in_deferred_string_type_definition)
|
||||
&& self.in_type_definition
|
||||
&& self.annotations_future_enabled
|
||||
@@ -1430,6 +1432,12 @@ where
|
||||
return;
|
||||
}
|
||||
|
||||
self.push_expr(expr);
|
||||
|
||||
let prev_in_f_string = self.in_f_string;
|
||||
let prev_in_literal = self.in_literal;
|
||||
let prev_in_type_definition = self.in_type_definition;
|
||||
|
||||
// Pre-visit.
|
||||
match &expr.node {
|
||||
ExprKind::Subscript { value, slice, .. } => {
|
||||
@@ -1541,10 +1549,10 @@ where
|
||||
}
|
||||
|
||||
for (code, name) in vec![
|
||||
(CheckCode::PDV007, "ix"),
|
||||
(CheckCode::PDV008, "at"),
|
||||
(CheckCode::PDV009, "iat"),
|
||||
(CheckCode::PDV011, "values"),
|
||||
(CheckCode::PD007, "ix"),
|
||||
(CheckCode::PD008, "at"),
|
||||
(CheckCode::PD009, "iat"),
|
||||
(CheckCode::PD011, "values"),
|
||||
] {
|
||||
if self.settings.enabled.contains(&code) {
|
||||
if attr == name {
|
||||
@@ -1637,7 +1645,7 @@ where
|
||||
if self.settings.enabled.contains(&CheckCode::T201)
|
||||
|| self.settings.enabled.contains(&CheckCode::T203)
|
||||
{
|
||||
flake8_print::plugins::print_call(self, expr, func);
|
||||
flake8_print::plugins::print_call(self, expr, func, keywords);
|
||||
}
|
||||
|
||||
// flake8-bugbear
|
||||
@@ -1926,17 +1934,17 @@ where
|
||||
}
|
||||
|
||||
// pandas-vet
|
||||
if self.settings.enabled.contains(&CheckCode::PDV002) {
|
||||
if self.settings.enabled.contains(&CheckCode::PD002) {
|
||||
self.add_checks(pandas_vet::checks::inplace_argument(keywords).into_iter());
|
||||
}
|
||||
|
||||
for (code, name) in vec![
|
||||
(CheckCode::PDV003, "isnull"),
|
||||
(CheckCode::PDV004, "notnull"),
|
||||
(CheckCode::PDV010, "pivot"),
|
||||
(CheckCode::PDV010, "unstack"),
|
||||
(CheckCode::PDV012, "read_table"),
|
||||
(CheckCode::PDV013, "stack"),
|
||||
(CheckCode::PD003, "isnull"),
|
||||
(CheckCode::PD004, "notnull"),
|
||||
(CheckCode::PD010, "pivot"),
|
||||
(CheckCode::PD010, "unstack"),
|
||||
(CheckCode::PD012, "read_table"),
|
||||
(CheckCode::PD013, "stack"),
|
||||
] {
|
||||
if self.settings.enabled.contains(&code) {
|
||||
if let ExprKind::Attribute { attr, .. } = &func.node {
|
||||
@@ -1947,15 +1955,90 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::PDV015) {
|
||||
if self.settings.enabled.contains(&CheckCode::PD015) {
|
||||
if let Some(check) = pandas_vet::checks::use_of_pd_merge(func) {
|
||||
self.add_check(check);
|
||||
};
|
||||
}
|
||||
|
||||
// flake8-datetimez
|
||||
if self.settings.enabled.contains(&CheckCode::DTZ001) {
|
||||
flake8_datetimez::plugins::call_datetime_without_tzinfo(
|
||||
self,
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::DTZ002) {
|
||||
flake8_datetimez::plugins::call_datetime_today(
|
||||
self,
|
||||
func,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::DTZ003) {
|
||||
flake8_datetimez::plugins::call_datetime_utcnow(
|
||||
self,
|
||||
func,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::DTZ004) {
|
||||
flake8_datetimez::plugins::call_datetime_utcfromtimestamp(
|
||||
self,
|
||||
func,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::DTZ005) {
|
||||
flake8_datetimez::plugins::call_datetime_now_without_tzinfo(
|
||||
self,
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::DTZ006) {
|
||||
flake8_datetimez::plugins::call_datetime_fromtimestamp(
|
||||
self,
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::DTZ007) {
|
||||
flake8_datetimez::plugins::call_datetime_strptime_without_zone(
|
||||
self,
|
||||
func,
|
||||
args,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::DTZ011) {
|
||||
flake8_datetimez::plugins::call_date_today(
|
||||
self,
|
||||
func,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::DTZ012) {
|
||||
flake8_datetimez::plugins::call_date_fromtimestamp(
|
||||
self,
|
||||
func,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
|
||||
// pygrep-hooks
|
||||
if self.settings.enabled.contains(&CheckCode::PGH001) {
|
||||
pygrep_hooks::checks::no_eval(self, func);
|
||||
pygrep_hooks::plugins::no_eval(self, func);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::PGH002) {
|
||||
pygrep_hooks::plugins::deprecated_log_warn(self, func);
|
||||
}
|
||||
|
||||
// pylint
|
||||
@@ -2426,6 +2509,29 @@ where
|
||||
self.visit_expr(value);
|
||||
self.in_type_definition = prev_in_type_definition;
|
||||
}
|
||||
} else if ["Arg", "DefaultArg", "NamedArg", "DefaultNamedArg"]
|
||||
.iter()
|
||||
.any(|target| {
|
||||
match_call_path(&call_path, "mypy_extensions", target, &self.from_imports)
|
||||
})
|
||||
{
|
||||
self.visit_expr(func);
|
||||
|
||||
// Ex) DefaultNamedArg(bool | None, name="some_prop_name")
|
||||
let mut arguments = args.iter().chain(keywords.iter().map(|keyword| {
|
||||
let KeywordData { value, .. } = &keyword.node;
|
||||
value
|
||||
}));
|
||||
if let Some(expr) = arguments.next() {
|
||||
self.in_type_definition = true;
|
||||
self.visit_expr(expr);
|
||||
self.in_type_definition = prev_in_type_definition;
|
||||
}
|
||||
for expr in arguments {
|
||||
self.in_type_definition = false;
|
||||
self.visit_expr(expr);
|
||||
self.in_type_definition = prev_in_type_definition;
|
||||
}
|
||||
} else {
|
||||
visitor::walk_expr(self, expr);
|
||||
}
|
||||
@@ -2505,6 +2611,8 @@ where
|
||||
self.in_type_definition = prev_in_type_definition;
|
||||
self.in_literal = prev_in_literal;
|
||||
self.in_f_string = prev_in_f_string;
|
||||
|
||||
self.pop_expr();
|
||||
}
|
||||
|
||||
fn visit_excepthandler(&mut self, excepthandler: &'b Excepthandler) {
|
||||
@@ -2650,7 +2758,7 @@ where
|
||||
kind: BindingKind::Argument,
|
||||
used: None,
|
||||
range: Range::from_located(arg),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2685,7 +2793,17 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
|
||||
fn pop_parent(&mut self) {
|
||||
self.parents.pop().expect("Attempted to pop without scope");
|
||||
self.parents.pop().expect("Attempted to pop without parent");
|
||||
}
|
||||
|
||||
fn push_expr(&mut self, expr: &'a Expr) {
|
||||
self.exprs.push(RefEquality(expr));
|
||||
}
|
||||
|
||||
fn pop_expr(&mut self) {
|
||||
self.exprs
|
||||
.pop()
|
||||
.expect("Attempted to pop without expression");
|
||||
}
|
||||
|
||||
fn push_scope(&mut self, scope: Scope<'a>) {
|
||||
@@ -2716,6 +2834,36 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the current `Stmt`.
|
||||
pub fn current_stmt(&self) -> &RefEquality<'a, Stmt> {
|
||||
self.parents.iter().rev().next().expect("No parent found")
|
||||
}
|
||||
|
||||
/// Return the parent `Stmt` of the current `Stmt`, if any.
|
||||
pub fn current_stmt_parent(&self) -> Option<&RefEquality<'a, Stmt>> {
|
||||
self.parents.iter().rev().nth(1)
|
||||
}
|
||||
|
||||
/// Return the grandparent `Stmt` of the current `Stmt`, if any.
|
||||
pub fn current_stmt_grandparent(&self) -> Option<&RefEquality<'a, Stmt>> {
|
||||
self.parents.iter().rev().nth(2)
|
||||
}
|
||||
|
||||
/// Return the current `Expr`.
|
||||
pub fn current_expr(&self) -> Option<&RefEquality<'a, Expr>> {
|
||||
self.exprs.iter().rev().next()
|
||||
}
|
||||
|
||||
/// Return the parent `Expr` of the current `Expr`.
|
||||
pub fn current_expr_parent(&self) -> Option<&RefEquality<'a, Expr>> {
|
||||
self.exprs.iter().rev().nth(1)
|
||||
}
|
||||
|
||||
/// Return the grandparent `Expr` of the current `Expr`.
|
||||
pub fn current_expr_grandparent(&self) -> Option<&RefEquality<'a, Expr>> {
|
||||
self.exprs.iter().rev().nth(2)
|
||||
}
|
||||
|
||||
pub fn current_scope(&self) -> &Scope {
|
||||
&self.scopes[*(self.scope_stack.last().expect("No current scope found"))]
|
||||
}
|
||||
@@ -2727,14 +2875,6 @@ impl<'a> Checker<'a> {
|
||||
.map(|index| &self.scopes[*index])
|
||||
}
|
||||
|
||||
pub fn current_parent(&self) -> &RefEquality<'a, Stmt> {
|
||||
self.parents.iter().rev().next().expect("No parent found")
|
||||
}
|
||||
|
||||
pub fn current_grandparent(&self) -> Option<&RefEquality<'a, Stmt>> {
|
||||
self.parents.iter().rev().nth(1)
|
||||
}
|
||||
|
||||
fn add_binding<'b>(&mut self, name: &'b str, binding: Binding<'a>)
|
||||
where
|
||||
'b: 'a,
|
||||
@@ -2964,7 +3104,7 @@ impl<'a> Checker<'a> {
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
let parent = self.current_parent().0;
|
||||
let parent = self.current_stmt().0;
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::F823) {
|
||||
let scopes: Vec<&Scope> = self
|
||||
@@ -3009,7 +3149,7 @@ impl<'a> Checker<'a> {
|
||||
kind: BindingKind::Annotation,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
return;
|
||||
@@ -3026,7 +3166,7 @@ impl<'a> Checker<'a> {
|
||||
kind: BindingKind::LoopVar,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
return;
|
||||
@@ -3039,7 +3179,7 @@ impl<'a> Checker<'a> {
|
||||
kind: BindingKind::Binding,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
return;
|
||||
@@ -3089,7 +3229,7 @@ impl<'a> Checker<'a> {
|
||||
)),
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
return;
|
||||
@@ -3102,7 +3242,7 @@ impl<'a> Checker<'a> {
|
||||
kind: BindingKind::Assignment,
|
||||
used: None,
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -3758,11 +3898,11 @@ pub fn check_ast(
|
||||
locator: &SourceCodeLocator,
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
settings: &Settings,
|
||||
autofix: bool,
|
||||
ignore_noqa: bool,
|
||||
autofix: flags::Autofix,
|
||||
noqa: flags::Noqa,
|
||||
path: &Path,
|
||||
) -> Vec<Check> {
|
||||
let mut checker = Checker::new(settings, noqa_line_for, autofix, ignore_noqa, path, locator);
|
||||
let mut checker = Checker::new(settings, noqa_line_for, autofix, noqa, path, locator);
|
||||
checker.push_scope(Scope::new(ScopeKind::Module));
|
||||
checker.bind_builtins();
|
||||
|
||||
@@ -9,19 +9,22 @@ use crate::checks::Check;
|
||||
use crate::directives::IsortDirectives;
|
||||
use crate::isort;
|
||||
use crate::isort::track::ImportTracker;
|
||||
use crate::settings::Settings;
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
fn check_import_blocks(
|
||||
tracker: ImportTracker,
|
||||
locator: &SourceCodeLocator,
|
||||
settings: &Settings,
|
||||
autofix: bool,
|
||||
autofix: flags::Autofix,
|
||||
package: Option<&Path>,
|
||||
) -> Vec<Check> {
|
||||
let mut checks = vec![];
|
||||
for block in tracker.into_iter() {
|
||||
if !block.imports.is_empty() {
|
||||
if let Some(check) = isort::plugins::check_imports(&block, locator, settings, autofix) {
|
||||
if let Some(check) =
|
||||
isort::plugins::check_imports(&block, locator, settings, autofix, package)
|
||||
{
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
@@ -34,12 +37,13 @@ pub fn check_imports(
|
||||
locator: &SourceCodeLocator,
|
||||
directives: &IsortDirectives,
|
||||
settings: &Settings,
|
||||
autofix: bool,
|
||||
autofix: flags::Autofix,
|
||||
path: &Path,
|
||||
package: Option<&Path>,
|
||||
) -> Vec<Check> {
|
||||
let mut tracker = ImportTracker::new(locator, directives, path);
|
||||
for stmt in python_ast {
|
||||
tracker.visit_stmt(stmt);
|
||||
}
|
||||
check_import_blocks(tracker, locator, settings, autofix)
|
||||
check_import_blocks(tracker, locator, settings, autofix, package)
|
||||
}
|
||||
90
src/checkers/lines.rs
Normal file
90
src/checkers/lines.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
//! Lint rules based on checking raw physical lines.
|
||||
|
||||
use crate::checks::{Check, CheckCode};
|
||||
use crate::pycodestyle::checks::{line_too_long, no_newline_at_end_of_file};
|
||||
use crate::pygrep_hooks::plugins::blanket_type_ignore;
|
||||
use crate::pyupgrade::checks::unnecessary_coding_comment;
|
||||
use crate::settings::{flags, Settings};
|
||||
|
||||
pub fn check_lines(
|
||||
contents: &str,
|
||||
commented_lines: &[usize],
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) -> Vec<Check> {
|
||||
let mut checks: Vec<Check> = vec![];
|
||||
|
||||
let enforce_unnecessary_coding_comment = settings.enabled.contains(&CheckCode::UP009);
|
||||
let enforce_line_too_long = settings.enabled.contains(&CheckCode::E501);
|
||||
let enforce_no_newline_at_end_of_file = settings.enabled.contains(&CheckCode::W292);
|
||||
let enforce_blanket_type_ignore = settings.enabled.contains(&CheckCode::PGH003);
|
||||
|
||||
let mut commented_lines_iter = commented_lines.iter().peekable();
|
||||
for (index, line) in contents.lines().enumerate() {
|
||||
while commented_lines_iter
|
||||
.next_if(|lineno| &(index + 1) == *lineno)
|
||||
.is_some()
|
||||
{
|
||||
if enforce_unnecessary_coding_comment {
|
||||
if index < 2 {
|
||||
if let Some(check) = unnecessary_coding_comment(
|
||||
index,
|
||||
line,
|
||||
matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(&CheckCode::UP009),
|
||||
) {
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_blanket_type_ignore {
|
||||
if commented_lines.contains(&(index + 1)) {
|
||||
if let Some(check) = blanket_type_ignore(index, line) {
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_line_too_long {
|
||||
if let Some(check) = line_too_long(index, line, settings.line_length) {
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_no_newline_at_end_of_file {
|
||||
if let Some(check) = no_newline_at_end_of_file(contents) {
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
|
||||
checks
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::check_lines;
|
||||
use crate::checks::CheckCode;
|
||||
use crate::settings::{flags, Settings};
|
||||
|
||||
#[test]
|
||||
fn e501_non_ascii_char() {
|
||||
let line = "'\u{4e9c}' * 2"; // 7 in UTF-32, 9 in UTF-8.
|
||||
let check_with_max_line_length = |line_length: usize| {
|
||||
check_lines(
|
||||
line,
|
||||
&[],
|
||||
&Settings {
|
||||
line_length,
|
||||
..Settings::for_rule(CheckCode::E501)
|
||||
},
|
||||
flags::Autofix::Enabled,
|
||||
)
|
||||
};
|
||||
assert!(!check_with_max_line_length(6).is_empty());
|
||||
assert!(check_with_max_line_length(7).is_empty());
|
||||
}
|
||||
}
|
||||
5
src/checkers/mod.rs
Normal file
5
src/checkers/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
pub mod ast;
|
||||
pub mod imports;
|
||||
pub mod lines;
|
||||
pub mod noqa;
|
||||
pub mod tokens;
|
||||
162
src/checkers/noqa.rs
Normal file
162
src/checkers/noqa.rs
Normal file
@@ -0,0 +1,162 @@
|
||||
//! `NoQA` enforcement and validation.
|
||||
|
||||
use nohash_hasher::IntMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::checks::{Check, CheckCode, CheckKind, CODE_REDIRECTS};
|
||||
use crate::noqa;
|
||||
use crate::noqa::{is_file_exempt, Directive};
|
||||
use crate::settings::{flags, Settings};
|
||||
|
||||
pub fn check_noqa(
|
||||
checks: &mut Vec<Check>,
|
||||
contents: &str,
|
||||
commented_lines: &[usize],
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) {
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<&str>)> = IntMap::default();
|
||||
let mut ignored = vec![];
|
||||
|
||||
let enforce_noqa = settings.enabled.contains(&CheckCode::RUF100);
|
||||
|
||||
checks.sort_by_key(|check| check.location);
|
||||
let mut checks_iter = checks.iter().enumerate().peekable();
|
||||
if let Some((_index, check)) = checks_iter.peek() {
|
||||
assert!(check.location.row() >= 1);
|
||||
}
|
||||
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
for lineno in commented_lines {
|
||||
// If we hit an exemption for the entire file, bail.
|
||||
if is_file_exempt(lines[lineno - 1]) {
|
||||
checks.drain(..);
|
||||
return;
|
||||
}
|
||||
|
||||
if enforce_noqa {
|
||||
noqa_directives
|
||||
.entry(lineno - 1)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[lineno - 1]), vec![]));
|
||||
}
|
||||
|
||||
// Remove any ignored checks.
|
||||
while let Some((index, check)) =
|
||||
checks_iter.next_if(|(_index, check)| check.location.row() <= *lineno)
|
||||
{
|
||||
// Grab the noqa (logical) line number for the current (physical) line.
|
||||
// If there are newlines at the end of the file, they won't be represented in
|
||||
// `noqa_line_for`, so fallback to the current line.
|
||||
let check_lineno = check.location.row();
|
||||
let noqa_lineno = noqa_line_for.get(&check_lineno).unwrap_or(&check_lineno);
|
||||
if noqa_lineno == lineno {
|
||||
let noqa = noqa_directives.entry(noqa_lineno - 1).or_insert_with(|| {
|
||||
(noqa::extract_noqa_directive(lines[noqa_lineno - 1]), vec![])
|
||||
});
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
ignored.push(index);
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if noqa::includes(check.kind.code(), codes) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
ignored.push(index);
|
||||
}
|
||||
}
|
||||
(Directive::None, ..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce that the noqa directive was actually used (RUF100).
|
||||
if enforce_noqa {
|
||||
for (row, (directive, matches)) in noqa_directives {
|
||||
match directive {
|
||||
Directive::All(spaces, start, end) => {
|
||||
if matches.is_empty() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnusedNOQA(None),
|
||||
Range {
|
||||
location: Location::new(row + 1, start),
|
||||
end_location: Location::new(row + 1, end),
|
||||
},
|
||||
);
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(check.kind.code())
|
||||
{
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
}
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
Directive::Codes(spaces, start, end, codes) => {
|
||||
let mut invalid_codes = vec![];
|
||||
let mut valid_codes = vec![];
|
||||
let mut self_ignore = false;
|
||||
for code in codes {
|
||||
let code = CODE_REDIRECTS.get(code).map_or(code, AsRef::as_ref);
|
||||
if code == CheckCode::RUF100.as_ref() {
|
||||
self_ignore = true;
|
||||
} else {
|
||||
if matches.contains(&code) || settings.external.contains(code) {
|
||||
valid_codes.push(code);
|
||||
} else {
|
||||
invalid_codes.push(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self_ignore {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !invalid_codes.is_empty() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnusedNOQA(Some(
|
||||
invalid_codes
|
||||
.iter()
|
||||
.map(|code| (*code).to_string())
|
||||
.collect(),
|
||||
)),
|
||||
Range {
|
||||
location: Location::new(row + 1, start),
|
||||
end_location: Location::new(row + 1, end),
|
||||
},
|
||||
);
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(check.kind.code())
|
||||
{
|
||||
if valid_codes.is_empty() {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
} else {
|
||||
check.amend(Fix::replacement(
|
||||
format!("# noqa: {}", valid_codes.join(", ")),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
}
|
||||
}
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
Directive::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ignored.sort_unstable();
|
||||
for index in ignored.iter().rev() {
|
||||
checks.swap_remove(*index);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ use rustpython_parser::lexer::{LexResult, Tok};
|
||||
use crate::checks::{Check, CheckCode};
|
||||
use crate::lex::docstring_detection::StateMachine;
|
||||
use crate::ruff::checks::Context;
|
||||
use crate::settings::flags;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
use crate::{eradicate, flake8_quotes, pycodestyle, ruff, Settings};
|
||||
|
||||
@@ -12,7 +13,7 @@ pub fn check_tokens(
|
||||
locator: &SourceCodeLocator,
|
||||
tokens: &[LexResult],
|
||||
settings: &Settings,
|
||||
autofix: bool,
|
||||
autofix: flags::Autofix,
|
||||
) -> Vec<Check> {
|
||||
let mut checks: Vec<Check> = vec![];
|
||||
|
||||
264
src/checks.rs
264
src/checks.rs
@@ -309,6 +309,16 @@ pub enum CheckCode {
|
||||
ARG005,
|
||||
// flake8-import-conventions
|
||||
ICN001,
|
||||
// flake8-datetimez
|
||||
DTZ001,
|
||||
DTZ002,
|
||||
DTZ003,
|
||||
DTZ004,
|
||||
DTZ005,
|
||||
DTZ006,
|
||||
DTZ007,
|
||||
DTZ011,
|
||||
DTZ012,
|
||||
// Ruff
|
||||
RUF001,
|
||||
RUF002,
|
||||
@@ -316,19 +326,21 @@ pub enum CheckCode {
|
||||
RUF100,
|
||||
// pygrep-hooks
|
||||
PGH001,
|
||||
PGH002,
|
||||
PGH003,
|
||||
// pandas-vet
|
||||
PDV002,
|
||||
PDV003,
|
||||
PDV004,
|
||||
PDV007,
|
||||
PDV008,
|
||||
PDV009,
|
||||
PDV010,
|
||||
PDV011,
|
||||
PDV012,
|
||||
PDV013,
|
||||
PDV015,
|
||||
PDV901,
|
||||
PD002,
|
||||
PD003,
|
||||
PD004,
|
||||
PD007,
|
||||
PD008,
|
||||
PD009,
|
||||
PD010,
|
||||
PD011,
|
||||
PD012,
|
||||
PD013,
|
||||
PD015,
|
||||
PD901,
|
||||
// flake8-errmsg
|
||||
EM101,
|
||||
EM102,
|
||||
@@ -361,6 +373,7 @@ pub enum CheckCategory {
|
||||
Flake8Simplify,
|
||||
Flake8TidyImports,
|
||||
Flake8UnusedArguments,
|
||||
Flake8Datetimez,
|
||||
Eradicate,
|
||||
PandasVet,
|
||||
PygrepHooks,
|
||||
@@ -403,6 +416,7 @@ impl CheckCategory {
|
||||
CheckCategory::Flake8TidyImports => "flake8-tidy-imports",
|
||||
CheckCategory::Flake8Simplify => "flake8-simplify",
|
||||
CheckCategory::Flake8UnusedArguments => "flake8-unused-arguments",
|
||||
CheckCategory::Flake8Datetimez => "flake8-datetimez",
|
||||
CheckCategory::Isort => "isort",
|
||||
CheckCategory::McCabe => "mccabe",
|
||||
CheckCategory::PandasVet => "pandas-vet",
|
||||
@@ -436,9 +450,10 @@ impl CheckCategory {
|
||||
CheckCategory::Flake8Simplify => vec![CheckCodePrefix::SIM],
|
||||
CheckCategory::Flake8TidyImports => vec![CheckCodePrefix::TID],
|
||||
CheckCategory::Flake8UnusedArguments => vec![CheckCodePrefix::ARG],
|
||||
CheckCategory::Flake8Datetimez => vec![CheckCodePrefix::DTZ],
|
||||
CheckCategory::Isort => vec![CheckCodePrefix::I],
|
||||
CheckCategory::McCabe => vec![CheckCodePrefix::C90],
|
||||
CheckCategory::PandasVet => vec![CheckCodePrefix::PDV],
|
||||
CheckCategory::PandasVet => vec![CheckCodePrefix::PD],
|
||||
CheckCategory::PEP8Naming => vec![CheckCodePrefix::N],
|
||||
CheckCategory::Pycodestyle => vec![CheckCodePrefix::E, CheckCodePrefix::W],
|
||||
CheckCategory::Pydocstyle => vec![CheckCodePrefix::D],
|
||||
@@ -526,6 +541,10 @@ impl CheckCategory {
|
||||
"https://pypi.org/project/flake8-unused-arguments/0.0.12/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
CheckCategory::Flake8Datetimez => Some((
|
||||
"https://pypi.org/project/flake8-datetimez/20.10.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
CheckCategory::Isort => {
|
||||
Some(("https://pypi.org/project/isort/5.10.1/", &Platform::PyPI))
|
||||
}
|
||||
@@ -573,6 +592,7 @@ pub enum LintSource {
|
||||
Lines,
|
||||
Tokens,
|
||||
Imports,
|
||||
NoQA,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -772,7 +792,7 @@ pub enum CheckKind {
|
||||
MissingTypeCls(String),
|
||||
MissingReturnTypePublicFunction(String),
|
||||
MissingReturnTypePrivateFunction(String),
|
||||
MissingReturnTypeMagicMethod(String),
|
||||
MissingReturnTypeSpecialMethod(String),
|
||||
MissingReturnTypeStaticMethod(String),
|
||||
MissingReturnTypeClassMethod(String),
|
||||
DynamicallyTypedExpression(String),
|
||||
@@ -886,6 +906,8 @@ pub enum CheckKind {
|
||||
BooleanPositionalValueInFunctionCall,
|
||||
// pygrep-hooks
|
||||
NoEval,
|
||||
DeprecatedLogWarn,
|
||||
BlanketTypeIgnore,
|
||||
// flake8-unused-arguments
|
||||
UnusedFunctionArgument(String),
|
||||
UnusedMethodArgument(String),
|
||||
@@ -916,6 +938,16 @@ pub enum CheckKind {
|
||||
AmbiguousUnicodeCharacterDocstring(char, char),
|
||||
AmbiguousUnicodeCharacterComment(char, char),
|
||||
UnusedNOQA(Option<Vec<String>>),
|
||||
// flake8-datetimez
|
||||
CallDatetimeWithoutTzinfo,
|
||||
CallDatetimeToday,
|
||||
CallDatetimeUtcnow,
|
||||
CallDatetimeUtcfromtimestamp,
|
||||
CallDatetimeNowWithoutTzinfo,
|
||||
CallDatetimeFromtimestamp,
|
||||
CallDatetimeStrptimeWithoutZone,
|
||||
CallDateToday,
|
||||
CallDateFromtimestamp,
|
||||
}
|
||||
|
||||
impl CheckCode {
|
||||
@@ -923,7 +955,8 @@ impl CheckCode {
|
||||
/// physical lines).
|
||||
pub fn lint_source(&self) -> &'static LintSource {
|
||||
match self {
|
||||
CheckCode::E501 | CheckCode::W292 | CheckCode::RUF100 | CheckCode::UP009 => {
|
||||
CheckCode::RUF100 => &LintSource::NoQA,
|
||||
CheckCode::E501 | CheckCode::W292 | CheckCode::UP009 | CheckCode::PGH003 => {
|
||||
&LintSource::Lines
|
||||
}
|
||||
CheckCode::ERA001
|
||||
@@ -1126,7 +1159,7 @@ impl CheckCode {
|
||||
CheckCode::ANN102 => CheckKind::MissingTypeCls("...".to_string()),
|
||||
CheckCode::ANN201 => CheckKind::MissingReturnTypePublicFunction("...".to_string()),
|
||||
CheckCode::ANN202 => CheckKind::MissingReturnTypePrivateFunction("...".to_string()),
|
||||
CheckCode::ANN204 => CheckKind::MissingReturnTypeMagicMethod("...".to_string()),
|
||||
CheckCode::ANN204 => CheckKind::MissingReturnTypeSpecialMethod("...".to_string()),
|
||||
CheckCode::ANN205 => CheckKind::MissingReturnTypeStaticMethod("...".to_string()),
|
||||
CheckCode::ANN206 => CheckKind::MissingReturnTypeClassMethod("...".to_string()),
|
||||
CheckCode::ANN401 => CheckKind::DynamicallyTypedExpression("...".to_string()),
|
||||
@@ -1260,6 +1293,8 @@ impl CheckCode {
|
||||
CheckCode::FBT003 => CheckKind::BooleanPositionalValueInFunctionCall,
|
||||
// pygrep-hooks
|
||||
CheckCode::PGH001 => CheckKind::NoEval,
|
||||
CheckCode::PGH002 => CheckKind::DeprecatedLogWarn,
|
||||
CheckCode::PGH003 => CheckKind::BlanketTypeIgnore,
|
||||
// flake8-unused-arguments
|
||||
CheckCode::ARG001 => CheckKind::UnusedFunctionArgument("...".to_string()),
|
||||
CheckCode::ARG002 => CheckKind::UnusedMethodArgument("...".to_string()),
|
||||
@@ -1271,22 +1306,32 @@ impl CheckCode {
|
||||
CheckKind::ImportAliasIsNotConventional("...".to_string(), "...".to_string())
|
||||
}
|
||||
// pandas-vet
|
||||
CheckCode::PDV002 => CheckKind::UseOfInplaceArgument,
|
||||
CheckCode::PDV003 => CheckKind::UseOfDotIsNull,
|
||||
CheckCode::PDV004 => CheckKind::UseOfDotNotNull,
|
||||
CheckCode::PDV007 => CheckKind::UseOfDotIx,
|
||||
CheckCode::PDV008 => CheckKind::UseOfDotAt,
|
||||
CheckCode::PDV009 => CheckKind::UseOfDotIat,
|
||||
CheckCode::PDV010 => CheckKind::UseOfDotPivotOrUnstack,
|
||||
CheckCode::PDV011 => CheckKind::UseOfDotValues,
|
||||
CheckCode::PDV012 => CheckKind::UseOfDotReadTable,
|
||||
CheckCode::PDV013 => CheckKind::UseOfDotStack,
|
||||
CheckCode::PDV015 => CheckKind::UseOfPdMerge,
|
||||
CheckCode::PDV901 => CheckKind::DfIsABadVariableName,
|
||||
CheckCode::PD002 => CheckKind::UseOfInplaceArgument,
|
||||
CheckCode::PD003 => CheckKind::UseOfDotIsNull,
|
||||
CheckCode::PD004 => CheckKind::UseOfDotNotNull,
|
||||
CheckCode::PD007 => CheckKind::UseOfDotIx,
|
||||
CheckCode::PD008 => CheckKind::UseOfDotAt,
|
||||
CheckCode::PD009 => CheckKind::UseOfDotIat,
|
||||
CheckCode::PD010 => CheckKind::UseOfDotPivotOrUnstack,
|
||||
CheckCode::PD011 => CheckKind::UseOfDotValues,
|
||||
CheckCode::PD012 => CheckKind::UseOfDotReadTable,
|
||||
CheckCode::PD013 => CheckKind::UseOfDotStack,
|
||||
CheckCode::PD015 => CheckKind::UseOfPdMerge,
|
||||
CheckCode::PD901 => CheckKind::DfIsABadVariableName,
|
||||
// flake8-errmsg
|
||||
CheckCode::EM101 => CheckKind::RawStringInException,
|
||||
CheckCode::EM102 => CheckKind::FStringInException,
|
||||
CheckCode::EM103 => CheckKind::DotFormatInException,
|
||||
// flake8-datetimez
|
||||
CheckCode::DTZ001 => CheckKind::CallDatetimeWithoutTzinfo,
|
||||
CheckCode::DTZ002 => CheckKind::CallDatetimeToday,
|
||||
CheckCode::DTZ003 => CheckKind::CallDatetimeUtcnow,
|
||||
CheckCode::DTZ004 => CheckKind::CallDatetimeUtcfromtimestamp,
|
||||
CheckCode::DTZ005 => CheckKind::CallDatetimeNowWithoutTzinfo,
|
||||
CheckCode::DTZ006 => CheckKind::CallDatetimeFromtimestamp,
|
||||
CheckCode::DTZ007 => CheckKind::CallDatetimeStrptimeWithoutZone,
|
||||
CheckCode::DTZ011 => CheckKind::CallDateToday,
|
||||
CheckCode::DTZ012 => CheckKind::CallDateFromtimestamp,
|
||||
// Ruff
|
||||
CheckCode::RUF001 => CheckKind::AmbiguousUnicodeCharacterString('𝐁', 'B'),
|
||||
CheckCode::RUF002 => CheckKind::AmbiguousUnicodeCharacterDocstring('𝐁', 'B'),
|
||||
@@ -1408,6 +1453,15 @@ impl CheckCode {
|
||||
CheckCode::D417 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D418 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D419 => CheckCategory::Pydocstyle,
|
||||
CheckCode::DTZ001 => CheckCategory::Flake8Datetimez,
|
||||
CheckCode::DTZ002 => CheckCategory::Flake8Datetimez,
|
||||
CheckCode::DTZ003 => CheckCategory::Flake8Datetimez,
|
||||
CheckCode::DTZ004 => CheckCategory::Flake8Datetimez,
|
||||
CheckCode::DTZ005 => CheckCategory::Flake8Datetimez,
|
||||
CheckCode::DTZ006 => CheckCategory::Flake8Datetimez,
|
||||
CheckCode::DTZ007 => CheckCategory::Flake8Datetimez,
|
||||
CheckCode::DTZ011 => CheckCategory::Flake8Datetimez,
|
||||
CheckCode::DTZ012 => CheckCategory::Flake8Datetimez,
|
||||
CheckCode::E402 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E501 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E711 => CheckCategory::Pycodestyle,
|
||||
@@ -1491,19 +1545,21 @@ impl CheckCode {
|
||||
CheckCode::N816 => CheckCategory::PEP8Naming,
|
||||
CheckCode::N817 => CheckCategory::PEP8Naming,
|
||||
CheckCode::N818 => CheckCategory::PEP8Naming,
|
||||
CheckCode::PDV002 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV003 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV004 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV007 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV008 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV009 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV010 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV011 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV012 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV013 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV015 => CheckCategory::PandasVet,
|
||||
CheckCode::PDV901 => CheckCategory::PandasVet,
|
||||
CheckCode::PD002 => CheckCategory::PandasVet,
|
||||
CheckCode::PD003 => CheckCategory::PandasVet,
|
||||
CheckCode::PD004 => CheckCategory::PandasVet,
|
||||
CheckCode::PD007 => CheckCategory::PandasVet,
|
||||
CheckCode::PD008 => CheckCategory::PandasVet,
|
||||
CheckCode::PD009 => CheckCategory::PandasVet,
|
||||
CheckCode::PD010 => CheckCategory::PandasVet,
|
||||
CheckCode::PD011 => CheckCategory::PandasVet,
|
||||
CheckCode::PD012 => CheckCategory::PandasVet,
|
||||
CheckCode::PD013 => CheckCategory::PandasVet,
|
||||
CheckCode::PD015 => CheckCategory::PandasVet,
|
||||
CheckCode::PD901 => CheckCategory::PandasVet,
|
||||
CheckCode::PGH001 => CheckCategory::PygrepHooks,
|
||||
CheckCode::PGH002 => CheckCategory::PygrepHooks,
|
||||
CheckCode::PGH003 => CheckCategory::PygrepHooks,
|
||||
CheckCode::PLC0414 => CheckCategory::Pylint,
|
||||
CheckCode::PLC2201 => CheckCategory::Pylint,
|
||||
CheckCode::PLC3002 => CheckCategory::Pylint,
|
||||
@@ -1733,7 +1789,7 @@ impl CheckKind {
|
||||
CheckKind::MissingTypeCls(_) => &CheckCode::ANN102,
|
||||
CheckKind::MissingReturnTypePublicFunction(_) => &CheckCode::ANN201,
|
||||
CheckKind::MissingReturnTypePrivateFunction(_) => &CheckCode::ANN202,
|
||||
CheckKind::MissingReturnTypeMagicMethod(_) => &CheckCode::ANN204,
|
||||
CheckKind::MissingReturnTypeSpecialMethod(_) => &CheckCode::ANN204,
|
||||
CheckKind::MissingReturnTypeStaticMethod(_) => &CheckCode::ANN205,
|
||||
CheckKind::MissingReturnTypeClassMethod(_) => &CheckCode::ANN206,
|
||||
CheckKind::DynamicallyTypedExpression(_) => &CheckCode::ANN401,
|
||||
@@ -1847,6 +1903,8 @@ impl CheckKind {
|
||||
CheckKind::BooleanPositionalValueInFunctionCall => &CheckCode::FBT003,
|
||||
// pygrep-hooks
|
||||
CheckKind::NoEval => &CheckCode::PGH001,
|
||||
CheckKind::DeprecatedLogWarn => &CheckCode::PGH002,
|
||||
CheckKind::BlanketTypeIgnore => &CheckCode::PGH003,
|
||||
// flake8-unused-arguments
|
||||
CheckKind::UnusedFunctionArgument(..) => &CheckCode::ARG001,
|
||||
CheckKind::UnusedMethodArgument(..) => &CheckCode::ARG002,
|
||||
@@ -1856,22 +1914,32 @@ impl CheckKind {
|
||||
// flake8-import-conventions
|
||||
CheckKind::ImportAliasIsNotConventional(..) => &CheckCode::ICN001,
|
||||
// pandas-vet
|
||||
CheckKind::UseOfInplaceArgument => &CheckCode::PDV002,
|
||||
CheckKind::UseOfDotIsNull => &CheckCode::PDV003,
|
||||
CheckKind::UseOfDotNotNull => &CheckCode::PDV004,
|
||||
CheckKind::UseOfDotIx => &CheckCode::PDV007,
|
||||
CheckKind::UseOfDotAt => &CheckCode::PDV008,
|
||||
CheckKind::UseOfDotIat => &CheckCode::PDV009,
|
||||
CheckKind::UseOfDotPivotOrUnstack => &CheckCode::PDV010,
|
||||
CheckKind::UseOfDotValues => &CheckCode::PDV011,
|
||||
CheckKind::UseOfDotReadTable => &CheckCode::PDV012,
|
||||
CheckKind::UseOfDotStack => &CheckCode::PDV013,
|
||||
CheckKind::UseOfPdMerge => &CheckCode::PDV015,
|
||||
CheckKind::DfIsABadVariableName => &CheckCode::PDV901,
|
||||
CheckKind::UseOfInplaceArgument => &CheckCode::PD002,
|
||||
CheckKind::UseOfDotIsNull => &CheckCode::PD003,
|
||||
CheckKind::UseOfDotNotNull => &CheckCode::PD004,
|
||||
CheckKind::UseOfDotIx => &CheckCode::PD007,
|
||||
CheckKind::UseOfDotAt => &CheckCode::PD008,
|
||||
CheckKind::UseOfDotIat => &CheckCode::PD009,
|
||||
CheckKind::UseOfDotPivotOrUnstack => &CheckCode::PD010,
|
||||
CheckKind::UseOfDotValues => &CheckCode::PD011,
|
||||
CheckKind::UseOfDotReadTable => &CheckCode::PD012,
|
||||
CheckKind::UseOfDotStack => &CheckCode::PD013,
|
||||
CheckKind::UseOfPdMerge => &CheckCode::PD015,
|
||||
CheckKind::DfIsABadVariableName => &CheckCode::PD901,
|
||||
// flake8-errmsg
|
||||
CheckKind::RawStringInException => &CheckCode::EM101,
|
||||
CheckKind::FStringInException => &CheckCode::EM102,
|
||||
CheckKind::DotFormatInException => &CheckCode::EM103,
|
||||
// flake8-datetimez
|
||||
CheckKind::CallDatetimeWithoutTzinfo => &CheckCode::DTZ001,
|
||||
CheckKind::CallDatetimeToday => &CheckCode::DTZ002,
|
||||
CheckKind::CallDatetimeUtcnow => &CheckCode::DTZ003,
|
||||
CheckKind::CallDatetimeUtcfromtimestamp => &CheckCode::DTZ004,
|
||||
CheckKind::CallDatetimeNowWithoutTzinfo => &CheckCode::DTZ005,
|
||||
CheckKind::CallDatetimeFromtimestamp => &CheckCode::DTZ006,
|
||||
CheckKind::CallDatetimeStrptimeWithoutZone => &CheckCode::DTZ007,
|
||||
CheckKind::CallDateToday => &CheckCode::DTZ011,
|
||||
CheckKind::CallDateFromtimestamp => &CheckCode::DTZ012,
|
||||
// Ruff
|
||||
CheckKind::AmbiguousUnicodeCharacterString(..) => &CheckCode::RUF001,
|
||||
CheckKind::AmbiguousUnicodeCharacterDocstring(..) => &CheckCode::RUF002,
|
||||
@@ -2390,8 +2458,8 @@ impl CheckKind {
|
||||
CheckKind::MissingReturnTypePrivateFunction(name) => {
|
||||
format!("Missing return type annotation for private function `{name}`")
|
||||
}
|
||||
CheckKind::MissingReturnTypeMagicMethod(name) => {
|
||||
format!("Missing return type annotation for magic method `{name}`")
|
||||
CheckKind::MissingReturnTypeSpecialMethod(name) => {
|
||||
format!("Missing return type annotation for special method `{name}`")
|
||||
}
|
||||
CheckKind::MissingReturnTypeStaticMethod(name) => {
|
||||
format!("Missing return type annotation for staticmethod `{name}`")
|
||||
@@ -2684,6 +2752,12 @@ impl CheckKind {
|
||||
}
|
||||
// pygrep-hooks
|
||||
CheckKind::NoEval => "No builtin `eval()` allowed".to_string(),
|
||||
CheckKind::DeprecatedLogWarn => {
|
||||
"`warn` is deprecated in favor of `warning`".to_string()
|
||||
}
|
||||
CheckKind::BlanketTypeIgnore => {
|
||||
"Use specific error codes when ignoring type issues".to_string()
|
||||
}
|
||||
// flake8-unused-arguments
|
||||
CheckKind::UnusedFunctionArgument(name) => {
|
||||
format!("Unused function argument: `{name}`")
|
||||
@@ -2711,13 +2785,13 @@ impl CheckKind {
|
||||
"`.notna` is preferred to `.notnull`; functionality is equivalent".to_string()
|
||||
}
|
||||
CheckKind::UseOfDotIx => {
|
||||
"``ix` i` deprecated; use more explicit `.loc` o` `.iloc`".to_string()
|
||||
"`.ix` is deprecated; use more explicit `.loc` or `.iloc`".to_string()
|
||||
}
|
||||
CheckKind::UseOfDotAt => {
|
||||
"Use `.loc` instead of `.at`. If speed is important, use numpy.".to_string()
|
||||
}
|
||||
CheckKind::UseOfDotIat => {
|
||||
"Use `.iloc` instea` of `.iat`. If speed is important, use numpy.".to_string()
|
||||
"Use `.iloc` instead of `.iat`. If speed is important, use numpy.".to_string()
|
||||
}
|
||||
CheckKind::UseOfDotPivotOrUnstack => "`.pivot_table` is preferred to `.pivot` or \
|
||||
`.unstack`; provides same functionality"
|
||||
@@ -2780,6 +2854,41 @@ impl CheckKind {
|
||||
format!("Unused `noqa` directive for: {codes}")
|
||||
}
|
||||
},
|
||||
// flake8-datetimez
|
||||
CheckKind::CallDatetimeWithoutTzinfo => "The use of `datetime.datetime()` without \
|
||||
`tzinfo` argument is not allowed"
|
||||
.to_string(),
|
||||
CheckKind::CallDatetimeToday => "The use of `datetime.datetime.today()` is not \
|
||||
allowed. Use `datetime.datetime.now(tz=)` instead."
|
||||
.to_string(),
|
||||
CheckKind::CallDatetimeUtcnow => "The use of `datetime.datetime.utcnow()` is not \
|
||||
allowed. Use `datetime.datetime.now(tz=)` instead."
|
||||
.to_string(),
|
||||
CheckKind::CallDatetimeUtcfromtimestamp => {
|
||||
"The use of `datetime.datetime.utcfromtimestamp()` is not allowed. Use \
|
||||
`datetime.datetime.fromtimestamp(, tz=)` instead."
|
||||
.to_string()
|
||||
}
|
||||
CheckKind::CallDatetimeNowWithoutTzinfo => "The use of `datetime.datetime.now()` \
|
||||
without `tz` argument is not allowed"
|
||||
.to_string(),
|
||||
CheckKind::CallDatetimeFromtimestamp => "The use of \
|
||||
`datetime.datetime.fromtimestamp()` without \
|
||||
`tz` argument is not allowed"
|
||||
.to_string(),
|
||||
CheckKind::CallDatetimeStrptimeWithoutZone => {
|
||||
"The use of `datetime.datetime.strptime()` without %z must be followed by \
|
||||
`.replace(tzinfo=)`"
|
||||
.to_string()
|
||||
}
|
||||
CheckKind::CallDateToday => "The use of `datetime.date.today()` is not allowed. Use \
|
||||
`datetime.datetime.now(tz=).date()` instead."
|
||||
.to_string(),
|
||||
CheckKind::CallDateFromtimestamp => {
|
||||
"The use of `datetime.date.fromtimestamp()` is not allowed. Use \
|
||||
`datetime.datetime.fromtimestamp(, tz=).date()` instead."
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2799,6 +2908,23 @@ impl CheckKind {
|
||||
CheckKind::StarArgUnpackingAfterKeywordArg => {
|
||||
"Star-arg unpacking after a keyword argument is strongly discouraged".to_string()
|
||||
}
|
||||
|
||||
// flake8-datetimez
|
||||
CheckKind::CallDatetimeToday => {
|
||||
"The use of `datetime.datetime.today()` is not allowed".to_string()
|
||||
}
|
||||
CheckKind::CallDatetimeUtcnow => {
|
||||
"The use of `datetime.datetime.utcnow()` is not allowed".to_string()
|
||||
}
|
||||
CheckKind::CallDatetimeUtcfromtimestamp => {
|
||||
"The use of `datetime.datetime.utcfromtimestamp()` is not allowed".to_string()
|
||||
}
|
||||
CheckKind::CallDateToday => {
|
||||
"The use of `datetime.date.today()` is not allowed.".to_string()
|
||||
}
|
||||
CheckKind::CallDateFromtimestamp => {
|
||||
"The use of `datetime.date.fromtimestamp()` is not allowed".to_string()
|
||||
}
|
||||
_ => self.body(),
|
||||
}
|
||||
}
|
||||
@@ -2817,7 +2943,6 @@ impl CheckKind {
|
||||
| CheckKind::CommentedOutCode
|
||||
| CheckKind::ConvertNamedTupleFunctionalToClass(..)
|
||||
| CheckKind::ConvertTypedDictFunctionalToClass(..)
|
||||
| CheckKind::RemoveSixCompat
|
||||
| CheckKind::DashedUnderlineAfterSection(..)
|
||||
| CheckKind::DeprecatedUnittestAlias(..)
|
||||
| CheckKind::DoNotAssertFalse
|
||||
@@ -2831,6 +2956,7 @@ impl CheckKind {
|
||||
| CheckKind::IsLiteral
|
||||
| CheckKind::KeyInDict(..)
|
||||
| CheckKind::MisplacedComparisonConstant(..)
|
||||
| CheckKind::MissingReturnTypeSpecialMethod(..)
|
||||
| CheckKind::NewLineAfterLastParagraph
|
||||
| CheckKind::NewLineAfterSectionName(..)
|
||||
| CheckKind::NoBlankLineAfterFunction(..)
|
||||
@@ -2845,13 +2971,14 @@ impl CheckKind {
|
||||
| CheckKind::NotIsTest
|
||||
| CheckKind::OneBlankLineAfterClass(..)
|
||||
| CheckKind::OneBlankLineBeforeClass(..)
|
||||
| CheckKind::PercentFormatExtraNamedArguments(..)
|
||||
| CheckKind::PEP3120UnnecessaryCodingComment
|
||||
| CheckKind::PPrintFound
|
||||
| CheckKind::PercentFormatExtraNamedArguments(..)
|
||||
| CheckKind::PrintFound
|
||||
| CheckKind::RaiseNotImplemented
|
||||
| CheckKind::RedundantOpenModes
|
||||
| CheckKind::RedundantTupleInExceptionHandler(..)
|
||||
| CheckKind::RemoveSixCompat
|
||||
| CheckKind::SectionNameEndsInColon(..)
|
||||
| CheckKind::SectionNotOverIndented(..)
|
||||
| CheckKind::SectionUnderlineAfterName(..)
|
||||
@@ -2938,6 +3065,19 @@ pub static CODE_REDIRECTS: Lazy<FxHashMap<&'static str, CheckCode>> = Lazy::new(
|
||||
// TODO(charlie): Remove by 2023-02-01.
|
||||
("I252", CheckCode::TID252),
|
||||
("M001", CheckCode::RUF100),
|
||||
// TODO(charlie): Remove by 2023-02-01.
|
||||
("PDV002", CheckCode::PD002),
|
||||
("PDV003", CheckCode::PD003),
|
||||
("PDV004", CheckCode::PD004),
|
||||
("PDV007", CheckCode::PD007),
|
||||
("PDV008", CheckCode::PD008),
|
||||
("PDV009", CheckCode::PD009),
|
||||
("PDV010", CheckCode::PD010),
|
||||
("PDV011", CheckCode::PD011),
|
||||
("PDV012", CheckCode::PD012),
|
||||
("PDV013", CheckCode::PD013),
|
||||
("PDV015", CheckCode::PD015),
|
||||
("PDV901", CheckCode::PD901),
|
||||
])
|
||||
});
|
||||
|
||||
@@ -2954,6 +3094,12 @@ pub static PREFIX_REDIRECTS: Lazy<FxHashMap<&'static str, &'static str>> = Lazy:
|
||||
("I25", "TID25"),
|
||||
("M", "RUF100"),
|
||||
("M0", "RUF100"),
|
||||
// TODO(charlie): Remove by 2023-02-01.
|
||||
("PDV", "PD"),
|
||||
("PDV0", "PD0"),
|
||||
("PDV01", "PD01"),
|
||||
("PDV9", "PD9"),
|
||||
("PDV90", "PD90"),
|
||||
])
|
||||
});
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{AsRefStr, EnumString};
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
use crate::one_time_warning;
|
||||
|
||||
#[derive(
|
||||
EnumString, AsRefStr, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize,
|
||||
@@ -162,6 +163,19 @@ pub enum CheckCodePrefix {
|
||||
D417,
|
||||
D418,
|
||||
D419,
|
||||
DTZ,
|
||||
DTZ0,
|
||||
DTZ00,
|
||||
DTZ001,
|
||||
DTZ002,
|
||||
DTZ003,
|
||||
DTZ004,
|
||||
DTZ005,
|
||||
DTZ006,
|
||||
DTZ007,
|
||||
DTZ01,
|
||||
DTZ011,
|
||||
DTZ012,
|
||||
E,
|
||||
E4,
|
||||
E40,
|
||||
@@ -303,9 +317,26 @@ pub enum CheckCodePrefix {
|
||||
N816,
|
||||
N817,
|
||||
N818,
|
||||
PD,
|
||||
PD0,
|
||||
PD00,
|
||||
PD002,
|
||||
PD003,
|
||||
PD004,
|
||||
PD007,
|
||||
PD008,
|
||||
PD009,
|
||||
PD01,
|
||||
PD010,
|
||||
PD011,
|
||||
PD012,
|
||||
PD013,
|
||||
PD015,
|
||||
PD9,
|
||||
PD90,
|
||||
PD901,
|
||||
PDV,
|
||||
PDV0,
|
||||
PDV00,
|
||||
PDV002,
|
||||
PDV003,
|
||||
PDV004,
|
||||
@@ -325,6 +356,8 @@ pub enum CheckCodePrefix {
|
||||
PGH0,
|
||||
PGH00,
|
||||
PGH001,
|
||||
PGH002,
|
||||
PGH003,
|
||||
PLC,
|
||||
PLC0,
|
||||
PLC04,
|
||||
@@ -971,6 +1004,47 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::D417 => vec![CheckCode::D417],
|
||||
CheckCodePrefix::D418 => vec![CheckCode::D418],
|
||||
CheckCodePrefix::D419 => vec![CheckCode::D419],
|
||||
CheckCodePrefix::DTZ => vec![
|
||||
CheckCode::DTZ001,
|
||||
CheckCode::DTZ002,
|
||||
CheckCode::DTZ003,
|
||||
CheckCode::DTZ004,
|
||||
CheckCode::DTZ005,
|
||||
CheckCode::DTZ006,
|
||||
CheckCode::DTZ007,
|
||||
CheckCode::DTZ011,
|
||||
CheckCode::DTZ012,
|
||||
],
|
||||
CheckCodePrefix::DTZ0 => vec![
|
||||
CheckCode::DTZ001,
|
||||
CheckCode::DTZ002,
|
||||
CheckCode::DTZ003,
|
||||
CheckCode::DTZ004,
|
||||
CheckCode::DTZ005,
|
||||
CheckCode::DTZ006,
|
||||
CheckCode::DTZ007,
|
||||
CheckCode::DTZ011,
|
||||
CheckCode::DTZ012,
|
||||
],
|
||||
CheckCodePrefix::DTZ00 => vec![
|
||||
CheckCode::DTZ001,
|
||||
CheckCode::DTZ002,
|
||||
CheckCode::DTZ003,
|
||||
CheckCode::DTZ004,
|
||||
CheckCode::DTZ005,
|
||||
CheckCode::DTZ006,
|
||||
CheckCode::DTZ007,
|
||||
],
|
||||
CheckCodePrefix::DTZ001 => vec![CheckCode::DTZ001],
|
||||
CheckCodePrefix::DTZ002 => vec![CheckCode::DTZ002],
|
||||
CheckCodePrefix::DTZ003 => vec![CheckCode::DTZ003],
|
||||
CheckCodePrefix::DTZ004 => vec![CheckCode::DTZ004],
|
||||
CheckCodePrefix::DTZ005 => vec![CheckCode::DTZ005],
|
||||
CheckCodePrefix::DTZ006 => vec![CheckCode::DTZ006],
|
||||
CheckCodePrefix::DTZ007 => vec![CheckCode::DTZ007],
|
||||
CheckCodePrefix::DTZ01 => vec![CheckCode::DTZ011, CheckCode::DTZ012],
|
||||
CheckCodePrefix::DTZ011 => vec![CheckCode::DTZ011],
|
||||
CheckCodePrefix::DTZ012 => vec![CheckCode::DTZ012],
|
||||
CheckCodePrefix::E => vec![
|
||||
CheckCode::E402,
|
||||
CheckCode::E501,
|
||||
@@ -1243,7 +1317,7 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::I00 => vec![CheckCode::I001],
|
||||
CheckCodePrefix::I001 => vec![CheckCode::I001],
|
||||
CheckCodePrefix::I2 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1252,7 +1326,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::TID252]
|
||||
}
|
||||
CheckCodePrefix::I25 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1261,7 +1335,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::TID252]
|
||||
}
|
||||
CheckCodePrefix::I252 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1274,7 +1348,7 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::ICN00 => vec![CheckCode::ICN001],
|
||||
CheckCodePrefix::ICN001 => vec![CheckCode::ICN001],
|
||||
CheckCodePrefix::M => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1283,7 +1357,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::RUF100]
|
||||
}
|
||||
CheckCodePrefix::M0 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1292,7 +1366,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::RUF100]
|
||||
}
|
||||
CheckCodePrefix::M001 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1368,66 +1442,252 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::N816 => vec![CheckCode::N816],
|
||||
CheckCodePrefix::N817 => vec![CheckCode::N817],
|
||||
CheckCodePrefix::N818 => vec![CheckCode::N818],
|
||||
CheckCodePrefix::PDV => vec![
|
||||
CheckCode::PDV002,
|
||||
CheckCode::PDV003,
|
||||
CheckCode::PDV004,
|
||||
CheckCode::PDV007,
|
||||
CheckCode::PDV008,
|
||||
CheckCode::PDV009,
|
||||
CheckCode::PDV010,
|
||||
CheckCode::PDV011,
|
||||
CheckCode::PDV012,
|
||||
CheckCode::PDV013,
|
||||
CheckCode::PDV015,
|
||||
CheckCode::PDV901,
|
||||
CheckCodePrefix::PD => vec![
|
||||
CheckCode::PD002,
|
||||
CheckCode::PD003,
|
||||
CheckCode::PD004,
|
||||
CheckCode::PD007,
|
||||
CheckCode::PD008,
|
||||
CheckCode::PD009,
|
||||
CheckCode::PD010,
|
||||
CheckCode::PD011,
|
||||
CheckCode::PD012,
|
||||
CheckCode::PD013,
|
||||
CheckCode::PD015,
|
||||
CheckCode::PD901,
|
||||
],
|
||||
CheckCodePrefix::PDV0 => vec![
|
||||
CheckCode::PDV002,
|
||||
CheckCode::PDV003,
|
||||
CheckCode::PDV004,
|
||||
CheckCode::PDV007,
|
||||
CheckCode::PDV008,
|
||||
CheckCode::PDV009,
|
||||
CheckCode::PDV010,
|
||||
CheckCode::PDV011,
|
||||
CheckCode::PDV012,
|
||||
CheckCode::PDV013,
|
||||
CheckCode::PDV015,
|
||||
CheckCodePrefix::PD0 => vec![
|
||||
CheckCode::PD002,
|
||||
CheckCode::PD003,
|
||||
CheckCode::PD004,
|
||||
CheckCode::PD007,
|
||||
CheckCode::PD008,
|
||||
CheckCode::PD009,
|
||||
CheckCode::PD010,
|
||||
CheckCode::PD011,
|
||||
CheckCode::PD012,
|
||||
CheckCode::PD013,
|
||||
CheckCode::PD015,
|
||||
],
|
||||
CheckCodePrefix::PDV00 => vec![
|
||||
CheckCode::PDV002,
|
||||
CheckCode::PDV003,
|
||||
CheckCode::PDV004,
|
||||
CheckCode::PDV007,
|
||||
CheckCode::PDV008,
|
||||
CheckCode::PDV009,
|
||||
CheckCodePrefix::PD00 => vec![
|
||||
CheckCode::PD002,
|
||||
CheckCode::PD003,
|
||||
CheckCode::PD004,
|
||||
CheckCode::PD007,
|
||||
CheckCode::PD008,
|
||||
CheckCode::PD009,
|
||||
],
|
||||
CheckCodePrefix::PDV002 => vec![CheckCode::PDV002],
|
||||
CheckCodePrefix::PDV003 => vec![CheckCode::PDV003],
|
||||
CheckCodePrefix::PDV004 => vec![CheckCode::PDV004],
|
||||
CheckCodePrefix::PDV007 => vec![CheckCode::PDV007],
|
||||
CheckCodePrefix::PDV008 => vec![CheckCode::PDV008],
|
||||
CheckCodePrefix::PDV009 => vec![CheckCode::PDV009],
|
||||
CheckCodePrefix::PDV01 => vec![
|
||||
CheckCode::PDV010,
|
||||
CheckCode::PDV011,
|
||||
CheckCode::PDV012,
|
||||
CheckCode::PDV013,
|
||||
CheckCode::PDV015,
|
||||
CheckCodePrefix::PD002 => vec![CheckCode::PD002],
|
||||
CheckCodePrefix::PD003 => vec![CheckCode::PD003],
|
||||
CheckCodePrefix::PD004 => vec![CheckCode::PD004],
|
||||
CheckCodePrefix::PD007 => vec![CheckCode::PD007],
|
||||
CheckCodePrefix::PD008 => vec![CheckCode::PD008],
|
||||
CheckCodePrefix::PD009 => vec![CheckCode::PD009],
|
||||
CheckCodePrefix::PD01 => vec![
|
||||
CheckCode::PD010,
|
||||
CheckCode::PD011,
|
||||
CheckCode::PD012,
|
||||
CheckCode::PD013,
|
||||
CheckCode::PD015,
|
||||
],
|
||||
CheckCodePrefix::PDV010 => vec![CheckCode::PDV010],
|
||||
CheckCodePrefix::PDV011 => vec![CheckCode::PDV011],
|
||||
CheckCodePrefix::PDV012 => vec![CheckCode::PDV012],
|
||||
CheckCodePrefix::PDV013 => vec![CheckCode::PDV013],
|
||||
CheckCodePrefix::PDV015 => vec![CheckCode::PDV015],
|
||||
CheckCodePrefix::PDV9 => vec![CheckCode::PDV901],
|
||||
CheckCodePrefix::PDV90 => vec![CheckCode::PDV901],
|
||||
CheckCodePrefix::PDV901 => vec![CheckCode::PDV901],
|
||||
CheckCodePrefix::PGH => vec![CheckCode::PGH001],
|
||||
CheckCodePrefix::PGH0 => vec![CheckCode::PGH001],
|
||||
CheckCodePrefix::PGH00 => vec![CheckCode::PGH001],
|
||||
CheckCodePrefix::PD010 => vec![CheckCode::PD010],
|
||||
CheckCodePrefix::PD011 => vec![CheckCode::PD011],
|
||||
CheckCodePrefix::PD012 => vec![CheckCode::PD012],
|
||||
CheckCodePrefix::PD013 => vec![CheckCode::PD013],
|
||||
CheckCodePrefix::PD015 => vec![CheckCode::PD015],
|
||||
CheckCodePrefix::PD9 => vec![CheckCode::PD901],
|
||||
CheckCodePrefix::PD90 => vec![CheckCode::PD901],
|
||||
CheckCodePrefix::PD901 => vec![CheckCode::PD901],
|
||||
CheckCodePrefix::PDV => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV` has been remapped to `PD`".bold()
|
||||
);
|
||||
vec![
|
||||
CheckCode::PD002,
|
||||
CheckCode::PD003,
|
||||
CheckCode::PD004,
|
||||
CheckCode::PD007,
|
||||
CheckCode::PD008,
|
||||
CheckCode::PD009,
|
||||
CheckCode::PD010,
|
||||
CheckCode::PD011,
|
||||
CheckCode::PD012,
|
||||
CheckCode::PD013,
|
||||
CheckCode::PD015,
|
||||
CheckCode::PD901,
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::PDV0 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV0` has been remapped to `PD0`".bold()
|
||||
);
|
||||
vec![
|
||||
CheckCode::PD002,
|
||||
CheckCode::PD003,
|
||||
CheckCode::PD004,
|
||||
CheckCode::PD007,
|
||||
CheckCode::PD008,
|
||||
CheckCode::PD009,
|
||||
CheckCode::PD010,
|
||||
CheckCode::PD011,
|
||||
CheckCode::PD012,
|
||||
CheckCode::PD013,
|
||||
CheckCode::PD015,
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::PDV002 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV002` has been remapped to `PD002`".bold()
|
||||
);
|
||||
vec![CheckCode::PD002]
|
||||
}
|
||||
CheckCodePrefix::PDV003 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV003` has been remapped to `PD003`".bold()
|
||||
);
|
||||
vec![CheckCode::PD003]
|
||||
}
|
||||
CheckCodePrefix::PDV004 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV004` has been remapped to `PD004`".bold()
|
||||
);
|
||||
vec![CheckCode::PD004]
|
||||
}
|
||||
CheckCodePrefix::PDV007 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV007` has been remapped to `PD007`".bold()
|
||||
);
|
||||
vec![CheckCode::PD007]
|
||||
}
|
||||
CheckCodePrefix::PDV008 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV008` has been remapped to `PD008`".bold()
|
||||
);
|
||||
vec![CheckCode::PD008]
|
||||
}
|
||||
CheckCodePrefix::PDV009 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV009` has been remapped to `PD009`".bold()
|
||||
);
|
||||
vec![CheckCode::PD009]
|
||||
}
|
||||
CheckCodePrefix::PDV01 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV01` has been remapped to `PD01`".bold()
|
||||
);
|
||||
vec![
|
||||
CheckCode::PD010,
|
||||
CheckCode::PD011,
|
||||
CheckCode::PD012,
|
||||
CheckCode::PD013,
|
||||
CheckCode::PD015,
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::PDV010 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV010` has been remapped to `PD010`".bold()
|
||||
);
|
||||
vec![CheckCode::PD010]
|
||||
}
|
||||
CheckCodePrefix::PDV011 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV011` has been remapped to `PD011`".bold()
|
||||
);
|
||||
vec![CheckCode::PD011]
|
||||
}
|
||||
CheckCodePrefix::PDV012 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV012` has been remapped to `PD012`".bold()
|
||||
);
|
||||
vec![CheckCode::PD012]
|
||||
}
|
||||
CheckCodePrefix::PDV013 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV013` has been remapped to `PD013`".bold()
|
||||
);
|
||||
vec![CheckCode::PD013]
|
||||
}
|
||||
CheckCodePrefix::PDV015 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV015` has been remapped to `PD015`".bold()
|
||||
);
|
||||
vec![CheckCode::PD015]
|
||||
}
|
||||
CheckCodePrefix::PDV9 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV9` has been remapped to `PD9`".bold()
|
||||
);
|
||||
vec![CheckCode::PD901]
|
||||
}
|
||||
CheckCodePrefix::PDV90 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV90` has been remapped to `PD90`".bold()
|
||||
);
|
||||
vec![CheckCode::PD901]
|
||||
}
|
||||
CheckCodePrefix::PDV901 => {
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
"`PDV901` has been remapped to `PD901`".bold()
|
||||
);
|
||||
vec![CheckCode::PD901]
|
||||
}
|
||||
CheckCodePrefix::PGH => vec![CheckCode::PGH001, CheckCode::PGH002, CheckCode::PGH003],
|
||||
CheckCodePrefix::PGH0 => vec![CheckCode::PGH001, CheckCode::PGH002, CheckCode::PGH003],
|
||||
CheckCodePrefix::PGH00 => vec![CheckCode::PGH001, CheckCode::PGH002, CheckCode::PGH003],
|
||||
CheckCodePrefix::PGH001 => vec![CheckCode::PGH001],
|
||||
CheckCodePrefix::PGH002 => vec![CheckCode::PGH002],
|
||||
CheckCodePrefix::PGH003 => vec![CheckCode::PGH003],
|
||||
CheckCodePrefix::PLC => {
|
||||
vec![CheckCode::PLC0414, CheckCode::PLC2201, CheckCode::PLC3002]
|
||||
}
|
||||
@@ -1603,7 +1863,7 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::TID25 => vec![CheckCode::TID252],
|
||||
CheckCodePrefix::TID252 => vec![CheckCode::TID252],
|
||||
CheckCodePrefix::U => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1628,7 +1888,7 @@ impl CheckCodePrefix {
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::U0 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1653,7 +1913,7 @@ impl CheckCodePrefix {
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::U00 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1671,7 +1931,7 @@ impl CheckCodePrefix {
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::U001 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1680,7 +1940,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP001]
|
||||
}
|
||||
CheckCodePrefix::U003 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1689,7 +1949,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP003]
|
||||
}
|
||||
CheckCodePrefix::U004 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1698,7 +1958,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP004]
|
||||
}
|
||||
CheckCodePrefix::U005 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1707,7 +1967,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP005]
|
||||
}
|
||||
CheckCodePrefix::U006 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1716,7 +1976,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP006]
|
||||
}
|
||||
CheckCodePrefix::U007 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1725,7 +1985,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP007]
|
||||
}
|
||||
CheckCodePrefix::U008 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1734,7 +1994,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP008]
|
||||
}
|
||||
CheckCodePrefix::U009 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1743,7 +2003,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP009]
|
||||
}
|
||||
CheckCodePrefix::U01 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1760,7 +2020,7 @@ impl CheckCodePrefix {
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::U010 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1769,7 +2029,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP010]
|
||||
}
|
||||
CheckCodePrefix::U011 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1778,7 +2038,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP011]
|
||||
}
|
||||
CheckCodePrefix::U012 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1787,7 +2047,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP012]
|
||||
}
|
||||
CheckCodePrefix::U013 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1796,7 +2056,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP013]
|
||||
}
|
||||
CheckCodePrefix::U014 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1805,7 +2065,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP014]
|
||||
}
|
||||
CheckCodePrefix::U015 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -1814,7 +2074,7 @@ impl CheckCodePrefix {
|
||||
vec![CheckCode::UP015]
|
||||
}
|
||||
CheckCodePrefix::U016 => {
|
||||
eprintln!(
|
||||
one_time_warning!(
|
||||
"{}{} {}",
|
||||
"warning".yellow().bold(),
|
||||
":".bold(),
|
||||
@@ -2095,6 +2355,19 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::D417 => SuffixLength::Three,
|
||||
CheckCodePrefix::D418 => SuffixLength::Three,
|
||||
CheckCodePrefix::D419 => SuffixLength::Three,
|
||||
CheckCodePrefix::DTZ => SuffixLength::Zero,
|
||||
CheckCodePrefix::DTZ0 => SuffixLength::One,
|
||||
CheckCodePrefix::DTZ00 => SuffixLength::Two,
|
||||
CheckCodePrefix::DTZ001 => SuffixLength::Three,
|
||||
CheckCodePrefix::DTZ002 => SuffixLength::Three,
|
||||
CheckCodePrefix::DTZ003 => SuffixLength::Three,
|
||||
CheckCodePrefix::DTZ004 => SuffixLength::Three,
|
||||
CheckCodePrefix::DTZ005 => SuffixLength::Three,
|
||||
CheckCodePrefix::DTZ006 => SuffixLength::Three,
|
||||
CheckCodePrefix::DTZ007 => SuffixLength::Three,
|
||||
CheckCodePrefix::DTZ01 => SuffixLength::Two,
|
||||
CheckCodePrefix::DTZ011 => SuffixLength::Three,
|
||||
CheckCodePrefix::DTZ012 => SuffixLength::Three,
|
||||
CheckCodePrefix::E => SuffixLength::Zero,
|
||||
CheckCodePrefix::E4 => SuffixLength::One,
|
||||
CheckCodePrefix::E40 => SuffixLength::Two,
|
||||
@@ -2236,9 +2509,26 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::N816 => SuffixLength::Three,
|
||||
CheckCodePrefix::N817 => SuffixLength::Three,
|
||||
CheckCodePrefix::N818 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD => SuffixLength::Zero,
|
||||
CheckCodePrefix::PD0 => SuffixLength::One,
|
||||
CheckCodePrefix::PD00 => SuffixLength::Two,
|
||||
CheckCodePrefix::PD002 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD003 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD004 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD007 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD008 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD009 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD01 => SuffixLength::Two,
|
||||
CheckCodePrefix::PD010 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD011 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD012 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD013 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD015 => SuffixLength::Three,
|
||||
CheckCodePrefix::PD9 => SuffixLength::One,
|
||||
CheckCodePrefix::PD90 => SuffixLength::Two,
|
||||
CheckCodePrefix::PD901 => SuffixLength::Three,
|
||||
CheckCodePrefix::PDV => SuffixLength::Zero,
|
||||
CheckCodePrefix::PDV0 => SuffixLength::One,
|
||||
CheckCodePrefix::PDV00 => SuffixLength::Two,
|
||||
CheckCodePrefix::PDV002 => SuffixLength::Three,
|
||||
CheckCodePrefix::PDV003 => SuffixLength::Three,
|
||||
CheckCodePrefix::PDV004 => SuffixLength::Three,
|
||||
@@ -2258,6 +2548,8 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::PGH0 => SuffixLength::One,
|
||||
CheckCodePrefix::PGH00 => SuffixLength::Two,
|
||||
CheckCodePrefix::PGH001 => SuffixLength::Three,
|
||||
CheckCodePrefix::PGH002 => SuffixLength::Three,
|
||||
CheckCodePrefix::PGH003 => SuffixLength::Three,
|
||||
CheckCodePrefix::PLC => SuffixLength::Zero,
|
||||
CheckCodePrefix::PLC0 => SuffixLength::One,
|
||||
CheckCodePrefix::PLC04 => SuffixLength::Two,
|
||||
@@ -2429,6 +2721,7 @@ pub const CATEGORIES: &[CheckCodePrefix] = &[
|
||||
CheckCodePrefix::BLE,
|
||||
CheckCodePrefix::C,
|
||||
CheckCodePrefix::D,
|
||||
CheckCodePrefix::DTZ,
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::EM,
|
||||
CheckCodePrefix::ERA,
|
||||
@@ -2437,7 +2730,7 @@ pub const CATEGORIES: &[CheckCodePrefix] = &[
|
||||
CheckCodePrefix::I,
|
||||
CheckCodePrefix::ICN,
|
||||
CheckCodePrefix::N,
|
||||
CheckCodePrefix::PDV,
|
||||
CheckCodePrefix::PD,
|
||||
CheckCodePrefix::PGH,
|
||||
CheckCodePrefix::PLC,
|
||||
CheckCodePrefix::PLE,
|
||||
|
||||
12
src/cli.rs
12
src/cli.rs
@@ -92,6 +92,12 @@ pub struct Cli {
|
||||
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_show_source"))]
|
||||
force_exclude: bool,
|
||||
#[clap(long, overrides_with("force_exclude"), hide = true)]
|
||||
no_force_exclude: bool,
|
||||
/// See the files Ruff will be run against with the current settings.
|
||||
#[arg(long)]
|
||||
pub show_files: bool,
|
||||
@@ -120,7 +126,7 @@ pub struct Cli {
|
||||
pub autoformat: bool,
|
||||
/// The name of the file when passing it through stdin.
|
||||
#[arg(long)]
|
||||
pub stdin_filename: Option<String>,
|
||||
pub stdin_filename: Option<PathBuf>,
|
||||
/// Explain a rule.
|
||||
#[arg(long)]
|
||||
pub explain: Option<CheckCode>,
|
||||
@@ -173,6 +179,7 @@ impl Cli {
|
||||
// TODO(charlie): Included in `pyproject.toml`, but not inherited.
|
||||
fix: resolve_bool_arg(self.fix, self.no_fix),
|
||||
format: self.format,
|
||||
force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -203,7 +210,7 @@ pub struct Arguments {
|
||||
pub show_files: bool,
|
||||
pub show_settings: bool,
|
||||
pub silent: bool,
|
||||
pub stdin_filename: Option<String>,
|
||||
pub stdin_filename: Option<PathBuf>,
|
||||
pub verbose: bool,
|
||||
pub watch: bool,
|
||||
}
|
||||
@@ -230,6 +237,7 @@ pub struct Overrides {
|
||||
// TODO(charlie): Captured in pyproject.toml as a default, but not part of `Settings`.
|
||||
pub fix: Option<bool>,
|
||||
pub format: Option<SerializationFormat>,
|
||||
pub force_exclude: Option<bool>,
|
||||
}
|
||||
|
||||
/// Map the CLI settings to a `LogLevel`.
|
||||
|
||||
@@ -17,9 +17,10 @@ use crate::cli::Overrides;
|
||||
use crate::iterators::par_iter;
|
||||
use crate::linter::{add_noqa_to_path, autoformat_path, lint_path, lint_stdin, Diagnostics};
|
||||
use crate::message::Message;
|
||||
use crate::resolver;
|
||||
use crate::resolver::{FileDiscovery, PyprojectDiscovery};
|
||||
use crate::settings::flags;
|
||||
use crate::settings::types::SerializationFormat;
|
||||
use crate::{packages, resolver};
|
||||
|
||||
/// Run the linter over a collection of files.
|
||||
pub fn run(
|
||||
@@ -27,24 +28,37 @@ pub fn run(
|
||||
pyproject_strategy: &PyprojectDiscovery,
|
||||
file_strategy: &FileDiscovery,
|
||||
overrides: &Overrides,
|
||||
cache: bool,
|
||||
autofix: &fixer::Mode,
|
||||
cache: flags::Cache,
|
||||
autofix: fixer::Mode,
|
||||
) -> Result<Diagnostics> {
|
||||
// Collect all the files to check.
|
||||
// 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 duration = start.elapsed();
|
||||
debug!("Identified files to lint in: {:?}", duration);
|
||||
|
||||
// Discover the package root for each Python file.
|
||||
let package_roots = packages::detect_package_roots(
|
||||
&paths
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(ignore::DirEntry::path)
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let start = Instant::now();
|
||||
let mut diagnostics: Diagnostics = par_iter(&paths)
|
||||
.map(|entry| {
|
||||
match entry {
|
||||
Ok(entry) => {
|
||||
let path = entry.path();
|
||||
let package = path
|
||||
.parent()
|
||||
.and_then(|parent| package_roots.get(parent))
|
||||
.and_then(|package| *package);
|
||||
let settings = resolver.resolve(path, pyproject_strategy);
|
||||
lint_path(path, settings, &cache.into(), autofix)
|
||||
lint_path(path, package, settings, cache, autofix)
|
||||
.map_err(|e| (Some(path.to_owned()), e.to_string()))
|
||||
}
|
||||
Err(e) => Err((
|
||||
@@ -102,7 +116,7 @@ fn read_from_stdin() -> Result<String> {
|
||||
pub fn run_stdin(
|
||||
strategy: &PyprojectDiscovery,
|
||||
filename: &Path,
|
||||
autofix: &fixer::Mode,
|
||||
autofix: fixer::Mode,
|
||||
) -> Result<Diagnostics> {
|
||||
let stdin = read_from_stdin()?;
|
||||
let settings = match strategy {
|
||||
|
||||
@@ -37,6 +37,7 @@ pub struct IsortDirectives {
|
||||
}
|
||||
|
||||
pub struct Directives {
|
||||
pub commented_lines: Vec<usize>,
|
||||
pub noqa_line_for: IntMap<usize, usize>,
|
||||
pub isort: IsortDirectives,
|
||||
}
|
||||
@@ -47,6 +48,7 @@ pub fn extract_directives(
|
||||
flags: Flags,
|
||||
) -> Directives {
|
||||
Directives {
|
||||
commented_lines: extract_commented_lines(lxr),
|
||||
noqa_line_for: if flags.contains(Flags::NOQA) {
|
||||
extract_noqa_line_for(lxr)
|
||||
} else {
|
||||
@@ -60,6 +62,16 @@ pub fn extract_directives(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_commented_lines(lxr: &[LexResult]) -> Vec<usize> {
|
||||
let mut commented_lines = Vec::new();
|
||||
for (start, tok, ..) in lxr.iter().flatten() {
|
||||
if matches!(tok, Tok::Comment) {
|
||||
commented_lines.push(start.row());
|
||||
}
|
||||
}
|
||||
commented_lines
|
||||
}
|
||||
|
||||
/// Extract a mapping from logical line to noqa line.
|
||||
pub fn extract_noqa_line_for(lxr: &[LexResult]) -> IntMap<usize, usize> {
|
||||
let mut noqa_line_for: IntMap<usize, usize> = IntMap::default();
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::checks::{CheckCode, CheckKind};
|
||||
use crate::eradicate::detection::comment_contains_code;
|
||||
use crate::settings::flags;
|
||||
use crate::{Check, Settings, SourceCodeLocator};
|
||||
|
||||
fn is_standalone_comment(line: &str) -> bool {
|
||||
@@ -23,7 +24,7 @@ pub fn commented_out_code(
|
||||
start: Location,
|
||||
end: Location,
|
||||
settings: &Settings,
|
||||
autofix: bool,
|
||||
autofix: flags::Autofix,
|
||||
) -> Option<Check> {
|
||||
let location = Location::new(start.row(), 0);
|
||||
let end_location = Location::new(end.row() + 1, 0);
|
||||
@@ -41,7 +42,9 @@ pub fn commented_out_code(
|
||||
end_location: end,
|
||||
},
|
||||
);
|
||||
if autofix && settings.fixable.contains(&CheckCode::ERA001) {
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.fixable.contains(&CheckCode::ERA001)
|
||||
{
|
||||
check.amend(Fix::deletion(location, end_location));
|
||||
}
|
||||
Some(check)
|
||||
|
||||
@@ -21,7 +21,6 @@ mod tests {
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(check_code),
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
|
||||
@@ -29,7 +29,6 @@ mod tests {
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(check_code),
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
|
||||
@@ -3,7 +3,7 @@ use rustpython_ast::{Cmpop, Constant, Expr, ExprKind, Located};
|
||||
|
||||
use crate::ast::helpers::match_module_member;
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
|
||||
fn is_sys(checker: &Checker, expr: &Expr, target: &str) -> bool {
|
||||
|
||||
45
src/flake8_annotations/fixes.rs
Normal file
45
src/flake8_annotations/fixes.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use anyhow::{bail, Result};
|
||||
use rustpython_ast::Stmt;
|
||||
use rustpython_parser::lexer;
|
||||
use rustpython_parser::lexer::Tok;
|
||||
|
||||
use crate::ast::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
/// ANN204
|
||||
pub fn add_return_none_annotation(locator: &SourceCodeLocator, stmt: &Stmt) -> Result<Fix> {
|
||||
let range = Range::from_located(stmt);
|
||||
let contents = locator.slice_source_code_range(&range);
|
||||
|
||||
// Find the colon (following the `def` keyword).
|
||||
let mut seen_lpar = false;
|
||||
let mut seen_rpar = false;
|
||||
let mut count: usize = 0;
|
||||
for (start, tok, ..) in lexer::make_tokenizer(&contents).flatten() {
|
||||
if seen_lpar && seen_rpar {
|
||||
if matches!(tok, Tok::Colon) {
|
||||
return Ok(Fix::insertion(
|
||||
" -> None".to_string(),
|
||||
helpers::to_absolute(start, range.location),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(tok, Tok::Lpar) {
|
||||
if count == 0 {
|
||||
seen_lpar = true;
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
if matches!(tok, Tok::Rpar) {
|
||||
count -= 1;
|
||||
if count == 0 {
|
||||
seen_rpar = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bail!("Unable to locate colon in function definition");
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Arguments, Expr, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::cast;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
use crate::visibility;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
mod fixes;
|
||||
pub mod helpers;
|
||||
pub mod plugins;
|
||||
pub mod settings;
|
||||
@@ -31,7 +32,6 @@ mod tests {
|
||||
CheckCode::ANN401,
|
||||
])
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
@@ -57,7 +57,6 @@ mod tests {
|
||||
CheckCode::ANN102,
|
||||
])
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
@@ -83,7 +82,6 @@ mod tests {
|
||||
CheckCode::ANN206,
|
||||
])
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
@@ -109,7 +107,6 @@ mod tests {
|
||||
CheckCode::ANN206,
|
||||
])
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
@@ -129,7 +126,6 @@ mod tests {
|
||||
},
|
||||
..Settings::for_rules(vec![CheckCode::ANN401])
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
@@ -149,7 +145,6 @@ mod tests {
|
||||
CheckCode::ANN206,
|
||||
])
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use log::error;
|
||||
use rustpython_ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::ast::{cast, visitor};
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{CheckCode, CheckKind};
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
use crate::flake8_annotations::fixes;
|
||||
use crate::flake8_annotations::helpers::match_function_def;
|
||||
use crate::visibility::Visibility;
|
||||
use crate::{visibility, Check};
|
||||
@@ -295,8 +297,8 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
check_dynamically_typed(checker, expr, || name.to_string());
|
||||
}
|
||||
} else {
|
||||
// Allow omission of return annotation in `__init__` functions, if the function
|
||||
// only returns `None` (explicitly or implicitly).
|
||||
// Allow omission of return annotation if the function only returns `None`
|
||||
// (explicitly or implicitly).
|
||||
if checker.settings.flake8_annotations.suppress_none_returning
|
||||
&& is_none_returning(body)
|
||||
{
|
||||
@@ -317,13 +319,6 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if visibility::is_magic(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN204) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeMagicMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if visibility::is_init(stmt) {
|
||||
// Allow omission of return annotation in `__init__` functions, as long as at
|
||||
// least one argument is typed.
|
||||
@@ -331,12 +326,26 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
if !(checker.settings.flake8_annotations.mypy_init_return
|
||||
&& has_any_typed_arg)
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeMagicMethod(name.to_string()),
|
||||
let mut check = Check::new(
|
||||
CheckKind::MissingReturnTypeSpecialMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
match fixes::add_return_none_annotation(checker.locator, stmt) {
|
||||
Ok(fix) => check.amend(fix),
|
||||
Err(e) => error!("Failed to generate fix: {e}"),
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
} else if visibility::is_magic(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN204) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeSpecialMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
match visibility {
|
||||
Visibility::Public => {
|
||||
|
||||
@@ -3,23 +3,37 @@ source: src/flake8_annotations/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
MissingReturnTypeMagicMethod: __init__
|
||||
MissingReturnTypeSpecialMethod: __init__
|
||||
location:
|
||||
row: 5
|
||||
column: 4
|
||||
end_location:
|
||||
row: 6
|
||||
column: 11
|
||||
fix: ~
|
||||
fix:
|
||||
content: " -> None"
|
||||
location:
|
||||
row: 5
|
||||
column: 22
|
||||
end_location:
|
||||
row: 5
|
||||
column: 22
|
||||
- kind:
|
||||
MissingReturnTypeMagicMethod: __init__
|
||||
MissingReturnTypeSpecialMethod: __init__
|
||||
location:
|
||||
row: 11
|
||||
column: 4
|
||||
end_location:
|
||||
row: 12
|
||||
column: 11
|
||||
fix: ~
|
||||
fix:
|
||||
content: " -> None"
|
||||
location:
|
||||
row: 11
|
||||
column: 27
|
||||
end_location:
|
||||
row: 11
|
||||
column: 27
|
||||
- kind:
|
||||
MissingReturnTypePrivateFunction: __init__
|
||||
location:
|
||||
|
||||
@@ -26,7 +26,6 @@ mod tests {
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(check_code),
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
|
||||
@@ -20,7 +20,6 @@ mod tests {
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(check_code),
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// BLE001
|
||||
|
||||
@@ -22,7 +22,6 @@ mod tests {
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(check_code),
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
|
||||
@@ -2,7 +2,7 @@ use rustpython_ast::{Arguments, ExprKind};
|
||||
use rustpython_parser::ast::{Constant, Expr};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
const FUNC_NAME_ALLOWLIST: &[&str] = &["get", "setdefault", "pop", "fromkeys"];
|
||||
|
||||
@@ -47,7 +47,6 @@ mod tests {
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&Settings::for_rule(check_code),
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
@@ -68,7 +67,6 @@ mod tests {
|
||||
},
|
||||
..Settings::for_rules(vec![CheckCode::B008])
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
|
||||
@@ -3,7 +3,7 @@ use rustpython_ast::{Constant, Expr, ExprKind, Keyword, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::helpers::match_module_member;
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
|
||||
fn is_abc_class(
|
||||
|
||||
@@ -2,7 +2,7 @@ use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location, Stmt, Stmt
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::code_gen::SourceGenerator;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use rustpython_ast::{ExprKind, Stmt, Withitem};
|
||||
|
||||
use crate::ast::helpers::match_module_member;
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B017
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B003
|
||||
|
||||
@@ -2,7 +2,7 @@ use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
|
||||
use crate::ast::types::{Range, ScopeKind};
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
fn is_cache_func(checker: &Checker, expr: &Expr) -> bool {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B016
|
||||
|
||||
@@ -7,7 +7,7 @@ use rustpython_ast::{
|
||||
use crate::ast::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
use crate::code_gen::SourceGenerator;
|
||||
|
||||
@@ -56,9 +56,12 @@ fn duplicate_handler_exceptions<'a>(
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
// TODO(charlie): If we have a single element, remove the tuple.
|
||||
let mut generator = SourceGenerator::new();
|
||||
generator.unparse_expr(&type_pattern(unique_elts), 0);
|
||||
if unique_elts.len() == 1 {
|
||||
generator.unparse_expr(unique_elts[0], 0);
|
||||
} else {
|
||||
generator.unparse_expr(&type_pattern(unique_elts), 0);
|
||||
}
|
||||
if let Ok(content) = generator.generate() {
|
||||
check.amend(Fix::replacement(
|
||||
content,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B021
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::ast::helpers::{
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::flake8_bugbear::plugins::mutable_argument_default::is_mutable_func;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::ast::helpers::collect_arg_names;
|
||||
use crate::ast::types::{Node, Range};
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -219,8 +219,8 @@ where
|
||||
// loop, flag it.
|
||||
for (name, expr, range) in suspicious_variables {
|
||||
if reassigned_in_loop.contains(name) {
|
||||
if !checker.seen_b023.contains(&expr) {
|
||||
checker.seen_b023.push(expr);
|
||||
if !checker.flake8_bugbear_seen.contains(&expr) {
|
||||
checker.flake8_bugbear_seen.push(expr);
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::FunctionUsesLoopVariable(name.to_string()),
|
||||
range,
|
||||
|
||||
@@ -2,7 +2,7 @@ use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::code_gen::SourceGenerator;
|
||||
use crate::python::identifiers::IDENTIFIER_REGEX;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
fn walk_stmt(checker: &mut Checker, body: &[Stmt], f: fn(&Stmt) -> bool) {
|
||||
|
||||
@@ -4,7 +4,7 @@ use rustpython_ast::{Expr, ExprKind};
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
#[derive(Default)]
|
||||
|
||||
@@ -3,7 +3,7 @@ use rustpython_ast::{Arguments, Constant, Expr, ExprKind, Operator};
|
||||
|
||||
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
const MUTABLE_FUNCS: &[(&str, &str)] = &[
|
||||
|
||||
@@ -2,7 +2,7 @@ use rustpython_ast::{ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::python::string::is_lower;
|
||||
|
||||
|
||||
@@ -1,52 +1,10 @@
|
||||
use anyhow::{bail, Result};
|
||||
use log::error;
|
||||
use rustpython_ast::{Excepthandler, ExcepthandlerKind, ExprKind, Located};
|
||||
use rustpython_parser::lexer;
|
||||
use rustpython_parser::lexer::Tok;
|
||||
use rustpython_ast::{Excepthandler, ExcepthandlerKind, ExprKind};
|
||||
|
||||
use crate::ast::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::code_gen::SourceGenerator;
|
||||
use crate::SourceCodeLocator;
|
||||
|
||||
/// Given a statement like `except (ValueError,)`, find the range of the
|
||||
/// parenthesized expression.
|
||||
fn match_tuple_range<T>(located: &Located<T>, locator: &SourceCodeLocator) -> Result<Range> {
|
||||
// Extract contents from the source code.
|
||||
let range = Range::from_located(located);
|
||||
let contents = locator.slice_source_code_range(&range);
|
||||
|
||||
// Find the left (opening) and right (closing) parentheses.
|
||||
let mut location = None;
|
||||
let mut end_location = None;
|
||||
let mut count: usize = 0;
|
||||
for (start, tok, end) in lexer::make_tokenizer(&contents).flatten() {
|
||||
if matches!(tok, Tok::Lpar) {
|
||||
if count == 0 {
|
||||
location = Some(helpers::to_absolute(start, range.location));
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if matches!(tok, Tok::Rpar) {
|
||||
count -= 1;
|
||||
if count == 0 {
|
||||
end_location = Some(helpers::to_absolute(end, range.location));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let (Some(location), Some(end_location)) = (location, end_location) else {
|
||||
bail!("Unable to find left and right parentheses");
|
||||
};
|
||||
Ok(Range {
|
||||
location,
|
||||
end_location,
|
||||
})
|
||||
}
|
||||
|
||||
/// B013
|
||||
pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[Excepthandler]) {
|
||||
@@ -68,16 +26,11 @@ pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[E
|
||||
let mut generator = SourceGenerator::new();
|
||||
generator.unparse_expr(elt, 0);
|
||||
if let Ok(content) = generator.generate() {
|
||||
match match_tuple_range(handler, checker.locator) {
|
||||
Ok(range) => {
|
||||
check.amend(Fix::replacement(
|
||||
content,
|
||||
range.location,
|
||||
range.end_location,
|
||||
));
|
||||
}
|
||||
Err(e) => error!("Failed to locate parentheses: {e}"),
|
||||
}
|
||||
check.amend(Fix::replacement(
|
||||
content,
|
||||
type_.location,
|
||||
type_.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
|
||||
@@ -4,7 +4,7 @@ use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location, Stmt, Stmt
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::code_gen::SourceGenerator;
|
||||
use crate::python::identifiers::IDENTIFIER_REGEX;
|
||||
@@ -59,7 +59,7 @@ pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
|
||||
// We can only replace a `setattr` call (which is an `Expr`) with an assignment
|
||||
// (which is a `Stmt`) if the `Expr` is already being used as a `Stmt`
|
||||
// (i.e., it's directly within an `StmtKind::Expr`).
|
||||
if let StmtKind::Expr { value: child } = &checker.current_parent().0.node {
|
||||
if let StmtKind::Expr { value: child } = &checker.current_stmt().0.node {
|
||||
if expr == child.as_ref() {
|
||||
let mut check = Check::new(CheckKind::SetAttrWithConstant, Range::from_located(expr));
|
||||
if checker.patch(check.kind.code()) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B026
|
||||
|
||||
@@ -2,7 +2,7 @@ use itertools::Itertools;
|
||||
use rustpython_ast::{Constant, Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B005
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Expr, ExprKind, Unaryop};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B002
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Constant, Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B004
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::ast::types::Range;
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// Identify all `ExprKind::Name` nodes in an AST.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
pub fn useless_comparison(checker: &mut Checker, expr: &Expr) {
|
||||
|
||||
@@ -2,7 +2,7 @@ use rustpython_ast::Expr;
|
||||
|
||||
use crate::ast::helpers::{collect_call_paths, match_call_path};
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B005
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Constant, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
// B018
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use rustpython_ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// B905
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user