Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b4aedb366 | ||
|
|
8123e3e94e | ||
|
|
9f9a545c51 | ||
|
|
5bf8219db3 | ||
|
|
529513bf02 | ||
|
|
124782771f | ||
|
|
98cab5cdba | ||
|
|
40f38c94a5 | ||
|
|
7839204bf7 | ||
|
|
e63ea704f0 | ||
|
|
4be09b45ea | ||
|
|
13e8ed0a0a | ||
|
|
4161d4ae32 | ||
|
|
99f7854d8c | ||
|
|
a580d1a858 | ||
|
|
86806a9e39 |
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.128
|
||||
rev: v0.0.131
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
633
Cargo.lock
generated
633
Cargo.lock
generated
@@ -94,133 +94,6 @@ dependencies = [
|
||||
"wait-timeout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-global-executor"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8121296a9f05be7f34aa4196b1747243b3b62e048bb7906f644f3fbfc490cf7"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"autocfg",
|
||||
"concurrent-queue",
|
||||
"futures-lite",
|
||||
"libc",
|
||||
"log",
|
||||
"parking",
|
||||
"polling",
|
||||
"slab",
|
||||
"socket2",
|
||||
"waker-fn",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02111fd8655a613c25069ea89fc8d9bb89331fa77486eb3bc059ee757cfa481c"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"autocfg",
|
||||
"blocking",
|
||||
"cfg-if 1.0.0",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"signal-hook",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-global-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-process",
|
||||
"crossbeam-utils",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"gloo-timers",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
@@ -238,15 +111,6 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
@@ -283,50 +147,6 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"byte-tools",
|
||||
"byteorder",
|
||||
"generic-array 0.12.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
|
||||
dependencies = [
|
||||
"byte-tools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-task",
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "0.2.17"
|
||||
@@ -357,46 +177,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.3.1"
|
||||
name = "cachedir"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cacache"
|
||||
version = "10.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c13caedf5b624de6448b78e980320a27266557350198dc67cf64bc8561c27e8"
|
||||
checksum = "e236bf5873ea57ec2877445297f4da008916bfae51567131acfc54a073d694f3"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"digest 0.9.0",
|
||||
"either",
|
||||
"futures",
|
||||
"hex 0.4.3",
|
||||
"memmap2",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sha-1 0.9.8",
|
||||
"sha2 0.9.9",
|
||||
"ssri",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cache-padded"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
@@ -582,15 +370,6 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101"
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "1.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
|
||||
dependencies = [
|
||||
"cache-padded",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "configparser"
|
||||
version = "3.0.2"
|
||||
@@ -616,15 +395,6 @@ version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
@@ -719,16 +489,6 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.81"
|
||||
@@ -785,24 +545,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
dependencies = [
|
||||
"generic-array 0.12.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||
dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "directories"
|
||||
version = "4.0.1"
|
||||
@@ -890,18 +632,6 @@ version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
@@ -940,7 +670,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.128-dev.0"
|
||||
version = "0.0.131-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
@@ -1014,129 +744,6 @@ version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
@@ -1167,18 +774,6 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.2"
|
||||
@@ -1209,18 +804,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hexf-parse"
|
||||
version = "0.2.1"
|
||||
@@ -1363,15 +946,6 @@ dependencies = [
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kv-log-macro"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop"
|
||||
version = "0.19.8"
|
||||
@@ -1508,7 +1082,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1532,15 +1105,6 @@ version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
@@ -1727,30 +1291,12 @@ version = "11.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
@@ -1923,18 +1469,6 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.4"
|
||||
@@ -1963,20 +1497,6 @@ dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"log",
|
||||
"wepoll-ffi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
@@ -2248,7 +1768,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.128"
|
||||
version = "0.0.131"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -2256,7 +1776,7 @@ dependencies = [
|
||||
"atty",
|
||||
"bincode",
|
||||
"bitflags",
|
||||
"cacache",
|
||||
"cachedir",
|
||||
"chrono",
|
||||
"clap 4.0.22",
|
||||
"clearscreen",
|
||||
@@ -2298,7 +1818,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.128"
|
||||
version = "0.0.131"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
@@ -2479,75 +1999,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
|
||||
dependencies = [
|
||||
"block-buffer 0.7.3",
|
||||
"digest 0.8.1",
|
||||
"fake-simd",
|
||||
"opaque-debug 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
|
||||
dependencies = [
|
||||
"block-buffer 0.7.3",
|
||||
"digest 0.8.1",
|
||||
"fake-simd",
|
||||
"opaque-debug 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.2.0"
|
||||
@@ -2581,37 +2032,12 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "ssri"
|
||||
version = "7.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9cec0d388f39fbe79d7aa600e8d38053bf97b1bc8d350da7c0ba800d0f423f2"
|
||||
dependencies = [
|
||||
"base64 0.10.1",
|
||||
"digest 0.8.1",
|
||||
"hex 0.3.2",
|
||||
"serde",
|
||||
"sha-1 0.8.2",
|
||||
"sha2 0.8.2",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
@@ -2856,12 +2282,6 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||
|
||||
[[package]]
|
||||
name = "unic-char-property"
|
||||
version = "0.9.0"
|
||||
@@ -3000,7 +2420,7 @@ version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f"
|
||||
dependencies = [
|
||||
"base64 0.13.1",
|
||||
"base64",
|
||||
"chunked_transfer",
|
||||
"flate2",
|
||||
"log",
|
||||
@@ -3024,16 +2444,6 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.0.0-alpha.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55"
|
||||
dependencies = [
|
||||
"ctor",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
@@ -3055,12 +2465,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
@@ -3109,18 +2513,6 @@ dependencies = [
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.83"
|
||||
@@ -3179,15 +2571,6 @@ dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wepoll-ffi"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.3.0"
|
||||
|
||||
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.128"
|
||||
version = "0.0.131"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
@@ -18,6 +18,7 @@ anyhow = { version = "1.0.66" }
|
||||
atty = { version = "0.2.14" }
|
||||
bincode = { version = "1.3.3" }
|
||||
bitflags = { version = "1.3.2" }
|
||||
cachedir = { version = "0.3.0" }
|
||||
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
colored = { version = "2.0.0" }
|
||||
@@ -52,7 +53,6 @@ update-informer = { version = "0.5.0", default-features = false, features = ["py
|
||||
walkdir = { version = "2.3.2" }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
cacache = { version = "10.0.1" } # uses async-std
|
||||
clearscreen = { version = "1.0.10" } # uses which
|
||||
|
||||
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
|
||||
|
||||
@@ -380,7 +380,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI
|
||||
| E714 | NotIsTest | Test for object identity should be `is not` | 🛠 |
|
||||
| E721 | TypeComparison | Do not compare types, use `isinstance()` | |
|
||||
| E722 | DoNotUseBareExcept | Do not use bare `except` | |
|
||||
| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | |
|
||||
| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | 🛠 |
|
||||
| E741 | AmbiguousVariableName | Ambiguous variable name: `...` | |
|
||||
| E742 | AmbiguousClassName | Ambiguous class name: `...` | |
|
||||
| E743 | AmbiguousFunctionName | Ambiguous function name: `...` | |
|
||||
@@ -466,6 +466,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
|
||||
| U011 | UnnecessaryLRUCacheParams | Unnecessary parameters to `functools.lru_cache` | 🛠 |
|
||||
| U012 | UnnecessaryEncodeUTF8 | Unnecessary call to `encode` as UTF-8 | 🛠 |
|
||||
| U013 | ConvertTypedDictFunctionalToClass | Convert `TypedDict` functional syntax to class syntax | 🛠 |
|
||||
| U014 | ConvertNamedTupleFunctionalToClass | Convert `NamedTuple` functional syntax to class syntax | 🛠 |
|
||||
|
||||
### pep8-naming
|
||||
|
||||
@@ -549,7 +550,7 @@ For more, see [flake8-bugbear](https://pypi.org/project/flake8-bugbear/22.10.27/
|
||||
| B007 | UnusedLoopControlVariable | Loop control variable `i` not used within the loop body | 🛠 |
|
||||
| B008 | FunctionCallArgumentDefault | Do not perform function call in argument defaults | |
|
||||
| B009 | GetAttrWithConstant | Do not call `getattr` with a constant attribute value. It is not any safer than normal property access. | 🛠 |
|
||||
| B010 | SetAttrWithConstant | Do not call `setattr` with a constant attribute value. It is not any safer than normal property access. | |
|
||||
| B010 | SetAttrWithConstant | Do not call `setattr` with a constant attribute value. It is not any safer than normal property access. | 🛠 |
|
||||
| B011 | DoNotAssertFalse | Do not `assert False` (`python -O` removes these calls), raise `AssertionError()` | 🛠 |
|
||||
| B012 | JumpStatementInFinally | `return/continue/break` inside finally blocks cause exceptions to be silenced | |
|
||||
| B013 | RedundantTupleInExceptionHandler | A length-one tuple literal is redundant. Write `except ValueError` instead of `except (ValueError,)`. | |
|
||||
@@ -820,7 +821,7 @@ including:
|
||||
- [`flake8-boolean-trap`](https://pypi.org/project/flake8-boolean-trap/)
|
||||
- [`mccabe`](https://pypi.org/project/mccabe/)
|
||||
- [`isort`](https://pypi.org/project/isort/)
|
||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (14/33)
|
||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (15/33)
|
||||
- [`autoflake`](https://pypi.org/project/autoflake/) (1/7)
|
||||
|
||||
Beyond rule-set parity, Ruff suffers from the following limitations vis-à-vis Flake8:
|
||||
@@ -852,7 +853,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
- [`mccabe`](https://pypi.org/project/mccabe/)
|
||||
|
||||
Ruff can also replace [`isort`](https://pypi.org/project/isort/), [`yesqa`](https://github.com/asottile/yesqa),
|
||||
and a subset of the rules implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (14/33).
|
||||
and a subset of the rules implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (15/33).
|
||||
|
||||
If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, free to file an Issue.
|
||||
|
||||
|
||||
4
flake8_to_ruff/Cargo.lock
generated
4
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.128"
|
||||
version = "0.0.131"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.128"
|
||||
version = "0.0.131"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.128-dev.0"
|
||||
version = "0.0.131-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
20
resources/test/fixtures/B006_B008.py
vendored
20
resources/test/fixtures/B006_B008.py
vendored
@@ -185,3 +185,23 @@ def nested_b008(a=random.randint(0, dt.datetime.now().year)):
|
||||
# Ignore lambda contents since they are evaluated at call time.
|
||||
def foo(f=lambda x: print(x)):
|
||||
f(1)
|
||||
|
||||
|
||||
from collections import abc
|
||||
from typing import Annotated, Dict, Optional, Sequence, Union, Set
|
||||
|
||||
|
||||
def immutable_annotations(
|
||||
a: Sequence[int] | None = [],
|
||||
b: Optional[abc.Mapping[int, int]] = {},
|
||||
c: Annotated[Union[abc.Set[str], abc.Sized], "annotation"] = set(),
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
def mutable_annotations(
|
||||
a: list[int] | None = [],
|
||||
b: Optional[Dict[int, int]] = {},
|
||||
c: Annotated[Union[Set[str], abc.Sized], "annotation"] = set(),
|
||||
):
|
||||
pass
|
||||
|
||||
1
resources/test/fixtures/B009_B010.py
vendored
1
resources/test/fixtures/B009_B010.py
vendored
@@ -34,3 +34,4 @@ setattr(foo, "bar", None)
|
||||
setattr(foo, "_123abc", None)
|
||||
setattr(foo, "abc123", None)
|
||||
setattr(foo, r"abc123", None)
|
||||
setattr(foo.bar, r"baz", None)
|
||||
|
||||
17
resources/test/fixtures/F841.py
vendored
17
resources/test/fixtures/F841.py
vendored
@@ -35,3 +35,20 @@ def f4():
|
||||
_ = 1
|
||||
__ = 1
|
||||
_discarded = 1
|
||||
|
||||
|
||||
a = 1
|
||||
|
||||
|
||||
def f5():
|
||||
global a
|
||||
|
||||
# Used in `f7` via `nonlocal`.
|
||||
b = 1
|
||||
|
||||
def f6():
|
||||
# F841
|
||||
b = 1
|
||||
|
||||
def f7():
|
||||
nonlocal b
|
||||
|
||||
8
resources/test/fixtures/M001.py
vendored
8
resources/test/fixtures/M001.py
vendored
@@ -18,6 +18,14 @@ def f() -> None:
|
||||
# Invalid (and unimplemented)
|
||||
d = 1 # noqa: F841, W191
|
||||
|
||||
# fmt: off
|
||||
# Invalid - no space before #
|
||||
d = 1# noqa: E501
|
||||
|
||||
# Invalid - many spaces before #
|
||||
d = 1 # noqa: E501
|
||||
# fmt: on
|
||||
|
||||
|
||||
# Valid
|
||||
_ = """Lorem ipsum dolor sit amet.
|
||||
|
||||
4
resources/test/fixtures/U013.py
vendored
4
resources/test/fixtures/U013.py
vendored
@@ -1,4 +1,5 @@
|
||||
from typing import TypedDict, NotRequired, Literal
|
||||
import typing
|
||||
|
||||
# dict literal
|
||||
MyType1 = TypedDict("MyType1", {"a": int, "b": str})
|
||||
@@ -27,3 +28,6 @@ MyType9 = TypedDict("MyType9", {"in": int, "x-y": int})
|
||||
|
||||
# using Literal type
|
||||
MyType10 = TypedDict("MyType10", {"key": Literal["value"]})
|
||||
|
||||
# using namespace TypedDict
|
||||
MyType11 = typing.TypedDict("MyType11", {"key": int})
|
||||
|
||||
22
resources/test/fixtures/U014.py
vendored
Normal file
22
resources/test/fixtures/U014.py
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
from typing import NamedTuple
|
||||
import typing
|
||||
|
||||
# with complex annotations
|
||||
NT1 = NamedTuple("NT1", [("a", int), ("b", tuple[str, ...])])
|
||||
|
||||
# with default values as list
|
||||
NT2 = NamedTuple(
|
||||
"NT2",
|
||||
[("a", int), ("b", str), ("c", list[bool])],
|
||||
defaults=["foo", [True]],
|
||||
)
|
||||
|
||||
# with namespace
|
||||
NT3 = typing.NamedTuple("NT3", [("a", int), ("b", str)])
|
||||
|
||||
# with too many default values
|
||||
NT4 = NamedTuple(
|
||||
"NT4",
|
||||
[("a", int), ("b", str)],
|
||||
defaults=[1, "bar", "baz"],
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.128"
|
||||
version = "0.0.131"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprKind, Location, StmtKind};
|
||||
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprKind, Location, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::SourceCodeLocator;
|
||||
|
||||
#[inline(always)]
|
||||
fn collect_call_path_inner<'a>(expr: &'a Expr, parts: &mut Vec<&'a str>) {
|
||||
@@ -261,6 +264,34 @@ pub fn to_absolute(relative: &Location, base: &Location) -> Location {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if a `Stmt` has leading content.
|
||||
pub fn match_leading_content(stmt: &Stmt, locator: &SourceCodeLocator) -> bool {
|
||||
let range = Range {
|
||||
location: Location::new(stmt.location.row(), 0),
|
||||
end_location: stmt.location,
|
||||
};
|
||||
let prefix = locator.slice_source_code_range(&range);
|
||||
prefix.chars().any(|char| !char.is_whitespace())
|
||||
}
|
||||
|
||||
/// Return `true` if a `Stmt` has trailing content.
|
||||
pub fn match_trailing_content(stmt: &Stmt, locator: &SourceCodeLocator) -> bool {
|
||||
let range = Range {
|
||||
location: stmt.end_location.unwrap(),
|
||||
end_location: Location::new(stmt.end_location.unwrap().row() + 1, 0),
|
||||
};
|
||||
let suffix = locator.slice_source_code_range(&range);
|
||||
for char in suffix.chars() {
|
||||
if char == '#' {
|
||||
return false;
|
||||
}
|
||||
if !char.is_whitespace() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
|
||||
@@ -3,3 +3,4 @@ pub mod operations;
|
||||
pub mod relocate;
|
||||
pub mod types;
|
||||
pub mod visitor;
|
||||
pub mod whitespace;
|
||||
|
||||
@@ -19,9 +19,7 @@ impl Range {
|
||||
pub fn from_located<T>(located: &Located<T>) -> Self {
|
||||
Range {
|
||||
location: located.location,
|
||||
end_location: located
|
||||
.end_location
|
||||
.expect("AST nodes should have end_location."),
|
||||
end_location: located.end_location.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,6 +81,7 @@ pub enum BindingKind {
|
||||
Binding,
|
||||
LoopVar,
|
||||
Global,
|
||||
Nonlocal,
|
||||
Builtin,
|
||||
ClassDefinition,
|
||||
Definition,
|
||||
|
||||
@@ -3,12 +3,6 @@ use rustpython_ast::{Located, Location};
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
|
||||
pub const TRIPLE_QUOTE_PREFIXES: &[&str] = &[
|
||||
"ur\"\"\"", "ur'''", "u\"\"\"", "u'''", "r\"\"\"", "r'''", "\"\"\"", "'''",
|
||||
];
|
||||
|
||||
pub const SINGLE_QUOTE_PREFIXES: &[&str] = &["ur\"", "ur'", "u\"", "u'", "r\"", "r'", "\"", "'"];
|
||||
|
||||
/// Extract the leading words from a line of text.
|
||||
pub fn leading_words(line: &str) -> String {
|
||||
line.trim()
|
||||
88
src/cache.rs
88
src/cache.rs
@@ -1,19 +1,11 @@
|
||||
// cacache uses asyncd-std which has no wasm support, so currently no caching
|
||||
// support on wasm
|
||||
#![cfg_attr(
|
||||
target_family = "wasm",
|
||||
allow(unused_imports, unused_variables, dead_code)
|
||||
)]
|
||||
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::fs;
|
||||
use std::fs::{create_dir_all, File, Metadata};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use cacache::Error::EntryNotFound;
|
||||
use filetime::FileTime;
|
||||
use log::error;
|
||||
use path_absolutize::Absolutize;
|
||||
@@ -82,28 +74,59 @@ fn cache_dir() -> &'static str {
|
||||
"./.ruff_cache"
|
||||
}
|
||||
|
||||
fn cache_key(path: &Path, settings: &Settings, autofix: &fixer::Mode) -> String {
|
||||
fn content_dir() -> &'static str {
|
||||
"content"
|
||||
}
|
||||
|
||||
fn cache_key(path: &Path, settings: &Settings, autofix: &fixer::Mode) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
CARGO_PKG_VERSION.hash(&mut hasher);
|
||||
path.absolutize().unwrap().hash(&mut hasher);
|
||||
settings.hash(&mut hasher);
|
||||
autofix.hash(&mut hasher);
|
||||
format!(
|
||||
"{}@{}@{}",
|
||||
path.absolutize().unwrap().to_string_lossy(),
|
||||
CARGO_PKG_VERSION,
|
||||
hasher.finish()
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
/// Initialize the cache directory.
|
||||
pub fn init() -> Result<()> {
|
||||
let path = Path::new(cache_dir());
|
||||
|
||||
// Create the cache directories.
|
||||
create_dir_all(path.join(content_dir()))?;
|
||||
|
||||
// Add the CACHEDIR.TAG.
|
||||
if !cachedir::is_tagged(path)? {
|
||||
cachedir::add_tag(path)?;
|
||||
}
|
||||
|
||||
// Add the .gitignore.
|
||||
let gitignore_path = path.join(".gitignore");
|
||||
if !gitignore_path.exists() {
|
||||
let mut file = File::create(gitignore_path)?;
|
||||
file.write_all(b"*")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_sync(key: &u64, value: &[u8]) -> Result<(), std::io::Error> {
|
||||
fs::write(
|
||||
Path::new(cache_dir())
|
||||
.join(content_dir())
|
||||
.join(format!("{key:x}")),
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn init() -> Result<()> {
|
||||
let gitignore_path = Path::new(cache_dir()).join(".gitignore");
|
||||
if gitignore_path.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
create_dir_all(cache_dir())?;
|
||||
let mut file = File::create(gitignore_path)?;
|
||||
file.write_all(b"*").map_err(|e| e.into())
|
||||
fn read_sync(key: &u64) -> Result<Vec<u8>, std::io::Error> {
|
||||
fs::read(
|
||||
Path::new(cache_dir())
|
||||
.join(content_dir())
|
||||
.join(format!("{key:x}")),
|
||||
)
|
||||
}
|
||||
|
||||
/// Get a value from the cache.
|
||||
pub fn get(
|
||||
path: &Path,
|
||||
metadata: &Metadata,
|
||||
@@ -115,9 +138,8 @@ pub fn get(
|
||||
return None;
|
||||
};
|
||||
|
||||
#[cfg(not(target_family = "wasm"))] // cacache needs async-std which doesn't support wasm
|
||||
match cacache::read_sync(cache_dir(), cache_key(path, settings, autofix)) {
|
||||
Ok(encoded) => match bincode::deserialize::<CheckResult>(&encoded[..]) {
|
||||
if let Ok(encoded) = read_sync(&cache_key(path, settings, autofix)) {
|
||||
match bincode::deserialize::<CheckResult>(&encoded[..]) {
|
||||
Ok(CheckResult {
|
||||
metadata: CacheMetadata { mtime },
|
||||
messages,
|
||||
@@ -127,13 +149,12 @@ pub fn get(
|
||||
}
|
||||
}
|
||||
Err(e) => error!("Failed to deserialize encoded cache entry: {e:?}"),
|
||||
},
|
||||
Err(EntryNotFound(..)) => {}
|
||||
Err(e) => error!("Failed to read from cache: {e:?}"),
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Set a value in the cache.
|
||||
pub fn set(
|
||||
path: &Path,
|
||||
metadata: &Metadata,
|
||||
@@ -146,18 +167,15 @@ pub fn set(
|
||||
return;
|
||||
};
|
||||
|
||||
#[cfg(not(target_family = "wasm"))] // modification date not supported on wasm
|
||||
let check_result = CheckResultRef {
|
||||
metadata: &CacheMetadata {
|
||||
mtime: FileTime::from_last_modification_time(metadata).unix_seconds(),
|
||||
},
|
||||
messages,
|
||||
};
|
||||
#[cfg(not(target_family = "wasm"))] // cacache needs async-std which doesn't support wasm
|
||||
if let Err(e) = cacache::write_sync(
|
||||
cache_dir(),
|
||||
cache_key(path, settings, autofix),
|
||||
bincode::serialize(&check_result).unwrap(),
|
||||
if let Err(e) = write_sync(
|
||||
&cache_key(path, settings, autofix),
|
||||
&bincode::serialize(&check_result).unwrap(),
|
||||
) {
|
||||
error!("Failed to write to cache: {e:?}")
|
||||
}
|
||||
|
||||
@@ -213,21 +213,74 @@ where
|
||||
|
||||
// Pre-visit.
|
||||
match &stmt.node {
|
||||
StmtKind::Global { names } | StmtKind::Nonlocal { names } => {
|
||||
let global_scope_id = self.scopes[GLOBAL_SCOPE_INDEX].id;
|
||||
let scope =
|
||||
&mut self.scopes[*(self.scope_stack.last().expect("No current scope found."))];
|
||||
if scope.id != global_scope_id {
|
||||
StmtKind::Global { names } => {
|
||||
let scope_index = *self.scope_stack.last().expect("No current scope found.");
|
||||
if scope_index != GLOBAL_SCOPE_INDEX {
|
||||
let scope = &mut self.scopes[scope_index];
|
||||
let usage = Some((scope.id, Range::from_located(stmt)));
|
||||
for name in names {
|
||||
// Add a binding to the current scope.
|
||||
scope.values.insert(
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::Global,
|
||||
used: Some((global_scope_id, Range::from_located(stmt))),
|
||||
used: usage,
|
||||
range: Range::from_located(stmt),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Mark the binding in the global scope as used.
|
||||
for name in names {
|
||||
if let Some(mut existing) = self.scopes[GLOBAL_SCOPE_INDEX]
|
||||
.values
|
||||
.get_mut(&name.as_str())
|
||||
{
|
||||
existing.used = usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::E741) {
|
||||
let location = Range::from_located(stmt);
|
||||
self.add_checks(
|
||||
names
|
||||
.iter()
|
||||
.filter_map(|name| {
|
||||
pycodestyle::checks::ambiguous_variable_name(name, location)
|
||||
})
|
||||
.into_iter(),
|
||||
);
|
||||
}
|
||||
}
|
||||
StmtKind::Nonlocal { names } => {
|
||||
let scope_index = *self.scope_stack.last().expect("No current scope found.");
|
||||
if scope_index != GLOBAL_SCOPE_INDEX {
|
||||
let scope = &mut self.scopes[scope_index];
|
||||
let usage = Some((scope.id, Range::from_located(stmt)));
|
||||
for name in names {
|
||||
// Add a binding to the current scope.
|
||||
scope.values.insert(
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::Global,
|
||||
used: usage,
|
||||
range: Range::from_located(stmt),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Mark the binding in the defining scopes as used too. (Skip the global scope
|
||||
// and the current scope.)
|
||||
for name in names {
|
||||
for index in self.scope_stack.iter().skip(1).rev().skip(1) {
|
||||
if let Some(mut existing) =
|
||||
self.scopes[*index].values.get_mut(&name.as_str())
|
||||
{
|
||||
existing.used = usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::E741) {
|
||||
@@ -928,11 +981,7 @@ where
|
||||
StmtKind::Assign { targets, value, .. } => {
|
||||
if self.settings.enabled.contains(&CheckCode::E731) {
|
||||
if let [target] = &targets[..] {
|
||||
if let Some(check) =
|
||||
pycodestyle::checks::do_not_assign_lambda(target, value, stmt)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
pycodestyle::plugins::do_not_assign_lambda(self, target, value, stmt)
|
||||
}
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::U001) {
|
||||
@@ -953,15 +1002,16 @@ where
|
||||
self, stmt, targets, value,
|
||||
);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::U014) {
|
||||
pyupgrade::plugins::convert_named_tuple_functional_to_class(
|
||||
self, stmt, targets, value,
|
||||
);
|
||||
}
|
||||
}
|
||||
StmtKind::AnnAssign { target, value, .. } => {
|
||||
if self.settings.enabled.contains(&CheckCode::E731) {
|
||||
if let Some(value) = value {
|
||||
if let Some(check) =
|
||||
pycodestyle::checks::do_not_assign_lambda(target, value, stmt)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
pycodestyle::plugins::do_not_assign_lambda(self, target, value, stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ pub fn check_lines(
|
||||
matches.push(check.kind.code().as_ref());
|
||||
ignored.push(index)
|
||||
}
|
||||
(Directive::Codes(_, _, codes), matches) => {
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_ref()) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
ignored.push(index);
|
||||
@@ -133,7 +133,7 @@ pub fn check_lines(
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
}
|
||||
(Directive::Codes(_, _, codes), matches) => {
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_ref()) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
} else {
|
||||
@@ -170,7 +170,7 @@ pub fn check_lines(
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
}
|
||||
(Directive::Codes(_, _, codes), matches) => {
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_ref()) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
} else {
|
||||
@@ -186,7 +186,7 @@ pub fn check_lines(
|
||||
if enforce_noqa {
|
||||
for (row, (directive, matches)) in noqa_directives {
|
||||
match directive {
|
||||
Directive::All(start, end) => {
|
||||
Directive::All(spaces, start, end) => {
|
||||
if matches.is_empty() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnusedNOQA(None),
|
||||
@@ -197,14 +197,14 @@ pub fn check_lines(
|
||||
);
|
||||
if autofix.patch() && settings.fixable.contains(check.kind.code()) {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
}
|
||||
line_checks.push(check);
|
||||
}
|
||||
}
|
||||
Directive::Codes(start, end, codes) => {
|
||||
Directive::Codes(spaces, start, end, codes) => {
|
||||
let mut invalid_codes = vec![];
|
||||
let mut valid_codes = vec![];
|
||||
for code in codes {
|
||||
@@ -226,12 +226,12 @@ pub fn check_lines(
|
||||
if autofix.patch() && settings.fixable.contains(check.kind.code()) {
|
||||
if valid_codes.is_empty() {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
} else {
|
||||
check.amend(Fix::replacement(
|
||||
format!(" # noqa: {}", valid_codes.join(", ")),
|
||||
format!("# noqa: {}", valid_codes.join(", ")),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
|
||||
@@ -170,6 +170,7 @@ pub enum CheckCode {
|
||||
U011,
|
||||
U012,
|
||||
U013,
|
||||
U014,
|
||||
// pydocstyle
|
||||
D100,
|
||||
D101,
|
||||
@@ -500,7 +501,8 @@ pub enum CheckKind {
|
||||
UnnecessaryFutureImport(Vec<String>),
|
||||
UnnecessaryLRUCacheParams,
|
||||
UnnecessaryEncodeUTF8,
|
||||
ConvertTypedDictFunctionalToClass,
|
||||
ConvertTypedDictFunctionalToClass(String),
|
||||
ConvertNamedTupleFunctionalToClass(String),
|
||||
// pydocstyle
|
||||
BlankLineAfterLastSection(String),
|
||||
BlankLineAfterSection(String),
|
||||
@@ -773,7 +775,8 @@ impl CheckCode {
|
||||
CheckCode::U010 => CheckKind::UnnecessaryFutureImport(vec!["...".to_string()]),
|
||||
CheckCode::U011 => CheckKind::UnnecessaryLRUCacheParams,
|
||||
CheckCode::U012 => CheckKind::UnnecessaryEncodeUTF8,
|
||||
CheckCode::U013 => CheckKind::ConvertTypedDictFunctionalToClass,
|
||||
CheckCode::U013 => CheckKind::ConvertTypedDictFunctionalToClass("...".to_string()),
|
||||
CheckCode::U014 => CheckKind::ConvertNamedTupleFunctionalToClass("...".to_string()),
|
||||
// pydocstyle
|
||||
CheckCode::D100 => CheckKind::PublicModule,
|
||||
CheckCode::D101 => CheckKind::PublicClass,
|
||||
@@ -1005,6 +1008,7 @@ impl CheckCode {
|
||||
CheckCode::U011 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U012 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U013 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U014 => CheckCategory::Pyupgrade,
|
||||
CheckCode::D100 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D101 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D102 => CheckCategory::Pydocstyle,
|
||||
@@ -1227,7 +1231,8 @@ impl CheckKind {
|
||||
CheckKind::UnnecessaryFutureImport(_) => &CheckCode::U010,
|
||||
CheckKind::UnnecessaryLRUCacheParams => &CheckCode::U011,
|
||||
CheckKind::UnnecessaryEncodeUTF8 => &CheckCode::U012,
|
||||
CheckKind::ConvertTypedDictFunctionalToClass => &CheckCode::U013,
|
||||
CheckKind::ConvertTypedDictFunctionalToClass(_) => &CheckCode::U013,
|
||||
CheckKind::ConvertNamedTupleFunctionalToClass(_) => &CheckCode::U014,
|
||||
// pydocstyle
|
||||
CheckKind::BlankLineAfterLastSection(_) => &CheckCode::D413,
|
||||
CheckKind::BlankLineAfterSection(_) => &CheckCode::D410,
|
||||
@@ -1776,8 +1781,11 @@ impl CheckKind {
|
||||
"Unnecessary parameters to `functools.lru_cache`".to_string()
|
||||
}
|
||||
CheckKind::UnnecessaryEncodeUTF8 => "Unnecessary call to `encode` as UTF-8".to_string(),
|
||||
CheckKind::ConvertTypedDictFunctionalToClass => {
|
||||
"Convert `TypedDict` functional syntax to class syntax".to_string()
|
||||
CheckKind::ConvertTypedDictFunctionalToClass(name) => {
|
||||
format!("Convert `{name}` from `TypedDict` functional to class syntax")
|
||||
}
|
||||
CheckKind::ConvertNamedTupleFunctionalToClass(name) => {
|
||||
format!("Convert `{name}` from `NamedTuple` functional to class syntax")
|
||||
}
|
||||
// pydocstyle
|
||||
CheckKind::FitsOnOneLine => "One-line docstring should fit on one line".to_string(),
|
||||
@@ -2038,46 +2046,53 @@ impl CheckKind {
|
||||
pub fn fixable(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
CheckKind::AmbiguousUnicodeCharacterString(_, _)
|
||||
| CheckKind::AmbiguousUnicodeCharacterDocstring(_, _)
|
||||
| CheckKind::BlankLineAfterLastSection(_)
|
||||
| CheckKind::BlankLineAfterSection(_)
|
||||
CheckKind::AmbiguousUnicodeCharacterString(..)
|
||||
| CheckKind::AmbiguousUnicodeCharacterDocstring(..)
|
||||
| CheckKind::BlankLineAfterLastSection(..)
|
||||
| CheckKind::BlankLineAfterSection(..)
|
||||
| CheckKind::BlankLineAfterSummary
|
||||
| CheckKind::BlankLineBeforeSection(_)
|
||||
| CheckKind::CapitalizeSectionName(_)
|
||||
| CheckKind::DashedUnderlineAfterSection(_)
|
||||
| CheckKind::DeprecatedUnittestAlias(_, _)
|
||||
| CheckKind::BlankLineBeforeSection(..)
|
||||
| CheckKind::CapitalizeSectionName(..)
|
||||
| CheckKind::ConvertNamedTupleFunctionalToClass(..)
|
||||
| CheckKind::ConvertTypedDictFunctionalToClass(..)
|
||||
| CheckKind::DashedUnderlineAfterSection(..)
|
||||
| CheckKind::DeprecatedUnittestAlias(..)
|
||||
| CheckKind::DoNotAssertFalse
|
||||
| CheckKind::DuplicateHandlerException(_)
|
||||
| CheckKind::DoNotAssignLambda
|
||||
| CheckKind::DuplicateHandlerException(..)
|
||||
| CheckKind::GetAttrWithConstant
|
||||
| CheckKind::IsLiteral
|
||||
| CheckKind::NewLineAfterLastParagraph
|
||||
| CheckKind::NewLineAfterSectionName(_)
|
||||
| CheckKind::NoBlankLineAfterFunction(_)
|
||||
| CheckKind::NoBlankLineBeforeClass(_)
|
||||
| CheckKind::NoBlankLineBeforeFunction(_)
|
||||
| CheckKind::NoBlankLinesBetweenHeaderAndContent(_)
|
||||
| CheckKind::NewLineAfterSectionName(..)
|
||||
| CheckKind::NoBlankLineAfterFunction(..)
|
||||
| CheckKind::NoBlankLineBeforeClass(..)
|
||||
| CheckKind::NoBlankLineBeforeFunction(..)
|
||||
| CheckKind::NoBlankLinesBetweenHeaderAndContent(..)
|
||||
| CheckKind::NoOverIndentation
|
||||
| CheckKind::NoSurroundingWhitespace
|
||||
| CheckKind::NoUnderIndentation
|
||||
| CheckKind::OneBlankLineAfterClass(_)
|
||||
| CheckKind::OneBlankLineBeforeClass(_)
|
||||
| CheckKind::NoneComparison(..)
|
||||
| CheckKind::NotInTest
|
||||
| CheckKind::NotIsTest
|
||||
| CheckKind::OneBlankLineAfterClass(..)
|
||||
| CheckKind::OneBlankLineBeforeClass(..)
|
||||
| CheckKind::PEP3120UnnecessaryCodingComment
|
||||
| CheckKind::PPrintFound
|
||||
| CheckKind::PrintFound
|
||||
| CheckKind::RaiseNotImplemented
|
||||
| CheckKind::SectionNameEndsInColon(_)
|
||||
| CheckKind::SectionNotOverIndented(_)
|
||||
| CheckKind::SectionUnderlineAfterName(_)
|
||||
| CheckKind::SectionUnderlineMatchesSectionLength(_)
|
||||
| CheckKind::SectionUnderlineNotOverIndented(_)
|
||||
| CheckKind::SectionNameEndsInColon(..)
|
||||
| CheckKind::SectionNotOverIndented(..)
|
||||
| CheckKind::SectionUnderlineAfterName(..)
|
||||
| CheckKind::SectionUnderlineMatchesSectionLength(..)
|
||||
| CheckKind::SectionUnderlineNotOverIndented(..)
|
||||
| CheckKind::SetAttrWithConstant
|
||||
| CheckKind::SuperCallWithParameters
|
||||
| CheckKind::TypeOfPrimitive(_)
|
||||
| CheckKind::UnnecessaryCollectionCall(_)
|
||||
| CheckKind::UnnecessaryComprehension(_)
|
||||
| CheckKind::TrueFalseComparison(..)
|
||||
| CheckKind::TypeOfPrimitive(..)
|
||||
| CheckKind::UnnecessaryCollectionCall(..)
|
||||
| CheckKind::UnnecessaryComprehension(..)
|
||||
| CheckKind::UnnecessaryEncodeUTF8
|
||||
| CheckKind::ConvertTypedDictFunctionalToClass
|
||||
| CheckKind::UnnecessaryFutureImport(_)
|
||||
| CheckKind::UnnecessaryFutureImport(..)
|
||||
| CheckKind::UnnecessaryGeneratorDict
|
||||
| CheckKind::UnnecessaryGeneratorList
|
||||
| CheckKind::UnnecessaryGeneratorSet
|
||||
@@ -2085,18 +2100,18 @@ impl CheckKind {
|
||||
| CheckKind::UnnecessaryListCall
|
||||
| CheckKind::UnnecessaryListComprehensionDict
|
||||
| CheckKind::UnnecessaryListComprehensionSet
|
||||
| CheckKind::UnnecessaryLiteralDict(_)
|
||||
| CheckKind::UnnecessaryLiteralSet(_)
|
||||
| CheckKind::UnnecessaryLiteralWithinListCall(_)
|
||||
| CheckKind::UnnecessaryLiteralWithinTupleCall(_)
|
||||
| CheckKind::UnnecessaryLiteralDict(..)
|
||||
| CheckKind::UnnecessaryLiteralSet(..)
|
||||
| CheckKind::UnnecessaryLiteralWithinListCall(..)
|
||||
| CheckKind::UnnecessaryLiteralWithinTupleCall(..)
|
||||
| CheckKind::UnsortedImports
|
||||
| CheckKind::UnusedImport(_, false)
|
||||
| CheckKind::UnusedLoopControlVariable(_)
|
||||
| CheckKind::UnusedNOQA(_)
|
||||
| CheckKind::UsePEP585Annotation(_)
|
||||
| CheckKind::UnusedLoopControlVariable(..)
|
||||
| CheckKind::UnusedNOQA(..)
|
||||
| CheckKind::UsePEP585Annotation(..)
|
||||
| CheckKind::UsePEP604Annotation
|
||||
| CheckKind::UselessMetaclassType
|
||||
| CheckKind::UselessObjectInheritance(_)
|
||||
| CheckKind::UselessObjectInheritance(..)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,6 +297,7 @@ pub enum CheckCodePrefix {
|
||||
U011,
|
||||
U012,
|
||||
U013,
|
||||
U014,
|
||||
W,
|
||||
W2,
|
||||
W29,
|
||||
@@ -1111,6 +1112,7 @@ impl CheckCodePrefix {
|
||||
CheckCode::U011,
|
||||
CheckCode::U012,
|
||||
CheckCode::U013,
|
||||
CheckCode::U014,
|
||||
],
|
||||
CheckCodePrefix::U0 => vec![
|
||||
CheckCode::U001,
|
||||
@@ -1125,6 +1127,7 @@ impl CheckCodePrefix {
|
||||
CheckCode::U011,
|
||||
CheckCode::U012,
|
||||
CheckCode::U013,
|
||||
CheckCode::U014,
|
||||
],
|
||||
CheckCodePrefix::U00 => vec![
|
||||
CheckCode::U001,
|
||||
@@ -1149,11 +1152,13 @@ impl CheckCodePrefix {
|
||||
CheckCode::U011,
|
||||
CheckCode::U012,
|
||||
CheckCode::U013,
|
||||
CheckCode::U014,
|
||||
],
|
||||
CheckCodePrefix::U010 => vec![CheckCode::U010],
|
||||
CheckCodePrefix::U011 => vec![CheckCode::U011],
|
||||
CheckCodePrefix::U012 => vec![CheckCode::U012],
|
||||
CheckCodePrefix::U013 => vec![CheckCode::U013],
|
||||
CheckCodePrefix::U014 => vec![CheckCode::U014],
|
||||
CheckCodePrefix::W => vec![CheckCode::W292, CheckCode::W605],
|
||||
CheckCodePrefix::W2 => vec![CheckCode::W292],
|
||||
CheckCodePrefix::W29 => vec![CheckCode::W292],
|
||||
@@ -1496,6 +1501,7 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::U011 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U012 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U013 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U014 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::W => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::W2 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::W29 => PrefixSpecificity::Tens,
|
||||
|
||||
5
src/docstrings/constants.rs
Normal file
5
src/docstrings/constants.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
pub const TRIPLE_QUOTE_PREFIXES: &[&str] = &[
|
||||
"ur\"\"\"", "ur'''", "u\"\"\"", "u'''", "r\"\"\"", "r'''", "\"\"\"", "'''",
|
||||
];
|
||||
|
||||
pub const SINGLE_QUOTE_PREFIXES: &[&str] = &["ur\"", "ur'", "u\"", "u'", "r\"", "r'", "\"", "'"];
|
||||
@@ -1,7 +1,7 @@
|
||||
pub mod constants;
|
||||
pub mod definition;
|
||||
pub mod extraction;
|
||||
pub mod google;
|
||||
pub mod helpers;
|
||||
pub mod numpy;
|
||||
pub mod sections;
|
||||
pub mod styles;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::docstrings::helpers;
|
||||
use crate::ast::whitespace;
|
||||
use crate::docstrings::styles::SectionStyle;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -14,7 +14,7 @@ pub(crate) struct SectionContext<'a> {
|
||||
fn suspected_as_section(line: &str, style: &SectionStyle) -> bool {
|
||||
style
|
||||
.lowercase_section_names()
|
||||
.contains(&helpers::leading_words(line).to_lowercase().as_str())
|
||||
.contains(&whitespace::leading_words(line).to_lowercase().as_str())
|
||||
}
|
||||
|
||||
/// Check if the suspected context is really a section header.
|
||||
@@ -64,7 +64,7 @@ pub(crate) fn section_contexts<'a>(
|
||||
let mut contexts = vec![];
|
||||
for lineno in suspected_section_indices {
|
||||
let context = SectionContext {
|
||||
section_name: helpers::leading_words(lines[lineno]),
|
||||
section_name: whitespace::leading_words(lines[lineno]),
|
||||
previous_line: lines[lineno - 1],
|
||||
line: lines[lineno],
|
||||
following_lines: &lines[lineno + 1..],
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use rustpython_ast::{Arguments, Expr, ExprKind};
|
||||
use rustpython_ast::{Arguments, Constant, Expr, ExprKind, Operator};
|
||||
|
||||
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
const MUTABLE_FUNCS: [(&str, &str); 7] = [
|
||||
const MUTABLE_FUNCS: &[(&str, &str)] = &[
|
||||
("", "dict"),
|
||||
("", "list"),
|
||||
("", "set"),
|
||||
@@ -16,6 +16,47 @@ const MUTABLE_FUNCS: [(&str, &str); 7] = [
|
||||
("collections", "deque"),
|
||||
];
|
||||
|
||||
const IMMUTABLE_TYPES: &[(&str, &str)] = &[
|
||||
("", "bool"),
|
||||
("", "bytes"),
|
||||
("", "complex"),
|
||||
("", "float"),
|
||||
("", "frozenset"),
|
||||
("", "int"),
|
||||
("", "object"),
|
||||
("", "range"),
|
||||
("", "str"),
|
||||
("collections.abc", "Sized"),
|
||||
("typing", "LiteralString"),
|
||||
("typing", "Sized"),
|
||||
];
|
||||
|
||||
const IMMUTABLE_GENERIC_TYPES: &[(&str, &str)] = &[
|
||||
("", "tuple"),
|
||||
("collections.abc", "ByteString"),
|
||||
("collections.abc", "Collection"),
|
||||
("collections.abc", "Container"),
|
||||
("collections.abc", "Iterable"),
|
||||
("collections.abc", "Mapping"),
|
||||
("collections.abc", "Reversible"),
|
||||
("collections.abc", "Sequence"),
|
||||
("collections.abc", "Set"),
|
||||
("typing", "AbstractSet"),
|
||||
("typing", "ByteString"),
|
||||
("typing", "Callable"),
|
||||
("typing", "Collection"),
|
||||
("typing", "Container"),
|
||||
("typing", "FrozenSet"),
|
||||
("typing", "Iterable"),
|
||||
("typing", "Literal"),
|
||||
("typing", "Mapping"),
|
||||
("typing", "Never"),
|
||||
("typing", "NoReturn"),
|
||||
("typing", "Reversible"),
|
||||
("typing", "Sequence"),
|
||||
("typing", "Tuple"),
|
||||
];
|
||||
|
||||
pub fn is_mutable_func(
|
||||
expr: &Expr,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
@@ -27,34 +68,106 @@ pub fn is_mutable_func(
|
||||
.any(|(module, member)| match_call_path(&call_path, module, member, from_imports))
|
||||
}
|
||||
|
||||
fn is_mutable_expr(
|
||||
expr: &Expr,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
) -> bool {
|
||||
match &expr.node {
|
||||
ExprKind::List { .. }
|
||||
| ExprKind::Dict { .. }
|
||||
| ExprKind::Set { .. }
|
||||
| ExprKind::ListComp { .. }
|
||||
| ExprKind::DictComp { .. }
|
||||
| ExprKind::SetComp { .. } => true,
|
||||
ExprKind::Call { func, .. } => is_mutable_func(func, from_imports, import_aliases),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_immutable_annotation(
|
||||
expr: &Expr,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
) -> bool {
|
||||
match &expr.node {
|
||||
ExprKind::Name { .. } | ExprKind::Attribute { .. } => {
|
||||
let call_path = dealias_call_path(collect_call_paths(expr), import_aliases);
|
||||
IMMUTABLE_TYPES
|
||||
.iter()
|
||||
.chain(IMMUTABLE_GENERIC_TYPES)
|
||||
.any(|(module, member)| match_call_path(&call_path, module, member, from_imports))
|
||||
}
|
||||
ExprKind::Subscript { value, slice, .. } => {
|
||||
let call_path = dealias_call_path(collect_call_paths(value), import_aliases);
|
||||
if IMMUTABLE_GENERIC_TYPES
|
||||
.iter()
|
||||
.any(|(module, member)| match_call_path(&call_path, module, member, from_imports))
|
||||
{
|
||||
true
|
||||
} else if match_call_path(&call_path, "typing", "Union", from_imports) {
|
||||
if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.iter()
|
||||
.all(|elt| is_immutable_annotation(elt, from_imports, import_aliases))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if match_call_path(&call_path, "typing", "Optional", from_imports) {
|
||||
is_immutable_annotation(slice, from_imports, import_aliases)
|
||||
} else if match_call_path(&call_path, "typing", "Annotated", from_imports) {
|
||||
if let ExprKind::Tuple { elts, .. } = &slice.node {
|
||||
elts.first().map_or(false, |elt| {
|
||||
is_immutable_annotation(elt, from_imports, import_aliases)
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ExprKind::BinOp {
|
||||
left,
|
||||
op: Operator::BitOr,
|
||||
right,
|
||||
} => {
|
||||
is_immutable_annotation(left, from_imports, import_aliases)
|
||||
&& is_immutable_annotation(right, from_imports, import_aliases)
|
||||
}
|
||||
ExprKind::Constant {
|
||||
value: Constant::None,
|
||||
..
|
||||
} => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// B006
|
||||
pub fn mutable_argument_default(checker: &mut Checker, arguments: &Arguments) {
|
||||
for expr in arguments
|
||||
.defaults
|
||||
// Scan in reverse order to right-align zip()
|
||||
for (arg, default) in arguments
|
||||
.kwonlyargs
|
||||
.iter()
|
||||
.chain(arguments.kw_defaults.iter())
|
||||
.rev()
|
||||
.zip(arguments.kw_defaults.iter().rev())
|
||||
.chain(
|
||||
arguments
|
||||
.args
|
||||
.iter()
|
||||
.rev()
|
||||
.chain(arguments.posonlyargs.iter().rev())
|
||||
.zip(arguments.defaults.iter().rev()),
|
||||
)
|
||||
{
|
||||
match &expr.node {
|
||||
ExprKind::List { .. }
|
||||
| ExprKind::Dict { .. }
|
||||
| ExprKind::Set { .. }
|
||||
| ExprKind::ListComp { .. }
|
||||
| ExprKind::DictComp { .. }
|
||||
| ExprKind::SetComp { .. } => {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MutableArgumentDefault,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
ExprKind::Call { func, .. } => {
|
||||
if is_mutable_func(func, &checker.from_imports, &checker.import_aliases) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MutableArgumentDefault,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
if is_mutable_expr(default, &checker.from_imports, &checker.import_aliases)
|
||||
&& arg.node.annotation.as_ref().map_or(true, |expr| {
|
||||
!is_immutable_annotation(expr, &checker.from_imports, &checker.import_aliases)
|
||||
})
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MutableArgumentDefault,
|
||||
Range::from_located(default),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,61 @@
|
||||
use rustpython_ast::{Constant, Expr, ExprKind};
|
||||
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::code_gen::SourceGenerator;
|
||||
use crate::python::identifiers::IDENTIFIER_REGEX;
|
||||
use crate::python::keyword::KWLIST;
|
||||
|
||||
fn assignment(obj: &Expr, name: &str, value: &Expr) -> Option<String> {
|
||||
let stmt = Stmt::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
StmtKind::Assign {
|
||||
targets: vec![Expr::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
ExprKind::Attribute {
|
||||
value: Box::new(obj.clone()),
|
||||
attr: name.to_string(),
|
||||
ctx: ExprContext::Store,
|
||||
},
|
||||
)],
|
||||
value: Box::new(value.clone()),
|
||||
type_comment: None,
|
||||
},
|
||||
);
|
||||
let mut generator = SourceGenerator::new();
|
||||
match generator.unparse_stmt(&stmt) {
|
||||
Ok(()) => generator.generate().ok(),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// B010
|
||||
pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if id == "setattr" {
|
||||
if let [_, arg, _] = args {
|
||||
if let [obj, name, value] = args {
|
||||
if let ExprKind::Constant {
|
||||
value: Constant::Str(value),
|
||||
value: Constant::Str(name),
|
||||
..
|
||||
} = &arg.node
|
||||
} = &name.node
|
||||
{
|
||||
if IDENTIFIER_REGEX.is_match(value) && !KWLIST.contains(&value.as_str()) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SetAttrWithConstant,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
if IDENTIFIER_REGEX.is_match(name) && !KWLIST.contains(&name.as_str()) {
|
||||
let mut check =
|
||||
Check::new(CheckKind::SetAttrWithConstant, Range::from_located(expr));
|
||||
if checker.patch(check.kind.code()) {
|
||||
if let Some(content) = assignment(obj, name, value) {
|
||||
check.amend(Fix::replacement(
|
||||
content,
|
||||
expr.location,
|
||||
expr.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use rustpython_ast::{Location, Stmt};
|
||||
use textwrap::{dedent, indent};
|
||||
|
||||
use crate::ast::helpers::{match_leading_content, match_trailing_content};
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace::leading_space;
|
||||
use crate::autofix::{fixer, Fix};
|
||||
use crate::checks::CheckKind;
|
||||
use crate::docstrings::helpers::leading_space;
|
||||
use crate::isort::{comments, format_imports};
|
||||
use crate::{Check, Settings, SourceCodeLocator};
|
||||
|
||||
@@ -27,34 +28,6 @@ fn extract_indentation(body: &[&Stmt], locator: &SourceCodeLocator) -> String {
|
||||
leading_space(&existing)
|
||||
}
|
||||
|
||||
fn match_leading_content(body: &[&Stmt], locator: &SourceCodeLocator) -> bool {
|
||||
let location = body.first().unwrap().location;
|
||||
let range = Range {
|
||||
location: Location::new(location.row(), 0),
|
||||
end_location: location,
|
||||
};
|
||||
let prefix = locator.slice_source_code_range(&range);
|
||||
prefix.chars().any(|char| !char.is_whitespace())
|
||||
}
|
||||
|
||||
fn match_trailing_content(body: &[&Stmt], locator: &SourceCodeLocator) -> bool {
|
||||
let end_location = body.last().unwrap().end_location.unwrap();
|
||||
let range = Range {
|
||||
location: end_location,
|
||||
end_location: Location::new(end_location.row() + 1, 0),
|
||||
};
|
||||
let suffix = locator.slice_source_code_range(&range);
|
||||
for char in suffix.chars() {
|
||||
if char == '#' {
|
||||
return false;
|
||||
}
|
||||
if !char.is_whitespace() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// I001
|
||||
pub fn check_imports(
|
||||
body: Vec<&Stmt>,
|
||||
@@ -75,8 +48,8 @@ pub fn check_imports(
|
||||
);
|
||||
|
||||
// Special-cases: there's leading or trailing content in the import block.
|
||||
let has_leading_content = match_leading_content(&body, locator);
|
||||
let has_trailing_content = match_trailing_content(&body, locator);
|
||||
let has_leading_content = match_leading_content(body.first().unwrap(), locator);
|
||||
let has_trailing_content = match_trailing_content(body.last().unwrap(), locator);
|
||||
|
||||
// Generate the sorted import block.
|
||||
let expected = format_imports(
|
||||
|
||||
@@ -188,7 +188,6 @@ pub fn lint_stdin(
|
||||
.collect())
|
||||
}
|
||||
|
||||
#[cfg_attr(target_family = "wasm", allow(unused_variables))]
|
||||
pub fn lint_path(
|
||||
path: &Path,
|
||||
settings: &Settings,
|
||||
@@ -198,7 +197,6 @@ pub fn lint_path(
|
||||
let metadata = path.metadata()?;
|
||||
|
||||
// Check the cache.
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
if let Some(messages) = cache::get(path, &metadata, settings, autofix, mode) {
|
||||
debug!("Cache hit for: {}", path.to_string_lossy());
|
||||
return Ok(messages);
|
||||
@@ -251,7 +249,7 @@ pub fn lint_path(
|
||||
Message::from_check(check, filename, source)
|
||||
})
|
||||
.collect();
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
|
||||
cache::set(path, &metadata, settings, autofix, &messages, mode);
|
||||
|
||||
Ok(messages)
|
||||
@@ -519,6 +517,7 @@ mod tests {
|
||||
#[test_case(CheckCode::U011, Path::new("U011_1.py"); "U011_1")]
|
||||
#[test_case(CheckCode::U012, Path::new("U012.py"); "U012")]
|
||||
#[test_case(CheckCode::U013, Path::new("U013.py"); "U013")]
|
||||
#[test_case(CheckCode::U014, Path::new("U014.py"); "U014")]
|
||||
#[test_case(CheckCode::W292, Path::new("W292_0.py"); "W292_0")]
|
||||
#[test_case(CheckCode::W292, Path::new("W292_1.py"); "W292_1")]
|
||||
#[test_case(CheckCode::W292, Path::new("W292_2.py"); "W292_2")]
|
||||
|
||||
23
src/main.rs
23
src/main.rs
@@ -4,7 +4,6 @@ use std::process::ExitCode;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::time::Instant;
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use ::ruff::cache;
|
||||
use ::ruff::checks::{CheckCode, CheckKind};
|
||||
use ::ruff::cli::{collect_per_file_ignores, extract_log_level, Cli};
|
||||
@@ -286,7 +285,7 @@ fn inner_main() -> Result<ExitCode> {
|
||||
}
|
||||
|
||||
// Extract settings for internal use.
|
||||
let autofix = configuration.fix;
|
||||
let fix_enabled: bool = configuration.fix;
|
||||
let settings = Settings::from_configuration(configuration);
|
||||
|
||||
if cli.show_files {
|
||||
@@ -294,12 +293,16 @@ fn inner_main() -> Result<ExitCode> {
|
||||
return Ok(ExitCode::SUCCESS);
|
||||
}
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
cache::init()?;
|
||||
// Initialize the cache.
|
||||
let mut cache_enabled: bool = !cli.no_cache;
|
||||
if cache_enabled && cache::init().is_err() {
|
||||
eprintln!("Unable to initialize cache; disabling...");
|
||||
cache_enabled = false;
|
||||
}
|
||||
|
||||
let printer = Printer::new(&cli.format, &log_level);
|
||||
if cli.watch {
|
||||
if autofix {
|
||||
if fix_enabled {
|
||||
eprintln!("Warning: --fix is not enabled in watch mode.");
|
||||
}
|
||||
|
||||
@@ -319,7 +322,7 @@ fn inner_main() -> Result<ExitCode> {
|
||||
printer.clear_screen()?;
|
||||
printer.write_to_user("Starting linter in watch mode...\n");
|
||||
|
||||
let messages = run_once(&cli.files, &settings, !cli.no_cache, false)?;
|
||||
let messages = run_once(&cli.files, &settings, cache_enabled, false)?;
|
||||
printer.write_continuously(&messages)?;
|
||||
|
||||
// Configure the file watcher.
|
||||
@@ -337,7 +340,7 @@ fn inner_main() -> Result<ExitCode> {
|
||||
printer.clear_screen()?;
|
||||
printer.write_to_user("File change detected...\n");
|
||||
|
||||
let messages = run_once(&cli.files, &settings, !cli.no_cache, false)?;
|
||||
let messages = run_once(&cli.files, &settings, cache_enabled, false)?;
|
||||
printer.write_continuously(&messages)?;
|
||||
}
|
||||
}
|
||||
@@ -362,15 +365,15 @@ fn inner_main() -> Result<ExitCode> {
|
||||
let messages = if is_stdin {
|
||||
let filename = cli.stdin_filename.unwrap_or_else(|| "-".to_string());
|
||||
let path = Path::new(&filename);
|
||||
run_once_stdin(&settings, path, autofix)?
|
||||
run_once_stdin(&settings, path, fix_enabled)?
|
||||
} else {
|
||||
run_once(&cli.files, &settings, !cli.no_cache, autofix)?
|
||||
run_once(&cli.files, &settings, cache_enabled, fix_enabled)?
|
||||
};
|
||||
|
||||
// Always try to print violations (the printer itself may suppress output),
|
||||
// unless we're writing fixes via stdin (in which case, the transformed
|
||||
// source code goes to stdout).
|
||||
if !(is_stdin && autofix) {
|
||||
if !(is_stdin && fix_enabled) {
|
||||
printer.write_once(&messages)?;
|
||||
}
|
||||
|
||||
|
||||
48
src/noqa.rs
48
src/noqa.rs
@@ -10,32 +10,40 @@ use regex::Regex;
|
||||
use crate::checks::{Check, CheckCode};
|
||||
|
||||
static NO_QA_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
Regex::new(r"(?P<noqa>\s*(?i:# noqa)(?::\s?(?P<codes>([A-Z]+[0-9]+(?:[,\s]+)?)+))?)")
|
||||
.expect("Invalid regex")
|
||||
Regex::new(
|
||||
r"(?P<spaces>\s*)(?P<noqa>(?i:# noqa)(?::\s?(?P<codes>([A-Z]+[0-9]+(?:[,\s]+)?)+))?)",
|
||||
)
|
||||
.expect("Invalid regex")
|
||||
});
|
||||
static SPLIT_COMMA_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").expect("Invalid regex"));
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Directive<'a> {
|
||||
None,
|
||||
All(usize, usize),
|
||||
Codes(usize, usize, Vec<&'a str>),
|
||||
All(usize, usize, usize),
|
||||
Codes(usize, usize, usize, Vec<&'a str>),
|
||||
}
|
||||
|
||||
pub fn extract_noqa_directive(line: &str) -> Directive {
|
||||
match NO_QA_REGEX.captures(line) {
|
||||
Some(caps) => match caps.name("noqa") {
|
||||
Some(noqa) => match caps.name("codes") {
|
||||
Some(codes) => Directive::Codes(
|
||||
noqa.start(),
|
||||
noqa.end(),
|
||||
SPLIT_COMMA_REGEX
|
||||
.split(codes.as_str())
|
||||
.map(|code| code.trim())
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect(),
|
||||
),
|
||||
None => Directive::All(noqa.start(), noqa.end()),
|
||||
Some(caps) => match caps.name("spaces") {
|
||||
Some(spaces) => match caps.name("noqa") {
|
||||
Some(noqa) => match caps.name("codes") {
|
||||
Some(codes) => Directive::Codes(
|
||||
spaces.as_str().chars().count(),
|
||||
noqa.start(),
|
||||
noqa.end(),
|
||||
SPLIT_COMMA_REGEX
|
||||
.split(codes.as_str())
|
||||
.map(|code| code.trim())
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect(),
|
||||
),
|
||||
None => {
|
||||
Directive::All(spaces.as_str().chars().count(), noqa.start(), noqa.end())
|
||||
}
|
||||
},
|
||||
None => Directive::None,
|
||||
},
|
||||
None => Directive::None,
|
||||
},
|
||||
@@ -92,12 +100,14 @@ fn add_noqa_inner(
|
||||
match extract_noqa_directive(line) {
|
||||
Directive::None => {
|
||||
output.push_str(line);
|
||||
output.push_str(" # noqa: ");
|
||||
}
|
||||
Directive::All(_, start, _) | Directive::Codes(_, start, ..) => {
|
||||
output.push_str(&line[..start]);
|
||||
output.push_str("# noqa: ");
|
||||
}
|
||||
Directive::All(start, _) => output.push_str(&line[..start]),
|
||||
Directive::Codes(start, ..) => output.push_str(&line[..start]),
|
||||
};
|
||||
let codes: Vec<&str> = codes.iter().map(|code| code.as_ref()).collect();
|
||||
output.push_str(" # noqa: ");
|
||||
output.push_str(&codes.join(", "));
|
||||
output.push('\n');
|
||||
count += 1;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use itertools::izip;
|
||||
use rustpython_ast::Location;
|
||||
use rustpython_parser::ast::{Cmpop, Expr, ExprKind, Stmt};
|
||||
use rustpython_parser::ast::{Cmpop, Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
@@ -46,19 +46,6 @@ pub fn ambiguous_function_name(name: &str, location: Range) -> Option<Check> {
|
||||
}
|
||||
}
|
||||
|
||||
/// E731
|
||||
pub fn do_not_assign_lambda(target: &Expr, value: &Expr, stmt: &Stmt) -> Option<Check> {
|
||||
if let ExprKind::Name { .. } = &target.node {
|
||||
if let ExprKind::Lambda { .. } = &value.node {
|
||||
return Some(Check::new(
|
||||
CheckKind::DoNotAssignLambda,
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// E721
|
||||
pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) -> Vec<Check> {
|
||||
let mut checks: Vec<Check> = vec![];
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
use anyhow::Result;
|
||||
use fnv::FnvHashMap;
|
||||
use itertools::izip;
|
||||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Unaryop};
|
||||
use log::error;
|
||||
use rustpython_ast::{Arguments, Location, StmtKind};
|
||||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Stmt, Unaryop};
|
||||
|
||||
use crate::ast::helpers::{match_leading_content, match_trailing_content};
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace::leading_space;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckKind, RejectedCmpop};
|
||||
@@ -260,3 +265,69 @@ pub fn not_tests(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn function(name: &str, args: &Arguments, body: &Expr) -> Result<String> {
|
||||
let body = Stmt::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
StmtKind::Return {
|
||||
value: Some(Box::new(body.clone())),
|
||||
},
|
||||
);
|
||||
let func = Stmt::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
StmtKind::FunctionDef {
|
||||
name: name.to_string(),
|
||||
args: Box::new(args.clone()),
|
||||
body: vec![body],
|
||||
decorator_list: vec![],
|
||||
returns: None,
|
||||
type_comment: None,
|
||||
},
|
||||
);
|
||||
let mut generator = SourceGenerator::new();
|
||||
generator.unparse_stmt(&func)?;
|
||||
generator.generate().map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// E731
|
||||
pub fn do_not_assign_lambda(checker: &mut Checker, target: &Expr, value: &Expr, stmt: &Stmt) {
|
||||
if let ExprKind::Name { id, .. } = &target.node {
|
||||
if let ExprKind::Lambda { args, body } = &value.node {
|
||||
let mut check = Check::new(CheckKind::DoNotAssignLambda, Range::from_located(stmt));
|
||||
if checker.patch(check.kind.code()) {
|
||||
if !match_leading_content(stmt, checker.locator)
|
||||
&& !match_trailing_content(stmt, checker.locator)
|
||||
{
|
||||
match function(id, args, body) {
|
||||
Ok(content) => {
|
||||
let indentation =
|
||||
&leading_space(&checker.locator.slice_source_code_range(&Range {
|
||||
location: Location::new(stmt.location.row(), 0),
|
||||
end_location: Location::new(stmt.location.row() + 1, 0),
|
||||
}));
|
||||
let mut indented = String::new();
|
||||
for (idx, line) in content.lines().enumerate() {
|
||||
if idx == 0 {
|
||||
indented.push_str(line);
|
||||
} else {
|
||||
indented.push('\n');
|
||||
indented.push_str(indentation);
|
||||
indented.push_str(line);
|
||||
}
|
||||
}
|
||||
check.amend(Fix::replacement(
|
||||
indented,
|
||||
stmt.location,
|
||||
stmt.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
Err(e) => error!("Failed to generate fix: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ use regex::Regex;
|
||||
use rustpython_ast::{Arg, Constant, ExprKind, Location, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
use crate::docstrings::constants;
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
use crate::docstrings::helpers;
|
||||
use crate::docstrings::sections::{section_contexts, SectionContext};
|
||||
use crate::docstrings::styles::SectionStyle;
|
||||
use crate::visibility::{is_init, is_magic, is_overload, is_staticmethod, Visibility};
|
||||
@@ -391,7 +392,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
return;
|
||||
}
|
||||
|
||||
let docstring_indent = helpers::indentation(checker, docstring);
|
||||
let docstring_indent = whitespace::indentation(checker, docstring);
|
||||
let mut has_seen_tab = docstring_indent.contains('\t');
|
||||
let mut is_over_indented = true;
|
||||
let mut over_indented_lines = vec![];
|
||||
@@ -408,7 +409,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let line_indent = helpers::leading_space(lines[i]);
|
||||
let line_indent = whitespace::leading_space(lines[i]);
|
||||
|
||||
// We only report tab indentation once, so only check if we haven't seen a tab
|
||||
// yet.
|
||||
@@ -427,7 +428,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
helpers::clean(&docstring_indent),
|
||||
whitespace::clean(&docstring_indent),
|
||||
Location::new(docstring.location.row() + i, 0),
|
||||
Location::new(docstring.location.row() + i, line_indent.len()),
|
||||
));
|
||||
@@ -464,7 +465,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
// If every line (except the last) is over-indented...
|
||||
if is_over_indented {
|
||||
for i in over_indented_lines {
|
||||
let line_indent = helpers::leading_space(lines[i]);
|
||||
let line_indent = whitespace::leading_space(lines[i]);
|
||||
if line_indent.len() > docstring_indent.len() {
|
||||
// We report over-indentation on every line. This isn't great, but
|
||||
// enables autofix.
|
||||
@@ -477,7 +478,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
helpers::clean(&docstring_indent),
|
||||
whitespace::clean(&docstring_indent),
|
||||
Location::new(docstring.location.row() + i, 0),
|
||||
Location::new(docstring.location.row() + i, line_indent.len()),
|
||||
));
|
||||
@@ -490,7 +491,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
// If the last line is over-indented...
|
||||
if !lines.is_empty() {
|
||||
let i = lines.len() - 1;
|
||||
let line_indent = helpers::leading_space(lines[i]);
|
||||
let line_indent = whitespace::leading_space(lines[i]);
|
||||
if line_indent.len() > docstring_indent.len() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::NoOverIndentation,
|
||||
@@ -501,7 +502,7 @@ pub fn indent(checker: &mut Checker, definition: &Definition) {
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
helpers::clean(&docstring_indent),
|
||||
whitespace::clean(&docstring_indent),
|
||||
Location::new(docstring.location.row() + i, 0),
|
||||
Location::new(docstring.location.row() + i, line_indent.len()),
|
||||
));
|
||||
@@ -541,7 +542,7 @@ pub fn newline_after_last_paragraph(checker: &mut Checker, definition: &Definiti
|
||||
// Insert a newline just before the end-quote(s).
|
||||
let content = format!(
|
||||
"\n{}",
|
||||
helpers::clean(&helpers::indentation(checker, docstring))
|
||||
whitespace::clean(&whitespace::indentation(checker, docstring))
|
||||
);
|
||||
check.amend(Fix::insertion(
|
||||
content,
|
||||
@@ -588,9 +589,9 @@ pub fn no_surrounding_whitespace(checker: &mut Checker, definition: &Definition)
|
||||
.next()
|
||||
.map(|line| line.to_lowercase())
|
||||
{
|
||||
for pattern in helpers::TRIPLE_QUOTE_PREFIXES
|
||||
for pattern in constants::TRIPLE_QUOTE_PREFIXES
|
||||
.iter()
|
||||
.chain(helpers::SINGLE_QUOTE_PREFIXES)
|
||||
.chain(constants::SINGLE_QUOTE_PREFIXES)
|
||||
{
|
||||
if first_line.starts_with(pattern) {
|
||||
check.amend(Fix::replacement(
|
||||
@@ -634,7 +635,7 @@ pub fn multi_line_summary_start(checker: &mut Checker, definition: &Definition)
|
||||
.next()
|
||||
.map(|line| line.to_lowercase())
|
||||
{
|
||||
if helpers::TRIPLE_QUOTE_PREFIXES.contains(&first_line.as_str()) {
|
||||
if constants::TRIPLE_QUOTE_PREFIXES.contains(&first_line.as_str()) {
|
||||
if checker.settings.enabled.contains(&CheckCode::D212) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MultiLineSummaryFirstLine,
|
||||
@@ -920,7 +921,7 @@ fn blanks_and_section_underline(
|
||||
// Add a dashed line (of the appropriate length) under the section header.
|
||||
let content = format!(
|
||||
"{}{}\n",
|
||||
helpers::clean(&helpers::indentation(checker, docstring)),
|
||||
whitespace::clean(&whitespace::indentation(checker, docstring)),
|
||||
"-".repeat(context.section_name.len())
|
||||
);
|
||||
check.amend(Fix::insertion(
|
||||
@@ -954,7 +955,7 @@ fn blanks_and_section_underline(
|
||||
// Add a dashed line (of the appropriate length) under the section header.
|
||||
let content = format!(
|
||||
"{}{}\n",
|
||||
helpers::clean(&helpers::indentation(checker, docstring)),
|
||||
whitespace::clean(&whitespace::indentation(checker, docstring)),
|
||||
"-".repeat(context.section_name.len())
|
||||
);
|
||||
check.amend(Fix::insertion(
|
||||
@@ -1030,7 +1031,7 @@ fn blanks_and_section_underline(
|
||||
// Replace the existing underline with a line of the appropriate length.
|
||||
let content = format!(
|
||||
"{}{}\n",
|
||||
helpers::clean(&helpers::indentation(checker, docstring)),
|
||||
whitespace::clean(&whitespace::indentation(checker, docstring)),
|
||||
"-".repeat(context.section_name.len())
|
||||
);
|
||||
check.amend(Fix::replacement(
|
||||
@@ -1057,8 +1058,8 @@ fn blanks_and_section_underline(
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D215) {
|
||||
let leading_space = helpers::leading_space(non_empty_line);
|
||||
let indentation = helpers::indentation(checker, docstring);
|
||||
let leading_space = whitespace::leading_space(non_empty_line);
|
||||
let indentation = whitespace::indentation(checker, docstring);
|
||||
if leading_space.len() > indentation.len() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::SectionUnderlineNotOverIndented(context.section_name.to_string()),
|
||||
@@ -1067,7 +1068,7 @@ fn blanks_and_section_underline(
|
||||
if checker.patch(check.kind.code()) {
|
||||
// Replace the existing indentation with whitespace of the appropriate length.
|
||||
check.amend(Fix::replacement(
|
||||
helpers::clean(&indentation),
|
||||
whitespace::clean(&indentation),
|
||||
Location::new(
|
||||
docstring.location.row()
|
||||
+ context.original_index
|
||||
@@ -1198,8 +1199,8 @@ fn common_section(
|
||||
}
|
||||
|
||||
if checker.settings.enabled.contains(&CheckCode::D214) {
|
||||
let leading_space = helpers::leading_space(context.line);
|
||||
let indentation = helpers::indentation(checker, docstring);
|
||||
let leading_space = whitespace::leading_space(context.line);
|
||||
let indentation = whitespace::indentation(checker, docstring);
|
||||
if leading_space.len() > indentation.len() {
|
||||
let mut check = Check::new(
|
||||
CheckKind::SectionNotOverIndented(context.section_name.to_string()),
|
||||
@@ -1208,7 +1209,7 @@ fn common_section(
|
||||
if checker.patch(check.kind.code()) {
|
||||
// Replace the existing indentation with whitespace of the appropriate length.
|
||||
check.amend(Fix::replacement(
|
||||
helpers::clean(&indentation),
|
||||
whitespace::clean(&indentation),
|
||||
Location::new(docstring.location.row() + context.original_index, 0),
|
||||
Location::new(
|
||||
docstring.location.row() + context.original_index,
|
||||
@@ -1400,13 +1401,13 @@ fn args_section(checker: &mut Checker, definition: &Definition, context: &Sectio
|
||||
fn parameters_section(checker: &mut Checker, definition: &Definition, context: &SectionContext) {
|
||||
// Collect the list of arguments documented in the docstring.
|
||||
let mut docstring_args: FnvHashSet<&str> = FnvHashSet::default();
|
||||
let section_level_indent = helpers::leading_space(context.line);
|
||||
let section_level_indent = whitespace::leading_space(context.line);
|
||||
for i in 1..context.following_lines.len() {
|
||||
let current_line = context.following_lines[i - 1];
|
||||
let current_leading_space = helpers::leading_space(current_line);
|
||||
let current_leading_space = whitespace::leading_space(current_line);
|
||||
let next_line = context.following_lines[i];
|
||||
if current_leading_space == section_level_indent
|
||||
&& (helpers::leading_space(next_line).len() > current_leading_space.len())
|
||||
&& (whitespace::leading_space(next_line).len() > current_leading_space.len())
|
||||
&& !next_line.trim().is_empty()
|
||||
{
|
||||
let parameters = if let Some(semi_index) = current_line.find(':') {
|
||||
|
||||
@@ -162,12 +162,13 @@ pub fn unnecessary_lru_cache_params(
|
||||
import_aliases,
|
||||
)
|
||||
{
|
||||
let range = Range {
|
||||
location: func.end_location.unwrap(),
|
||||
end_location: expr.end_location.unwrap(),
|
||||
};
|
||||
// Ex) `functools.lru_cache()`
|
||||
if keywords.is_empty() {
|
||||
return Some(Check::new(
|
||||
CheckKind::UnnecessaryLRUCacheParams,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
return Some(Check::new(CheckKind::UnnecessaryLRUCacheParams, range));
|
||||
}
|
||||
// Ex) `functools.lru_cache(maxsize=None)`
|
||||
if target_version >= PythonVersion::Py39 && keywords.len() == 1 {
|
||||
@@ -181,10 +182,7 @@ pub fn unnecessary_lru_cache_params(
|
||||
}
|
||||
)
|
||||
{
|
||||
return Some(Check::new(
|
||||
CheckKind::UnnecessaryLRUCacheParams,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
return Some(Check::new(CheckKind::UnnecessaryLRUCacheParams, range));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,34 +191,3 @@ pub fn remove_unnecessary_future_import(
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// U011
|
||||
pub fn remove_unnecessary_lru_cache_params(
|
||||
locator: &SourceCodeLocator,
|
||||
decor_at: &Location,
|
||||
) -> Option<Fix> {
|
||||
let contents = locator.slice_source_code_at(decor_at);
|
||||
let mut fix_start = None;
|
||||
let mut fix_end = None;
|
||||
let mut count: usize = 0;
|
||||
for (start, tok, end) in lexer::make_tokenizer(&contents).flatten() {
|
||||
if matches!(tok, Tok::Lpar) {
|
||||
if count == 0 {
|
||||
fix_start = Some(helpers::to_absolute(&start, decor_at));
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
|
||||
if matches!(tok, Tok::Rpar) {
|
||||
count -= 1;
|
||||
if count == 0 {
|
||||
fix_end = Some(helpers::to_absolute(&end, decor_at));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
match (fix_start, fix_end) {
|
||||
(Some(start), Some(end)) => Some(Fix::deletion(start, end)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
208
src/pyupgrade/plugins/convert_named_tuple_functional_to_class.rs
Normal file
208
src/pyupgrade/plugins/convert_named_tuple_functional_to_class.rs
Normal file
@@ -0,0 +1,208 @@
|
||||
use anyhow::{bail, Result};
|
||||
use log::error;
|
||||
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Keyword, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::helpers::match_module_member;
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::code_gen::SourceGenerator;
|
||||
use crate::python::identifiers::IDENTIFIER_REGEX;
|
||||
use crate::python::keyword::KWLIST;
|
||||
|
||||
/// Return the typename, args, keywords and mother class
|
||||
fn match_named_tuple_assign<'a>(
|
||||
checker: &Checker,
|
||||
targets: &'a [Expr],
|
||||
value: &'a Expr,
|
||||
) -> Option<(&'a str, &'a [Expr], &'a [Keyword], &'a ExprKind)> {
|
||||
if let Some(target) = targets.get(0) {
|
||||
if let ExprKind::Name { id: typename, .. } = &target.node {
|
||||
if let ExprKind::Call {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
} = &value.node
|
||||
{
|
||||
if match_module_member(
|
||||
func,
|
||||
"typing",
|
||||
"NamedTuple",
|
||||
&checker.from_imports,
|
||||
&checker.import_aliases,
|
||||
) {
|
||||
return Some((typename, args, keywords, &func.node));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Generate a `StmtKind::AnnAssign` representing the provided property
|
||||
/// definition.
|
||||
fn create_property_assignment_stmt(
|
||||
property: &str,
|
||||
annotation: &ExprKind,
|
||||
value: Option<&ExprKind>,
|
||||
) -> Stmt {
|
||||
Stmt::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
StmtKind::AnnAssign {
|
||||
target: Box::new(Expr::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
ExprKind::Name {
|
||||
id: property.to_string(),
|
||||
ctx: ExprContext::Load,
|
||||
},
|
||||
)),
|
||||
annotation: Box::new(Expr::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
annotation.clone(),
|
||||
)),
|
||||
value: value
|
||||
.map(|v| Box::new(Expr::new(Default::default(), Default::default(), v.clone()))),
|
||||
simple: 1,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Match the `defaults` keyword in a `NamedTuple(...)` call.
|
||||
fn match_defaults(keywords: &[Keyword]) -> Result<&[Expr]> {
|
||||
match keywords.iter().find(|keyword| {
|
||||
if let Some(arg) = &keyword.node.arg {
|
||||
arg.as_str() == "defaults"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
Some(defaults) => match &defaults.node.value.node {
|
||||
ExprKind::List { elts, .. } => Ok(elts),
|
||||
ExprKind::Tuple { elts, .. } => Ok(elts),
|
||||
_ => bail!("Expected defaults to be `ExprKind::List` | `ExprKind::Tuple`"),
|
||||
},
|
||||
None => Ok(&[]),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a list of property assignments from the `NamedTuple` arguments.
|
||||
fn create_properties_from_args(args: &[Expr], defaults: &[Expr]) -> Result<Vec<Stmt>> {
|
||||
if let Some(fields) = args.get(1) {
|
||||
if let ExprKind::List { elts, .. } = &fields.node {
|
||||
let padded_defaults = if elts.len() >= defaults.len() {
|
||||
std::iter::repeat(None)
|
||||
.take(elts.len() - defaults.len())
|
||||
.chain(defaults.iter().map(Some))
|
||||
} else {
|
||||
bail!("Defaults must be `None` or an iterable of at least the number of fields")
|
||||
};
|
||||
elts.iter()
|
||||
.zip(padded_defaults)
|
||||
.map(|(field, default)| {
|
||||
if let ExprKind::Tuple { elts, .. } = &field.node {
|
||||
if let [field_name, annotation] = elts.as_slice() {
|
||||
if let ExprKind::Constant {
|
||||
value: Constant::Str(property),
|
||||
..
|
||||
} = &field_name.node
|
||||
{
|
||||
if IDENTIFIER_REGEX.is_match(property)
|
||||
&& !KWLIST.contains(&property.as_str())
|
||||
{
|
||||
Ok(create_property_assignment_stmt(
|
||||
property,
|
||||
&annotation.node,
|
||||
default.map(|d| &d.node),
|
||||
))
|
||||
} else {
|
||||
bail!("Invalid property name: {}", property)
|
||||
}
|
||||
} else {
|
||||
bail!("Expected `field_name` to be `Constant::Str`")
|
||||
}
|
||||
} else {
|
||||
bail!("Expected `elts` to have exactly two elements")
|
||||
}
|
||||
} else {
|
||||
bail!("Expected `field` to be `ExprKind::Tuple`")
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
bail!("Expected argument to be `ExprKind::List`")
|
||||
}
|
||||
} else {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a `StmtKind:ClassDef` statement based on the provided body and
|
||||
/// keywords.
|
||||
fn create_class_def_stmt(typename: &str, body: Vec<Stmt>, base_class: &ExprKind) -> Stmt {
|
||||
Stmt::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
StmtKind::ClassDef {
|
||||
name: typename.to_string(),
|
||||
bases: vec![Expr::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
base_class.clone(),
|
||||
)],
|
||||
keywords: vec![],
|
||||
body,
|
||||
decorator_list: vec![],
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn convert_to_class(
|
||||
stmt: &Stmt,
|
||||
typename: &str,
|
||||
body: Vec<Stmt>,
|
||||
base_class: &ExprKind,
|
||||
) -> Result<Fix> {
|
||||
let mut generator = SourceGenerator::new();
|
||||
generator.unparse_stmt(&create_class_def_stmt(typename, body, base_class))?;
|
||||
let content = generator.generate()?;
|
||||
Ok(Fix::replacement(
|
||||
content,
|
||||
stmt.location,
|
||||
stmt.end_location.unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
/// U014
|
||||
pub fn convert_named_tuple_functional_to_class(
|
||||
checker: &mut Checker,
|
||||
stmt: &Stmt,
|
||||
targets: &[Expr],
|
||||
value: &Expr,
|
||||
) {
|
||||
if let Some((typename, args, keywords, base_class)) =
|
||||
match_named_tuple_assign(checker, targets, value)
|
||||
{
|
||||
match match_defaults(keywords) {
|
||||
Ok(defaults) => {
|
||||
if let Ok(properties) = create_properties_from_args(args, defaults) {
|
||||
let mut check = Check::new(
|
||||
CheckKind::ConvertNamedTupleFunctionalToClass(typename.to_string()),
|
||||
Range::from_located(stmt),
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
match convert_to_class(stmt, typename, properties, base_class) {
|
||||
Ok(fix) => check.amend(fix),
|
||||
Err(err) => error!("Failed to convert `NamedTuple`: {}", err),
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
Err(err) => error!("Failed to parse defaults: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ use anyhow::{bail, Result};
|
||||
use log::error;
|
||||
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Keyword, KeywordData, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::helpers::match_module_member;
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
@@ -10,11 +11,13 @@ use crate::code_gen::SourceGenerator;
|
||||
use crate::python::identifiers::IDENTIFIER_REGEX;
|
||||
use crate::python::keyword::KWLIST;
|
||||
|
||||
/// Return the class name, arguments, and keywords for a `TypedDict` assignment.
|
||||
/// Return the class name, arguments, keywords and base class for a `TypedDict`
|
||||
/// assignment.
|
||||
fn match_typed_dict_assign<'a>(
|
||||
checker: &Checker,
|
||||
targets: &'a [Expr],
|
||||
value: &'a Expr,
|
||||
) -> Option<(&'a str, &'a [Expr], &'a [Keyword])> {
|
||||
) -> Option<(&'a str, &'a [Expr], &'a [Keyword], &'a ExprKind)> {
|
||||
if let Some(target) = targets.get(0) {
|
||||
if let ExprKind::Name { id: class_name, .. } = &target.node {
|
||||
if let ExprKind::Call {
|
||||
@@ -23,10 +26,14 @@ fn match_typed_dict_assign<'a>(
|
||||
keywords,
|
||||
} = &value.node
|
||||
{
|
||||
if let ExprKind::Name { id: func_name, .. } = &func.node {
|
||||
if func_name == "TypedDict" {
|
||||
return Some((class_name, args, keywords));
|
||||
}
|
||||
if match_module_member(
|
||||
func,
|
||||
"typing",
|
||||
"TypedDict",
|
||||
&checker.from_imports,
|
||||
&checker.import_aliases,
|
||||
) {
|
||||
return Some((class_name, args, keywords, &func.node));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,12 +72,13 @@ fn create_pass_stmt() -> Stmt {
|
||||
Stmt::new(Default::default(), Default::default(), StmtKind::Pass)
|
||||
}
|
||||
|
||||
/// Generate a `StmtKind:ClassDef` statement bsaed on the provided body and
|
||||
/// keywords.
|
||||
/// Generate a `StmtKind:ClassDef` statement based on the provided body,
|
||||
/// keywords and base class.
|
||||
fn create_class_def_stmt(
|
||||
class_name: &str,
|
||||
body: Vec<Stmt>,
|
||||
total_keyword: Option<KeywordData>,
|
||||
base_class: &ExprKind,
|
||||
) -> Stmt {
|
||||
let keywords = match total_keyword {
|
||||
Some(keyword) => vec![Keyword::new(
|
||||
@@ -88,10 +96,7 @@ fn create_class_def_stmt(
|
||||
bases: vec![Expr::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
ExprKind::Name {
|
||||
id: "TypedDict".to_string(),
|
||||
ctx: ExprContext::Load,
|
||||
},
|
||||
base_class.clone(),
|
||||
)],
|
||||
keywords,
|
||||
body,
|
||||
@@ -150,11 +155,11 @@ fn get_properties_from_keywords(keywords: &[Keyword]) -> Result<Vec<Stmt>> {
|
||||
|
||||
// The only way to have the `total` keyword is to use the args version, like:
|
||||
// (`TypedDict('name', {'a': int}, total=True)`)
|
||||
fn get_total_from_only_keyword(keywords: &[Keyword]) -> Option<KeywordData> {
|
||||
fn get_total_from_only_keyword(keywords: &[Keyword]) -> Option<&KeywordData> {
|
||||
match keywords.get(0) {
|
||||
Some(keyword) => match &keyword.node.arg {
|
||||
Some(arg) => match arg.as_str() {
|
||||
"total" => Some(keyword.node.clone()),
|
||||
"total" => Some(&keyword.node),
|
||||
_ => None,
|
||||
},
|
||||
None => None,
|
||||
@@ -171,7 +176,7 @@ fn get_properties_and_total(
|
||||
// dict and keywords. For example, the following is illegal:
|
||||
// MyType = TypedDict('MyType', {'a': int, 'b': str}, a=int, b=str)
|
||||
if let Some(dict) = args.get(1) {
|
||||
let total = get_total_from_only_keyword(keywords);
|
||||
let total = get_total_from_only_keyword(keywords).cloned();
|
||||
match &dict.node {
|
||||
ExprKind::Dict { keys, values } => {
|
||||
Ok((get_properties_from_dict_literal(keys, values)?, total))
|
||||
@@ -188,15 +193,21 @@ fn get_properties_and_total(
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a `Fix` to convert a `TypedDict` to a functional class.
|
||||
fn convert_to_functional_class(
|
||||
/// Generate a `Fix` to convert a `TypedDict` from functional to class.
|
||||
fn convert_to_class(
|
||||
stmt: &Stmt,
|
||||
class_name: &str,
|
||||
body: Vec<Stmt>,
|
||||
total_keyword: Option<KeywordData>,
|
||||
base_class: &ExprKind,
|
||||
) -> Result<Fix> {
|
||||
let mut generator = SourceGenerator::new();
|
||||
generator.unparse_stmt(&create_class_def_stmt(class_name, body, total_keyword))?;
|
||||
generator.unparse_stmt(&create_class_def_stmt(
|
||||
class_name,
|
||||
body,
|
||||
total_keyword,
|
||||
base_class,
|
||||
))?;
|
||||
let content = generator.generate()?;
|
||||
Ok(Fix::replacement(
|
||||
content,
|
||||
@@ -212,16 +223,18 @@ pub fn convert_typed_dict_functional_to_class(
|
||||
targets: &[Expr],
|
||||
value: &Expr,
|
||||
) {
|
||||
if let Some((class_name, args, keywords)) = match_typed_dict_assign(targets, value) {
|
||||
if let Some((class_name, args, keywords, base_class)) =
|
||||
match_typed_dict_assign(checker, targets, value)
|
||||
{
|
||||
match get_properties_and_total(args, keywords) {
|
||||
Err(err) => error!("Failed to parse TypedDict: {}", err),
|
||||
Ok((body, total_keyword)) => {
|
||||
let mut check = Check::new(
|
||||
CheckKind::ConvertTypedDictFunctionalToClass,
|
||||
CheckKind::ConvertTypedDictFunctionalToClass(class_name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
match convert_to_functional_class(stmt, class_name, body, total_keyword) {
|
||||
match convert_to_class(stmt, class_name, body, total_keyword, base_class) {
|
||||
Ok(fix) => check.amend(fix),
|
||||
Err(err) => error!("Failed to convert TypedDict: {}", err),
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub use convert_named_tuple_functional_to_class::convert_named_tuple_functional_to_class;
|
||||
pub use convert_typed_dict_functional_to_class::convert_typed_dict_functional_to_class;
|
||||
pub use deprecated_unittest_alias::deprecated_unittest_alias;
|
||||
pub use super_call_with_parameters::super_call_with_parameters;
|
||||
@@ -10,6 +11,7 @@ pub use use_pep604_annotation::use_pep604_annotation;
|
||||
pub use useless_metaclass_type::useless_metaclass_type;
|
||||
pub use useless_object_inheritance::useless_object_inheritance;
|
||||
|
||||
mod convert_named_tuple_functional_to_class;
|
||||
mod convert_typed_dict_functional_to_class;
|
||||
mod deprecated_unittest_alias;
|
||||
mod super_call_with_parameters;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::pyupgrade::{checks, fixes};
|
||||
use crate::pyupgrade::checks;
|
||||
|
||||
/// U011
|
||||
pub fn unnecessary_lru_cache_params(checker: &mut Checker, decorator_list: &[Expr]) {
|
||||
@@ -12,11 +13,7 @@ pub fn unnecessary_lru_cache_params(checker: &mut Checker, decorator_list: &[Exp
|
||||
&checker.import_aliases,
|
||||
) {
|
||||
if checker.patch(check.kind.code()) {
|
||||
if let Some(fix) =
|
||||
fixes::remove_unnecessary_lru_cache_params(checker.locator, &check.location)
|
||||
{
|
||||
check.amend(fix);
|
||||
}
|
||||
check.amend(Fix::deletion(check.location, check.end_location));
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
|
||||
@@ -90,4 +90,28 @@ expression: checks
|
||||
row: 170
|
||||
column: 48
|
||||
fix: ~
|
||||
- kind: MutableArgumentDefault
|
||||
location:
|
||||
row: 203
|
||||
column: 26
|
||||
end_location:
|
||||
row: 203
|
||||
column: 28
|
||||
fix: ~
|
||||
- kind: MutableArgumentDefault
|
||||
location:
|
||||
row: 204
|
||||
column: 34
|
||||
end_location:
|
||||
row: 204
|
||||
column: 36
|
||||
fix: ~
|
||||
- kind: MutableArgumentDefault
|
||||
location:
|
||||
row: 205
|
||||
column: 61
|
||||
end_location:
|
||||
row: 205
|
||||
column: 66
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -9,7 +9,16 @@ expression: checks
|
||||
end_location:
|
||||
row: 33
|
||||
column: 25
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: foo.bar = None
|
||||
location:
|
||||
row: 33
|
||||
column: 0
|
||||
end_location:
|
||||
row: 33
|
||||
column: 25
|
||||
applied: false
|
||||
- kind: SetAttrWithConstant
|
||||
location:
|
||||
row: 34
|
||||
@@ -17,7 +26,16 @@ expression: checks
|
||||
end_location:
|
||||
row: 34
|
||||
column: 29
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: foo._123abc = None
|
||||
location:
|
||||
row: 34
|
||||
column: 0
|
||||
end_location:
|
||||
row: 34
|
||||
column: 29
|
||||
applied: false
|
||||
- kind: SetAttrWithConstant
|
||||
location:
|
||||
row: 35
|
||||
@@ -25,7 +43,16 @@ expression: checks
|
||||
end_location:
|
||||
row: 35
|
||||
column: 28
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: foo.abc123 = None
|
||||
location:
|
||||
row: 35
|
||||
column: 0
|
||||
end_location:
|
||||
row: 35
|
||||
column: 28
|
||||
applied: false
|
||||
- kind: SetAttrWithConstant
|
||||
location:
|
||||
row: 36
|
||||
@@ -33,5 +60,31 @@ expression: checks
|
||||
end_location:
|
||||
row: 36
|
||||
column: 29
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: foo.abc123 = None
|
||||
location:
|
||||
row: 36
|
||||
column: 0
|
||||
end_location:
|
||||
row: 36
|
||||
column: 29
|
||||
applied: false
|
||||
- kind: SetAttrWithConstant
|
||||
location:
|
||||
row: 37
|
||||
column: 0
|
||||
end_location:
|
||||
row: 37
|
||||
column: 30
|
||||
fix:
|
||||
patch:
|
||||
content: foo.bar.baz = None
|
||||
location:
|
||||
row: 37
|
||||
column: 0
|
||||
end_location:
|
||||
row: 37
|
||||
column: 30
|
||||
applied: false
|
||||
|
||||
|
||||
@@ -9,7 +9,16 @@ expression: checks
|
||||
end_location:
|
||||
row: 2
|
||||
column: 19
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: "def f(x):\n return (2 * x)"
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
end_location:
|
||||
row: 2
|
||||
column: 19
|
||||
applied: false
|
||||
- kind: DoNotAssignLambda
|
||||
location:
|
||||
row: 4
|
||||
@@ -17,7 +26,16 @@ expression: checks
|
||||
end_location:
|
||||
row: 4
|
||||
column: 19
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: "def f(x):\n return (2 * x)"
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 19
|
||||
applied: false
|
||||
- kind: DoNotAssignLambda
|
||||
location:
|
||||
row: 7
|
||||
@@ -25,5 +43,14 @@ expression: checks
|
||||
end_location:
|
||||
row: 7
|
||||
column: 29
|
||||
fix: ~
|
||||
fix:
|
||||
patch:
|
||||
content: "def this(y, z):\n return (2 * x)"
|
||||
location:
|
||||
row: 7
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
column: 29
|
||||
applied: false
|
||||
|
||||
|
||||
@@ -47,4 +47,13 @@ expression: checks
|
||||
row: 21
|
||||
column: 9
|
||||
fix: ~
|
||||
- kind:
|
||||
UnusedVariable: b
|
||||
location:
|
||||
row: 51
|
||||
column: 8
|
||||
end_location:
|
||||
row: 51
|
||||
column: 9
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 5
|
||||
column: 1
|
||||
column: 10
|
||||
end_location:
|
||||
row: 5
|
||||
column: 12
|
||||
@@ -22,7 +22,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 11
|
||||
column: 1
|
||||
column: 20
|
||||
end_location:
|
||||
row: 11
|
||||
column: 22
|
||||
@@ -39,7 +39,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 16
|
||||
column: 1
|
||||
column: 10
|
||||
end_location:
|
||||
row: 16
|
||||
column: 24
|
||||
@@ -56,7 +56,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 21
|
||||
column: 1
|
||||
column: 20
|
||||
end_location:
|
||||
row: 21
|
||||
column: 34
|
||||
@@ -73,7 +73,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 27
|
||||
column: 1
|
||||
column: 10
|
||||
end_location:
|
||||
row: 28
|
||||
column: 1
|
||||
@@ -90,7 +90,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 33
|
||||
column: 1
|
||||
column: 10
|
||||
end_location:
|
||||
row: 35
|
||||
column: 1
|
||||
@@ -107,7 +107,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 40
|
||||
column: 1
|
||||
column: 20
|
||||
end_location:
|
||||
row: 42
|
||||
column: 19
|
||||
@@ -124,7 +124,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 47
|
||||
column: 1
|
||||
column: 20
|
||||
end_location:
|
||||
row: 51
|
||||
column: 1
|
||||
@@ -141,7 +141,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 56
|
||||
column: 1
|
||||
column: 20
|
||||
end_location:
|
||||
row: 62
|
||||
column: 1
|
||||
@@ -158,7 +158,7 @@ expression: checks
|
||||
- kind: UnnecessaryLRUCacheParams
|
||||
location:
|
||||
row: 67
|
||||
column: 1
|
||||
column: 20
|
||||
end_location:
|
||||
row: 72
|
||||
column: 1
|
||||
|
||||
@@ -2,157 +2,184 @@
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType1
|
||||
location:
|
||||
row: 4
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
row: 5
|
||||
column: 52
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType1(TypedDict):\n a: int\n b: str"
|
||||
location:
|
||||
row: 4
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
row: 5
|
||||
column: 52
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType2
|
||||
location:
|
||||
row: 7
|
||||
row: 8
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
row: 8
|
||||
column: 50
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType2(TypedDict):\n a: int\n b: str"
|
||||
location:
|
||||
row: 7
|
||||
row: 8
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
row: 8
|
||||
column: 50
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType3
|
||||
location:
|
||||
row: 10
|
||||
row: 11
|
||||
column: 0
|
||||
end_location:
|
||||
row: 10
|
||||
row: 11
|
||||
column: 44
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType3(TypedDict):\n a: int\n b: str"
|
||||
location:
|
||||
row: 10
|
||||
row: 11
|
||||
column: 0
|
||||
end_location:
|
||||
row: 10
|
||||
row: 11
|
||||
column: 44
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType4
|
||||
location:
|
||||
row: 13
|
||||
row: 14
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
row: 14
|
||||
column: 30
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType4(TypedDict):\n pass"
|
||||
location:
|
||||
row: 13
|
||||
row: 14
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
row: 14
|
||||
column: 30
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType5
|
||||
location:
|
||||
row: 16
|
||||
row: 17
|
||||
column: 0
|
||||
end_location:
|
||||
row: 16
|
||||
row: 17
|
||||
column: 46
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType5(TypedDict):\n a: 'hello'"
|
||||
location:
|
||||
row: 16
|
||||
row: 17
|
||||
column: 0
|
||||
end_location:
|
||||
row: 16
|
||||
row: 17
|
||||
column: 46
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType6
|
||||
location:
|
||||
row: 17
|
||||
row: 18
|
||||
column: 0
|
||||
end_location:
|
||||
row: 17
|
||||
row: 18
|
||||
column: 41
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType6(TypedDict):\n a: 'hello'"
|
||||
location:
|
||||
row: 17
|
||||
row: 18
|
||||
column: 0
|
||||
end_location:
|
||||
row: 17
|
||||
row: 18
|
||||
column: 41
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType7
|
||||
location:
|
||||
row: 20
|
||||
row: 21
|
||||
column: 0
|
||||
end_location:
|
||||
row: 20
|
||||
row: 21
|
||||
column: 56
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType7(TypedDict):\n a: NotRequired[dict]"
|
||||
location:
|
||||
row: 20
|
||||
row: 21
|
||||
column: 0
|
||||
end_location:
|
||||
row: 20
|
||||
row: 21
|
||||
column: 56
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType8
|
||||
location:
|
||||
row: 23
|
||||
row: 24
|
||||
column: 0
|
||||
end_location:
|
||||
row: 23
|
||||
row: 24
|
||||
column: 65
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType8(TypedDict, total=False):\n x: int\n y: int"
|
||||
location:
|
||||
row: 23
|
||||
row: 24
|
||||
column: 0
|
||||
end_location:
|
||||
row: 23
|
||||
row: 24
|
||||
column: 65
|
||||
applied: false
|
||||
- kind: ConvertTypedDictFunctionalToClass
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType10
|
||||
location:
|
||||
row: 29
|
||||
row: 30
|
||||
column: 0
|
||||
end_location:
|
||||
row: 29
|
||||
row: 30
|
||||
column: 59
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType10(TypedDict):\n key: Literal['value']"
|
||||
location:
|
||||
row: 29
|
||||
row: 30
|
||||
column: 0
|
||||
end_location:
|
||||
row: 29
|
||||
row: 30
|
||||
column: 59
|
||||
applied: false
|
||||
- kind:
|
||||
ConvertTypedDictFunctionalToClass: MyType11
|
||||
location:
|
||||
row: 33
|
||||
column: 0
|
||||
end_location:
|
||||
row: 33
|
||||
column: 53
|
||||
fix:
|
||||
patch:
|
||||
content: "class MyType11(typing.TypedDict):\n key: int"
|
||||
location:
|
||||
row: 33
|
||||
column: 0
|
||||
end_location:
|
||||
row: 33
|
||||
column: 53
|
||||
applied: false
|
||||
|
||||
|
||||
59
src/snapshots/ruff__linter__tests__U014_U014.py.snap
Normal file
59
src/snapshots/ruff__linter__tests__U014_U014.py.snap
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
ConvertNamedTupleFunctionalToClass: NT1
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 5
|
||||
column: 61
|
||||
fix:
|
||||
patch:
|
||||
content: "class NT1(NamedTuple):\n a: int\n b: tuple[str, ...]"
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 5
|
||||
column: 61
|
||||
applied: false
|
||||
- kind:
|
||||
ConvertNamedTupleFunctionalToClass: NT2
|
||||
location:
|
||||
row: 8
|
||||
column: 0
|
||||
end_location:
|
||||
row: 12
|
||||
column: 1
|
||||
fix:
|
||||
patch:
|
||||
content: "class NT2(NamedTuple):\n a: int\n b: str = 'foo'\n c: list[bool] = [True]"
|
||||
location:
|
||||
row: 8
|
||||
column: 0
|
||||
end_location:
|
||||
row: 12
|
||||
column: 1
|
||||
applied: false
|
||||
- kind:
|
||||
ConvertNamedTupleFunctionalToClass: NT3
|
||||
location:
|
||||
row: 15
|
||||
column: 0
|
||||
end_location:
|
||||
row: 15
|
||||
column: 56
|
||||
fix:
|
||||
patch:
|
||||
content: "class NT3(typing.NamedTuple):\n a: int\n b: str"
|
||||
location:
|
||||
row: 15
|
||||
column: 0
|
||||
end_location:
|
||||
row: 15
|
||||
column: 56
|
||||
applied: false
|
||||
|
||||
@@ -65,4 +65,13 @@ expression: checks
|
||||
row: 37
|
||||
column: 14
|
||||
fix: ~
|
||||
- kind:
|
||||
UnusedVariable: b
|
||||
location:
|
||||
row: 51
|
||||
column: 8
|
||||
end_location:
|
||||
row: 51
|
||||
column: 9
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ expression: checks
|
||||
UnusedNOQA: ~
|
||||
location:
|
||||
row: 9
|
||||
column: 9
|
||||
column: 11
|
||||
end_location:
|
||||
row: 9
|
||||
column: 17
|
||||
@@ -25,7 +25,7 @@ expression: checks
|
||||
- E501
|
||||
location:
|
||||
row: 13
|
||||
column: 9
|
||||
column: 11
|
||||
end_location:
|
||||
row: 13
|
||||
column: 23
|
||||
@@ -45,7 +45,7 @@ expression: checks
|
||||
- E501
|
||||
location:
|
||||
row: 16
|
||||
column: 9
|
||||
column: 11
|
||||
end_location:
|
||||
row: 16
|
||||
column: 29
|
||||
@@ -61,16 +61,17 @@ expression: checks
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- F841
|
||||
- W191
|
||||
location:
|
||||
row: 19
|
||||
column: 9
|
||||
column: 11
|
||||
end_location:
|
||||
row: 19
|
||||
column: 29
|
||||
fix:
|
||||
patch:
|
||||
content: " # noqa: F841"
|
||||
content: ""
|
||||
location:
|
||||
row: 19
|
||||
column: 9
|
||||
@@ -78,60 +79,107 @@ expression: checks
|
||||
row: 19
|
||||
column: 29
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- E501
|
||||
location:
|
||||
row: 23
|
||||
column: 9
|
||||
end_location:
|
||||
row: 23
|
||||
column: 21
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 23
|
||||
column: 9
|
||||
end_location:
|
||||
row: 23
|
||||
column: 21
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedVariable: d
|
||||
location:
|
||||
row: 26
|
||||
column: 4
|
||||
end_location:
|
||||
row: 26
|
||||
column: 5
|
||||
fix: ~
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- E501
|
||||
location:
|
||||
row: 26
|
||||
column: 32
|
||||
end_location:
|
||||
row: 26
|
||||
column: 44
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 26
|
||||
column: 9
|
||||
end_location:
|
||||
row: 26
|
||||
column: 44
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- F841
|
||||
location:
|
||||
row: 44
|
||||
column: 3
|
||||
row: 52
|
||||
column: 5
|
||||
end_location:
|
||||
row: 44
|
||||
row: 52
|
||||
column: 23
|
||||
fix:
|
||||
patch:
|
||||
content: " # noqa: E501"
|
||||
content: "# noqa: E501"
|
||||
location:
|
||||
row: 44
|
||||
column: 3
|
||||
row: 52
|
||||
column: 5
|
||||
end_location:
|
||||
row: 44
|
||||
row: 52
|
||||
column: 23
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA:
|
||||
- E501
|
||||
location:
|
||||
row: 52
|
||||
column: 3
|
||||
row: 60
|
||||
column: 5
|
||||
end_location:
|
||||
row: 52
|
||||
row: 60
|
||||
column: 17
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 52
|
||||
row: 60
|
||||
column: 3
|
||||
end_location:
|
||||
row: 52
|
||||
row: 60
|
||||
column: 17
|
||||
applied: false
|
||||
- kind:
|
||||
UnusedNOQA: ~
|
||||
location:
|
||||
row: 60
|
||||
column: 3
|
||||
row: 68
|
||||
column: 5
|
||||
end_location:
|
||||
row: 60
|
||||
row: 68
|
||||
column: 11
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 60
|
||||
row: 68
|
||||
column: 3
|
||||
end_location:
|
||||
row: 60
|
||||
row: 68
|
||||
column: 11
|
||||
applied: false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user