mirror of https://github.com/astral-sh/ruff
Merge branch 'main' into sasanjac/2195-Implement-configuration-options-from-`flake8-type-checking`
This commit is contained in:
commit
b307200e42
|
|
@ -109,21 +109,6 @@ jobs:
|
|||
./scripts/add_rule.py --name FirstRule --code TST001 --linter test
|
||||
- run: cargo check
|
||||
|
||||
maturin-build:
|
||||
name: "maturin build"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- run: pip install maturin
|
||||
- run: maturin build -b bin
|
||||
- run: python scripts/transform_readme.py --target pypi
|
||||
|
||||
typos:
|
||||
name: "spell check"
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
|
|
@ -289,9 +289,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.6"
|
||||
version = "4.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
|
||||
checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
|
|
@ -308,7 +308,7 @@ version = "4.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe"
|
||||
dependencies = [
|
||||
"clap 4.1.6",
|
||||
"clap 4.1.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -317,7 +317,7 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4160b4a4f72ef58bd766bad27c09e6ef1cc9d82a22f6a0f55d152985a4a48e31"
|
||||
dependencies = [
|
||||
"clap 4.1.6",
|
||||
"clap 4.1.8",
|
||||
"clap_complete",
|
||||
"clap_complete_fig",
|
||||
]
|
||||
|
|
@ -328,15 +328,15 @@ version = "4.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63a06158a72dbb088f864887b4409fd22600ba379f3cee3040f842234cc5c2d0"
|
||||
dependencies = [
|
||||
"clap 4.1.6",
|
||||
"clap 4.1.8",
|
||||
"clap_complete",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.1.0"
|
||||
version = "4.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
||||
checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
|
|
@ -427,9 +427,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "console_log"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494"
|
||||
checksum = "878ad067d4089144a36ee412d665916c665430eb84c0057b9987f424a5d15c03"
|
||||
dependencies = [
|
||||
"log",
|
||||
"web-sys",
|
||||
|
|
@ -770,10 +770,10 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
|||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.253"
|
||||
version = "0.0.254"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.6",
|
||||
"clap 4.1.8",
|
||||
"colored",
|
||||
"configparser",
|
||||
"once_cell",
|
||||
|
|
@ -1080,12 +1080,6 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
|
||||
[[package]]
|
||||
name = "joinery"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.61"
|
||||
|
|
@ -1369,15 +1363,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom8"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "5.1.0"
|
||||
|
|
@ -1405,7 +1390,6 @@ dependencies = [
|
|||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1415,7 +1399,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1447,27 +1430,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e0072973714303aa6e3631c7e8e777970cf4bdd25dc4932e41031027b8bcc4e"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0629cbd6b897944899b1f10496d9c4a7ac5878d45fd61bc22e9e79bfbbc29597"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
|
|
@ -1757,16 +1719,6 @@ dependencies = [
|
|||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
|
@ -1870,9 +1822,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.6.1"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
|
||||
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
|
|
@ -1880,9 +1832,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.10.2"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b"
|
||||
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
|
|
@ -1981,14 +1933,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.253"
|
||||
version = "0.0.254"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bisection",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
"clap 4.1.6",
|
||||
"clap 4.1.8",
|
||||
"colored",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
|
|
@ -2015,6 +1967,7 @@ dependencies = [
|
|||
"path-absolutize",
|
||||
"regex",
|
||||
"result-like",
|
||||
"ruff_cache",
|
||||
"ruff_macros",
|
||||
"ruff_python",
|
||||
"ruff_rustpython",
|
||||
|
|
@ -2032,15 +1985,25 @@ dependencies = [
|
|||
"test-case",
|
||||
"textwrap",
|
||||
"thiserror",
|
||||
"titlecase",
|
||||
"toml",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cache"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"globset",
|
||||
"itertools",
|
||||
"regex",
|
||||
"ruff_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.253"
|
||||
version = "0.0.254"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
|
|
@ -2050,7 +2013,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"cachedir",
|
||||
"chrono",
|
||||
"clap 4.1.6",
|
||||
"clap 4.1.8",
|
||||
"clap_complete_command",
|
||||
"clearscreen",
|
||||
"colored",
|
||||
|
|
@ -2066,6 +2029,7 @@ dependencies = [
|
|||
"rayon",
|
||||
"regex",
|
||||
"ruff",
|
||||
"ruff_cache",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -2083,7 +2047,7 @@ name = "ruff_dev"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.6",
|
||||
"clap 4.1.8",
|
||||
"itertools",
|
||||
"libcst",
|
||||
"once_cell",
|
||||
|
|
@ -2138,7 +2102,7 @@ name = "ruff_python_formatter"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.6",
|
||||
"clap 4.1.8",
|
||||
"insta",
|
||||
"is-macro",
|
||||
"itertools",
|
||||
|
|
@ -2231,7 +2195,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=aa8336ee94492b52458ed8e1517238e5c6c2914c#aa8336ee94492b52458ed8e1517238e5c6c2914c"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=1871a1632e310985414211222f5bf8069678892f#1871a1632e310985414211222f5bf8069678892f"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-compiler-core",
|
||||
|
|
@ -2240,7 +2204,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=aa8336ee94492b52458ed8e1517238e5c6c2914c#aa8336ee94492b52458ed8e1517238e5c6c2914c"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=1871a1632e310985414211222f5bf8069678892f#1871a1632e310985414211222f5bf8069678892f"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"bitflags",
|
||||
|
|
@ -2265,24 +2229,21 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=aa8336ee94492b52458ed8e1517238e5c6c2914c#aa8336ee94492b52458ed8e1517238e5c6c2914c"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=1871a1632e310985414211222f5bf8069678892f#1871a1632e310985414211222f5bf8069678892f"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
"bstr 0.2.17",
|
||||
"itertools",
|
||||
"lz4_flex",
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num_enum",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=aa8336ee94492b52458ed8e1517238e5c6c2914c#aa8336ee94492b52458ed8e1517238e5c6c2914c"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=1871a1632e310985414211222f5bf8069678892f#1871a1632e310985414211222f5bf8069678892f"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
|
|
@ -2297,7 +2258,7 @@ dependencies = [
|
|||
"rustc-hash",
|
||||
"rustpython-ast",
|
||||
"rustpython-compiler-core",
|
||||
"thiserror",
|
||||
"serde",
|
||||
"tiny-keccak",
|
||||
"unic-emoji-char",
|
||||
"unic-ucd-ident",
|
||||
|
|
@ -2327,9 +2288,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.11"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a5fb6c61f29e723026dc8e923d94c694313212abbecbbe5f55a7748eec5b307"
|
||||
checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
|
|
@ -2339,9 +2300,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.11"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f188d036977451159430f3b8dc82ec76364a42b7e289c2b18a9a18f4470058e9"
|
||||
checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -2553,9 +2514,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.108"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -2626,18 +2587,18 @@ checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8"
|
|||
|
||||
[[package]]
|
||||
name = "test-case"
|
||||
version = "2.2.2"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21d6cf5a7dffb3f9dceec8e6b8ca528d9bd71d36c9f074defb548ce161f598c0"
|
||||
checksum = "679b019fb241da62cc449b33b224d19ebe1c6767b495569765115dd7f7f9fba4"
|
||||
dependencies = [
|
||||
"test-case-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case-macros"
|
||||
version = "2.2.2"
|
||||
name = "test-case-core"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e45b7bf6e19353ddd832745c8fcf77a17a93171df7151187f26623f2b75b5b26"
|
||||
checksum = "72dc21b5887f4032c4656502d085dc28f2afbb686f25f216472bb0526f4b1b88"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro-error",
|
||||
|
|
@ -2646,6 +2607,19 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case-macros"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3786898e0be151a96f730fd529b0e8a10f5990fa2a7ea14e37ca27613c05190"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"test-case-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.0"
|
||||
|
|
@ -2752,22 +2726,11 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "titlecase"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38397a8cdb017cfeb48bf6c154d6de975ac69ffeed35980fde199d2ee0842042"
|
||||
dependencies = [
|
||||
"joinery",
|
||||
"lazy_static",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.6.0"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb9d890e4dc9298b70f740f615f2e05b9db37dce531f6b24fb77ac993f9f217"
|
||||
checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
|
|
@ -2777,24 +2740,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.5.1"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5"
|
||||
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.18.1"
|
||||
version = "0.19.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b"
|
||||
checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"nom8",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2949,7 +2912,7 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
|||
[[package]]
|
||||
name = "unicode_names2"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/youknowone/unicode_names2.git?tag=v0.6.0+character-alias#4ce16aa85cbcdd9cc830410f1a72ef9a235f2fde"
|
||||
source = "git+https://github.com/youknowone/unicode_names2.git?rev=4ce16aa85cbcdd9cc830410f1a72ef9a235f2fde#4ce16aa85cbcdd9cc830410f1a72ef9a235f2fde"
|
||||
dependencies = [
|
||||
"phf",
|
||||
]
|
||||
|
|
@ -3285,6 +3248,15 @@ version = "0.42.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faf09497b8f8b5ac5d3bb4d05c0a99be20f26fd3d5f2db7b0716e946d5103658"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
|
|
|
|||
42
Cargo.toml
42
Cargo.toml
|
|
@ -6,22 +6,42 @@ edition = "2021"
|
|||
rust-version = "1.67.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = { version = "1.0.66" }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
itertools = { version = "0.10.5" }
|
||||
anyhow = { version = "1.0.69" }
|
||||
bitflags = { version = "1.3.2" }
|
||||
chrono = { version = "0.4.23", default-features = false, features = ["clock"] }
|
||||
clap = { version = "4.1.8", features = ["derive"] }
|
||||
colored = { version = "2.0.0" }
|
||||
filetime = { version = "0.2.20" }
|
||||
glob = { version = "0.3.1" }
|
||||
globset = { version = "0.4.10" }
|
||||
ignore = { version = "0.4.20" }
|
||||
insta = { version = "1.28.0" }
|
||||
is-macro = { version = "0.2.2" }
|
||||
itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "80e4c1399f95e5beb532fdd1e209ad2dbb470438" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
regex = { version = "1.6.0" }
|
||||
log = { version = "0.4.17" }
|
||||
once_cell = { version = "1.17.1" }
|
||||
path-absolutize = { version = "3.0.14" }
|
||||
proc-macro2 = { version = "1.0.51" }
|
||||
quote = { version = "1.0.23" }
|
||||
regex = { version = "1.7.1" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "aa8336ee94492b52458ed8e1517238e5c6c2914c" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "aa8336ee94492b52458ed8e1517238e5c6c2914c" }
|
||||
schemars = { version = "0.8.11" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "1871a1632e310985414211222f5bf8069678892f" }
|
||||
rustpython-parser = { features = [
|
||||
"lalrpop",
|
||||
"serde",
|
||||
], git = "https://github.com/RustPython/RustPython.git", rev = "1871a1632e310985414211222f5bf8069678892f" }
|
||||
schemars = { version = "0.8.12" }
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = { version = "1.0.93" }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
similar = { version = "2.2.1" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
toml = { version = "0.6.0" }
|
||||
syn = { version = "1.0.109" }
|
||||
test-case = { version = "3.0.0" }
|
||||
textwrap = { version = "0.16.0" }
|
||||
toml = { version = "0.7.2" }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
|
|||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.253'
|
||||
rev: 'v0.0.254'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.253"
|
||||
version = "0.0.254"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
colored = { version = "2.0.0" }
|
||||
colored = { workspace = true }
|
||||
configparser = { version = "3.0.2" }
|
||||
once_cell = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.253"
|
||||
version = "0.0.254"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
|
|
@ -19,61 +19,64 @@ doctest = false
|
|||
ruff_macros = { path = "../ruff_macros" }
|
||||
ruff_python = { path = "../ruff_python" }
|
||||
ruff_rustpython = { path = "../ruff_rustpython" }
|
||||
ruff_cache = { path = "../ruff_cache" }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
bisection = { version = "0.1.0" }
|
||||
bitflags = { version = "1.3.2" }
|
||||
bitflags = { workspace = true }
|
||||
cfg-if = { version = "1.0.0" }
|
||||
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
|
||||
chrono = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive", "env", "string"] }
|
||||
colored = { version = "2.0.0" }
|
||||
colored = { workspace = true }
|
||||
derivative = { version = "2.2.0" }
|
||||
dirs = { version = "4.0.0" }
|
||||
fern = { version = "0.6.1" }
|
||||
glob = { version = "0.3.0" }
|
||||
globset = { version = "0.4.9" }
|
||||
ignore = { version = "0.4.18" }
|
||||
imperative = { version = "1.0.3" }
|
||||
glob = { workspace = true }
|
||||
globset = { workspace = true }
|
||||
ignore = { workspace = true }
|
||||
imperative = { version = "1.0.4" }
|
||||
is-macro = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
libcst = { workspace = true }
|
||||
log = { version = "0.4.17" }
|
||||
log = { workspace = true }
|
||||
natord = { version = "1.0.9" }
|
||||
nohash-hasher = { version = "0.2.0" }
|
||||
num-bigint = { version = "0.4.3" }
|
||||
num-traits = "0.2.15"
|
||||
num-traits = { version = "0.2.15" }
|
||||
once_cell = { workspace = true }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
path-absolutize = { workspace = true, features = [
|
||||
"once_cell_cache",
|
||||
"use_unix_paths_on_wasm",
|
||||
] }
|
||||
regex = { workspace = true }
|
||||
result-like = "0.4.6"
|
||||
result-like = { version = "0.4.6" }
|
||||
rustc-hash = { workspace = true }
|
||||
rustpython-common = { workspace = true }
|
||||
rustpython-parser = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
semver = { version = "1.0.16" }
|
||||
serde = { workspace = true }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
shellexpand = { workspace = true }
|
||||
smallvec = { version = "1.10.0" }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
textwrap = { version = "0.16.0" }
|
||||
thiserror = { version = "1.0" }
|
||||
titlecase = { version = "2.2.1" }
|
||||
textwrap = { workspace = true }
|
||||
thiserror = { version = "1.0.38" }
|
||||
toml = { workspace = true }
|
||||
|
||||
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
|
||||
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
|
||||
getrandom = { version = "0.2.7", features = ["js"] }
|
||||
getrandom = { version = "0.2.8", features = ["js"] }
|
||||
console_error_panic_hook = { version = "0.1.7" }
|
||||
console_log = { version = "0.2.0" }
|
||||
serde-wasm-bindgen = { version = "0.4" }
|
||||
js-sys = { version = "0.3.60" }
|
||||
wasm-bindgen = { version = "0.2.83" }
|
||||
console_log = { version = "0.2.1" }
|
||||
serde-wasm-bindgen = { version = "0.4.5" }
|
||||
js-sys = { version = "0.3.61" }
|
||||
wasm-bindgen = { version = "0.2.84" }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.19.0", features = ["yaml", "redactions"] }
|
||||
test-case = { version = "2.2.2" }
|
||||
wasm-bindgen-test = { version = "0.3.33" }
|
||||
insta = { workspace = true, features = ["yaml", "redactions"] }
|
||||
test-case = { workspace = true }
|
||||
wasm-bindgen-test = { version = "0.3.34" }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
|
||||
criterion = { version = "0.4.0" }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# From https://github.com/PyCQA/flake8-pyi/blob/4212bec43dbc4020a59b90e2957c9488575e57ba/tests/type_comments.pyi
|
||||
|
||||
from collections.abc import Sequence
|
||||
from typing import TypeAlias
|
||||
|
||||
A: TypeAlias = None # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
B: TypeAlias = None # type: str # And here's an extra comment about why it's that type # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
C: TypeAlias = None #type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
D: TypeAlias = None # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
E: TypeAlias = None# type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
F: TypeAlias = None#type:int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
|
||||
def func(
|
||||
arg1, # type: dict[str, int] # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
arg2 # type: Sequence[bytes] # And here's some more info about this arg # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
): ...
|
||||
|
||||
class Foo:
|
||||
Attr: TypeAlias = None # type: set[str] # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
|
||||
G: TypeAlias = None # type: ignore
|
||||
H: TypeAlias = None # type: ignore[attr-defined]
|
||||
I: TypeAlias = None #type: ignore
|
||||
J: TypeAlias = None # type: ignore
|
||||
K: TypeAlias = None# type: ignore
|
||||
L: TypeAlias = None#type:ignore
|
||||
|
||||
# Whole line commented out # type: int
|
||||
M: TypeAlias = None # type: can't parse me!
|
||||
|
||||
class Bar:
|
||||
N: TypeAlias = None # type: can't parse me either!
|
||||
# This whole line is commented out and indented # type: str
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# From https://github.com/PyCQA/flake8-pyi/blob/4212bec43dbc4020a59b90e2957c9488575e57ba/tests/type_comments.pyi
|
||||
|
||||
from collections.abc import Sequence
|
||||
from typing import TypeAlias
|
||||
|
||||
A: TypeAlias = None # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
B: TypeAlias = None # type: str # And here's an extra comment about why it's that type # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
C: TypeAlias = None #type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
D: TypeAlias = None # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
E: TypeAlias = None# type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
F: TypeAlias = None#type:int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
|
||||
def func(
|
||||
arg1, # type: dict[str, int] # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
arg2 # type: Sequence[bytes] # And here's some more info about this arg # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
): ...
|
||||
|
||||
class Foo:
|
||||
Attr: TypeAlias = None # type: set[str] # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
|
||||
G: TypeAlias = None # type: ignore
|
||||
H: TypeAlias = None # type: ignore[attr-defined]
|
||||
I: TypeAlias = None #type: ignore
|
||||
J: TypeAlias = None # type: ignore
|
||||
K: TypeAlias = None# type: ignore
|
||||
L: TypeAlias = None#type:ignore
|
||||
|
||||
# Whole line commented out # type: int
|
||||
M: TypeAlias = None # type: can't parse me!
|
||||
|
||||
class Bar:
|
||||
N: TypeAlias = None # type: can't parse me either!
|
||||
# This whole line is commented out and indented # type: str
|
||||
|
|
@ -293,3 +293,30 @@ def x(y):
|
|||
|
||||
def foo(baz: str) -> str:
|
||||
return baz
|
||||
|
||||
|
||||
def end_of_statement():
|
||||
def example():
|
||||
if True:
|
||||
return ""
|
||||
|
||||
|
||||
def example():
|
||||
if True:
|
||||
return ""
|
||||
|
||||
|
||||
def example():
|
||||
if True:
|
||||
return "" # type: ignore
|
||||
|
||||
|
||||
def example():
|
||||
if True:
|
||||
return "" ;
|
||||
|
||||
|
||||
def example():
|
||||
if True:
|
||||
return "" \
|
||||
; # type: ignore
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
"yoda" <= compare # SIM300
|
||||
"yoda" < compare # SIM300
|
||||
42 > age # SIM300
|
||||
-42 > age # SIM300
|
||||
+42 > age # SIM300
|
||||
YODA == age # SIM300
|
||||
YODA > age # SIM300
|
||||
YODA >= age # SIM300
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
from typing import TYPE_CHECKING, Any, ClassVar
|
||||
|
||||
|
||||
import attrs
|
||||
|
||||
from ....import unknown
|
||||
from ..protocol import commands, definitions, responses
|
||||
from ..server import example
|
||||
from .. import server
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
#: E211
|
||||
spam (1)
|
||||
#: E211 E211
|
||||
dict ['key'] = list [index]
|
||||
#: E211
|
||||
dict['key'] ['subkey'] = list[index]
|
||||
#: Okay
|
||||
spam(1)
|
||||
dict['key'] = list[index]
|
||||
|
||||
|
||||
# This is not prohibited by PEP8, but avoid it.
|
||||
class Foo (Bar, Baz):
|
||||
pass
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#: E231
|
||||
a = (1,2)
|
||||
#: E231
|
||||
a[b1,:]
|
||||
#: E231
|
||||
a = [{'a':''}]
|
||||
#: Okay
|
||||
a = (4,)
|
||||
b = (5, )
|
||||
c = {'text': text[5:]}
|
||||
|
||||
result = {
|
||||
'key1': 'value',
|
||||
'key2': 'value',
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
from functools import cached_property
|
||||
|
||||
from gi.repository import GObject
|
||||
|
||||
# Bad examples
|
||||
|
||||
def bad_liouiwnlkjl():
|
||||
|
|
@ -76,6 +78,11 @@ class Thingy:
|
|||
"""This property method docstring does not need to be written in imperative mood."""
|
||||
return self._beep
|
||||
|
||||
@GObject.Property
|
||||
def good_custom_property(self):
|
||||
"""This property method docstring does not need to be written in imperative mood."""
|
||||
return self._beep
|
||||
|
||||
@cached_property
|
||||
def good_cached_property(self):
|
||||
"""This property method docstring does not need to be written in imperative mood."""
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
"""Test case: strings used within calls within type annotations."""
|
||||
|
||||
from typing import Callable
|
||||
|
||||
import bpy
|
||||
from mypy_extensions import VarArg
|
||||
|
||||
from foo import Bar
|
||||
|
||||
|
||||
class LightShow(bpy.types.Operator):
|
||||
label = "Create Character"
|
||||
name = "lightshow.letter_creation"
|
||||
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH") # OK
|
||||
|
||||
|
||||
def f(x: Callable[[VarArg("os")], None]): # F821
|
||||
pass
|
||||
|
||||
|
||||
f(Callable[["Bar"], None])
|
||||
f(Callable[["Baz"], None])
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
"""Test case: strings used within calls within type annotations."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Callable
|
||||
|
||||
import bpy
|
||||
from mypy_extensions import VarArg
|
||||
|
||||
from foo import Bar
|
||||
|
||||
|
||||
class LightShow(bpy.types.Operator):
|
||||
label = "Create Character"
|
||||
name = "lightshow.letter_creation"
|
||||
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH") # OK
|
||||
|
||||
|
||||
def f(x: Callable[[VarArg("os")], None]): # F821
|
||||
pass
|
||||
|
||||
|
||||
f(Callable[["Bar"], None])
|
||||
f(Callable[["Baz"], None])
|
||||
|
|
@ -11,6 +11,9 @@ if 10 == 100: # [comparison-of-constants] R0133
|
|||
if 1 == 3: # [comparison-of-constants] R0133
|
||||
pass
|
||||
|
||||
if 1 == -3: # [comparison-of-constants] R0133
|
||||
pass
|
||||
|
||||
x = 0
|
||||
if 4 == 3 == x: # [comparison-of-constants] R0133
|
||||
pass
|
||||
|
|
@ -35,6 +38,12 @@ if argc != 1: # correct
|
|||
if argc != 2: # [magic-value-comparison]
|
||||
pass
|
||||
|
||||
if argc != -2: # [magic-value-comparison]
|
||||
pass
|
||||
|
||||
if argc != +2: # [magic-value-comparison]
|
||||
pass
|
||||
|
||||
if __name__ == "__main__": # correct
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -25,22 +25,7 @@ avoid-escape = true
|
|||
max-complexity = 10
|
||||
|
||||
[tool.ruff.pep8-naming]
|
||||
ignore-names = [
|
||||
"setUp",
|
||||
"tearDown",
|
||||
"setUpClass",
|
||||
"tearDownClass",
|
||||
"setUpModule",
|
||||
"tearDownModule",
|
||||
"asyncSetUp",
|
||||
"asyncTearDown",
|
||||
"setUpTestData",
|
||||
"failureException",
|
||||
"longMessage",
|
||||
"maxDiff",
|
||||
]
|
||||
classmethod-decorators = ["classmethod", "pydantic.validator"]
|
||||
staticmethod-decorators = ["staticmethod"]
|
||||
classmethod-decorators = ["pydantic.validator"]
|
||||
|
||||
[tool.ruff.flake8-tidy-imports]
|
||||
ban-relative-imports = "parents"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,292 @@
|
|||
use std::path::Path;
|
||||
|
||||
use nohash_hasher::IntMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::{Expr, Stmt};
|
||||
use smallvec::smallvec;
|
||||
|
||||
use ruff_python::typing::TYPING_EXTENSIONS;
|
||||
|
||||
use crate::ast::helpers::{collect_call_path, from_relative_import, Exceptions};
|
||||
use crate::ast::types::{Binding, BindingKind, CallPath, ExecutionContext, RefEquality, Scope};
|
||||
use crate::resolver::is_interface_definition_path;
|
||||
use crate::visibility::{module_visibility, Modifier, VisibleScope};
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct Context<'a> {
|
||||
pub typing_modules: &'a [String],
|
||||
pub module_path: Option<Vec<String>>,
|
||||
// Retain all scopes and parent nodes, along with a stack of indexes to track which are active
|
||||
// at various points in time.
|
||||
pub parents: Vec<RefEquality<'a, Stmt>>,
|
||||
pub depths: FxHashMap<RefEquality<'a, Stmt>, usize>,
|
||||
pub child_to_parent: FxHashMap<RefEquality<'a, Stmt>, RefEquality<'a, Stmt>>,
|
||||
// A stack of all bindings created in any scope, at any point in execution.
|
||||
pub bindings: Vec<Binding<'a>>,
|
||||
// Map from binding index to indexes of bindings that redefine it in other scopes.
|
||||
pub redefinitions: IntMap<usize, Vec<usize>>,
|
||||
pub exprs: Vec<RefEquality<'a, Expr>>,
|
||||
pub scopes: Vec<Scope<'a>>,
|
||||
pub scope_stack: Vec<usize>,
|
||||
pub dead_scopes: Vec<(usize, Vec<usize>)>,
|
||||
// Body iteration; used to peek at siblings.
|
||||
pub body: &'a [Stmt],
|
||||
pub body_index: usize,
|
||||
// Internal, derivative state.
|
||||
pub visible_scope: VisibleScope,
|
||||
pub in_annotation: bool,
|
||||
pub in_type_definition: bool,
|
||||
pub in_deferred_string_type_definition: bool,
|
||||
pub in_deferred_type_definition: bool,
|
||||
pub in_exception_handler: bool,
|
||||
pub in_literal: bool,
|
||||
pub in_subscript: bool,
|
||||
pub in_type_checking_block: bool,
|
||||
pub seen_import_boundary: bool,
|
||||
pub futures_allowed: bool,
|
||||
pub annotations_future_enabled: bool,
|
||||
pub handled_exceptions: Vec<Exceptions>,
|
||||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
pub fn new(
|
||||
typing_modules: &'a [String],
|
||||
path: &'a Path,
|
||||
module_path: Option<Vec<String>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
typing_modules,
|
||||
module_path,
|
||||
parents: Vec::default(),
|
||||
depths: FxHashMap::default(),
|
||||
child_to_parent: FxHashMap::default(),
|
||||
bindings: Vec::default(),
|
||||
redefinitions: IntMap::default(),
|
||||
exprs: Vec::default(),
|
||||
scopes: Vec::default(),
|
||||
scope_stack: Vec::default(),
|
||||
dead_scopes: Vec::default(),
|
||||
body: &[],
|
||||
body_index: 0,
|
||||
visible_scope: VisibleScope {
|
||||
modifier: Modifier::Module,
|
||||
visibility: module_visibility(path),
|
||||
},
|
||||
in_annotation: false,
|
||||
in_type_definition: false,
|
||||
in_deferred_string_type_definition: false,
|
||||
in_deferred_type_definition: false,
|
||||
in_exception_handler: false,
|
||||
in_literal: false,
|
||||
in_subscript: false,
|
||||
in_type_checking_block: false,
|
||||
seen_import_boundary: false,
|
||||
futures_allowed: true,
|
||||
annotations_future_enabled: is_interface_definition_path(path),
|
||||
handled_exceptions: Vec::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the `Expr` is a reference to `typing.${target}`.
|
||||
pub fn match_typing_expr(&self, expr: &Expr, target: &str) -> bool {
|
||||
self.resolve_call_path(expr).map_or(false, |call_path| {
|
||||
self.match_typing_call_path(&call_path, target)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return `true` if the call path is a reference to `typing.${target}`.
|
||||
pub fn match_typing_call_path(&self, call_path: &CallPath, target: &str) -> bool {
|
||||
if call_path.as_slice() == ["typing", target] {
|
||||
return true;
|
||||
}
|
||||
|
||||
if TYPING_EXTENSIONS.contains(target) {
|
||||
if call_path.as_slice() == ["typing_extensions", target] {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if self.typing_modules.iter().any(|module| {
|
||||
let mut module: CallPath = module.split('.').collect();
|
||||
module.push(target);
|
||||
*call_path == module
|
||||
}) {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Return the current `Binding` for a given `name`.
|
||||
pub fn find_binding(&self, member: &str) -> Option<&Binding> {
|
||||
self.current_scopes()
|
||||
.find_map(|scope| scope.bindings.get(member))
|
||||
.map(|index| &self.bindings[*index])
|
||||
}
|
||||
|
||||
/// Return `true` if `member` is bound as a builtin.
|
||||
pub fn is_builtin(&self, member: &str) -> bool {
|
||||
self.find_binding(member)
|
||||
.map_or(false, |binding| binding.kind.is_builtin())
|
||||
}
|
||||
|
||||
/// Resolves the call path, e.g. if you have a file
|
||||
///
|
||||
/// ```python
|
||||
/// from sys import version_info as python_version
|
||||
/// print(python_version)
|
||||
/// ```
|
||||
///
|
||||
/// then `python_version` from the print statement will resolve to `sys.version_info`.
|
||||
pub fn resolve_call_path<'b>(&'a self, value: &'b Expr) -> Option<CallPath<'a>>
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
let call_path = collect_call_path(value);
|
||||
let Some(head) = call_path.first() else {
|
||||
return None;
|
||||
};
|
||||
let Some(binding) = self.find_binding(head) else {
|
||||
return None;
|
||||
};
|
||||
match &binding.kind {
|
||||
BindingKind::Importation(.., name) | BindingKind::SubmoduleImportation(name, ..) => {
|
||||
if name.starts_with('.') {
|
||||
if let Some(module) = &self.module_path {
|
||||
let mut source_path = from_relative_import(module, name);
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
Some(source_path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
let mut source_path: CallPath = name.split('.').collect();
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
Some(source_path)
|
||||
}
|
||||
}
|
||||
BindingKind::FromImportation(.., name) => {
|
||||
if name.starts_with('.') {
|
||||
if let Some(module) = &self.module_path {
|
||||
let mut source_path = from_relative_import(module, name);
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
Some(source_path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
let mut source_path: CallPath = name.split('.').collect();
|
||||
source_path.extend(call_path.into_iter().skip(1));
|
||||
Some(source_path)
|
||||
}
|
||||
}
|
||||
BindingKind::Builtin => {
|
||||
let mut source_path: CallPath = smallvec![];
|
||||
source_path.push("");
|
||||
source_path.extend(call_path);
|
||||
Some(source_path)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_parent(&mut self, parent: &'a Stmt) {
|
||||
let num_existing = self.parents.len();
|
||||
self.parents.push(RefEquality(parent));
|
||||
self.depths
|
||||
.insert(self.parents[num_existing].clone(), num_existing);
|
||||
if num_existing > 0 {
|
||||
self.child_to_parent.insert(
|
||||
self.parents[num_existing].clone(),
|
||||
self.parents[num_existing - 1].clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop_parent(&mut self) {
|
||||
self.parents.pop().expect("Attempted to pop without parent");
|
||||
}
|
||||
|
||||
pub fn push_expr(&mut self, expr: &'a Expr) {
|
||||
self.exprs.push(RefEquality(expr));
|
||||
}
|
||||
|
||||
pub fn pop_expr(&mut self) {
|
||||
self.exprs
|
||||
.pop()
|
||||
.expect("Attempted to pop without expression");
|
||||
}
|
||||
|
||||
pub fn push_scope(&mut self, scope: Scope<'a>) {
|
||||
self.scope_stack.push(self.scopes.len());
|
||||
self.scopes.push(scope);
|
||||
}
|
||||
|
||||
pub fn pop_scope(&mut self) {
|
||||
self.dead_scopes.push((
|
||||
self.scope_stack
|
||||
.pop()
|
||||
.expect("Attempted to pop without scope"),
|
||||
self.scope_stack.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
/// 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 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)
|
||||
}
|
||||
|
||||
/// Return the `Stmt` that immediately follows the current `Stmt`, if any.
|
||||
pub fn current_sibling_stmt(&self) -> Option<&'a Stmt> {
|
||||
self.body.get(self.body_index + 1)
|
||||
}
|
||||
|
||||
pub fn current_scope(&self) -> &Scope {
|
||||
&self.scopes[*(self.scope_stack.last().expect("No current scope found"))]
|
||||
}
|
||||
|
||||
pub fn current_scope_parent(&self) -> Option<&Scope> {
|
||||
self.scope_stack
|
||||
.iter()
|
||||
.rev()
|
||||
.nth(1)
|
||||
.map(|index| &self.scopes[*index])
|
||||
}
|
||||
|
||||
pub fn current_scopes(&self) -> impl Iterator<Item = &Scope> {
|
||||
self.scope_stack
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|index| &self.scopes[*index])
|
||||
}
|
||||
|
||||
pub const fn in_exception_handler(&self) -> bool {
|
||||
self.in_exception_handler
|
||||
}
|
||||
|
||||
pub const fn execution_context(&self) -> ExecutionContext {
|
||||
if self.in_type_checking_block
|
||||
|| self.in_annotation
|
||||
|| self.in_deferred_string_type_definition
|
||||
{
|
||||
ExecutionContext::Typing
|
||||
} else {
|
||||
ExecutionContext::Runtime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use crate::ast::context::Context;
|
||||
use crate::ast::helpers::{map_callable, to_call_path};
|
||||
use crate::ast::types::{Scope, ScopeKind};
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
const CLASS_METHODS: [&str; 3] = ["__new__", "__init_subclass__", "__class_getitem__"];
|
||||
const METACLASS_BASES: [(&str, &str); 2] = [("", "type"), ("abc", "ABCMeta")];
|
||||
|
|
@ -16,7 +16,7 @@ pub enum FunctionType {
|
|||
|
||||
/// Classify a function based on its scope, name, and decorators.
|
||||
pub fn classify(
|
||||
checker: &Checker,
|
||||
ctx: &Context,
|
||||
scope: &Scope,
|
||||
name: &str,
|
||||
decorator_list: &[Expr],
|
||||
|
|
@ -29,12 +29,12 @@ pub fn classify(
|
|||
if decorator_list.iter().any(|expr| {
|
||||
// The method is decorated with a static method decorator (like
|
||||
// `@staticmethod`).
|
||||
checker
|
||||
.resolve_call_path(map_callable(expr))
|
||||
ctx.resolve_call_path(map_callable(expr))
|
||||
.map_or(false, |call_path| {
|
||||
staticmethod_decorators
|
||||
.iter()
|
||||
.any(|decorator| call_path == to_call_path(decorator))
|
||||
call_path.as_slice() == ["", "staticmethod"]
|
||||
|| staticmethod_decorators
|
||||
.iter()
|
||||
.any(|decorator| call_path == to_call_path(decorator))
|
||||
})
|
||||
}) {
|
||||
FunctionType::StaticMethod
|
||||
|
|
@ -42,7 +42,7 @@ pub fn classify(
|
|||
// Special-case class method, like `__new__`.
|
||||
|| scope.bases.iter().any(|expr| {
|
||||
// The class itself extends a known metaclass, so all methods are class methods.
|
||||
checker.resolve_call_path(map_callable(expr)).map_or(false, |call_path| {
|
||||
ctx.resolve_call_path(map_callable(expr)).map_or(false, |call_path| {
|
||||
METACLASS_BASES
|
||||
.iter()
|
||||
.any(|(module, member)| call_path.as_slice() == [*module, *member])
|
||||
|
|
@ -50,7 +50,8 @@ pub fn classify(
|
|||
})
|
||||
|| decorator_list.iter().any(|expr| {
|
||||
// The method is decorated with a class method decorator (like `@classmethod`).
|
||||
checker.resolve_call_path(map_callable(expr)).map_or(false, |call_path| {
|
||||
ctx.resolve_call_path(map_callable(expr)).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "classmethod"] ||
|
||||
classmethod_decorators
|
||||
.iter()
|
||||
.any(|decorator| call_path == to_call_path(decorator))
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ use rustpython_parser::ast::{
|
|||
use rustpython_parser::{lexer, Mode, StringKind, Tok};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::ast::context::Context;
|
||||
use crate::ast::types::{Binding, BindingKind, CallPath, Range};
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::source_code::{Generator, Indexer, Locator, Stylist};
|
||||
|
||||
/// Create an `Expr` with default location from an `ExprKind`.
|
||||
|
|
@ -99,17 +99,16 @@ pub fn format_call_path(call_path: &[&str]) -> String {
|
|||
}
|
||||
|
||||
/// Return `true` if the `Expr` contains a reference to `${module}.${target}`.
|
||||
pub fn contains_call_path(checker: &Checker, expr: &Expr, target: &[&str]) -> bool {
|
||||
pub fn contains_call_path(ctx: &Context, expr: &Expr, target: &[&str]) -> bool {
|
||||
any_over_expr(expr, &|expr| {
|
||||
checker
|
||||
.resolve_call_path(expr)
|
||||
ctx.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| call_path.as_slice() == target)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return `true` if the `Expr` contains an expression that appears to include a
|
||||
/// side-effect (like a function call).
|
||||
pub fn contains_effect(checker: &Checker, expr: &Expr) -> bool {
|
||||
pub fn contains_effect(ctx: &Context, expr: &Expr) -> bool {
|
||||
any_over_expr(expr, &|expr| {
|
||||
// Accept empty initializers.
|
||||
if let ExprKind::Call {
|
||||
|
|
@ -125,7 +124,7 @@ pub fn contains_effect(checker: &Checker, expr: &Expr) -> bool {
|
|||
|| id == "tuple"
|
||||
|| id == "dict"
|
||||
|| id == "frozenset")
|
||||
&& checker.is_builtin(id);
|
||||
&& ctx.is_builtin(id);
|
||||
return !is_empty_initializer;
|
||||
}
|
||||
}
|
||||
|
|
@ -669,10 +668,10 @@ pub fn has_comments_in(range: Range, locator: &Locator) -> bool {
|
|||
}
|
||||
|
||||
/// Return `true` if the body uses `locals()`, `globals()`, `vars()`, `eval()`.
|
||||
pub fn uses_magic_variable_access(checker: &Checker, body: &[Stmt]) -> bool {
|
||||
pub fn uses_magic_variable_access(ctx: &Context, body: &[Stmt]) -> bool {
|
||||
any_over_body(body, &|expr| {
|
||||
if let ExprKind::Call { func, .. } = &expr.node {
|
||||
checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
ctx.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "locals"]
|
||||
|| call_path.as_slice() == ["", "globals"]
|
||||
|| call_path.as_slice() == ["", "vars"]
|
||||
|
|
@ -1113,6 +1112,32 @@ pub fn first_colon_range(range: Range, locator: &Locator) -> Option<Range> {
|
|||
range
|
||||
}
|
||||
|
||||
/// Given a statement, find its "logical end".
|
||||
///
|
||||
/// For example: the statement could be following by a trailing semicolon, by an end-of-line
|
||||
/// comment, or by any number of continuation lines (and then by a comment, and so on).
|
||||
pub fn end_of_statement(stmt: &Stmt, locator: &Locator) -> Location {
|
||||
let contents = locator.skip(stmt.end_location.unwrap());
|
||||
|
||||
// End-of-file, so just return the end of the statement.
|
||||
if contents.is_empty() {
|
||||
return stmt.end_location.unwrap();
|
||||
}
|
||||
|
||||
// Otherwise, find the end of the last line that's "part of" the statement.
|
||||
for (lineno, line) in contents.lines().enumerate() {
|
||||
if line.ends_with('\\') {
|
||||
continue;
|
||||
}
|
||||
return to_absolute(
|
||||
Location::new(lineno + 1, line.chars().count()),
|
||||
stmt.end_location.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
unreachable!("Expected to find end-of-statement")
|
||||
}
|
||||
|
||||
/// Return the `Range` of the first `Elif` or `Else` token in an `If` statement.
|
||||
pub fn elif_else_range(stmt: &Stmt, locator: &Locator) -> Option<Range> {
|
||||
let StmtKind::If { body, orelse, .. } = &stmt.node else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
pub mod branch_detection;
|
||||
pub mod cast;
|
||||
pub mod comparable;
|
||||
pub mod context;
|
||||
pub mod function_type;
|
||||
pub mod hashable;
|
||||
pub mod helpers;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ use rustc_hash::FxHashMap;
|
|||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Located, Stmt, StmtKind};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use crate::ast::context::Context;
|
||||
use crate::ast::helpers::any_over_expr;
|
||||
use crate::ast::types::{BindingKind, Scope};
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
|
|
@ -19,7 +19,7 @@ bitflags! {
|
|||
|
||||
/// Extract the names bound to a given __all__ assignment.
|
||||
pub fn extract_all_names(
|
||||
checker: &Checker,
|
||||
ctx: &Context,
|
||||
stmt: &Stmt,
|
||||
scope: &Scope,
|
||||
) -> (Vec<String>, AllNamesFlags) {
|
||||
|
|
@ -38,7 +38,7 @@ pub fn extract_all_names(
|
|||
}
|
||||
|
||||
fn extract_elts<'a>(
|
||||
checker: &'a Checker,
|
||||
ctx: &'a Context,
|
||||
expr: &'a Expr,
|
||||
) -> (Option<&'a Vec<Expr>>, AllNamesFlags) {
|
||||
match &expr.node {
|
||||
|
|
@ -60,7 +60,7 @@ pub fn extract_all_names(
|
|||
} => {
|
||||
// Allow `tuple()` and `list()` calls.
|
||||
if keywords.is_empty() && args.len() <= 1 {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
if ctx.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "tuple"]
|
||||
|| call_path.as_slice() == ["", "list"]
|
||||
}) {
|
||||
|
|
@ -96,7 +96,7 @@ pub fn extract_all_names(
|
|||
// Grab the existing bound __all__ values.
|
||||
if let StmtKind::AugAssign { .. } = &stmt.node {
|
||||
if let Some(index) = scope.bindings.get("__all__") {
|
||||
if let BindingKind::Export(existing) = &checker.bindings[*index].kind {
|
||||
if let BindingKind::Export(existing) = &ctx.bindings[*index].kind {
|
||||
names.extend_from_slice(existing);
|
||||
}
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ pub fn extract_all_names(
|
|||
let mut current_right = right;
|
||||
loop {
|
||||
// Process the right side, which should be a "real" value.
|
||||
let (elts, new_flags) = extract_elts(checker, current_right);
|
||||
let (elts, new_flags) = extract_elts(ctx, current_right);
|
||||
flags |= new_flags;
|
||||
if let Some(elts) = elts {
|
||||
add_to_names(&mut names, elts, &mut flags);
|
||||
|
|
@ -125,7 +125,7 @@ pub fn extract_all_names(
|
|||
current_left = left;
|
||||
current_right = right;
|
||||
} else {
|
||||
let (elts, new_flags) = extract_elts(checker, current_left);
|
||||
let (elts, new_flags) = extract_elts(ctx, current_left);
|
||||
flags |= new_flags;
|
||||
if let Some(elts) = elts {
|
||||
add_to_names(&mut names, elts, &mut flags);
|
||||
|
|
@ -134,7 +134,7 @@ pub fn extract_all_names(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let (elts, new_flags) = extract_elts(checker, value);
|
||||
let (elts, new_flags) = extract_elts(ctx, value);
|
||||
flags |= new_flags;
|
||||
if let Some(elts) = elts {
|
||||
add_to_names(&mut names, elts, &mut flags);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
use rustpython_parser::ast::{Expr, Stmt};
|
||||
|
||||
use crate::ast::types::RefEquality;
|
||||
use crate::checkers::ast::AnnotationContext;
|
||||
use crate::docstrings::definition::Definition;
|
||||
use crate::visibility::{Visibility, VisibleScope};
|
||||
use crate::Range;
|
||||
|
||||
type Context<'a> = (Vec<usize>, Vec<RefEquality<'a, Stmt>>);
|
||||
|
||||
/// A collection of AST nodes that are deferred for later analysis.
|
||||
/// Used to, e.g., store functions, whose bodies shouldn't be analyzed until all
|
||||
/// module-level definitions have been analyzed.
|
||||
#[derive(Default)]
|
||||
pub struct Deferred<'a> {
|
||||
pub definitions: Vec<(Definition<'a>, Visibility, Context<'a>)>,
|
||||
pub string_type_definitions: Vec<(Range, &'a str, AnnotationContext, Context<'a>)>,
|
||||
pub type_definitions: Vec<(&'a Expr, AnnotationContext, Context<'a>)>,
|
||||
pub functions: Vec<(&'a Stmt, Context<'a>, VisibleScope)>,
|
||||
pub lambdas: Vec<(&'a Expr, Context<'a>)>,
|
||||
pub for_loops: Vec<(&'a Stmt, Context<'a>)>,
|
||||
pub assignments: Vec<Context<'a>>,
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,17 +1,20 @@
|
|||
#![allow(dead_code, unused_imports, unused_variables)]
|
||||
|
||||
use bisection::bisect_left;
|
||||
use itertools::Itertools;
|
||||
use rustpython_parser::ast::Location;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rules::pycodestyle::logical_lines::{iter_logical_lines, TokenFlags};
|
||||
use crate::rules::pycodestyle::rules::{
|
||||
extraneous_whitespace, indentation, missing_whitespace_after_keyword, space_around_operator,
|
||||
whitespace_around_keywords, whitespace_around_named_parameter_equals,
|
||||
whitespace_before_comment,
|
||||
extraneous_whitespace, indentation, missing_whitespace, missing_whitespace_after_keyword,
|
||||
missing_whitespace_around_operator, space_around_operator, whitespace_around_keywords,
|
||||
whitespace_around_named_parameter_equals, whitespace_before_comment,
|
||||
whitespace_before_parameters,
|
||||
};
|
||||
use crate::settings::Settings;
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::{Locator, Stylist};
|
||||
|
||||
/// Return the amount of indentation, expanding tabs to the next multiple of 8.
|
||||
|
|
@ -40,6 +43,7 @@ pub fn check_logical_lines(
|
|||
locator: &Locator,
|
||||
stylist: &Stylist,
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
|
|
@ -147,6 +151,44 @@ pub fn check_logical_lines(
|
|||
});
|
||||
}
|
||||
}
|
||||
for (location, kind) in missing_whitespace_around_operator(&line.tokens) {
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "logical_lines")]
|
||||
let should_fix = autofix.into() && settings.rules.should_fix(&Rule::MissingWhitespace);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
let should_fix = false;
|
||||
|
||||
for diagnostic in missing_whitespace(&line.text, start_loc.row(), should_fix) {
|
||||
if settings.rules.enabled(diagnostic.kind.rule()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if line.flags.contains(TokenFlags::BRACKET) {
|
||||
#[cfg(feature = "logical_lines")]
|
||||
let should_fix =
|
||||
autofix.into() && settings.rules.should_fix(&Rule::WhitespaceBeforeParameters);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
let should_fix = false;
|
||||
|
||||
for diagnostic in whitespace_before_parameters(&line.tokens, should_fix) {
|
||||
if settings.rules.enabled(diagnostic.kind.rule()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (index, kind) in indentation(
|
||||
|
|
@ -261,7 +303,7 @@ f()"#;
|
|||
.into_iter()
|
||||
.map(|line| line.text)
|
||||
.collect();
|
||||
let expected = vec!["def f():", "\"xxx\"", "", "x = 1", "f()"];
|
||||
let expected = vec!["def f():", "\"xxxxxxxxxxxxxxxxxxxx\"", "", "x = 1", "f()"];
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use crate::lex::docstring_detection::StateMachine;
|
|||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rules::ruff::rules::Context;
|
||||
use crate::rules::{
|
||||
eradicate, flake8_commas, flake8_implicit_str_concat, flake8_quotes, pycodestyle, pyupgrade,
|
||||
ruff,
|
||||
eradicate, flake8_commas, flake8_implicit_str_concat, flake8_pyi, flake8_quotes, pycodestyle,
|
||||
pyupgrade, ruff,
|
||||
};
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::Locator;
|
||||
|
|
@ -18,6 +18,7 @@ pub fn check_tokens(
|
|||
tokens: &[LexResult],
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
is_interface_definition: bool,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
|
|
@ -55,6 +56,7 @@ pub fn check_tokens(
|
|||
.enabled(&Rule::TrailingCommaOnBareTupleProhibited)
|
||||
|| settings.rules.enabled(&Rule::TrailingCommaProhibited);
|
||||
let enforce_extraneous_parenthesis = settings.rules.enabled(&Rule::ExtraneousParentheses);
|
||||
let enforce_type_comment_in_stub = settings.rules.enabled(&Rule::TypeCommentInStub);
|
||||
|
||||
// RUF001, RUF002, RUF003
|
||||
if enforce_ambiguous_unicode_character {
|
||||
|
|
@ -161,5 +163,10 @@ pub fn check_tokens(
|
|||
);
|
||||
}
|
||||
|
||||
// PYI033
|
||||
if enforce_type_comment_in_stub && is_interface_definition {
|
||||
diagnostics.extend(flake8_pyi::rules::type_comment_in_stub(tokens));
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
|||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E203") => Rule::WhitespaceBeforePunctuation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E211") => Rule::WhitespaceBeforeParameters,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E221") => Rule::MultipleSpacesBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E222") => Rule::MultipleSpacesAfterOperator,
|
||||
|
|
@ -37,6 +39,16 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
|||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E224") => Rule::TabAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E225") => Rule::MissingWhitespaceAroundOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E226") => Rule::MissingWhitespaceAroundArithmeticOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E227") => Rule::MissingWhitespaceAroundBitwiseOrShiftOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E228") => Rule::MissingWhitespaceAroundModuloOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E231") => Rule::MissingWhitespace,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E251") => Rule::UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E252") => Rule::MissingWhitespaceAroundParameterEquals,
|
||||
|
|
@ -501,6 +513,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
|||
(Flake8Pyi, "011") => Rule::TypedArgumentSimpleDefaults,
|
||||
(Flake8Pyi, "014") => Rule::ArgumentSimpleDefaults,
|
||||
(Flake8Pyi, "021") => Rule::DocstringInStub,
|
||||
(Flake8Pyi, "033") => Rule::TypeCommentInStub,
|
||||
|
||||
// flake8-pytest-style
|
||||
(Flake8PytestStyle, "001") => Rule::IncorrectFixtureParenthesesStyle,
|
||||
|
|
|
|||
|
|
@ -1,70 +1,36 @@
|
|||
//! Abstractions for Google-style docstrings.
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashSet;
|
||||
use crate::docstrings::sections::SectionKind;
|
||||
|
||||
pub(crate) static GOOGLE_SECTION_NAMES: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||
FxHashSet::from_iter([
|
||||
"Args",
|
||||
"Arguments",
|
||||
"Attention",
|
||||
"Attributes",
|
||||
"Caution",
|
||||
"Danger",
|
||||
"Error",
|
||||
"Example",
|
||||
"Examples",
|
||||
"Hint",
|
||||
"Important",
|
||||
"Keyword Args",
|
||||
"Keyword Arguments",
|
||||
"Methods",
|
||||
"Note",
|
||||
"Notes",
|
||||
"Return",
|
||||
"Returns",
|
||||
"Raises",
|
||||
"References",
|
||||
"See Also",
|
||||
"Tip",
|
||||
"Todo",
|
||||
"Warning",
|
||||
"Warnings",
|
||||
"Warns",
|
||||
"Yield",
|
||||
"Yields",
|
||||
])
|
||||
});
|
||||
|
||||
pub(crate) static LOWERCASE_GOOGLE_SECTION_NAMES: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||
FxHashSet::from_iter([
|
||||
"args",
|
||||
"arguments",
|
||||
"attention",
|
||||
"attributes",
|
||||
"caution",
|
||||
"danger",
|
||||
"error",
|
||||
"example",
|
||||
"examples",
|
||||
"hint",
|
||||
"important",
|
||||
"keyword args",
|
||||
"keyword arguments",
|
||||
"methods",
|
||||
"note",
|
||||
"notes",
|
||||
"return",
|
||||
"returns",
|
||||
"raises",
|
||||
"references",
|
||||
"see also",
|
||||
"tip",
|
||||
"todo",
|
||||
"warning",
|
||||
"warnings",
|
||||
"warns",
|
||||
"yield",
|
||||
"yields",
|
||||
])
|
||||
});
|
||||
pub(crate) static GOOGLE_SECTIONS: &[SectionKind] = &[
|
||||
SectionKind::Attributes,
|
||||
SectionKind::Examples,
|
||||
SectionKind::Methods,
|
||||
SectionKind::Notes,
|
||||
SectionKind::Raises,
|
||||
SectionKind::References,
|
||||
SectionKind::Returns,
|
||||
SectionKind::SeeAlso,
|
||||
SectionKind::Yields,
|
||||
// Google-only
|
||||
SectionKind::Args,
|
||||
SectionKind::Arguments,
|
||||
SectionKind::Attention,
|
||||
SectionKind::Caution,
|
||||
SectionKind::Danger,
|
||||
SectionKind::Error,
|
||||
SectionKind::Example,
|
||||
SectionKind::Hint,
|
||||
SectionKind::Important,
|
||||
SectionKind::KeywordArgs,
|
||||
SectionKind::KeywordArguments,
|
||||
SectionKind::Note,
|
||||
SectionKind::Notes,
|
||||
SectionKind::Return,
|
||||
SectionKind::Tip,
|
||||
SectionKind::Todo,
|
||||
SectionKind::Warning,
|
||||
SectionKind::Warnings,
|
||||
SectionKind::Warns,
|
||||
SectionKind::Yield,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,40 +1,20 @@
|
|||
//! Abstractions for NumPy-style docstrings.
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashSet;
|
||||
use crate::docstrings::sections::SectionKind;
|
||||
|
||||
pub(crate) static LOWERCASE_NUMPY_SECTION_NAMES: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||
FxHashSet::from_iter([
|
||||
"short summary",
|
||||
"extended summary",
|
||||
"parameters",
|
||||
"returns",
|
||||
"yields",
|
||||
"other parameters",
|
||||
"raises",
|
||||
"see also",
|
||||
"notes",
|
||||
"references",
|
||||
"examples",
|
||||
"attributes",
|
||||
"methods",
|
||||
])
|
||||
});
|
||||
|
||||
pub(crate) static NUMPY_SECTION_NAMES: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||
FxHashSet::from_iter([
|
||||
"Short Summary",
|
||||
"Extended Summary",
|
||||
"Parameters",
|
||||
"Returns",
|
||||
"Yields",
|
||||
"Other Parameters",
|
||||
"Raises",
|
||||
"See Also",
|
||||
"Notes",
|
||||
"References",
|
||||
"Examples",
|
||||
"Attributes",
|
||||
"Methods",
|
||||
])
|
||||
});
|
||||
pub(crate) static NUMPY_SECTIONS: &[SectionKind] = &[
|
||||
SectionKind::Attributes,
|
||||
SectionKind::Examples,
|
||||
SectionKind::Methods,
|
||||
SectionKind::Notes,
|
||||
SectionKind::Raises,
|
||||
SectionKind::References,
|
||||
SectionKind::Returns,
|
||||
SectionKind::SeeAlso,
|
||||
SectionKind::Yields,
|
||||
// NumPy-only
|
||||
SectionKind::ExtendedSummary,
|
||||
SectionKind::OtherParameters,
|
||||
SectionKind::Parameters,
|
||||
SectionKind::ShortSummary,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,8 +1,126 @@
|
|||
use strum_macros::EnumIter;
|
||||
|
||||
use crate::ast::whitespace;
|
||||
use crate::docstrings::styles::SectionStyle;
|
||||
|
||||
#[derive(EnumIter, PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum SectionKind {
|
||||
Args,
|
||||
Arguments,
|
||||
Attention,
|
||||
Attributes,
|
||||
Caution,
|
||||
Danger,
|
||||
Error,
|
||||
Example,
|
||||
Examples,
|
||||
ExtendedSummary,
|
||||
Hint,
|
||||
Important,
|
||||
KeywordArgs,
|
||||
KeywordArguments,
|
||||
Methods,
|
||||
Note,
|
||||
Notes,
|
||||
OtherParameters,
|
||||
Parameters,
|
||||
Raises,
|
||||
References,
|
||||
Return,
|
||||
Returns,
|
||||
SeeAlso,
|
||||
ShortSummary,
|
||||
Tip,
|
||||
Todo,
|
||||
Warning,
|
||||
Warnings,
|
||||
Warns,
|
||||
Yield,
|
||||
Yields,
|
||||
}
|
||||
|
||||
impl SectionKind {
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
match s.to_ascii_lowercase().as_str() {
|
||||
"args" => Some(Self::Args),
|
||||
"arguments" => Some(Self::Arguments),
|
||||
"attention" => Some(Self::Attention),
|
||||
"attributes" => Some(Self::Attributes),
|
||||
"caution" => Some(Self::Caution),
|
||||
"danger" => Some(Self::Danger),
|
||||
"error" => Some(Self::Error),
|
||||
"example" => Some(Self::Example),
|
||||
"examples" => Some(Self::Examples),
|
||||
"extended summary" => Some(Self::ExtendedSummary),
|
||||
"hint" => Some(Self::Hint),
|
||||
"important" => Some(Self::Important),
|
||||
"keyword args" => Some(Self::KeywordArgs),
|
||||
"keyword arguments" => Some(Self::KeywordArguments),
|
||||
"methods" => Some(Self::Methods),
|
||||
"note" => Some(Self::Note),
|
||||
"notes" => Some(Self::Notes),
|
||||
"other parameters" => Some(Self::OtherParameters),
|
||||
"parameters" => Some(Self::Parameters),
|
||||
"raises" => Some(Self::Raises),
|
||||
"references" => Some(Self::References),
|
||||
"return" => Some(Self::Return),
|
||||
"returns" => Some(Self::Returns),
|
||||
"see also" => Some(Self::SeeAlso),
|
||||
"short summary" => Some(Self::ShortSummary),
|
||||
"tip" => Some(Self::Tip),
|
||||
"todo" => Some(Self::Todo),
|
||||
"warning" => Some(Self::Warning),
|
||||
"warnings" => Some(Self::Warnings),
|
||||
"warns" => Some(Self::Warns),
|
||||
"yield" => Some(Self::Yield),
|
||||
"yields" => Some(Self::Yields),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Args => "Args",
|
||||
Self::Arguments => "Arguments",
|
||||
Self::Attention => "Attention",
|
||||
Self::Attributes => "Attributes",
|
||||
Self::Caution => "Caution",
|
||||
Self::Danger => "Danger",
|
||||
Self::Error => "Error",
|
||||
Self::Example => "Example",
|
||||
Self::Examples => "Examples",
|
||||
Self::ExtendedSummary => "Extended Summary",
|
||||
Self::Hint => "Hint",
|
||||
Self::Important => "Important",
|
||||
Self::KeywordArgs => "Keyword Args",
|
||||
Self::KeywordArguments => "Keyword Arguments",
|
||||
Self::Methods => "Methods",
|
||||
Self::Note => "Note",
|
||||
Self::Notes => "Notes",
|
||||
Self::OtherParameters => "Other Parameters",
|
||||
Self::Parameters => "Parameters",
|
||||
Self::Raises => "Raises",
|
||||
Self::References => "References",
|
||||
Self::Return => "Return",
|
||||
Self::Returns => "Returns",
|
||||
Self::SeeAlso => "See Also",
|
||||
Self::ShortSummary => "Short Summary",
|
||||
Self::Tip => "Tip",
|
||||
Self::Todo => "Todo",
|
||||
Self::Warning => "Warning",
|
||||
Self::Warnings => "Warnings",
|
||||
Self::Warns => "Warns",
|
||||
Self::Yield => "Yield",
|
||||
Self::Yields => "Yields",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SectionContext<'a> {
|
||||
/// The "kind" of the section, e.g. "SectionKind::Args" or "SectionKind::Returns".
|
||||
pub(crate) kind: SectionKind,
|
||||
/// The name of the section as it appears in the docstring, e.g. "Args" or "Returns".
|
||||
pub(crate) section_name: &'a str,
|
||||
pub(crate) previous_line: &'a str,
|
||||
pub(crate) line: &'a str,
|
||||
|
|
@ -11,10 +129,13 @@ pub(crate) struct SectionContext<'a> {
|
|||
pub(crate) original_index: usize,
|
||||
}
|
||||
|
||||
fn suspected_as_section(line: &str, style: &SectionStyle) -> bool {
|
||||
style
|
||||
.lowercase_section_names()
|
||||
.contains(&whitespace::leading_words(line).to_lowercase().as_str())
|
||||
fn suspected_as_section(line: &str, style: &SectionStyle) -> Option<SectionKind> {
|
||||
if let Some(kind) = SectionKind::from_str(whitespace::leading_words(line)) {
|
||||
if style.sections().contains(&kind) {
|
||||
return Some(kind);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Check if the suspected context is really a section header.
|
||||
|
|
@ -49,21 +170,15 @@ pub(crate) fn section_contexts<'a>(
|
|||
lines: &'a [&'a str],
|
||||
style: &SectionStyle,
|
||||
) -> Vec<SectionContext<'a>> {
|
||||
let suspected_section_indices: Vec<usize> = lines
|
||||
let mut contexts = vec![];
|
||||
for (kind, lineno) in lines
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(lineno, line)| {
|
||||
if lineno > 0 && suspected_as_section(line, style) {
|
||||
Some(lineno)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut contexts = vec![];
|
||||
for lineno in suspected_section_indices {
|
||||
.skip(1)
|
||||
.filter_map(|(lineno, line)| suspected_as_section(line, style).map(|kind| (kind, lineno)))
|
||||
{
|
||||
let context = SectionContext {
|
||||
kind,
|
||||
section_name: whitespace::leading_words(lines[lineno]),
|
||||
previous_line: lines[lineno - 1],
|
||||
line: lines[lineno],
|
||||
|
|
@ -76,11 +191,12 @@ pub(crate) fn section_contexts<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let mut truncated_contexts = vec![];
|
||||
let mut truncated_contexts = Vec::with_capacity(contexts.len());
|
||||
let mut end: Option<usize> = None;
|
||||
for context in contexts.into_iter().rev() {
|
||||
let next_end = context.original_index;
|
||||
truncated_contexts.push(SectionContext {
|
||||
kind: context.kind,
|
||||
section_name: context.section_name,
|
||||
previous_line: context.previous_line,
|
||||
line: context.line,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::docstrings::google::{GOOGLE_SECTION_NAMES, LOWERCASE_GOOGLE_SECTION_NAMES};
|
||||
use crate::docstrings::numpy::{LOWERCASE_NUMPY_SECTION_NAMES, NUMPY_SECTION_NAMES};
|
||||
use crate::docstrings::google::GOOGLE_SECTIONS;
|
||||
use crate::docstrings::numpy::NUMPY_SECTIONS;
|
||||
use crate::docstrings::sections::SectionKind;
|
||||
|
||||
pub(crate) enum SectionStyle {
|
||||
Numpy,
|
||||
|
|
@ -10,17 +8,10 @@ pub(crate) enum SectionStyle {
|
|||
}
|
||||
|
||||
impl SectionStyle {
|
||||
pub(crate) fn section_names(&self) -> &Lazy<FxHashSet<&'static str>> {
|
||||
pub(crate) fn sections(&self) -> &[SectionKind] {
|
||||
match self {
|
||||
SectionStyle::Numpy => &NUMPY_SECTION_NAMES,
|
||||
SectionStyle::Google => &GOOGLE_SECTION_NAMES,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lowercase_section_names(&self) -> &Lazy<FxHashSet<&'static str>> {
|
||||
match self {
|
||||
SectionStyle::Numpy => &LOWERCASE_NUMPY_SECTION_NAMES,
|
||||
SectionStyle::Google => &LOWERCASE_GOOGLE_SECTION_NAMES,
|
||||
SectionStyle::Numpy => NUMPY_SECTIONS,
|
||||
SectionStyle::Google => GOOGLE_SECTIONS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -577,6 +577,7 @@ mod tests {
|
|||
pydocstyle: Some(pydocstyle::settings::Options {
|
||||
convention: Some(Convention::Numpy),
|
||||
ignore_decorators: None,
|
||||
property_decorators: None,
|
||||
}),
|
||||
..default_options([Linter::Pydocstyle.into()])
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use globset::GlobMatcher;
|
||||
use log::debug;
|
||||
use path_absolutize::{path_dedot, Absolutize};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::hashable::{HashableGlobMatcher, HashableHashSet};
|
||||
|
||||
/// Extract the absolute path and basename (as strings) from a Path.
|
||||
pub fn extract_path_names(path: &Path) -> Result<(&str, &str)> {
|
||||
|
|
@ -25,11 +24,7 @@ pub fn extract_path_names(path: &Path) -> Result<(&str, &str)> {
|
|||
/// Create a set with codes matching the pattern/code pairs.
|
||||
pub(crate) fn ignores_from_path<'a>(
|
||||
path: &Path,
|
||||
pattern_code_pairs: &'a [(
|
||||
HashableGlobMatcher,
|
||||
HashableGlobMatcher,
|
||||
HashableHashSet<Rule>,
|
||||
)],
|
||||
pattern_code_pairs: &'a [(GlobMatcher, GlobMatcher, FxHashSet<Rule>)],
|
||||
) -> FxHashSet<&'a Rule> {
|
||||
let (file_path, file_basename) = extract_path_names(path).expect("Unable to parse filename");
|
||||
pattern_code_pairs
|
||||
|
|
@ -39,8 +34,8 @@ pub(crate) fn ignores_from_path<'a>(
|
|||
debug!(
|
||||
"Adding per-file ignores for {:?} due to basename match on {:?}: {:?}",
|
||||
path,
|
||||
basename.deref().glob().regex(),
|
||||
&**codes
|
||||
basename.glob().regex(),
|
||||
codes
|
||||
);
|
||||
return Some(codes.iter());
|
||||
}
|
||||
|
|
@ -48,8 +43,8 @@ pub(crate) fn ignores_from_path<'a>(
|
|||
debug!(
|
||||
"Adding per-file ignores for {:?} due to absolute match on {:?}: {:?}",
|
||||
path,
|
||||
absolute.deref().glob().regex(),
|
||||
&**codes
|
||||
absolute.glob().regex(),
|
||||
codes
|
||||
);
|
||||
return Some(codes.iter());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ pub use violation::{AutofixKind, Availability as AutofixAvailability};
|
|||
|
||||
mod ast;
|
||||
mod autofix;
|
||||
pub mod cache;
|
||||
mod checkers;
|
||||
mod codes;
|
||||
mod cst;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use crate::doc_lines::{doc_lines_from_ast, doc_lines_from_tokens};
|
|||
use crate::message::{Message, Source};
|
||||
use crate::noqa::{add_noqa, rule_is_ignored};
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::resolver::is_interface_definition_path;
|
||||
use crate::rules::pycodestyle;
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::{Indexer, Locator, Stylist};
|
||||
|
|
@ -83,7 +84,14 @@ pub fn check_path(
|
|||
.iter_enabled()
|
||||
.any(|rule_code| rule_code.lint_source().is_tokens())
|
||||
{
|
||||
diagnostics.extend(check_tokens(locator, &tokens, settings, autofix));
|
||||
let is_interface_definition = is_interface_definition_path(path);
|
||||
diagnostics.extend(check_tokens(
|
||||
locator,
|
||||
&tokens,
|
||||
settings,
|
||||
autofix,
|
||||
is_interface_definition,
|
||||
));
|
||||
}
|
||||
|
||||
// Run the filesystem-based rules.
|
||||
|
|
@ -101,7 +109,13 @@ pub fn check_path(
|
|||
.iter_enabled()
|
||||
.any(|rule_code| rule_code.lint_source().is_logical_lines())
|
||||
{
|
||||
diagnostics.extend(check_logical_lines(&tokens, locator, stylist, settings));
|
||||
diagnostics.extend(check_logical_lines(
|
||||
&tokens,
|
||||
locator,
|
||||
stylist,
|
||||
settings,
|
||||
flags::Autofix::Enabled,
|
||||
));
|
||||
}
|
||||
|
||||
// Run the AST-based rules.
|
||||
|
|
|
|||
|
|
@ -53,16 +53,28 @@ ruff_macros::register_rules!(
|
|||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MultipleSpacesAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MissingWhitespace,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MultipleSpacesBeforeKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundArithmeticOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundBitwiseOrShiftOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundModuloOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::TabAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::WhitespaceBeforeParameters,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
rules::pycodestyle::rules::TabBeforeKeyword,
|
||||
rules::pycodestyle::rules::MultipleImportsOnOneLine,
|
||||
rules::pycodestyle::rules::ModuleImportNotAtTopOfFile,
|
||||
|
|
@ -475,6 +487,7 @@ ruff_macros::register_rules!(
|
|||
rules::flake8_pyi::rules::DocstringInStub,
|
||||
rules::flake8_pyi::rules::TypedArgumentSimpleDefaults,
|
||||
rules::flake8_pyi::rules::ArgumentSimpleDefaults,
|
||||
rules::flake8_pyi::rules::TypeCommentInStub,
|
||||
// flake8-pytest-style
|
||||
rules::flake8_pytest_style::rules::IncorrectFixtureParenthesesStyle,
|
||||
rules::flake8_pytest_style::rules::FixturePositionalArgs,
|
||||
|
|
@ -828,19 +841,26 @@ impl Rule {
|
|||
| Rule::MultipleStatementsOnOneLineColon
|
||||
| Rule::UselessSemicolon
|
||||
| Rule::MultipleStatementsOnOneLineSemicolon
|
||||
| Rule::TrailingCommaProhibited => &LintSource::Tokens,
|
||||
| Rule::TrailingCommaProhibited
|
||||
| Rule::TypeCommentInStub => &LintSource::Tokens,
|
||||
Rule::IOError => &LintSource::Io,
|
||||
Rule::UnsortedImports | Rule::MissingRequiredImport => &LintSource::Imports,
|
||||
Rule::ImplicitNamespacePackage | Rule::InvalidModuleName => &LintSource::Filesystem,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
Rule::IndentationWithInvalidMultiple
|
||||
| Rule::IndentationWithInvalidMultipleComment
|
||||
| Rule::MissingWhitespace
|
||||
| Rule::MissingWhitespaceAfterKeyword
|
||||
| Rule::MissingWhitespaceAroundArithmeticOperator
|
||||
| Rule::MissingWhitespaceAroundBitwiseOrShiftOperator
|
||||
| Rule::MissingWhitespaceAroundModuloOperator
|
||||
| Rule::MissingWhitespaceAroundOperator
|
||||
| Rule::MissingWhitespaceAroundParameterEquals
|
||||
| Rule::MultipleLeadingHashesForBlockComment
|
||||
| Rule::MultipleSpacesAfterKeyword
|
||||
| Rule::MultipleSpacesAfterOperator
|
||||
| Rule::MultipleSpacesBeforeKeyword
|
||||
| Rule::MultipleSpacesBeforeOperator
|
||||
| Rule::MissingWhitespaceAfterKeyword
|
||||
| Rule::NoIndentedBlock
|
||||
| Rule::NoIndentedBlockComment
|
||||
| Rule::NoSpaceAfterBlockComment
|
||||
|
|
@ -853,10 +873,10 @@ impl Rule {
|
|||
| Rule::TooFewSpacesBeforeInlineComment
|
||||
| Rule::UnexpectedIndentation
|
||||
| Rule::UnexpectedIndentationComment
|
||||
| Rule::UnexpectedSpacesAroundKeywordParameterEquals
|
||||
| Rule::WhitespaceAfterOpenBracket
|
||||
| Rule::WhitespaceBeforeCloseBracket
|
||||
| Rule::UnexpectedSpacesAroundKeywordParameterEquals
|
||||
| Rule::MissingWhitespaceAroundParameterEquals
|
||||
| Rule::WhitespaceBeforeParameters
|
||||
| Rule::WhitespaceBeforePunctuation => &LintSource::LogicalLines,
|
||||
_ => &LintSource::Ast,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ impl Violation for SysVersionSlice1Referenced {
|
|||
|
||||
fn is_sys(checker: &Checker, expr: &Expr, target: &str) -> bool {
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["sys", target])
|
||||
}
|
||||
|
|
@ -306,6 +307,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
|||
/// YTT202
|
||||
pub fn name_or_attribute(checker: &mut Checker, expr: &Expr) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["six", "PY3"])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ pub fn overloaded_name(checker: &Checker, definition: &Definition) -> Option<Str
|
|||
| DefinitionKind::NestedFunction(stmt)
|
||||
| DefinitionKind::Method(stmt) = definition.kind
|
||||
{
|
||||
if visibility::is_overload(checker, cast::decorator_list(stmt)) {
|
||||
if visibility::is_overload(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
let (name, ..) = match_function_def(stmt);
|
||||
Some(name.to_string())
|
||||
} else {
|
||||
|
|
@ -51,7 +51,7 @@ pub fn is_overload_impl(checker: &Checker, definition: &Definition, overloaded_n
|
|||
| DefinitionKind::NestedFunction(stmt)
|
||||
| DefinitionKind::Method(stmt) = definition.kind
|
||||
{
|
||||
if visibility::is_overload(checker, cast::decorator_list(stmt)) {
|
||||
if visibility::is_overload(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
false
|
||||
} else {
|
||||
let (name, ..) = match_function_def(stmt);
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ fn check_dynamically_typed<F>(
|
|||
) where
|
||||
F: FnOnce() -> String,
|
||||
{
|
||||
if checker.match_typing_expr(annotation, "Any") {
|
||||
if checker.ctx.match_typing_expr(annotation, "Any") {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
AnyType { name: func() },
|
||||
Range::from_located(annotation),
|
||||
|
|
@ -482,7 +482,8 @@ pub fn definition(
|
|||
.skip(
|
||||
// If this is a non-static method, skip `cls` or `self`.
|
||||
usize::from(
|
||||
is_method && !visibility::is_staticmethod(checker, cast::decorator_list(stmt)),
|
||||
is_method
|
||||
&& !visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt)),
|
||||
),
|
||||
)
|
||||
{
|
||||
|
|
@ -580,10 +581,10 @@ pub fn definition(
|
|||
}
|
||||
|
||||
// ANN101, ANN102
|
||||
if is_method && !visibility::is_staticmethod(checker, cast::decorator_list(stmt)) {
|
||||
if is_method && !visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
||||
if arg.node.annotation.is_none() {
|
||||
if visibility::is_classmethod(checker, cast::decorator_list(stmt)) {
|
||||
if visibility::is_classmethod(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if checker.settings.rules.enabled(&Rule::MissingTypeCls) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeCls {
|
||||
|
|
@ -619,7 +620,7 @@ pub fn definition(
|
|||
// (explicitly or implicitly).
|
||||
checker.settings.flake8_annotations.suppress_none_returning && is_none_returning(body)
|
||||
) {
|
||||
if is_method && visibility::is_classmethod(checker, cast::decorator_list(stmt)) {
|
||||
if is_method && visibility::is_classmethod(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
|
|
@ -632,7 +633,8 @@ pub fn definition(
|
|||
helpers::identifier_range(stmt, checker.locator),
|
||||
));
|
||||
}
|
||||
} else if is_method && visibility::is_staticmethod(checker, cast::decorator_list(stmt))
|
||||
} else if is_method
|
||||
&& visibility::is_staticmethod(&checker.ctx, cast::decorator_list(stmt))
|
||||
{
|
||||
if checker
|
||||
.settings
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! Settings for the `flake-annotations` plugin.
|
||||
|
||||
use ruff_macros::CacheKey;
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
|
@ -60,7 +61,7 @@ pub struct Options {
|
|||
pub ignore_fully_untyped: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Hash)]
|
||||
#[derive(Debug, Default, CacheKey)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct Settings {
|
||||
pub mypy_init_return: bool,
|
||||
|
|
|
|||
|
|
@ -26,16 +26,22 @@ pub fn is_untyped_exception(type_: Option<&Expr>, checker: &Checker) -> bool {
|
|||
type_.map_or(true, |type_| {
|
||||
if let ExprKind::Tuple { elts, .. } = &type_.node {
|
||||
elts.iter().any(|type_| {
|
||||
checker.resolve_call_path(type_).map_or(false, |call_path| {
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(type_)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "Exception"]
|
||||
|| call_path.as_slice() == ["", "BaseException"]
|
||||
})
|
||||
})
|
||||
} else {
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(type_)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "Exception"]
|
||||
|| call_path.as_slice() == ["", "BaseException"]
|
||||
})
|
||||
})
|
||||
} else {
|
||||
checker.resolve_call_path(type_).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["", "Exception"]
|
||||
|| call_path.as_slice() == ["", "BaseException"]
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ pub fn bad_file_permissions(
|
|||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["os", "chmod"])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ fn unparse_string_format_expression(checker: &mut Checker, expr: &Expr) -> Optio
|
|||
op: Operator::Add | Operator::Mod,
|
||||
..
|
||||
} => {
|
||||
let Some(parent) = checker.current_expr_parent() else {
|
||||
let Some(parent) = checker.ctx.current_expr_parent() else {
|
||||
if any_over_expr(expr, &has_string_literal) {
|
||||
return Some(unparse_expr(expr, checker.stylist));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ pub fn hashlib_insecure_hash_functions(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if let Some(hashlib_call) = checker.resolve_call_path(func).and_then(|call_path| {
|
||||
if let Some(hashlib_call) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
|
||||
if call_path.as_slice() == ["hashlib", "new"] {
|
||||
Some(HashlibCall::New)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -37,9 +37,13 @@ pub fn jinja2_autoescape_false(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["jinja2", "Environment"]
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["jinja2", "Environment"]
|
||||
})
|
||||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
|
||||
if let Some(autoescape_arg) = call_args.get_argument("autoescape", None) {
|
||||
|
|
|
|||
|
|
@ -24,9 +24,13 @@ pub fn logging_config_insecure_listen(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["logging", "config", "listen"]
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["logging", "config", "listen"]
|
||||
})
|
||||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
|
||||
if call_args.get_argument("verify", None).is_none() {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ pub fn request_with_no_cert_validation(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if let Some(target) = checker.resolve_call_path(func).and_then(|call_path| {
|
||||
if let Some(target) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
|
||||
if call_path.len() == 2 {
|
||||
if call_path[0] == "requests" && REQUESTS_HTTP_VERBS.contains(&call_path[1]) {
|
||||
return Some("requests");
|
||||
|
|
|
|||
|
|
@ -34,11 +34,15 @@ pub fn request_without_timeout(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
HTTP_VERBS
|
||||
.iter()
|
||||
.any(|func_name| call_path.as_slice() == ["requests", func_name])
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
HTTP_VERBS
|
||||
.iter()
|
||||
.any(|func_name| call_path.as_slice() == ["requests", func_name])
|
||||
})
|
||||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
if let Some(timeout_arg) = call_args.get_argument("timeout", None) {
|
||||
if let Some(timeout) = match &timeout_arg.node {
|
||||
|
|
|
|||
|
|
@ -25,9 +25,13 @@ pub fn snmp_insecure_version(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pysnmp", "hlapi", "CommunityData"]
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pysnmp", "hlapi", "CommunityData"]
|
||||
})
|
||||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
if let Some(mp_model_arg) = call_args.get_argument("mpModel", None) {
|
||||
if let ExprKind::Constant {
|
||||
|
|
|
|||
|
|
@ -27,9 +27,13 @@ pub fn snmp_weak_cryptography(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pysnmp", "hlapi", "UsmUserData"]
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["pysnmp", "hlapi", "UsmUserData"]
|
||||
})
|
||||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
if call_args.len() < 3 {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
|
|
|||
|
|
@ -34,12 +34,14 @@ impl Violation for UnsafeYAMLLoad {
|
|||
/// S506
|
||||
pub fn unsafe_yaml_load(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["yaml", "load"])
|
||||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
if let Some(loader_arg) = call_args.get_argument("Loader", Some(1)) {
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(loader_arg)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["yaml", "SafeLoader"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Settings for the `flake8-bandit` plugin.
|
||||
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use ruff_macros::{CacheKey, ConfigurationOptions};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ pub struct Options {
|
|||
pub check_typed_exception: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash)]
|
||||
#[derive(Debug, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub hardcoded_tmp_directory: Vec<String>,
|
||||
pub check_typed_exception: bool,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ pub fn blind_except(
|
|||
return;
|
||||
};
|
||||
for exception in ["BaseException", "Exception"] {
|
||||
if id == exception && checker.is_builtin(exception) {
|
||||
if id == exception && checker.ctx.is_builtin(exception) {
|
||||
// If the exception is re-raised, don't flag an error.
|
||||
if body.iter().any(|stmt| {
|
||||
if let StmtKind::Raise { exc, .. } = &stmt.node {
|
||||
|
|
|
|||
|
|
@ -42,12 +42,14 @@ fn is_abc_class(checker: &Checker, bases: &[Expr], keywords: &[Keyword]) -> bool
|
|||
.as_ref()
|
||||
.map_or(false, |arg| arg == "metaclass")
|
||||
&& checker
|
||||
.ctx
|
||||
.resolve_call_path(&keyword.node.value)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["abc", "ABCMeta"]
|
||||
})
|
||||
}) || bases.iter().any(|base| {
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(base)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["abc", "ABC"])
|
||||
})
|
||||
|
|
@ -106,7 +108,7 @@ pub fn abstract_base_class(
|
|||
continue;
|
||||
};
|
||||
|
||||
let has_abstract_decorator = is_abstract(checker, decorator_list);
|
||||
let has_abstract_decorator = is_abstract(&checker.ctx, decorator_list);
|
||||
has_abstract_method |= has_abstract_decorator;
|
||||
|
||||
if !checker
|
||||
|
|
@ -117,7 +119,10 @@ pub fn abstract_base_class(
|
|||
continue;
|
||||
}
|
||||
|
||||
if !has_abstract_decorator && is_empty_body(body) && !is_overload(checker, decorator_list) {
|
||||
if !has_abstract_decorator
|
||||
&& is_empty_body(body)
|
||||
&& !is_overload(&checker.ctx, decorator_list)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
EmptyMethodWithoutAbstractDecorator {
|
||||
name: format!("{name}.{method_name}"),
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ pub fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: &[With
|
|||
return;
|
||||
}
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(args.first().unwrap())
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["", "Exception"])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,15 +19,18 @@ impl Violation for CachedInstanceMethod {
|
|||
}
|
||||
|
||||
fn is_cache_func(checker: &Checker, expr: &Expr) -> bool {
|
||||
checker.resolve_call_path(expr).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["functools", "lru_cache"]
|
||||
|| call_path.as_slice() == ["functools", "cache"]
|
||||
})
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["functools", "lru_cache"]
|
||||
|| call_path.as_slice() == ["functools", "cache"]
|
||||
})
|
||||
}
|
||||
|
||||
/// B019
|
||||
pub fn cached_instance_method(checker: &mut Checker, decorator_list: &[Expr]) {
|
||||
if !matches!(checker.current_scope().kind, ScopeKind::Class(_)) {
|
||||
if !matches!(checker.ctx.current_scope().kind, ScopeKind::Class(_)) {
|
||||
return;
|
||||
}
|
||||
for decorator in decorator_list {
|
||||
|
|
|
|||
|
|
@ -38,14 +38,17 @@ const IMMUTABLE_FUNCS: &[&[&str]] = &[
|
|||
];
|
||||
|
||||
fn is_immutable_func(checker: &Checker, func: &Expr, extend_immutable_calls: &[CallPath]) -> bool {
|
||||
checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
IMMUTABLE_FUNCS
|
||||
.iter()
|
||||
.any(|target| call_path.as_slice() == *target)
|
||||
|| extend_immutable_calls
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
IMMUTABLE_FUNCS
|
||||
.iter()
|
||||
.any(|target| call_path == *target)
|
||||
})
|
||||
.any(|target| call_path.as_slice() == *target)
|
||||
|| extend_immutable_calls
|
||||
.iter()
|
||||
.any(|target| call_path == *target)
|
||||
})
|
||||
}
|
||||
|
||||
struct ArgumentDefaultVisitor<'a> {
|
||||
|
|
|
|||
|
|
@ -67,11 +67,14 @@ const IMMUTABLE_GENERIC_TYPES: &[&[&str]] = &[
|
|||
];
|
||||
|
||||
pub fn is_mutable_func(checker: &Checker, func: &Expr) -> bool {
|
||||
checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
MUTABLE_FUNCS
|
||||
.iter()
|
||||
.any(|target| call_path.as_slice() == *target)
|
||||
})
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
MUTABLE_FUNCS
|
||||
.iter()
|
||||
.any(|target| call_path.as_slice() == *target)
|
||||
})
|
||||
}
|
||||
|
||||
fn is_mutable_expr(checker: &Checker, expr: &Expr) -> bool {
|
||||
|
|
@ -89,40 +92,44 @@ fn is_mutable_expr(checker: &Checker, expr: &Expr) -> bool {
|
|||
|
||||
fn is_immutable_annotation(checker: &Checker, expr: &Expr) -> bool {
|
||||
match &expr.node {
|
||||
ExprKind::Name { .. } | ExprKind::Attribute { .. } => {
|
||||
checker.resolve_call_path(expr).map_or(false, |call_path| {
|
||||
ExprKind::Name { .. } | ExprKind::Attribute { .. } => checker
|
||||
.ctx
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| {
|
||||
IMMUTABLE_TYPES
|
||||
.iter()
|
||||
.chain(IMMUTABLE_GENERIC_TYPES)
|
||||
.any(|target| call_path.as_slice() == *target)
|
||||
})
|
||||
}
|
||||
}),
|
||||
ExprKind::Subscript { value, slice, .. } => {
|
||||
checker.resolve_call_path(value).map_or(false, |call_path| {
|
||||
if IMMUTABLE_GENERIC_TYPES
|
||||
.iter()
|
||||
.any(|target| call_path.as_slice() == *target)
|
||||
{
|
||||
true
|
||||
} else if call_path.as_slice() == ["typing", "Union"] {
|
||||
if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.iter().all(|elt| is_immutable_annotation(checker, elt))
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(value)
|
||||
.map_or(false, |call_path| {
|
||||
if IMMUTABLE_GENERIC_TYPES
|
||||
.iter()
|
||||
.any(|target| call_path.as_slice() == *target)
|
||||
{
|
||||
true
|
||||
} else if call_path.as_slice() == ["typing", "Union"] {
|
||||
if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.iter().all(|elt| is_immutable_annotation(checker, elt))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if call_path.as_slice() == ["typing", "Optional"] {
|
||||
is_immutable_annotation(checker, slice)
|
||||
} else if call_path.as_slice() == ["typing", "Annotated"] {
|
||||
if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.first()
|
||||
.map_or(false, |elt| is_immutable_annotation(checker, elt))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if call_path.as_slice() == ["typing", "Optional"] {
|
||||
is_immutable_annotation(checker, slice)
|
||||
} else if call_path.as_slice() == ["typing", "Annotated"] {
|
||||
if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.first()
|
||||
.map_or(false, |elt| is_immutable_annotation(checker, elt))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
ExprKind::BinOp {
|
||||
left,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,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_stmt().node {
|
||||
if let StmtKind::Expr { value: child } = &checker.ctx.current_stmt().node {
|
||||
if expr == child.as_ref() {
|
||||
let mut diagnostic = Diagnostic::new(SetAttrWithConstant, Range::from_located(expr));
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ pub fn unused_loop_control_variable(
|
|||
}
|
||||
|
||||
// Avoid fixing any variables that _may_ be used, but undetectably so.
|
||||
let certainty = Certainty::from(!helpers::uses_magic_variable_access(checker, body));
|
||||
let certainty = Certainty::from(!helpers::uses_magic_variable_access(&checker.ctx, body));
|
||||
|
||||
// Attempt to rename the variable by prepending an underscore, but avoid
|
||||
// applying the fix if doing so wouldn't actually cause us to ignore the
|
||||
|
|
@ -163,14 +163,14 @@ pub fn unused_loop_control_variable(
|
|||
if let Some(rename) = rename {
|
||||
if certainty.into() && checker.patch(diagnostic.kind.rule()) {
|
||||
// Find the `BindingKind::LoopVar` corresponding to the name.
|
||||
let scope = checker.current_scope();
|
||||
let scope = checker.ctx.current_scope();
|
||||
let binding = scope
|
||||
.bindings
|
||||
.get(name)
|
||||
.into_iter()
|
||||
.chain(scope.rebounds.get(name).into_iter().flatten())
|
||||
.find_map(|index| {
|
||||
let binding = &checker.bindings[*index];
|
||||
let binding = &checker.ctx.bindings[*index];
|
||||
binding
|
||||
.source
|
||||
.as_ref()
|
||||
|
|
|
|||
|
|
@ -22,9 +22,12 @@ impl Violation for UselessContextlibSuppress {
|
|||
/// B022
|
||||
pub fn useless_contextlib_suppress(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
|
||||
if args.is_empty()
|
||||
&& checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["contextlib", "suppress"]
|
||||
})
|
||||
&& checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["contextlib", "suppress"]
|
||||
})
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UselessContextlibSuppress,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub fn zip_without_explicit_strict(
|
|||
) {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if id == "zip"
|
||||
&& checker.is_builtin("zip")
|
||||
&& checker.ctx.is_builtin("zip")
|
||||
&& !kwargs.iter().any(|keyword| {
|
||||
keyword
|
||||
.node
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Settings for the `flake8-bugbear` plugin.
|
||||
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use ruff_macros::{CacheKey, ConfigurationOptions};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ pub struct Options {
|
|||
pub extend_immutable_calls: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Hash)]
|
||||
#[derive(Debug, Default, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub extend_immutable_calls: Vec<String>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Settings for the `flake8-builtins` plugin.
|
||||
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use ruff_macros::{CacheKey, ConfigurationOptions};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ pub struct Options {
|
|||
pub builtins_ignorelist: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Hash)]
|
||||
#[derive(Debug, Default, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub builtins_ignorelist: Vec<String>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ pub fn unnecessary_call_around_sorted(
|
|||
if inner != "sorted" {
|
||||
return;
|
||||
}
|
||||
if !checker.is_builtin(inner) || !checker.is_builtin(outer) {
|
||||
if !checker.ctx.is_builtin(inner) || !checker.ctx.is_builtin(outer) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ pub fn unnecessary_collection_call(
|
|||
}
|
||||
_ => return,
|
||||
};
|
||||
if !checker.is_builtin(id) {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ pub fn unnecessary_comprehension(
|
|||
ExprKind::SetComp { .. } => "set",
|
||||
_ => return,
|
||||
};
|
||||
if !checker.is_builtin(id) {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ pub fn unnecessary_double_cast_or_process(
|
|||
let Some(inner) = helpers::function_name(func) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin(inner) || !checker.is_builtin(outer) {
|
||||
if !checker.ctx.is_builtin(inner) || !checker.ctx.is_builtin(outer) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ pub fn unnecessary_generator_list(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("list", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("list") {
|
||||
if !checker.ctx.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::GeneratorExp { .. } = argument {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub fn unnecessary_generator_set(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("set") {
|
||||
if !checker.ctx.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::GeneratorExp { .. } = argument {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ pub fn unnecessary_list_call(checker: &mut Checker, expr: &Expr, func: &Expr, ar
|
|||
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("list") {
|
||||
if !checker.ctx.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
if !matches!(argument, ExprKind::ListComp { .. }) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ pub fn unnecessary_list_comprehension_dict(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("dict") {
|
||||
if !checker.ctx.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let ExprKind::ListComp { elt, .. } = &argument else {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ pub fn unnecessary_list_comprehension_set(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("set") {
|
||||
if !checker.ctx.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::ListComp { .. } = &argument {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ pub fn unnecessary_literal_dict(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("dict", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("dict") {
|
||||
if !checker.ctx.is_builtin("dict") {
|
||||
return;
|
||||
}
|
||||
let (kind, elts) = match argument {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ pub fn unnecessary_literal_set(
|
|||
let Some(argument) = helpers::exactly_one_argument_with_matching_function("set", func, args, keywords) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("set") {
|
||||
if !checker.ctx.is_builtin("set") {
|
||||
return;
|
||||
}
|
||||
let kind = match argument {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ pub fn unnecessary_literal_within_list_call(
|
|||
let Some(argument) = helpers::first_argument_with_matching_function("list", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("list") {
|
||||
if !checker.ctx.is_builtin("list") {
|
||||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub fn unnecessary_literal_within_tuple_call(
|
|||
let Some(argument) = helpers::first_argument_with_matching_function("tuple", func, args) else {
|
||||
return;
|
||||
};
|
||||
if !checker.is_builtin("tuple") {
|
||||
if !checker.ctx.is_builtin("tuple") {
|
||||
return;
|
||||
}
|
||||
let argument_kind = match argument {
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ pub fn unnecessary_map(
|
|||
};
|
||||
match id {
|
||||
"map" => {
|
||||
if !checker.is_builtin(id) {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ pub fn unnecessary_map(
|
|||
}
|
||||
}
|
||||
"list" | "set" => {
|
||||
if !checker.is_builtin(id) {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ pub fn unnecessary_map(
|
|||
}
|
||||
}
|
||||
"dict" => {
|
||||
if !checker.is_builtin(id) {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ pub fn unnecessary_subscript_reversal(
|
|||
if !(id == "set" || id == "sorted" || id == "reversed") {
|
||||
return;
|
||||
}
|
||||
if !checker.is_builtin(id) {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
let ExprKind::Subscript { slice, .. } = &first_arg.node else {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Settings for the `flake8-comprehensions` plugin.
|
||||
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use ruff_macros::{CacheKey, ConfigurationOptions};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ pub struct Options {
|
|||
pub allow_dict_calls_with_keyword_arguments: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Hash)]
|
||||
#[derive(Debug, Default, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub allow_dict_calls_with_keyword_arguments: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,9 +124,13 @@ pub fn call_datetime_without_tzinfo(
|
|||
keywords: &[Keyword],
|
||||
location: Range,
|
||||
) {
|
||||
if !checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime"]
|
||||
}) {
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime"]
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -153,9 +157,13 @@ pub fn call_datetime_without_tzinfo(
|
|||
/// It uses the system local timezone.
|
||||
/// Use `datetime.datetime.now(tz=)` instead.
|
||||
pub fn call_datetime_today(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "today"]
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "today"]
|
||||
})
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(CallDatetimeToday, location));
|
||||
|
|
@ -171,9 +179,13 @@ pub fn call_datetime_today(checker: &mut Checker, func: &Expr, location: Range)
|
|||
/// UTC. As such, the recommended way to create an object representing the
|
||||
/// current time in UTC is by calling `datetime.now(timezone.utc)`.
|
||||
pub fn call_datetime_utcnow(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "utcnow"]
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "utcnow"]
|
||||
})
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(CallDatetimeUtcnow, location));
|
||||
|
|
@ -190,9 +202,13 @@ pub fn call_datetime_utcnow(checker: &mut Checker, func: &Expr, location: Range)
|
|||
/// specific timestamp in UTC is by calling `datetime.fromtimestamp(timestamp,
|
||||
/// tz=timezone.utc)`.
|
||||
pub fn call_datetime_utcfromtimestamp(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "utcfromtimestamp"]
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "utcfromtimestamp"]
|
||||
})
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(CallDatetimeUtcfromtimestamp, location));
|
||||
|
|
@ -207,9 +223,13 @@ pub fn call_datetime_now_without_tzinfo(
|
|||
keywords: &[Keyword],
|
||||
location: Range,
|
||||
) {
|
||||
if !checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "now"]
|
||||
}) {
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "now"]
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -245,9 +265,13 @@ pub fn call_datetime_fromtimestamp(
|
|||
keywords: &[Keyword],
|
||||
location: Range,
|
||||
) {
|
||||
if !checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "fromtimestamp"]
|
||||
}) {
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "fromtimestamp"]
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -282,9 +306,13 @@ pub fn call_datetime_strptime_without_zone(
|
|||
args: &[Expr],
|
||||
location: Range,
|
||||
) {
|
||||
if !checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "strptime"]
|
||||
}) {
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "datetime", "strptime"]
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -299,7 +327,7 @@ pub fn call_datetime_strptime_without_zone(
|
|||
}
|
||||
};
|
||||
|
||||
let (Some(grandparent), Some(parent)) = (checker.current_expr_grandparent(), checker.current_expr_parent()) else {
|
||||
let (Some(grandparent), Some(parent)) = (checker.ctx.current_expr_grandparent(), checker.ctx.current_expr_parent()) else {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
CallDatetimeStrptimeWithoutZone,
|
||||
location,
|
||||
|
|
@ -335,9 +363,13 @@ pub fn call_datetime_strptime_without_zone(
|
|||
/// It uses the system local timezone.
|
||||
/// Use `datetime.datetime.now(tz=).date()` instead.
|
||||
pub fn call_date_today(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "date", "today"]
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "date", "today"]
|
||||
})
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(CallDateToday, location));
|
||||
|
|
@ -351,9 +383,13 @@ pub fn call_date_today(checker: &mut Checker, func: &Expr, location: Range) {
|
|||
/// It uses the system local timezone.
|
||||
/// Use `datetime.datetime.fromtimestamp(, tz=).date()` instead.
|
||||
pub fn call_date_fromtimestamp(checker: &mut Checker, func: &Expr, location: Range) {
|
||||
if checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "date", "fromtimestamp"]
|
||||
}) {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["datetime", "date", "fromtimestamp"]
|
||||
})
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(CallDateFromtimestamp, location));
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const DEBUGGERS: &[&[&str]] = &[
|
|||
|
||||
/// Checks for the presence of a debugger call.
|
||||
pub fn debugger_call(checker: &mut Checker, expr: &Expr, func: &Expr) {
|
||||
if let Some(target) = checker.resolve_call_path(func).and_then(|call_path| {
|
||||
if let Some(target) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
|
||||
DEBUGGERS
|
||||
.iter()
|
||||
.find(|target| call_path.as_slice() == **target)
|
||||
|
|
|
|||
|
|
@ -4,22 +4,28 @@ use crate::checkers::ast::Checker;
|
|||
|
||||
/// Return `true` if a Python class appears to be a Django model, based on its base classes.
|
||||
pub fn is_model(checker: &Checker, base: &Expr) -> bool {
|
||||
checker.resolve_call_path(base).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "db", "models", "Model"]
|
||||
})
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(base)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "db", "models", "Model"]
|
||||
})
|
||||
}
|
||||
|
||||
/// Return `true` if a Python class appears to be a Django model form, based on its base classes.
|
||||
pub fn is_model_form(checker: &Checker, base: &Expr) -> bool {
|
||||
checker.resolve_call_path(base).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "forms", "ModelForm"]
|
||||
|| call_path.as_slice() == ["django", "forms", "models", "ModelForm"]
|
||||
})
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(base)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "forms", "ModelForm"]
|
||||
|| call_path.as_slice() == ["django", "forms", "models", "ModelForm"]
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the name of the field type, if the expression is constructor for a Django model field.
|
||||
pub fn get_model_field_name<'a>(checker: &'a Checker, expr: &'a Expr) -> Option<&'a str> {
|
||||
checker.resolve_call_path(expr).and_then(|call_path| {
|
||||
checker.ctx.resolve_call_path(expr).and_then(|call_path| {
|
||||
let call_path = call_path.as_slice();
|
||||
if !call_path.starts_with(&["django", "db", "models"]) {
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -46,9 +46,13 @@ pub fn locals_in_render_function(
|
|||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if !checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "shortcuts", "render"]
|
||||
}) {
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "shortcuts", "render"]
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -83,6 +87,7 @@ fn is_locals_call(checker: &Checker, expr: &Expr) -> bool {
|
|||
return false
|
||||
};
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["", "locals"])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Settings for the `flake8-errmsg` plugin.
|
||||
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use ruff_macros::{CacheKey, ConfigurationOptions};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ pub struct Options {
|
|||
pub max_string_length: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Hash)]
|
||||
#[derive(Debug, Default, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub max_string_length: usize,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Settings for the `flake8-implicit-str-concat` plugin.
|
||||
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use ruff_macros::{CacheKey, ConfigurationOptions};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ pub struct Options {
|
|||
pub allow_multiline: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash)]
|
||||
#[derive(Debug, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub allow_multiline: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,10 @@
|
|||
//! Settings for import conventions.
|
||||
|
||||
use std::hash::Hash;
|
||||
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use ruff_macros::{CacheKey, ConfigurationOptions};
|
||||
use rustc_hash::FxHashMap;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::settings::hashable::HashableHashMap;
|
||||
|
||||
const CONVENTIONAL_ALIASES: &[(&str, &str)] = &[
|
||||
("altair", "alt"),
|
||||
("matplotlib", "mpl"),
|
||||
|
|
@ -64,9 +60,9 @@ pub struct Options {
|
|||
pub extend_aliases: Option<FxHashMap<String, String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash)]
|
||||
#[derive(Debug, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub aliases: HashableHashMap<String, String>,
|
||||
pub aliases: FxHashMap<String, String>,
|
||||
}
|
||||
|
||||
fn default_aliases() -> FxHashMap<String, String> {
|
||||
|
|
@ -90,7 +86,7 @@ fn resolve_aliases(options: Options) -> FxHashMap<String, String> {
|
|||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
aliases: default_aliases().into(),
|
||||
aliases: default_aliases(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +94,7 @@ impl Default for Settings {
|
|||
impl From<Options> for Settings {
|
||||
fn from(options: Options) -> Self {
|
||||
Self {
|
||||
aliases: resolve_aliases(options).into(),
|
||||
aliases: resolve_aliases(options),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -106,7 +102,7 @@ impl From<Options> for Settings {
|
|||
impl From<Settings> for Options {
|
||||
fn from(settings: Settings) -> Self {
|
||||
Self {
|
||||
aliases: Some(settings.aliases.into()),
|
||||
aliases: Some(settings.aliases),
|
||||
extend_aliases: None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ fn check_log_record_attr_clash(checker: &mut Checker, extra: &Keyword) {
|
|||
}
|
||||
ExprKind::Call { func, keywords, .. } => {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["", "dict"])
|
||||
{
|
||||
|
|
@ -180,7 +181,7 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
|
|||
.rules
|
||||
.enabled(&Rule::LoggingRedundantExcInfo)
|
||||
{
|
||||
if !checker.in_exception_handler() {
|
||||
if !checker.ctx.in_exception_handler() {
|
||||
return;
|
||||
}
|
||||
if let Some(exc_info) = find_keyword(keywords, "exc_info") {
|
||||
|
|
@ -193,9 +194,12 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
|
|||
..
|
||||
}
|
||||
) || if let ExprKind::Call { func, .. } = &exc_info.node.value.node {
|
||||
checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["sys", "exc_info"]
|
||||
})
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["sys", "exc_info"]
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}) {
|
||||
|
|
|
|||
|
|
@ -242,11 +242,7 @@ pub fn dupe_class_field_definitions<'a, 'b>(
|
|||
Range::from_located(stmt),
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
let deleted: Vec<&Stmt> = checker
|
||||
.deletions
|
||||
.iter()
|
||||
.map(std::convert::Into::into)
|
||||
.collect();
|
||||
let deleted: Vec<&Stmt> = checker.deletions.iter().map(Into::into).collect();
|
||||
let locator = checker.locator;
|
||||
match delete_stmt(
|
||||
stmt,
|
||||
|
|
@ -281,6 +277,7 @@ where
|
|||
|
||||
if !bases.iter().any(|expr| {
|
||||
checker
|
||||
.ctx
|
||||
.resolve_call_path(expr)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["enum", "Enum"])
|
||||
}) {
|
||||
|
|
@ -295,6 +292,7 @@ where
|
|||
|
||||
if let ExprKind::Call { func, .. } = &value.node {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["enum", "auto"])
|
||||
{
|
||||
|
|
@ -337,7 +335,7 @@ pub fn unnecessary_comprehension_any_all(
|
|||
) {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if (id == "all" || id == "any") && args.len() == 1 {
|
||||
if !checker.is_builtin(id) {
|
||||
if !checker.ctx.is_builtin(id) {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::ListComp { .. } = args[0].node {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ impl Violation for PPrintFound {
|
|||
/// T201, T203
|
||||
pub fn print_call(checker: &mut Checker, func: &Expr, keywords: &[Keyword]) {
|
||||
let diagnostic = {
|
||||
let call_path = checker.resolve_call_path(func);
|
||||
let call_path = checker.ctx.resolve_call_path(func);
|
||||
if call_path
|
||||
.as_ref()
|
||||
.map_or(false, |call_path| *call_path.as_slice() == ["", "print"])
|
||||
|
|
@ -43,13 +43,13 @@ pub fn print_call(checker: &mut Checker, func: &Expr, keywords: &[Keyword]) {
|
|||
.find(|keyword| keyword.node.arg.as_ref().map_or(false, |arg| arg == "file"))
|
||||
{
|
||||
if !is_const_none(&keyword.node.value) {
|
||||
if checker
|
||||
.resolve_call_path(&keyword.node.value)
|
||||
.map_or(true, |call_path| {
|
||||
if checker.ctx.resolve_call_path(&keyword.node.value).map_or(
|
||||
true,
|
||||
|call_path| {
|
||||
call_path.as_slice() != ["sys", "stdout"]
|
||||
&& call_path.as_slice() != ["sys", "stderr"]
|
||||
})
|
||||
{
|
||||
},
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ mod tests {
|
|||
#[test_case(Rule::ArgumentSimpleDefaults, Path::new("PYI014.pyi"))]
|
||||
#[test_case(Rule::DocstringInStub, Path::new("PYI021.py"))]
|
||||
#[test_case(Rule::DocstringInStub, Path::new("PYI021.pyi"))]
|
||||
#[test_case(Rule::TypeCommentInStub, Path::new("PYI033.py"))]
|
||||
#[test_case(Rule::TypeCommentInStub, Path::new("PYI033.pyi"))]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
|
|
|||
|
|
@ -70,9 +70,13 @@ pub fn bad_version_info_comparison(
|
|||
return;
|
||||
};
|
||||
|
||||
if !checker.resolve_call_path(left).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["sys", "version_info"]
|
||||
}) {
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(left)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["sys", "version_info"]
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub use simple_defaults::{
|
|||
argument_simple_defaults, typed_argument_simple_defaults, ArgumentSimpleDefaults,
|
||||
TypedArgumentSimpleDefaults,
|
||||
};
|
||||
pub use type_comment_in_stub::{type_comment_in_stub, TypeCommentInStub};
|
||||
pub use unrecognized_platform::{
|
||||
unrecognized_platform, UnrecognizedPlatformCheck, UnrecognizedPlatformName,
|
||||
};
|
||||
|
|
@ -17,4 +18,5 @@ mod non_empty_stub_body;
|
|||
mod pass_statement_stub_body;
|
||||
mod prefix_type_params;
|
||||
mod simple_defaults;
|
||||
mod type_comment_in_stub;
|
||||
mod unrecognized_platform;
|
||||
|
|
|
|||
|
|
@ -71,12 +71,12 @@ pub fn prefix_type_params(checker: &mut Checker, value: &Expr, targets: &[Expr])
|
|||
};
|
||||
|
||||
if let ExprKind::Call { func, .. } = &value.node {
|
||||
let Some(kind) = checker.resolve_call_path(func).and_then(|call_path| {
|
||||
if checker.match_typing_call_path(&call_path, "ParamSpec") {
|
||||
let Some(kind) = checker.ctx.resolve_call_path(func).and_then(|call_path| {
|
||||
if checker.ctx.match_typing_call_path(&call_path, "ParamSpec") {
|
||||
Some(VarKind::ParamSpec)
|
||||
} else if checker.match_typing_call_path(&call_path, "TypeVar") {
|
||||
} else if checker.ctx.match_typing_call_path(&call_path, "TypeVar") {
|
||||
Some(VarKind::TypeVar)
|
||||
} else if checker.match_typing_call_path(&call_path, "TypeVarTuple") {
|
||||
} else if checker.ctx.match_typing_call_path(&call_path, "TypeVarTuple") {
|
||||
Some(VarKind::TypeVarTuple)
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ fn is_valid_default_value_with_annotation(default: &Expr, checker: &Checker) ->
|
|||
// `sys.stdin`, etc.
|
||||
ExprKind::Attribute { .. } => {
|
||||
if checker
|
||||
.ctx
|
||||
.resolve_call_path(default)
|
||||
.map_or(false, |call_path| {
|
||||
ALLOWED_ATTRIBUTES_IN_DEFAULTS
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::Tok;
|
||||
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
use crate::Range;
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for the use of type comments (e.g., `x = 1 # type: int`) in stub
|
||||
/// files.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Stub (`.pyi`) files should use type annotations directly, rather
|
||||
/// than type comments, even if they're intended to support Python 2, since
|
||||
/// stub files are not executed at runtime. The one exception is `# type: ignore`.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// x = 1 # type: int
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// x: int = 1
|
||||
/// ```
|
||||
pub struct TypeCommentInStub;
|
||||
);
|
||||
impl Violation for TypeCommentInStub {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Don't use type comments in stub file")
|
||||
}
|
||||
}
|
||||
|
||||
static TYPE_COMMENT_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^#\s*type:\s*([^#]+)(\s*#.*?)?$").unwrap());
|
||||
static TYPE_IGNORE_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^#\s*type:\s*ignore([^#]+)?(\s*#.*?)?$").unwrap());
|
||||
|
||||
/// PYI033
|
||||
pub fn type_comment_in_stub(tokens: &[LexResult]) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
for token in tokens.iter().flatten() {
|
||||
if let (location, Tok::Comment(comment), end_location) = token {
|
||||
if TYPE_COMMENT_REGEX.is_match(comment) && !TYPE_IGNORE_REGEX.is_match(comment) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
TypeCommentInStub,
|
||||
Range {
|
||||
location: *location,
|
||||
end_location: *end_location,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
|
@ -103,9 +103,13 @@ pub fn unrecognized_platform(
|
|||
|
||||
let diagnostic_unrecognized_platform_check =
|
||||
Diagnostic::new(UnrecognizedPlatformCheck, Range::from_located(expr));
|
||||
if !checker.resolve_call_path(left).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["sys", "platform"]
|
||||
}) {
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(left)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["sys", "platform"]
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pyi/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
---
|
||||
source: crates/ruff/src/rules/flake8_pyi/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 6
|
||||
column: 21
|
||||
end_location:
|
||||
row: 6
|
||||
column: 127
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 7
|
||||
column: 21
|
||||
end_location:
|
||||
row: 7
|
||||
column: 183
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 8
|
||||
column: 21
|
||||
end_location:
|
||||
row: 8
|
||||
column: 126
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 9
|
||||
column: 21
|
||||
end_location:
|
||||
row: 9
|
||||
column: 132
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 10
|
||||
column: 19
|
||||
end_location:
|
||||
row: 10
|
||||
column: 128
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 11
|
||||
column: 19
|
||||
end_location:
|
||||
row: 11
|
||||
column: 123
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 14
|
||||
column: 11
|
||||
end_location:
|
||||
row: 14
|
||||
column: 128
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 15
|
||||
column: 10
|
||||
end_location:
|
||||
row: 15
|
||||
column: 172
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 19
|
||||
column: 28
|
||||
end_location:
|
||||
row: 19
|
||||
column: 139
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 29
|
||||
column: 21
|
||||
end_location:
|
||||
row: 29
|
||||
column: 44
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
TypeCommentInStub: ~
|
||||
location:
|
||||
row: 32
|
||||
column: 25
|
||||
end_location:
|
||||
row: 32
|
||||
column: 55
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue