Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20234c6156 | ||
|
|
de767cc026 | ||
|
|
ce1663d302 | ||
|
|
f40e4bcd14 | ||
|
|
e7d40d435f | ||
|
|
ef8fe31c0c | ||
|
|
226f682c99 | ||
|
|
468ffd29fb | ||
|
|
a61126ab23 | ||
|
|
54c7c25861 | ||
|
|
eff7700d92 | ||
|
|
8934f6938d | ||
|
|
8f0fc3033a | ||
|
|
4107bc828d | ||
|
|
706d28cabc | ||
|
|
4da2264722 | ||
|
|
bf88c815aa | ||
|
|
8a4831dd5b |
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.187
|
||||
rev: v0.0.190
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -724,7 +724,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.187-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.187"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1901,7 +1901,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.187"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.29",
|
||||
@@ -1919,7 +1919,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.187"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.187"
|
||||
version = "0.0.190"
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
@@ -43,7 +43,7 @@ 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.187", 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 = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "c01f014b1269eedcf4bdb45d5fbc62ae2beecf31" }
|
||||
|
||||
73
README.md
73
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. -->
|
||||
@@ -159,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.187
|
||||
rev: v0.0.190
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -866,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.
|
||||
@@ -874,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` is deprecated; use more explicit `.loc` or `.iloc` | |
|
||||
| PDV008 | UseOfDotAt | Use `.loc` instead of `.at`. If speed is important, use numpy. | |
|
||||
| PDV009 | UseOfDotIat | Use `.iloc` instead 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)
|
||||
|
||||
@@ -1186,6 +1203,7 @@ 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/)
|
||||
@@ -1240,6 +1258,7 @@ 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/)
|
||||
@@ -1746,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),
|
||||
|
||||
4
flake8_to_ruff/Cargo.lock
generated
4
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.187"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.187"
|
||||
version = "0.0.190"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.187-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,
|
||||
@@ -317,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),
|
||||
@@ -366,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),
|
||||
@@ -415,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,
|
||||
@@ -464,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,
|
||||
@@ -521,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,
|
||||
@@ -606,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,
|
||||
|
||||
@@ -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()
|
||||
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:
|
||||
|
||||
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")
|
||||
@@ -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=}")
|
||||
|
||||
7
resources/test/fixtures/ruff/RUF100.py
vendored
7
resources/test/fixtures/ruff/RUF100.py
vendored
@@ -79,3 +79,10 @@ _ = """Here's a source: https://github.com/ethereum/web3.py/blob/ffe59daf10edc19
|
||||
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)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.187"
|
||||
version = "0.0.190"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.187"
|
||||
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![];
|
||||
|
||||
22
src/cache.rs
22
src/cache.rs
@@ -8,6 +8,7 @@ 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};
|
||||
|
||||
@@ -15,6 +16,7 @@ use crate::autofix::fixer;
|
||||
use crate::message::Message;
|
||||
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,12 +36,12 @@ struct CheckResult {
|
||||
messages: Vec<Message>,
|
||||
}
|
||||
|
||||
fn cache_dir() -> &'static str {
|
||||
"./.ruff_cache"
|
||||
fn cache_dir() -> &'static Path {
|
||||
Path::new(CACHE_DIR.as_ref().map_or(".ruff_cache", String::as_str))
|
||||
}
|
||||
|
||||
fn content_dir() -> &'static str {
|
||||
"content"
|
||||
fn content_dir() -> &'static Path {
|
||||
Path::new("content")
|
||||
}
|
||||
|
||||
fn cache_key<P: AsRef<Path>>(path: P, settings: &Settings, autofix: fixer::Mode) -> u64 {
|
||||
@@ -53,7 +55,7 @@ fn cache_key<P: AsRef<Path>>(path: P, settings: &Settings, autofix: fixer::Mode)
|
||||
|
||||
/// 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()))?;
|
||||
@@ -75,19 +77,13 @@ 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.
|
||||
|
||||
@@ -37,10 +37,10 @@ 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;
|
||||
@@ -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,7 +96,7 @@ 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> {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -187,6 +184,13 @@ impl<'a> Checker<'a> {
|
||||
&& 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}`.
|
||||
pub fn match_typing_expr(&self, expr: &Expr, target: &str) -> bool {
|
||||
let call_path = dealias_call_path(collect_call_paths(expr), &self.import_aliases);
|
||||
@@ -543,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()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -648,7 +652,7 @@ where
|
||||
),
|
||||
used: None,
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
@@ -688,7 +692,7 @@ where
|
||||
None
|
||||
},
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -847,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()),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -878,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()),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -947,7 +951,7 @@ where
|
||||
None
|
||||
},
|
||||
range,
|
||||
source: Some(self.current_parent().clone()),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1179,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);
|
||||
}
|
||||
@@ -1382,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()),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1403,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
|
||||
@@ -1432,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, .. } => {
|
||||
@@ -1543,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 {
|
||||
@@ -1639,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
|
||||
@@ -1928,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 {
|
||||
@@ -1949,12 +1955,84 @@ 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::plugins::no_eval(self, func);
|
||||
@@ -2431,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);
|
||||
}
|
||||
@@ -2510,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) {
|
||||
@@ -2655,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()),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -2690,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>) {
|
||||
@@ -2721,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"))]
|
||||
}
|
||||
@@ -2732,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,
|
||||
@@ -2969,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
|
||||
@@ -3014,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;
|
||||
@@ -3031,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;
|
||||
@@ -3044,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;
|
||||
@@ -3094,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;
|
||||
@@ -3107,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()),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,18 +100,32 @@ pub fn check_noqa(
|
||||
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 matches.contains(&code) || settings.external.contains(code) {
|
||||
valid_codes.push(code.to_string());
|
||||
if code == CheckCode::RUF100.as_ref() {
|
||||
self_ignore = true;
|
||||
} else {
|
||||
invalid_codes.push(code.to_string());
|
||||
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)),
|
||||
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),
|
||||
|
||||
225
src/checks.rs
225
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,
|
||||
@@ -319,18 +329,18 @@ pub enum CheckCode {
|
||||
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,
|
||||
@@ -363,6 +373,7 @@ pub enum CheckCategory {
|
||||
Flake8Simplify,
|
||||
Flake8TidyImports,
|
||||
Flake8UnusedArguments,
|
||||
Flake8Datetimez,
|
||||
Eradicate,
|
||||
PandasVet,
|
||||
PygrepHooks,
|
||||
@@ -405,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",
|
||||
@@ -438,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],
|
||||
@@ -528,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))
|
||||
}
|
||||
@@ -921,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 {
|
||||
@@ -1279,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'),
|
||||
@@ -1416,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,
|
||||
@@ -1499,18 +1545,18 @@ 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,
|
||||
@@ -1868,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,
|
||||
@@ -2798,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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2817,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(),
|
||||
}
|
||||
}
|
||||
@@ -2957,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),
|
||||
])
|
||||
});
|
||||
|
||||
@@ -2973,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"),
|
||||
])
|
||||
});
|
||||
|
||||
|
||||
@@ -163,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,
|
||||
@@ -304,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,
|
||||
@@ -974,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,
|
||||
@@ -1371,62 +1442,246 @@ 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::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],
|
||||
@@ -2100,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,
|
||||
@@ -2241,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,
|
||||
@@ -2436,6 +2721,7 @@ pub const CATEGORIES: &[CheckCodePrefix] = &[
|
||||
CheckCodePrefix::BLE,
|
||||
CheckCodePrefix::C,
|
||||
CheckCodePrefix::D,
|
||||
CheckCodePrefix::DTZ,
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::EM,
|
||||
CheckCodePrefix::ERA,
|
||||
@@ -2444,7 +2730,7 @@ pub const CATEGORIES: &[CheckCodePrefix] = &[
|
||||
CheckCodePrefix::I,
|
||||
CheckCodePrefix::ICN,
|
||||
CheckCodePrefix::N,
|
||||
CheckCodePrefix::PDV,
|
||||
CheckCodePrefix::PD,
|
||||
CheckCodePrefix::PGH,
|
||||
CheckCodePrefix::PLC,
|
||||
CheckCodePrefix::PLE,
|
||||
|
||||
@@ -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,
|
||||
@@ -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),
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -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`.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
36
src/flake8_datetimez/mod.rs
Normal file
36
src/flake8_datetimez/mod.rs
Normal file
@@ -0,0 +1,36 @@
|
||||
pub mod plugins;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::convert::AsRef;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
use crate::linter::test_path;
|
||||
use crate::settings;
|
||||
|
||||
#[test_case(CheckCode::DTZ001, Path::new("DTZ001.py"); "DTZ001")]
|
||||
#[test_case(CheckCode::DTZ002, Path::new("DTZ002.py"); "DTZ002")]
|
||||
#[test_case(CheckCode::DTZ003, Path::new("DTZ003.py"); "DTZ003")]
|
||||
#[test_case(CheckCode::DTZ004, Path::new("DTZ004.py"); "DTZ004")]
|
||||
#[test_case(CheckCode::DTZ005, Path::new("DTZ005.py"); "DTZ005")]
|
||||
#[test_case(CheckCode::DTZ006, Path::new("DTZ006.py"); "DTZ006")]
|
||||
#[test_case(CheckCode::DTZ007, Path::new("DTZ007.py"); "DTZ007")]
|
||||
#[test_case(CheckCode::DTZ011, Path::new("DTZ011.py"); "DTZ011")]
|
||||
#[test_case(CheckCode::DTZ012, Path::new("DTZ012.py"); "DTZ012")]
|
||||
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/flake8_datetimez")
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(check_code),
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
240
src/flake8_datetimez/plugins.rs
Normal file
240
src/flake8_datetimez/plugins.rs
Normal file
@@ -0,0 +1,240 @@
|
||||
use rustpython_ast::{Constant, Expr, ExprKind, Keyword};
|
||||
|
||||
use crate::ast::helpers::{
|
||||
collect_call_paths, dealias_call_path, has_non_none_keyword, is_const_none, match_call_path,
|
||||
};
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
pub fn call_datetime_without_tzinfo(
|
||||
checker: &mut Checker,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
location: Range,
|
||||
) {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if !match_call_path(&call_path, "datetime", "datetime", &checker.from_imports) {
|
||||
return;
|
||||
}
|
||||
|
||||
// no args / no args unqualified
|
||||
if args.len() < 8 && keywords.is_empty() {
|
||||
checker.add_check(Check::new(CheckKind::CallDatetimeWithoutTzinfo, location));
|
||||
return;
|
||||
}
|
||||
|
||||
// none args
|
||||
if args.len() == 8 && is_const_none(&args[7]) {
|
||||
checker.add_check(Check::new(CheckKind::CallDatetimeWithoutTzinfo, location));
|
||||
return;
|
||||
}
|
||||
|
||||
// no kwargs / none kwargs
|
||||
if !has_non_none_keyword(keywords, "tzinfo") {
|
||||
checker.add_check(Check::new(CheckKind::CallDatetimeWithoutTzinfo, location));
|
||||
}
|
||||
}
|
||||
|
||||
/// DTZ002
|
||||
pub fn call_datetime_today(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if match_call_path(
|
||||
&call_path,
|
||||
"datetime.datetime",
|
||||
"today",
|
||||
&checker.from_imports,
|
||||
) {
|
||||
checker.add_check(Check::new(CheckKind::CallDatetimeToday, location));
|
||||
}
|
||||
}
|
||||
|
||||
/// DTZ003
|
||||
pub fn call_datetime_utcnow(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if match_call_path(
|
||||
&call_path,
|
||||
"datetime.datetime",
|
||||
"utcnow",
|
||||
&checker.from_imports,
|
||||
) {
|
||||
checker.add_check(Check::new(CheckKind::CallDatetimeUtcnow, location));
|
||||
}
|
||||
}
|
||||
|
||||
/// DTZ004
|
||||
pub fn call_datetime_utcfromtimestamp(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if match_call_path(
|
||||
&call_path,
|
||||
"datetime.datetime",
|
||||
"utcfromtimestamp",
|
||||
&checker.from_imports,
|
||||
) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::CallDatetimeUtcfromtimestamp,
|
||||
location,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// DTZ005
|
||||
pub fn call_datetime_now_without_tzinfo(
|
||||
checker: &mut Checker,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
location: Range,
|
||||
) {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if !match_call_path(
|
||||
&call_path,
|
||||
"datetime.datetime",
|
||||
"now",
|
||||
&checker.from_imports,
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// no args / no args unqualified
|
||||
if args.is_empty() && keywords.is_empty() {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::CallDatetimeNowWithoutTzinfo,
|
||||
location,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
// none args
|
||||
if !args.is_empty() && is_const_none(&args[0]) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::CallDatetimeNowWithoutTzinfo,
|
||||
location,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
// wrong keywords / none keyword
|
||||
if !keywords.is_empty() && !has_non_none_keyword(keywords, "tz") {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::CallDatetimeNowWithoutTzinfo,
|
||||
location,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// DTZ006
|
||||
pub fn call_datetime_fromtimestamp(
|
||||
checker: &mut Checker,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
location: Range,
|
||||
) {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if !match_call_path(
|
||||
&call_path,
|
||||
"datetime.datetime",
|
||||
"fromtimestamp",
|
||||
&checker.from_imports,
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// no args / no args unqualified
|
||||
if args.len() < 2 && keywords.is_empty() {
|
||||
checker.add_check(Check::new(CheckKind::CallDatetimeFromtimestamp, location));
|
||||
return;
|
||||
}
|
||||
|
||||
// none args
|
||||
if args.len() > 1 && is_const_none(&args[1]) {
|
||||
checker.add_check(Check::new(CheckKind::CallDatetimeFromtimestamp, location));
|
||||
return;
|
||||
}
|
||||
|
||||
// wrong keywords / none keyword
|
||||
if !keywords.is_empty() && !has_non_none_keyword(keywords, "tz") {
|
||||
checker.add_check(Check::new(CheckKind::CallDatetimeFromtimestamp, location));
|
||||
}
|
||||
}
|
||||
|
||||
/// DTZ007
|
||||
pub fn call_datetime_strptime_without_zone(
|
||||
checker: &mut Checker,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
location: Range,
|
||||
) {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if !match_call_path(
|
||||
&call_path,
|
||||
"datetime.datetime",
|
||||
"strptime",
|
||||
&checker.from_imports,
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Does the `strptime` call contain a format string with a timezone specifier?
|
||||
if let Some(ExprKind::Constant {
|
||||
value: Constant::Str(format),
|
||||
kind: None,
|
||||
}) = args.get(1).as_ref().map(|arg| &arg.node)
|
||||
{
|
||||
if format.contains("%z") {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let (Some(grandparent), Some(parent)) = (checker.current_expr_grandparent(), checker.current_expr_parent()) else {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::CallDatetimeStrptimeWithoutZone,
|
||||
location,
|
||||
));
|
||||
return;
|
||||
};
|
||||
|
||||
if let ExprKind::Call { keywords, .. } = &grandparent.0.node {
|
||||
if let ExprKind::Attribute { attr, .. } = &parent.0.node {
|
||||
// Ex) `datetime.strptime(...).astimezone()`
|
||||
if attr == "astimezone" {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ex) `datetime.strptime(...).replace(tzinfo=UTC)`
|
||||
if attr == "replace" {
|
||||
if has_non_none_keyword(keywords, "tzinfo") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::CallDatetimeStrptimeWithoutZone,
|
||||
location,
|
||||
));
|
||||
}
|
||||
|
||||
/// DTZ011
|
||||
pub fn call_date_today(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if match_call_path(&call_path, "datetime.date", "today", &checker.from_imports) {
|
||||
checker.add_check(Check::new(CheckKind::CallDateToday, location));
|
||||
}
|
||||
}
|
||||
|
||||
/// DTZ012
|
||||
pub fn call_date_fromtimestamp(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if match_call_path(
|
||||
&call_path,
|
||||
"datetime.date",
|
||||
"fromtimestamp",
|
||||
&checker.from_imports,
|
||||
) {
|
||||
checker.add_check(Check::new(CheckKind::CallDateFromtimestamp, location));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
source: src/flake8_datetimez/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CallDatetimeWithoutTzinfo
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 38
|
||||
fix: ~
|
||||
- kind: CallDatetimeWithoutTzinfo
|
||||
location:
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
column: 47
|
||||
fix: ~
|
||||
- kind: CallDatetimeWithoutTzinfo
|
||||
location:
|
||||
row: 10
|
||||
column: 0
|
||||
end_location:
|
||||
row: 10
|
||||
column: 37
|
||||
fix: ~
|
||||
- kind: CallDatetimeWithoutTzinfo
|
||||
location:
|
||||
row: 13
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
column: 42
|
||||
fix: ~
|
||||
- kind: CallDatetimeWithoutTzinfo
|
||||
location:
|
||||
row: 18
|
||||
column: 0
|
||||
end_location:
|
||||
row: 18
|
||||
column: 29
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
source: src/flake8_datetimez/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CallDatetimeToday
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 25
|
||||
fix: ~
|
||||
- kind: CallDatetimeToday
|
||||
location:
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
column: 16
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
source: src/flake8_datetimez/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CallDatetimeUtcnow
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 26
|
||||
fix: ~
|
||||
- kind: CallDatetimeUtcnow
|
||||
location:
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
column: 17
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
source: src/flake8_datetimez/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CallDatetimeUtcfromtimestamp
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 40
|
||||
fix: ~
|
||||
- kind: CallDatetimeUtcfromtimestamp
|
||||
location:
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
column: 31
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
source: src/flake8_datetimez/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CallDatetimeNowWithoutTzinfo
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 23
|
||||
fix: ~
|
||||
- kind: CallDatetimeNowWithoutTzinfo
|
||||
location:
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
column: 48
|
||||
fix: ~
|
||||
- kind: CallDatetimeNowWithoutTzinfo
|
||||
location:
|
||||
row: 10
|
||||
column: 0
|
||||
end_location:
|
||||
row: 10
|
||||
column: 27
|
||||
fix: ~
|
||||
- kind: CallDatetimeNowWithoutTzinfo
|
||||
location:
|
||||
row: 13
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
column: 30
|
||||
fix: ~
|
||||
- kind: CallDatetimeNowWithoutTzinfo
|
||||
location:
|
||||
row: 18
|
||||
column: 0
|
||||
end_location:
|
||||
row: 18
|
||||
column: 14
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
source: src/flake8_datetimez/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CallDatetimeFromtimestamp
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 37
|
||||
fix: ~
|
||||
- kind: CallDatetimeFromtimestamp
|
||||
location:
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
column: 64
|
||||
fix: ~
|
||||
- kind: CallDatetimeFromtimestamp
|
||||
location:
|
||||
row: 10
|
||||
column: 0
|
||||
end_location:
|
||||
row: 10
|
||||
column: 43
|
||||
fix: ~
|
||||
- kind: CallDatetimeFromtimestamp
|
||||
location:
|
||||
row: 13
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
column: 46
|
||||
fix: ~
|
||||
- kind: CallDatetimeFromtimestamp
|
||||
location:
|
||||
row: 18
|
||||
column: 0
|
||||
end_location:
|
||||
row: 18
|
||||
column: 28
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
source: src/flake8_datetimez/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CallDatetimeStrptimeWithoutZone
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 53
|
||||
fix: ~
|
||||
- kind: CallDatetimeStrptimeWithoutZone
|
||||
location:
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
column: 52
|
||||
fix: ~
|
||||
- kind: CallDatetimeStrptimeWithoutZone
|
||||
location:
|
||||
row: 10
|
||||
column: 0
|
||||
end_location:
|
||||
row: 10
|
||||
column: 52
|
||||
fix: ~
|
||||
- kind: CallDatetimeStrptimeWithoutZone
|
||||
location:
|
||||
row: 13
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
column: 52
|
||||
fix: ~
|
||||
- kind: CallDatetimeStrptimeWithoutZone
|
||||
location:
|
||||
row: 35
|
||||
column: 0
|
||||
end_location:
|
||||
row: 35
|
||||
column: 43
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
source: src/flake8_datetimez/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CallDateToday
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 21
|
||||
fix: ~
|
||||
- kind: CallDateToday
|
||||
location:
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
column: 12
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
source: src/flake8_datetimez/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CallDateFromtimestamp
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 33
|
||||
fix: ~
|
||||
- kind: CallDateFromtimestamp
|
||||
location:
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
column: 24
|
||||
fix: ~
|
||||
|
||||
@@ -1,2 +1,29 @@
|
||||
pub mod checks;
|
||||
pub mod types;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::convert::AsRef;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
use crate::linter::test_path;
|
||||
use crate::settings;
|
||||
|
||||
#[test_case(CheckCode::T100, Path::new("T100.py"); "T100")]
|
||||
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/flake8_debugger")
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(check_code),
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
source: src/flake8_print/mod.rs
|
||||
source: src/flake8_debugger/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
@@ -16,80 +16,80 @@ expression: checks
|
||||
Debugger:
|
||||
Import: pdb
|
||||
location:
|
||||
row: 4
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
row: 3
|
||||
column: 10
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Import: builtins.breakpoint
|
||||
location:
|
||||
row: 6
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 6
|
||||
row: 5
|
||||
column: 31
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Import: pdb.set_trace
|
||||
location:
|
||||
row: 7
|
||||
row: 6
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
row: 6
|
||||
column: 31
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Import: celery.contrib.rdb.set_trace
|
||||
location:
|
||||
row: 8
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 8
|
||||
row: 7
|
||||
column: 40
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Import: celery.contrib.rdb
|
||||
location:
|
||||
row: 10
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 10
|
||||
row: 9
|
||||
column: 25
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Call: breakpoint
|
||||
location:
|
||||
row: 13
|
||||
row: 11
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
row: 11
|
||||
column: 12
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Call: set_trace
|
||||
location:
|
||||
row: 14
|
||||
row: 12
|
||||
column: 0
|
||||
end_location:
|
||||
row: 14
|
||||
row: 12
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Call: set_trace
|
||||
location:
|
||||
row: 15
|
||||
row: 13
|
||||
column: 0
|
||||
end_location:
|
||||
row: 15
|
||||
row: 13
|
||||
column: 11
|
||||
fix: ~
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// Check whether a function call is a `print` or `pprint` invocation
|
||||
pub fn print_call(
|
||||
func: &Expr,
|
||||
check_print: bool,
|
||||
check_pprint: bool,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if check_print && id == "print" {
|
||||
return Some(Check::new(CheckKind::PrintFound, location));
|
||||
} else if check_pprint && id == "pprint" {
|
||||
return Some(Check::new(CheckKind::PPrintFound, location));
|
||||
}
|
||||
}
|
||||
|
||||
if let ExprKind::Attribute { value, attr, .. } = &func.node {
|
||||
if let ExprKind::Name { id, .. } = &value.node {
|
||||
if check_pprint && id == "pprint" && attr == "pprint" {
|
||||
return Some(Check::new(CheckKind::PPrintFound, location));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
mod checks;
|
||||
pub mod plugins;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -13,7 +12,6 @@ mod tests {
|
||||
use crate::linter::test_path;
|
||||
use crate::settings;
|
||||
|
||||
#[test_case(CheckCode::T100, Path::new("T100.py"); "T100")]
|
||||
#[test_case(CheckCode::T201, Path::new("T201.py"); "T201")]
|
||||
#[test_case(CheckCode::T203, Path::new("T203.py"); "T203")]
|
||||
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
|
||||
|
||||
@@ -1,26 +1,47 @@
|
||||
use log::error;
|
||||
use rustpython_ast::{Expr, Stmt, StmtKind};
|
||||
use rustpython_ast::{Expr, Keyword, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::helpers::{collect_call_paths, dealias_call_path, is_const_none, match_call_path};
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::helpers;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::checks::CheckCode;
|
||||
use crate::flake8_print::checks;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// T201, T203
|
||||
pub fn print_call(checker: &mut Checker, expr: &Expr, func: &Expr) {
|
||||
let Some(mut check) = checks::print_call(
|
||||
func,
|
||||
checker.settings.enabled.contains(&CheckCode::T201),
|
||||
checker.settings.enabled.contains(&CheckCode::T203),
|
||||
Range::from_located(expr),
|
||||
) else {
|
||||
return;
|
||||
pub fn print_call(checker: &mut Checker, expr: &Expr, func: &Expr, keywords: &[Keyword]) {
|
||||
let mut check = {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), &checker.import_aliases);
|
||||
if match_call_path(&call_path, "", "print", &checker.from_imports) {
|
||||
// If the print call has a `file=` argument (that isn't `None`, `"sys.stdout"`,
|
||||
// or `"sys.stderr"`), don't trigger T201.
|
||||
if let Some(keyword) = keywords
|
||||
.iter()
|
||||
.find(|keyword| keyword.node.arg.as_ref().map_or(false, |arg| arg == "file"))
|
||||
{
|
||||
if !is_const_none(&keyword.node.value) {
|
||||
let call_path = collect_call_paths(&keyword.node.value);
|
||||
if !(match_call_path(&call_path, "sys", "stdout", &checker.from_imports)
|
||||
|| match_call_path(&call_path, "sys", "stderr", &checker.from_imports))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Check::new(CheckKind::PrintFound, Range::from_located(expr))
|
||||
} else if match_call_path(&call_path, "pprint", "pprint", &checker.from_imports) {
|
||||
Check::new(CheckKind::PPrintFound, Range::from_located(expr))
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if !checker.settings.enabled.contains(check.kind.code()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if checker.patch(check.kind.code()) {
|
||||
let defined_by = checker.current_parent();
|
||||
let defined_in = checker.current_grandparent();
|
||||
let defined_by = checker.current_stmt();
|
||||
let defined_in = checker.current_stmt_parent();
|
||||
if matches!(defined_by.0.node, StmtKind::Expr { .. }) {
|
||||
let deleted: Vec<&Stmt> = checker.deletions.iter().map(|node| node.0).collect();
|
||||
match helpers::delete_stmt(
|
||||
|
||||
@@ -4,17 +4,62 @@ expression: checks
|
||||
---
|
||||
- kind: PrintFound
|
||||
location:
|
||||
row: 1
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 1
|
||||
row: 4
|
||||
column: 22
|
||||
fix:
|
||||
content: ""
|
||||
location:
|
||||
row: 1
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 2
|
||||
row: 5
|
||||
column: 0
|
||||
- kind: PrintFound
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 5
|
||||
column: 33
|
||||
fix:
|
||||
content: ""
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 6
|
||||
column: 0
|
||||
- kind: PrintFound
|
||||
location:
|
||||
row: 6
|
||||
column: 0
|
||||
end_location:
|
||||
row: 6
|
||||
column: 39
|
||||
fix:
|
||||
content: ""
|
||||
location:
|
||||
row: 6
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
column: 0
|
||||
- kind: PrintFound
|
||||
location:
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
column: 39
|
||||
fix:
|
||||
content: ""
|
||||
location:
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 8
|
||||
column: 0
|
||||
|
||||
|
||||
@@ -19,17 +19,17 @@ expression: checks
|
||||
column: 0
|
||||
- kind: PPrintFound
|
||||
location:
|
||||
row: 8
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 8
|
||||
row: 7
|
||||
column: 30
|
||||
fix:
|
||||
content: ""
|
||||
location:
|
||||
row: 8
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
row: 8
|
||||
column: 0
|
||||
|
||||
|
||||
@@ -12,50 +12,34 @@ expression: checks
|
||||
fix: ~
|
||||
- kind: UnnecessaryAssign
|
||||
location:
|
||||
row: 12
|
||||
row: 13
|
||||
column: 11
|
||||
end_location:
|
||||
row: 12
|
||||
row: 13
|
||||
column: 12
|
||||
fix: ~
|
||||
- kind: UnnecessaryAssign
|
||||
location:
|
||||
row: 18
|
||||
column: 11
|
||||
end_location:
|
||||
row: 18
|
||||
column: 12
|
||||
fix: ~
|
||||
- kind: UnnecessaryAssign
|
||||
location:
|
||||
row: 25
|
||||
column: 11
|
||||
end_location:
|
||||
row: 25
|
||||
column: 12
|
||||
fix: ~
|
||||
- kind: UnnecessaryAssign
|
||||
location:
|
||||
row: 31
|
||||
row: 19
|
||||
column: 15
|
||||
end_location:
|
||||
row: 31
|
||||
row: 19
|
||||
column: 16
|
||||
fix: ~
|
||||
- kind: UnnecessaryAssign
|
||||
location:
|
||||
row: 43
|
||||
row: 31
|
||||
column: 11
|
||||
end_location:
|
||||
row: 43
|
||||
row: 31
|
||||
column: 17
|
||||
fix: ~
|
||||
- kind: UnnecessaryAssign
|
||||
location:
|
||||
row: 51
|
||||
row: 39
|
||||
column: 11
|
||||
end_location:
|
||||
row: 51
|
||||
row: 39
|
||||
column: 20
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ impl<'a> Visitor<'a> for ReturnVisitor<'a> {
|
||||
.push((stmt.location, stmt.end_location.unwrap()));
|
||||
visitor::walk_stmt(self, stmt);
|
||||
}
|
||||
|
||||
_ => {
|
||||
visitor::walk_stmt(self, stmt);
|
||||
}
|
||||
@@ -108,6 +109,17 @@ impl<'a> Visitor<'a> for ReturnVisitor<'a> {
|
||||
|
||||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
match &expr.node {
|
||||
ExprKind::Call { .. } => {
|
||||
// Arbitrary function calls can have side effects, so we conservatively treat
|
||||
// every function call as a reference to every known variable.
|
||||
for name in self.stack.assigns.keys() {
|
||||
self.stack
|
||||
.refs
|
||||
.entry(name)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(self.in_f_string.unwrap_or(expr.location));
|
||||
}
|
||||
}
|
||||
ExprKind::Name { id, .. } => {
|
||||
self.stack
|
||||
.refs
|
||||
|
||||
@@ -47,6 +47,7 @@ pub mod flake8_boolean_trap;
|
||||
pub mod flake8_bugbear;
|
||||
mod flake8_builtins;
|
||||
mod flake8_comprehensions;
|
||||
mod flake8_datetimez;
|
||||
mod flake8_debugger;
|
||||
pub mod flake8_errmsg;
|
||||
mod flake8_import_conventions;
|
||||
|
||||
@@ -103,6 +103,10 @@ fn inner_main() -> Result<ExitCode> {
|
||||
// Extract options that are included in `Settings`, but only apply at the top
|
||||
// level.
|
||||
let file_strategy = FileDiscovery {
|
||||
force_exclude: match &pyproject_strategy {
|
||||
PyprojectDiscovery::Fixed(settings) => settings.force_exclude,
|
||||
PyprojectDiscovery::Hierarchical(settings) => settings.force_exclude,
|
||||
},
|
||||
respect_gitignore: match &pyproject_strategy {
|
||||
PyprojectDiscovery::Fixed(settings) => settings.respect_gitignore,
|
||||
PyprojectDiscovery::Hierarchical(settings) => settings.respect_gitignore,
|
||||
|
||||
@@ -3,7 +3,7 @@ use rustpython_ast::{Constant, Expr, ExprKind, Keyword};
|
||||
use crate::ast::types::Range;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
/// PDV002
|
||||
/// PD002
|
||||
pub fn inplace_argument(keywords: &[Keyword]) -> Option<Check> {
|
||||
for keyword in keywords {
|
||||
let arg = keyword.node.arg.as_ref()?;
|
||||
@@ -27,7 +27,7 @@ pub fn inplace_argument(keywords: &[Keyword]) -> Option<Check> {
|
||||
None
|
||||
}
|
||||
|
||||
/// PDV015
|
||||
/// PD015
|
||||
pub fn use_of_pd_merge(func: &Expr) -> Option<Check> {
|
||||
if let ExprKind::Attribute { attr, value, .. } = &func.node {
|
||||
if let ExprKind::Name { id, .. } = &value.node {
|
||||
@@ -42,7 +42,7 @@ pub fn use_of_pd_merge(func: &Expr) -> Option<Check> {
|
||||
None
|
||||
}
|
||||
|
||||
/// PDV901
|
||||
/// PD901
|
||||
pub fn assignment_to_df(targets: &[Expr]) -> Option<Check> {
|
||||
if targets.len() != 1 {
|
||||
return None;
|
||||
|
||||
@@ -18,7 +18,7 @@ mod tests {
|
||||
|
||||
fn check_code(contents: &str, expected: &[CheckCode]) -> Result<()> {
|
||||
let contents = dedent(contents);
|
||||
let settings = settings::Settings::for_rules(CheckCodePrefix::PDV.codes());
|
||||
let settings = settings::Settings::for_rules(CheckCodePrefix::PD.codes());
|
||||
let tokens: Vec<LexResult> = rustpython_helpers::tokenize(&contents);
|
||||
let locator = SourceCodeLocator::new(&contents);
|
||||
let directives = directives::extract_directives(
|
||||
@@ -46,20 +46,20 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case("df.drop(['a'], axis=1, inplace=False)", &[]; "PDV002_pass")]
|
||||
#[test_case("df.drop(['a'], axis=1, inplace=True)", &[CheckCode::PDV002]; "PDV002_fail")]
|
||||
#[test_case("nas = pd.isna(val)", &[]; "PDV003_pass")]
|
||||
#[test_case("nulls = pd.isnull(val)", &[CheckCode::PDV003]; "PDV003_fail")]
|
||||
#[test_case("print('bah humbug')", &[]; "PDV003_allows_other_calls")]
|
||||
#[test_case("not_nas = pd.notna(val)", &[]; "PDV004_pass")]
|
||||
#[test_case("not_nulls = pd.notnull(val)", &[CheckCode::PDV004]; "PDV004_fail")]
|
||||
#[test_case("new_df = df.loc['d':, 'A':'C']", &[]; "PDV007_pass_loc")]
|
||||
#[test_case("new_df = df.iloc[[1, 3, 5], [1, 3]]", &[]; "PDV007_pass_iloc")]
|
||||
#[test_case("s = df.ix[[0, 2], 'A']", &[CheckCode::PDV007]; "PDV007_fail")]
|
||||
#[test_case("index = df.loc[:, ['B', 'A']]", &[]; "PDV008_pass")]
|
||||
#[test_case("index = df.at[:, ['B', 'A']]", &[CheckCode::PDV008]; "PDV008_fail")]
|
||||
#[test_case("index = df.iloc[:, 1:3]", &[]; "PDV009_pass")]
|
||||
#[test_case("index = df.iat[:, 1:3]", &[CheckCode::PDV009]; "PDV009_fail")]
|
||||
#[test_case("df.drop(['a'], axis=1, inplace=False)", &[]; "PD002_pass")]
|
||||
#[test_case("df.drop(['a'], axis=1, inplace=True)", &[CheckCode::PD002]; "PD002_fail")]
|
||||
#[test_case("nas = pd.isna(val)", &[]; "PD003_pass")]
|
||||
#[test_case("nulls = pd.isnull(val)", &[CheckCode::PD003]; "PD003_fail")]
|
||||
#[test_case("print('bah humbug')", &[]; "PD003_allows_other_calls")]
|
||||
#[test_case("not_nas = pd.notna(val)", &[]; "PD004_pass")]
|
||||
#[test_case("not_nulls = pd.notnull(val)", &[CheckCode::PD004]; "PD004_fail")]
|
||||
#[test_case("new_df = df.loc['d':, 'A':'C']", &[]; "PD007_pass_loc")]
|
||||
#[test_case("new_df = df.iloc[[1, 3, 5], [1, 3]]", &[]; "PD007_pass_iloc")]
|
||||
#[test_case("s = df.ix[[0, 2], 'A']", &[CheckCode::PD007]; "PD007_fail")]
|
||||
#[test_case("index = df.loc[:, ['B', 'A']]", &[]; "PD008_pass")]
|
||||
#[test_case("index = df.at[:, ['B', 'A']]", &[CheckCode::PD008]; "PD008_fail")]
|
||||
#[test_case("index = df.iloc[:, 1:3]", &[]; "PD009_pass")]
|
||||
#[test_case("index = df.iat[:, 1:3]", &[CheckCode::PD009]; "PD009_fail")]
|
||||
#[test_case(r#"table = df.pivot_table(
|
||||
df,
|
||||
values='D',
|
||||
@@ -68,42 +68,42 @@ mod tests {
|
||||
aggfunc=np.sum,
|
||||
fill_value=0
|
||||
)
|
||||
"#, &[]; "PDV010_pass")]
|
||||
"#, &[]; "PD010_pass")]
|
||||
#[test_case(r#"table = pd.pivot(
|
||||
df,
|
||||
index='foo',
|
||||
columns='bar',
|
||||
values='baz'
|
||||
)
|
||||
"#, &[CheckCode::PDV010]; "PDV010_fail_pivot")]
|
||||
#[test_case("result = df.to_array()", &[]; "PDV011_pass_to_array")]
|
||||
#[test_case("result = df.array", &[]; "PDV011_pass_array")]
|
||||
#[test_case("result = df.values", &[CheckCode::PDV011]; "PDV011_fail_values")]
|
||||
// TODO: Check that the attribute access is NOT a method call
|
||||
// #[test_case("result = {}.values()", &[]; "PDV011_pass_values_call")]
|
||||
#[test_case("result = values", &[]; "PDV011_pass_node_name")]
|
||||
#[test_case("employees = pd.read_csv(input_file)", &[]; "PDV012_pass_read_csv")]
|
||||
#[test_case("employees = pd.read_table(input_file)", &[CheckCode::PDV012]; "PDV012_fail_read_table")]
|
||||
#[test_case("employees = read_table", &[]; "PDV012_node_Name_pass")]
|
||||
"#, &[CheckCode::PD010]; "PD010_fail_pivot")]
|
||||
#[test_case("result = df.to_array()", &[]; "PD011_pass_to_array")]
|
||||
#[test_case("result = df.array", &[]; "PD011_pass_array")]
|
||||
#[test_case("result = df.values", &[CheckCode::PD011]; "PD011_fail_values")]
|
||||
// TODO(edgarrmondragon): Check that the attribute access is NOT a method call.
|
||||
// #[test_case("result = {}.values()", &[]; "PD011_pass_values_call")]
|
||||
#[test_case("result = values", &[]; "PD011_pass_node_name")]
|
||||
#[test_case("employees = pd.read_csv(input_file)", &[]; "PD012_pass_read_csv")]
|
||||
#[test_case("employees = pd.read_table(input_file)", &[CheckCode::PD012]; "PD012_fail_read_table")]
|
||||
#[test_case("employees = read_table", &[]; "PD012_node_Name_pass")]
|
||||
#[test_case(r#"table = df.melt(
|
||||
id_vars='airline',
|
||||
value_vars=['ATL', 'DEN', 'DFW'],
|
||||
value_name='airline delay'
|
||||
)
|
||||
"#, &[]; "PDV013_pass")]
|
||||
#[test_case("table = df.stack(level=-1, dropna=True)", &[CheckCode::PDV013]; "PDV013_fail_stack")]
|
||||
"#, &[]; "PD013_pass")]
|
||||
#[test_case("table = df.stack(level=-1, dropna=True)", &[CheckCode::PD013]; "PD013_fail_stack")]
|
||||
#[test_case("df1.merge(df2)", &[]; "PD015_pass_merge_on_dataframe")]
|
||||
#[test_case("df1.merge(df2, 'inner')", &[]; "PD015_pass_merge_on_dataframe_with_multiple_args")]
|
||||
#[test_case("pd.merge(df1, df2)", &[CheckCode::PDV015]; "PD015_fail_merge_on_pandas_object")]
|
||||
#[test_case("pd.merge(df1, df2)", &[CheckCode::PD015]; "PD015_fail_merge_on_pandas_object")]
|
||||
#[test_case(
|
||||
"pd.to_datetime(timestamp * 10 ** 9).strftime('%Y-%m-%d %H:%M:%S.%f')",
|
||||
&[];
|
||||
"PD015_pass_other_pd_function"
|
||||
)]
|
||||
#[test_case("employees = pd.DataFrame(employee_dict)", &[]; "PDV901_pass_non_df")]
|
||||
#[test_case("employees_df = pd.DataFrame(employee_dict)", &[]; "PDV901_pass_part_df")]
|
||||
#[test_case("my_function(df=data)", &[]; "PDV901_pass_df_param")]
|
||||
#[test_case("df = pd.DataFrame()", &[CheckCode::PDV901]; "PDV901_fail_df_var")]
|
||||
#[test_case("employees = pd.DataFrame(employee_dict)", &[]; "PD901_pass_non_df")]
|
||||
#[test_case("employees_df = pd.DataFrame(employee_dict)", &[]; "PD901_pass_part_df")]
|
||||
#[test_case("my_function(df=data)", &[]; "PD901_pass_df_param")]
|
||||
#[test_case("df = pd.DataFrame()", &[CheckCode::PD901]; "PD901_fail_df_var")]
|
||||
fn test_pandas_vet(code: &str, expected: &[CheckCode]) -> Result<()> {
|
||||
check_code(code, expected)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1349,39 +1349,22 @@ fn missing_args(checker: &mut Checker, docstring: &Docstring, docstrings_args: &
|
||||
|
||||
// See: `GOOGLE_ARGS_REGEX` in `pydocstyle/checker.py`.
|
||||
static GOOGLE_ARGS_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^\s*(\w+)\s*(\(.*?\))?\s*:\n?\s*.+").unwrap());
|
||||
Lazy::new(|| Regex::new(r"^\s*(\w+)\s*(\(.*?\))?\s*:.+").unwrap());
|
||||
|
||||
fn args_section(checker: &mut Checker, docstring: &Docstring, context: &SectionContext) {
|
||||
let mut args_sections: Vec<String> = vec![];
|
||||
for line in textwrap::dedent(&context.following_lines.join("\n"))
|
||||
.trim()
|
||||
.lines()
|
||||
{
|
||||
if line.chars().next().map_or(true, char::is_whitespace) {
|
||||
// This is a continuation of documentation for the last
|
||||
// parameter because it does start with whitespace.
|
||||
if let Some(current) = args_sections.last_mut() {
|
||||
current.push_str(line);
|
||||
}
|
||||
} else {
|
||||
// This line is the start of documentation for the next
|
||||
// parameter because it doesn't start with any whitespace.
|
||||
args_sections.push(line.to_string());
|
||||
let mut matches = Vec::new();
|
||||
for line in context.following_lines {
|
||||
if let Some(captures) = GOOGLE_ARGS_REGEX.captures(line) {
|
||||
matches.push(captures);
|
||||
}
|
||||
}
|
||||
|
||||
missing_args(
|
||||
checker,
|
||||
docstring,
|
||||
// Collect the list of arguments documented in the docstring.
|
||||
&args_sections
|
||||
&matches
|
||||
.iter()
|
||||
.filter_map(
|
||||
|section| match GOOGLE_ARGS_REGEX.captures(section.as_str()) {
|
||||
Some(caps) => caps.get(1).map(|arg_name| arg_name.as_str()),
|
||||
None => None,
|
||||
},
|
||||
)
|
||||
.filter_map(|captures| captures.get(1).map(|arg_name| arg_name.as_str()))
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,17 @@ expression: checks
|
||||
row: 367
|
||||
column: 11
|
||||
fix: ~
|
||||
- kind:
|
||||
DocumentAllArguments:
|
||||
- skip
|
||||
- verbose
|
||||
location:
|
||||
row: 370
|
||||
column: 4
|
||||
end_location:
|
||||
row: 382
|
||||
column: 11
|
||||
fix: ~
|
||||
- kind:
|
||||
DocumentAllArguments:
|
||||
- y
|
||||
|
||||
@@ -96,6 +96,7 @@ mod tests {
|
||||
#[test_case(CheckCode::F821, Path::new("F821_4.py"); "F821_4")]
|
||||
#[test_case(CheckCode::F821, Path::new("F821_5.py"); "F821_5")]
|
||||
#[test_case(CheckCode::F821, Path::new("F821_6.py"); "F821_6")]
|
||||
#[test_case(CheckCode::F821, Path::new("F821_7.py"); "F821_7")]
|
||||
#[test_case(CheckCode::F822, Path::new("F822.py"); "F822")]
|
||||
#[test_case(CheckCode::F823, Path::new("F823.py"); "F823")]
|
||||
#[test_case(CheckCode::F831, Path::new("F831.py"); "F831")]
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
source: src/pyflakes/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
UndefinedName: Undefined
|
||||
location:
|
||||
row: 11
|
||||
column: 20
|
||||
end_location:
|
||||
row: 11
|
||||
column: 31
|
||||
fix: ~
|
||||
- kind:
|
||||
UndefinedName: Undefined
|
||||
location:
|
||||
row: 12
|
||||
column: 25
|
||||
end_location:
|
||||
row: 12
|
||||
column: 36
|
||||
fix: ~
|
||||
- kind:
|
||||
UndefinedName: Undefined
|
||||
location:
|
||||
row: 13
|
||||
column: 20
|
||||
end_location:
|
||||
row: 13
|
||||
column: 31
|
||||
fix: ~
|
||||
|
||||
@@ -13,7 +13,7 @@ pub fn used_prior_global_declaration(checker: &mut Checker, name: &str, expr: &E
|
||||
_ => return,
|
||||
};
|
||||
if let Some(stmt) = globals.get(name) {
|
||||
if expr.location < stmt.location {
|
||||
if checker.range_for(expr).location < stmt.location {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::UsedPriorGlobalDeclaration(name.to_string(), stmt.location.row()),
|
||||
Range::from_located(expr),
|
||||
|
||||
@@ -134,4 +134,15 @@ expression: checks
|
||||
row: 105
|
||||
column: 9
|
||||
fix: ~
|
||||
- kind:
|
||||
UsedPriorGlobalDeclaration:
|
||||
- x
|
||||
- 114
|
||||
location:
|
||||
row: 113
|
||||
column: 10
|
||||
end_location:
|
||||
row: 113
|
||||
column: 17
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -65,8 +65,8 @@ pub fn unnecessary_future_import(checker: &mut Checker, stmt: &Stmt, names: &[Lo
|
||||
|
||||
if checker.patch(check.kind.code()) {
|
||||
let deleted: Vec<&Stmt> = checker.deletions.iter().map(|node| node.0).collect();
|
||||
let defined_by = checker.current_parent();
|
||||
let defined_in = checker.current_grandparent();
|
||||
let defined_by = checker.current_stmt();
|
||||
let defined_in = checker.current_stmt_parent();
|
||||
match fixes::remove_unnecessary_future_import(
|
||||
checker.locator,
|
||||
&removable_index,
|
||||
|
||||
@@ -14,8 +14,8 @@ pub fn useless_metaclass_type(checker: &mut Checker, stmt: &Stmt, value: &Expr,
|
||||
};
|
||||
if checker.patch(check.kind.code()) {
|
||||
let deleted: Vec<&Stmt> = checker.deletions.iter().map(|node| node.0).collect();
|
||||
let defined_by = checker.current_parent();
|
||||
let defined_in = checker.current_grandparent();
|
||||
let defined_by = checker.current_stmt();
|
||||
let defined_in = checker.current_stmt_parent();
|
||||
match helpers::delete_stmt(
|
||||
defined_by.0,
|
||||
defined_in.map(|node| node.0),
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::settings::{pyproject, Settings};
|
||||
/// The strategy used to discover Python files in the filesystem..
|
||||
#[derive(Debug)]
|
||||
pub struct FileDiscovery {
|
||||
pub force_exclude: bool,
|
||||
pub respect_gitignore: bool,
|
||||
}
|
||||
|
||||
@@ -263,7 +264,7 @@ pub fn python_files_in_path(
|
||||
|
||||
// Respect our own exclusion behavior.
|
||||
if let Ok(entry) = &result {
|
||||
if entry.depth() > 0 {
|
||||
if file_strategy.force_exclude || entry.depth() > 0 {
|
||||
let path = entry.path();
|
||||
let resolver = resolver.read().unwrap();
|
||||
let settings = resolver.resolve(path, pyproject_strategy);
|
||||
|
||||
@@ -38,6 +38,7 @@ mod tests {
|
||||
&settings::Settings::for_rules(vec![
|
||||
CheckCode::RUF100,
|
||||
CheckCode::E501,
|
||||
CheckCode::F401,
|
||||
CheckCode::F841,
|
||||
]),
|
||||
)?;
|
||||
|
||||
@@ -182,4 +182,22 @@ expression: checks
|
||||
end_location:
|
||||
row: 71
|
||||
column: 11
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- shelve
|
||||
- false
|
||||
location:
|
||||
row: 85
|
||||
column: 7
|
||||
end_location:
|
||||
row: 85
|
||||
column: 13
|
||||
fix:
|
||||
content: ""
|
||||
location:
|
||||
row: 85
|
||||
column: 0
|
||||
end_location:
|
||||
row: 86
|
||||
column: 0
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ pub struct Configuration {
|
||||
pub fix: Option<bool>,
|
||||
pub fixable: Option<Vec<CheckCodePrefix>>,
|
||||
pub format: Option<SerializationFormat>,
|
||||
pub force_exclude: Option<bool>,
|
||||
pub ignore: Option<Vec<CheckCodePrefix>>,
|
||||
pub ignore_init_module_imports: Option<bool>,
|
||||
pub line_length: Option<usize>,
|
||||
@@ -96,6 +97,7 @@ impl Configuration {
|
||||
fix: options.fix,
|
||||
fixable: options.fixable,
|
||||
format: options.format,
|
||||
force_exclude: options.force_exclude,
|
||||
ignore: options.ignore,
|
||||
ignore_init_module_imports: options.ignore_init_module_imports,
|
||||
line_length: options.line_length,
|
||||
@@ -159,6 +161,7 @@ impl Configuration {
|
||||
fix: self.fix.or(config.fix),
|
||||
fixable: self.fixable.or(config.fixable),
|
||||
format: self.format.or(config.format),
|
||||
force_exclude: self.force_exclude.or(config.force_exclude),
|
||||
ignore: self.ignore.or(config.ignore),
|
||||
ignore_init_module_imports: self
|
||||
.ignore_init_module_imports
|
||||
@@ -208,6 +211,9 @@ impl Configuration {
|
||||
if let Some(format) = overrides.format {
|
||||
self.format = Some(format);
|
||||
}
|
||||
if let Some(force_exclude) = overrides.force_exclude {
|
||||
self.force_exclude = Some(force_exclude);
|
||||
}
|
||||
if let Some(ignore) = overrides.ignore {
|
||||
self.ignore = Some(ignore);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ pub struct Settings {
|
||||
pub fix: bool,
|
||||
pub fixable: FxHashSet<CheckCode>,
|
||||
pub format: SerializationFormat,
|
||||
pub force_exclude: bool,
|
||||
pub ignore_init_module_imports: bool,
|
||||
pub line_length: usize,
|
||||
pub per_file_ignores: Vec<(GlobMatcher, GlobMatcher, FxHashSet<CheckCode>)>,
|
||||
@@ -127,6 +128,7 @@ impl Settings {
|
||||
.into_iter(),
|
||||
),
|
||||
format: config.format.unwrap_or(SerializationFormat::Text),
|
||||
force_exclude: config.force_exclude.unwrap_or(false),
|
||||
ignore_init_module_imports: config.ignore_init_module_imports.unwrap_or_default(),
|
||||
line_length: config.line_length.unwrap_or(88),
|
||||
per_file_ignores: resolve_per_file_ignores(
|
||||
@@ -199,6 +201,7 @@ impl Settings {
|
||||
fix: false,
|
||||
fixable: FxHashSet::from_iter([check_code]),
|
||||
format: SerializationFormat::Text,
|
||||
force_exclude: false,
|
||||
ignore_init_module_imports: false,
|
||||
line_length: 88,
|
||||
per_file_ignores: vec![],
|
||||
@@ -231,6 +234,7 @@ impl Settings {
|
||||
fix: false,
|
||||
fixable: FxHashSet::from_iter(check_codes),
|
||||
format: SerializationFormat::Text,
|
||||
force_exclude: false,
|
||||
ignore_init_module_imports: false,
|
||||
line_length: 88,
|
||||
per_file_ignores: vec![],
|
||||
|
||||
@@ -165,6 +165,24 @@ pub struct Options {
|
||||
"#
|
||||
)]
|
||||
pub format: Option<SerializationFormat>,
|
||||
#[option(
|
||||
doc = r#"
|
||||
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 = r#"false"#,
|
||||
value_type = "bool",
|
||||
example = r#"
|
||||
force-exclude = true
|
||||
"#
|
||||
)]
|
||||
pub force_exclude: Option<bool>,
|
||||
#[option(
|
||||
doc = r"
|
||||
A list of check code prefixes to ignore. Prefixes can specify exact checks (like
|
||||
|
||||
@@ -129,6 +129,8 @@ mod tests {
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
force_exclude: None,
|
||||
ignore: None,
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
@@ -138,7 +140,6 @@ mod tests {
|
||||
show_source: None,
|
||||
src: None,
|
||||
target_version: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
@@ -176,6 +177,8 @@ line-length = 79
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
force_exclude: None,
|
||||
format: None,
|
||||
ignore: None,
|
||||
ignore_init_module_imports: None,
|
||||
line_length: Some(79),
|
||||
@@ -185,7 +188,6 @@ line-length = 79
|
||||
show_source: None,
|
||||
src: None,
|
||||
target_version: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
@@ -214,26 +216,27 @@ exclude = ["foo.py"]
|
||||
Some(Tools {
|
||||
ruff: Some(Options {
|
||||
allowed_confusables: None,
|
||||
line_length: None,
|
||||
fix: None,
|
||||
extend: None,
|
||||
dummy_variable_rgx: None,
|
||||
exclude: Some(vec!["foo.py".to_string()]),
|
||||
extend: None,
|
||||
extend_exclude: None,
|
||||
select: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
force_exclude: None,
|
||||
format: None,
|
||||
ignore: None,
|
||||
ignore_init_module_imports: None,
|
||||
extend_ignore: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
respect_gitignore: None,
|
||||
dummy_variable_rgx: None,
|
||||
select: None,
|
||||
show_source: None,
|
||||
src: None,
|
||||
target_version: None,
|
||||
show_source: None,
|
||||
unfixable: None,
|
||||
flake8_annotations: None,
|
||||
flake8_errmsg: None,
|
||||
flake8_bugbear: None,
|
||||
@@ -270,6 +273,8 @@ select = ["E501"]
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
force_exclude: None,
|
||||
format: None,
|
||||
ignore: None,
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
@@ -279,7 +284,6 @@ select = ["E501"]
|
||||
show_source: None,
|
||||
src: None,
|
||||
target_version: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
@@ -318,6 +322,8 @@ ignore = ["E501"]
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
force_exclude: None,
|
||||
format: None,
|
||||
ignore: Some(vec![CheckCodePrefix::E501]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
@@ -327,7 +333,6 @@ ignore = ["E501"]
|
||||
show_source: None,
|
||||
src: None,
|
||||
target_version: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
@@ -408,6 +413,7 @@ other-attribute = 1
|
||||
extend_ignore: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
force_exclude: None,
|
||||
unfixable: None,
|
||||
per_file_ignores: Some(FxHashMap::from_iter([(
|
||||
"__init__.py".to_string(),
|
||||
|
||||
@@ -55,12 +55,33 @@ fn test_stdin_json() -> Result<()> {
|
||||
.failure();
|
||||
assert_eq!(
|
||||
str::from_utf8(&output.get_output().stdout)?,
|
||||
"[\n {\n \"code\": \"F401\",\n \"message\": \"`os` imported but unused\",\n \
|
||||
\"fix\": {\n \"content\": \"\",\n \"location\": {\n \"row\": 1,\n \
|
||||
\"column\": 0\n },\n \"end_location\": {\n \"row\": 2,\n \
|
||||
\"column\": 0\n }\n },\n \"location\": {\n \"row\": 1,\n \
|
||||
\"column\": 8\n },\n \"end_location\": {\n \"row\": 1,\n \"column\": \
|
||||
10\n },\n \"filename\": \"F401.py\"\n }\n]\n"
|
||||
r#"[
|
||||
{
|
||||
"code": "F401",
|
||||
"message": "`os` imported but unused",
|
||||
"fix": {
|
||||
"content": "",
|
||||
"location": {
|
||||
"row": 1,
|
||||
"column": 0
|
||||
},
|
||||
"end_location": {
|
||||
"row": 2,
|
||||
"column": 0
|
||||
}
|
||||
},
|
||||
"location": {
|
||||
"row": 1,
|
||||
"column": 8
|
||||
},
|
||||
"end_location": {
|
||||
"row": 1,
|
||||
"column": 10
|
||||
},
|
||||
"filename": "F401.py"
|
||||
}
|
||||
]
|
||||
"#
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user