From aa9b4688b978c3dca712b8e4a7905b4e6e59aaa1 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sat, 9 Mar 2024 09:39:17 +0100 Subject: [PATCH 01/77] use rust to fetch imports; wip --- Cargo.lock | 867 +++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 13 + main.py | 12 + pyproject.toml | 8 +- src/lib.rs | 105 ++++++ 5 files changed, 1003 insertions(+), 2 deletions(-) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 main.py create mode 100644 src/lib.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..105add60 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,867 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + +[[package]] +name = "anyhow" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "deptryrs" +version = "0.1.0" +dependencies = [ + "pyo3", + "rustpython-parser", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "embed-doc-image" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af36f591236d9d822425cb6896595658fa558fcebf5ee8accac1d4b92c47166e" +dependencies = [ + "base64", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "indoc" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" + +[[package]] +name = "is-macro" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7d079e129b77477a49c5c4f1cfe9ce6c2c909ef52520693e8e811a714c7b20" +dependencies = [ + "Inflector", + "pmutil", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "malachite" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6cf7f4730c30071ba374fac86ad35b1cb7a0716f774737768667ea3fa1828e3" +dependencies = [ + "malachite-base", + "malachite-nz", + "malachite-q", +] + +[[package]] +name = "malachite-base" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b06bfa98a4b4802af5a4263b4ad4660e28e51e8490f6354eb9336c70767e1c5" +dependencies = [ + "itertools 0.9.0", + "rand 0.7.3", + "rand_chacha", + "ryu", + "sha3", +] + +[[package]] +name = "malachite-bigint" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a5110aee54537b0cef214efbebdd7df79b7408db8eef4f6a4b6db9d0d8fc01b" +dependencies = [ + "derive_more", + "malachite", + "num-integer", + "num-traits", + "paste", +] + +[[package]] +name = "malachite-nz" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e21c64b7af5be3dc8cef16f786243faf59459fe4ba93b44efdeb264e5ade4" +dependencies = [ + "embed-doc-image", + "itertools 0.9.0", + "malachite-base", +] + +[[package]] +name = "malachite-q" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3755e541d5134b5016594c9043094172c4dda9259b3ce824a7b8101941850360" +dependencies = [ + "itertools 0.9.0", + "malachite-base", + "malachite-nz", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pmutil" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3894e5d549cccbe44afecf72922f277f603cd4bb0219c8342631ef18fffbe004" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pyo3" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53bdbb96d49157e65d45cc287af5f32ffadd5f4761438b527b055fb0d4bb8233" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "parking_lot", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deaa5745de3f5231ce10517a1f5dd97d53e5a2fd77aa6b5842292085831d48d7" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b42531d03e08d4ef1f6e85a2ed422eb678b8cd62b762e53891c05faf0d4afa" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7305c720fa01b8055ec95e484a6eca7a83c841267f0dd5280f0c8b8551d2c158" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c7e9b68bb9c3149c5b0cade5d07f953d6d125eb4337723c4ccdb665f1f96185" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustpython-ast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf9438da3660e6b88bd659fdc0cd13bcff4b85c584026a48b800c75bf0f8d00" +dependencies = [ + "is-macro", + "malachite-bigint", + "rustpython-parser-core", + "static_assertions", +] + +[[package]] +name = "rustpython-parser" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9db993974ff12f33c5be8a801741463691502f85ead5c503277937c4077bd92a" +dependencies = [ + "anyhow", + "is-macro", + "itertools 0.10.5", + "lalrpop-util", + "log", + "malachite-bigint", + "num-traits", + "phf", + "phf_codegen", + "rustc-hash", + "rustpython-ast", + "rustpython-parser-core", + "tiny-keccak", + "unic-emoji-char", + "unic-ucd-ident", + "unicode_names2", +] + +[[package]] +name = "rustpython-parser-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9d560c6dd4dc774d4bbad48c770e074c178c4ed5f6fd0521fcdb639af21bdd" +dependencies = [ + "is-macro", + "memchr", + "rustpython-parser-vendored", +] + +[[package]] +name = "rustpython-parser-vendored" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ae3062d7fe5fe38073f3a1c7145ed9a04e15f6e4a596d642c7db2d5cd2b51b" +dependencies = [ + "memchr", + "once_cell", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer", + "digest", + "keccak", + "opaque-debug", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-emoji-char" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode_names2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446c96c6dd42604779487f0a981060717156648c1706aa1f464677f03c6cc059" + +[[package]] +name = "unindent" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..a0037dcc --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "deptryrs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "deptryrs" +crate-type = ["cdylib"] + +[dependencies] +pyo3 = "0.20.0" +rustpython-parser = "0.3.0" diff --git a/main.py b/main.py new file mode 100644 index 00000000..8fb65435 --- /dev/null +++ b/main.py @@ -0,0 +1,12 @@ +# ruff: noqa + +from __future__ import annotations + +from deptryrs import get_imports_from_file + +try: + ast = get_imports_from_file("deptry/utils.py") + print(ast) +except Exception as e: # It will catch the PyIOError thrown by Rust + print(type(e)) + print(e) diff --git a/pyproject.toml b/pyproject.toml index 16206565..64b20ef0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,10 @@ classifiers = [ "Topic :: Software Development :: Quality Assurance", ] +[tool.maturin] +python-source = "deptry" +features = ["pyo3/extension-module"] + [tool.poetry.dependencies] python = ">=3.8,<4.0" chardet = ">=4.0.0" @@ -44,8 +48,8 @@ types-chardet = "5.0.4.6" types-colorama = { version = "0.4.15.20240205", markers = "sys_platform == 'win32'" } [build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +requires = ["maturin>=1.5,<2.0"] +build-backend = "maturin" [tool.coverage.report] skip_empty = true diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..df183ddf --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,105 @@ +use pyo3::prelude::*; +use pyo3::exceptions::{PyFileNotFoundError, PyIOError, PySyntaxError}; +use rustpython_parser::{ast, parse, Mode, text_size}; +use std::collections::HashMap; +use std::fs; + + +use std::io::ErrorKind; + +#[pyfunction] +fn get_imports_from_file(file_path: String) -> PyResult { + let ast: ast::Mod = get_ast_from_file(file_path.clone())?; + let imported_modules = extract_imports_from_ast(ast, &file_path); + + // Print the imported modules in a readable multi-line format + println!("{:#?}", imported_modules); + // Convert the HashMap debug representation to a String + let imports_str = format!("{:#?}", imported_modules); + // Return the string representation of imported modules + Ok(imports_str) +} + +/// Read a file and return its contents as a String. +fn read_file(file_path: String) -> PyResult { + let file_content: PyResult = fs::read_to_string(&file_path) + .map_err(|e| { + if e.kind() == ErrorKind::NotFound { + PyFileNotFoundError::new_err(format!("File not found: '{}'", file_path)) + } else { + PyIOError::new_err(format!("An error occured: '{}'", e)) + } + }); + return file_content +} + +/// Read a Python file, and return it as an AST, +fn get_ast_from_file(file_path: String) -> PyResult { + let file_content: String = read_file(file_path.clone())?; + let file_content_slice: &str = &file_content; + + let ast: ast::Mod = parse(&file_content_slice, Mode::Module, "") + .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e)))?; + return Ok(ast); +} + +#[derive(Debug, Clone)] +struct Location { + file: String, + lineno: usize, + col_offset: usize, +} + +struct ImportVisitor { + imports: HashMap>, + file_path: String, + phantom: std::marker::PhantomData, +} + +impl ImportVisitor { + fn new(file_path: String) -> Self { + ImportVisitor { + imports: HashMap::new(), + file_path, + phantom: std::marker::PhantomData, + } + } +} + +impl ast:: for ImportVisitor { + fn visit_stmt_import(&mut self, node: ast::StmtImport) { + for alias in &node.names { + let name = alias.name.split('.').next().unwrap_or_default().to_string(); + self.imports.entry(name).or_default().push(Location { + file: self.file_path.clone(), + lineno: alias.location.row(), + col_offset: alias.location.column(), + }); + } + } + + fn visit_stmt_import_from(&mut self, node: StmtImportFrom) { + let module_name = node.module.as_ref().map_or("", String::as_str).split('.').next().unwrap_or_default().to_string(); + for alias in &node.names { + let name = if module_name.is_empty() { + alias.name.clone() + } else { + format!("{}.{}", module_name, alias.name) + }; + self.imports.entry(name).or_default().push(Location { + file: self.file_path.clone(), + lineno: alias.location.row(), + col_offset: alias.location.column(), + }); + } + } +} + + + +/// A Python module implemented in Rust. +#[pymodule] +fn deptryrs(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_function(wrap_pyfunction!(get_imports_from_file, m)?)?; + Ok(()) +} From 0f8366dd704c00b0e1a0ba9a5234573df8dd180a Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sat, 9 Mar 2024 10:42:29 +0100 Subject: [PATCH 02/77] Now, we print all imports to console --- Cargo.lock | 1 + Cargo.toml | 1 + src/lib.rs | 105 +++++++++++++++--------------------------------- src/location.rs | 8 ++++ src/visitor.rs | 53 ++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 72 deletions(-) create mode 100644 src/location.rs create mode 100644 src/visitor.rs diff --git a/Cargo.lock b/Cargo.lock index 105add60..80474da3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,7 @@ name = "deptryrs" version = "0.1.0" dependencies = [ "pyo3", + "rustpython-ast", "rustpython-parser", ] diff --git a/Cargo.toml b/Cargo.toml index a0037dcc..8ad2bcc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,4 +10,5 @@ crate-type = ["cdylib"] [dependencies] pyo3 = "0.20.0" +rustpython-ast = { version = "0.3.0", features = ["visitor"] } rustpython-parser = "0.3.0" diff --git a/src/lib.rs b/src/lib.rs index df183ddf..13dc7b3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,19 +1,24 @@ use pyo3::prelude::*; use pyo3::exceptions::{PyFileNotFoundError, PyIOError, PySyntaxError}; -use rustpython_parser::{ast, parse, Mode, text_size}; +use rustpython_parser::{parse, Mode}; +use rustpython_ast::{Mod, Stmt}; use std::collections::HashMap; use std::fs; - use std::io::ErrorKind; +mod visitor; +use visitor::ImportVisitor; +mod location; +use location::Location; +use rustpython_ast::Visitor; + + #[pyfunction] fn get_imports_from_file(file_path: String) -> PyResult { - let ast: ast::Mod = get_ast_from_file(file_path.clone())?; + let ast: Mod = get_ast_from_file(&file_path)?; let imported_modules = extract_imports_from_ast(ast, &file_path); - // Print the imported modules in a readable multi-line format - println!("{:#?}", imported_modules); // Convert the HashMap debug representation to a String let imports_str = format!("{:#?}", imported_modules); // Return the string representation of imported modules @@ -21,81 +26,37 @@ fn get_imports_from_file(file_path: String) -> PyResult { } /// Read a file and return its contents as a String. -fn read_file(file_path: String) -> PyResult { - let file_content: PyResult = fs::read_to_string(&file_path) - .map_err(|e| { - if e.kind() == ErrorKind::NotFound { - PyFileNotFoundError::new_err(format!("File not found: '{}'", file_path)) - } else { - PyIOError::new_err(format!("An error occured: '{}'", e)) - } - }); - return file_content +fn read_file(file_path: &str) -> PyResult { + fs::read_to_string(file_path) + .map_err(|e| { + if e.kind() == ErrorKind::NotFound { + PyFileNotFoundError::new_err(format!("File not found: '{}'", file_path)) + } else { + PyIOError::new_err(format!("An error occured: '{}'", e)) + } + }) } /// Read a Python file, and return it as an AST, -fn get_ast_from_file(file_path: String) -> PyResult { - let file_content: String = read_file(file_path.clone())?; - let file_content_slice: &str = &file_content; - - let ast: ast::Mod = parse(&file_content_slice, Mode::Module, "") - .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e)))?; - return Ok(ast); -} - -#[derive(Debug, Clone)] -struct Location { - file: String, - lineno: usize, - col_offset: usize, -} - -struct ImportVisitor { - imports: HashMap>, - file_path: String, - phantom: std::marker::PhantomData, +fn get_ast_from_file(file_path: &str) -> PyResult { + let file_content: String = read_file(file_path)?; + parse(&file_content, Mode::Module, file_path) + .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e))) } -impl ImportVisitor { - fn new(file_path: String) -> Self { - ImportVisitor { - imports: HashMap::new(), - file_path, - phantom: std::marker::PhantomData, - } - } -} - -impl ast:: for ImportVisitor { - fn visit_stmt_import(&mut self, node: ast::StmtImport) { - for alias in &node.names { - let name = alias.name.split('.').next().unwrap_or_default().to_string(); - self.imports.entry(name).or_default().push(Location { - file: self.file_path.clone(), - lineno: alias.location.row(), - col_offset: alias.location.column(), - }); - } - } +fn extract_imports_from_ast(ast: Mod, file_path: &str) { + let mut visitor = ImportVisitor::new(file_path.to_string()); - fn visit_stmt_import_from(&mut self, node: StmtImportFrom) { - let module_name = node.module.as_ref().map_or("", String::as_str).split('.').next().unwrap_or_default().to_string(); - for alias in &node.names { - let name = if module_name.is_empty() { - alias.name.clone() - } else { - format!("{}.{}", module_name, alias.name) - }; - self.imports.entry(name).or_default().push(Location { - file: self.file_path.clone(), - lineno: alias.location.row(), - col_offset: alias.location.column(), - }); + match ast { + Mod::Module(module) => { + for stmt in module.body + { + visitor.visit_stmt(stmt); + } + }, + _ => {} } } -} - - /// A Python module implemented in Rust. #[pymodule] diff --git a/src/location.rs b/src/location.rs new file mode 100644 index 00000000..60f9d8d5 --- /dev/null +++ b/src/location.rs @@ -0,0 +1,8 @@ + +#[derive(Debug)] +#[derive(Clone)] +pub struct Location { + file: String, + lineno: usize, + col_offset: usize, +} diff --git a/src/visitor.rs b/src/visitor.rs new file mode 100644 index 00000000..304fe273 --- /dev/null +++ b/src/visitor.rs @@ -0,0 +1,53 @@ +use rustpython_ast::{ + self, Visitor, StmtImport, StmtImportFrom, Stmt, Mod, +}; +use std::collections::HashMap; +use crate::location::Location; + +#[derive(Debug, Clone)] + + +pub struct ImportVisitor { + imports: HashMap>, + file_path: String, +} + +impl ImportVisitor { + pub fn new(file_path: String) -> Self { + ImportVisitor { + imports: HashMap::new(), + file_path, + } + } +} + +impl Visitor for ImportVisitor { + // Override this method to handle 'import' statements. + fn visit_stmt_import(&mut self, node: StmtImport) { + println!("{:#?}", node); + // for alias in &node.names { + // let location = Location { + // file: self.file_path.clone(), + // lineno: node.location.row(), + // col_offset: node.location.column(), + // }; + // self.imports.entry(alias.symbol.clone()).or_default().push(location); + // } + } + + // Override this method to handle 'import from' statements. + fn visit_stmt_import_from(&mut self, node: StmtImportFrom) { + println!("{:#?}", node); + // if let Some(module) = &node.module { + // for alias in &node.names { + // let full_name = format!("{}.{}", module.join("."), alias.symbol); + // let location = Location { + // file: self.file_path.clone(), + // lineno: node.location.row(), + // col_offset: node.location.column(), + // }; + // self.imports.entry(full_name).or_default().push(location); + // } + // } + } +} From 815a9cff890ab5b86a3ac93ad7928dac41d79e2a Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sat, 9 Mar 2024 11:11:25 +0100 Subject: [PATCH 03/77] working draft that returns ranges --- src/lib.rs | 31 +++++++++++++++---------------- src/location.rs | 2 +- src/visitor.rs | 48 +++++++++++++++++++++--------------------------- 3 files changed, 37 insertions(+), 44 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 13dc7b3b..a6659466 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ -use pyo3::prelude::*; use pyo3::exceptions::{PyFileNotFoundError, PyIOError, PySyntaxError}; -use rustpython_parser::{parse, Mode}; +use pyo3::prelude::*; use rustpython_ast::{Mod, Stmt}; +use rustpython_parser::{parse, Mode}; use std::collections::HashMap; use std::fs; @@ -12,7 +12,7 @@ use visitor::ImportVisitor; mod location; use location::Location; use rustpython_ast::Visitor; - +use rustpython_parser::text_size::TextRange; #[pyfunction] fn get_imports_from_file(file_path: String) -> PyResult { @@ -27,14 +27,13 @@ fn get_imports_from_file(file_path: String) -> PyResult { /// Read a file and return its contents as a String. fn read_file(file_path: &str) -> PyResult { - fs::read_to_string(file_path) - .map_err(|e| { - if e.kind() == ErrorKind::NotFound { - PyFileNotFoundError::new_err(format!("File not found: '{}'", file_path)) - } else { - PyIOError::new_err(format!("An error occured: '{}'", e)) - } - }) + fs::read_to_string(file_path).map_err(|e| { + if e.kind() == ErrorKind::NotFound { + PyFileNotFoundError::new_err(format!("File not found: '{}'", file_path)) + } else { + PyIOError::new_err(format!("An error occured: '{}'", e)) + } + }) } /// Read a Python file, and return it as an AST, @@ -44,19 +43,19 @@ fn get_ast_from_file(file_path: &str) -> PyResult { .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e))) } -fn extract_imports_from_ast(ast: Mod, file_path: &str) { +fn extract_imports_from_ast(ast: Mod, file_path: &str) -> HashMap> { let mut visitor = ImportVisitor::new(file_path.to_string()); match ast { Mod::Module(module) => { - for stmt in module.body - { + for stmt in module.body { visitor.visit_stmt(stmt); } - }, - _ => {} } + _ => {} } + visitor.get_imports() +} /// A Python module implemented in Rust. #[pymodule] diff --git a/src/location.rs b/src/location.rs index 60f9d8d5..42a206ef 100644 --- a/src/location.rs +++ b/src/location.rs @@ -3,6 +3,6 @@ #[derive(Clone)] pub struct Location { file: String, - lineno: usize, + range: usize, col_offset: usize, } diff --git a/src/visitor.rs b/src/visitor.rs index 304fe273..ed7701d3 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -1,14 +1,11 @@ -use rustpython_ast::{ - self, Visitor, StmtImport, StmtImportFrom, Stmt, Mod, -}; +use rustpython_ast::{self, Mod, Stmt, StmtImport, StmtImportFrom, Visitor}; +use rustpython_parser::text_size::TextRange; use std::collections::HashMap; -use crate::location::Location; #[derive(Debug, Clone)] - pub struct ImportVisitor { - imports: HashMap>, + imports: HashMap>, file_path: String, } @@ -19,35 +16,32 @@ impl ImportVisitor { file_path, } } + pub fn get_imports(self) -> HashMap> { + self.imports + } } impl Visitor for ImportVisitor { // Override this method to handle 'import' statements. fn visit_stmt_import(&mut self, node: StmtImport) { - println!("{:#?}", node); - // for alias in &node.names { - // let location = Location { - // file: self.file_path.clone(), - // lineno: node.location.row(), - // col_offset: node.location.column(), - // }; - // self.imports.entry(alias.symbol.clone()).or_default().push(location); - // } + // println!("{:#?}", node); + for alias in &node.names { + self.imports + .entry(alias.name.to_string()) + .or_default() + .push(alias.range); + } } // Override this method to handle 'import from' statements. fn visit_stmt_import_from(&mut self, node: StmtImportFrom) { - println!("{:#?}", node); - // if let Some(module) = &node.module { - // for alias in &node.names { - // let full_name = format!("{}.{}", module.join("."), alias.symbol); - // let location = Location { - // file: self.file_path.clone(), - // lineno: node.location.row(), - // col_offset: node.location.column(), - // }; - // self.imports.entry(full_name).or_default().push(location); - // } - // } + if let Some(module) = &node.module { + let module_name = module.to_string(); + let module_range = node.range; + self.imports + .entry(module_name) + .or_default() + .push(module_range); + } } } From d17607a28f9a6d97f6028c0f93c4fb6c15b80729 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sat, 9 Mar 2024 11:17:42 +0100 Subject: [PATCH 04/77] working draft that returns ranges --- src/lib.rs | 22 +++++++++++----------- src/visitor.rs | 9 +++------ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a6659466..61ae8e5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,10 +14,16 @@ use location::Location; use rustpython_ast::Visitor; use rustpython_parser::text_size::TextRange; +#[pymodule] +fn deptryrs(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_function(wrap_pyfunction!(get_imports_from_file, m)?)?; + Ok(()) +} + #[pyfunction] fn get_imports_from_file(file_path: String) -> PyResult { - let ast: Mod = get_ast_from_file(&file_path)?; - let imported_modules = extract_imports_from_ast(ast, &file_path); + let ast = get_ast_from_file(&file_path)?; + let imported_modules = extract_imports_from_ast(ast); // Convert the HashMap debug representation to a String let imports_str = format!("{:#?}", imported_modules); @@ -43,8 +49,9 @@ fn get_ast_from_file(file_path: &str) -> PyResult { .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e))) } -fn extract_imports_from_ast(ast: Mod, file_path: &str) -> HashMap> { - let mut visitor = ImportVisitor::new(file_path.to_string()); +/// Extract all imports from an AST +fn extract_imports_from_ast(ast: Mod) -> HashMap> { + let mut visitor = ImportVisitor::new(); match ast { Mod::Module(module) => { @@ -56,10 +63,3 @@ fn extract_imports_from_ast(ast: Mod, file_path: &str) -> HashMap PyResult<()> { - m.add_function(wrap_pyfunction!(get_imports_from_file, m)?)?; - Ok(()) -} diff --git a/src/visitor.rs b/src/visitor.rs index ed7701d3..9663b159 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -6,14 +6,14 @@ use std::collections::HashMap; pub struct ImportVisitor { imports: HashMap>, - file_path: String, } +/// Used to walk through an AST and extract all imported modules +/// It will return a HashMap, where each key is a module and the value is a vector of TextRanges. impl ImportVisitor { - pub fn new(file_path: String) -> Self { + pub fn new() -> Self { ImportVisitor { imports: HashMap::new(), - file_path, } } pub fn get_imports(self) -> HashMap> { @@ -22,9 +22,7 @@ impl ImportVisitor { } impl Visitor for ImportVisitor { - // Override this method to handle 'import' statements. fn visit_stmt_import(&mut self, node: StmtImport) { - // println!("{:#?}", node); for alias in &node.names { self.imports .entry(alias.name.to_string()) @@ -33,7 +31,6 @@ impl Visitor for ImportVisitor { } } - // Override this method to handle 'import from' statements. fn visit_stmt_import_from(&mut self, node: StmtImportFrom) { if let Some(module) = &node.module { let module_name = module.to_string(); From 0158164347a756c41fd553de0e2d879cb8b3857d Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sat, 9 Mar 2024 14:29:45 +0100 Subject: [PATCH 05/77] remove the PythonImportExtractor --- deptry/imports/extract.py | 16 ++-- deptry/imports/extractors/__init__.py | 8 +- .../extractors/python_import_extractor.py | 31 -------- main.py | 7 +- pyproject.toml | 1 + src/lib.rs | 74 ++++++++++++++++--- src/location.rs | 29 ++++++-- src/visitor.rs | 30 ++++++-- 8 files changed, 127 insertions(+), 69 deletions(-) delete mode 100644 deptry/imports/extractors/python_import_extractor.py diff --git a/deptry/imports/extract.py b/deptry/imports/extract.py index d195ab37..ff91eee5 100644 --- a/deptry/imports/extract.py +++ b/deptry/imports/extract.py @@ -4,12 +4,13 @@ from collections import defaultdict from typing import TYPE_CHECKING -from deptry.imports.extractors import NotebookImportExtractor, PythonImportExtractor +from deptryrs import get_imports_from_file + +from deptry.imports.extractors import NotebookImportExtractor if TYPE_CHECKING: from pathlib import Path - from deptry.imports.extractors.base import ImportExtractor from deptry.imports.location import Location @@ -31,14 +32,11 @@ def get_imported_modules_for_list_of_files(list_of_files: list[Path]) -> dict[st def get_imported_modules_from_file(path_to_file: Path) -> dict[str, list[Location]]: logging.debug("Scanning %s...", path_to_file) - modules = _get_extractor_class(path_to_file)(path_to_file).extract_imports() + if path_to_file.suffix == ".ipynb": + modules = NotebookImportExtractor(path_to_file).extract_imports() + elif path_to_file.suffix == ".py": + modules = get_imports_from_file(str(path_to_file)) logging.debug("Found the following imports in %s: %s", path_to_file, modules) return modules - - -def _get_extractor_class(path_to_file: Path) -> type[ImportExtractor]: - if path_to_file.suffix == ".ipynb": - return NotebookImportExtractor - return PythonImportExtractor diff --git a/deptry/imports/extractors/__init__.py b/deptry/imports/extractors/__init__.py index 3e7659fe..a9281cce 100644 --- a/deptry/imports/extractors/__init__.py +++ b/deptry/imports/extractors/__init__.py @@ -1,9 +1,3 @@ from __future__ import annotations -from deptry.imports.extractors.notebook_import_extractor import NotebookImportExtractor -from deptry.imports.extractors.python_import_extractor import PythonImportExtractor - -__all__ = ( - "NotebookImportExtractor", - "PythonImportExtractor", -) +__all__ = "NotebookImportExtractor" diff --git a/deptry/imports/extractors/python_import_extractor.py b/deptry/imports/extractors/python_import_extractor.py deleted file mode 100644 index e240e9d8..00000000 --- a/deptry/imports/extractors/python_import_extractor.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import annotations - -import ast -import logging -from dataclasses import dataclass -from typing import TYPE_CHECKING - -from deptry.imports.extractors.base import ImportExtractor - -if TYPE_CHECKING: - from deptry.imports.location import Location - - -@dataclass -class PythonImportExtractor(ImportExtractor): - """Extract import statements from a Python module.""" - - def extract_imports(self) -> dict[str, list[Location]]: - """Extract all imported top-level modules from the Python file.""" - try: - with self.file.open() as python_file: - tree = ast.parse(python_file.read(), str(self.file)) - except (SyntaxError, ValueError): - try: - with self.file.open(encoding=self._get_file_encoding(self.file)) as python_file: - tree = ast.parse(python_file.read(), str(self.file)) - except UnicodeDecodeError: - logging.warning("Warning: File %s could not be decoded. Skipping...", self.file) - return {} - - return self._extract_imports_from_ast(tree) diff --git a/main.py b/main.py index 8fb65435..2b36f33a 100644 --- a/main.py +++ b/main.py @@ -5,8 +5,11 @@ from deptryrs import get_imports_from_file try: - ast = get_imports_from_file("deptry/utils.py") - print(ast) + imports_with_locations = get_imports_from_file("deptry/utils.py") + for k, v in imports_with_locations.items(): + print(k) + print(v) + print(v[0].line + 1) except Exception as e: # It will catch the PyIOError thrown by Rust print(type(e)) print(e) diff --git a/pyproject.toml b/pyproject.toml index 64b20ef0..69b55768 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,7 @@ extend_exclude = [ "tests", "scripts", ] +known_first_party = ["deptryrs"] [tool.deptry.per_rule_ignores] DEP001 = ["tomllib"] diff --git a/src/lib.rs b/src/lib.rs index 61ae8e5a..aa9435e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,24 +11,31 @@ mod visitor; use visitor::ImportVisitor; mod location; use location::Location; +use pyo3::types::{PyDict, PyList}; +use pyo3::{PyObject, PyResult}; use rustpython_ast::Visitor; +use rustpython_parser::source_code::LineIndex; use rustpython_parser::text_size::TextRange; #[pymodule] fn deptryrs(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(get_imports_from_file, m)?)?; + m.add_class::()?; Ok(()) } #[pyfunction] -fn get_imports_from_file(file_path: String) -> PyResult { - let ast = get_ast_from_file(&file_path)?; +fn get_imports_from_file(py: Python<'_>, file_path: String) -> PyResult { + let file_content = read_file(&file_path)?; + let ast = get_ast_from_file_content(&file_content, &file_path)?; let imported_modules = extract_imports_from_ast(ast); - - // Convert the HashMap debug representation to a String - let imports_str = format!("{:#?}", imported_modules); - // Return the string representation of imported modules - Ok(imports_str) + let imports_with_locations = convert_imports_with_textranges_to_location_objects( + imported_modules, + &file_path, + &file_content, + ); + let imports_dict = convert_to_python_dict(py, imports_with_locations); + Ok(imports_dict) } /// Read a file and return its contents as a String. @@ -43,8 +50,7 @@ fn read_file(file_path: &str) -> PyResult { } /// Read a Python file, and return it as an AST, -fn get_ast_from_file(file_path: &str) -> PyResult { - let file_content: String = read_file(file_path)?; +fn get_ast_from_file_content(file_content: &str, file_path: &str) -> PyResult { parse(&file_content, Mode::Module, file_path) .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e))) } @@ -63,3 +69,53 @@ fn extract_imports_from_ast(ast: Mod) -> HashMap> { } visitor.get_imports() } + +/// Imports now have associated TextRanges, which is the amount of bytes since the start of the file. +/// This function takes thata s input, and converts it to imports with associated Location objects, +/// That carry information such as the file name, the line number, and the column offset. +fn convert_imports_with_textranges_to_location_objects( + imports: HashMap>, + file_path: &str, + source_code: &str, +) -> HashMap> { + let line_index = LineIndex::from_source_text(source_code); + let mut imports_with_locations = HashMap::>::new(); + + for (module, ranges) in imports { + let locations: Vec = ranges + .iter() + .map(|range| { + let start_line = line_index.line_index(range.start()).get() as usize; + let start_col = line_index + .source_location(range.start(), source_code) + .column + .get() as usize; + Location { + file: file_path.to_string(), + line: Some(start_line), + column: Some(start_col), + } + }) + .collect(); + imports_with_locations.insert(module, locations); + } + imports_with_locations +} + +fn convert_to_python_dict( + py: Python<'_>, + imports_with_locations: HashMap>, +) -> PyObject { + let imports_dict = PyDict::new(py); + + for (module, locations) in imports_with_locations { + let py_locations: Vec = locations + .into_iter() + .map(|location| location.into_py(py)) + .collect(); + let locations_list = PyList::new(py, &py_locations); + imports_dict.set_item(module, locations_list).unwrap(); + } + + imports_dict.into() +} diff --git a/src/location.rs b/src/location.rs index 42a206ef..c7e59d1b 100644 --- a/src/location.rs +++ b/src/location.rs @@ -1,8 +1,27 @@ +use pyo3::prelude::*; -#[derive(Debug)] -#[derive(Clone)] +#[pyclass] +#[derive(Clone, Debug)] pub struct Location { - file: String, - range: usize, - col_offset: usize, + #[pyo3(get, set)] + pub file: String, + #[pyo3(get, set)] + pub line: Option, + #[pyo3(get, set)] + pub column: Option, +} + +#[pymethods] +impl Location { + #[new] + pub fn new(file: String, line: Option, column: Option) -> Self { + Location { file, line, column } + } + + fn __repr__(&self) -> PyResult { + Ok(format!( + "Location(file='{}', line={:?}, column={:?})", + self.file, self.line, self.column + )) + } } diff --git a/src/visitor.rs b/src/visitor.rs index 9663b159..45c4d16d 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -1,21 +1,19 @@ -use rustpython_ast::{self, Mod, Stmt, StmtImport, StmtImportFrom, Visitor}; +use rustpython_ast::{self, StmtImport, StmtImportFrom, Visitor}; use rustpython_parser::text_size::TextRange; use std::collections::HashMap; #[derive(Debug, Clone)] - pub struct ImportVisitor { imports: HashMap>, } -/// Used to walk through an AST and extract all imported modules -/// It will return a HashMap, where each key is a module and the value is a vector of TextRanges. impl ImportVisitor { pub fn new() -> Self { ImportVisitor { imports: HashMap::new(), } } + pub fn get_imports(self) -> HashMap> { self.imports } @@ -24,8 +22,9 @@ impl ImportVisitor { impl Visitor for ImportVisitor { fn visit_stmt_import(&mut self, node: StmtImport) { for alias in &node.names { + let top_level_module = get_top_level_module_name(&alias.name.to_string()); self.imports - .entry(alias.name.to_string()) + .entry(top_level_module) .or_default() .push(alias.range); } @@ -34,11 +33,30 @@ impl Visitor for ImportVisitor { fn visit_stmt_import_from(&mut self, node: StmtImportFrom) { if let Some(module) = &node.module { let module_name = module.to_string(); + let top_level_module = get_top_level_module_name(&module_name); let module_range = node.range; self.imports - .entry(module_name) + .entry(top_level_module) .or_default() .push(module_range); } } } + +/// Extracts the top-level module name from a potentially nested module path. +/// e.g. when a module_name is `foo.bar`, this returns `foo`. +/// +/// # Arguments +/// +/// * `module_name` - The potentially nested module name. +/// +/// # Returns +/// +/// The top-level module name. +fn get_top_level_module_name(module_name: &str) -> String { + module_name + .split('.') + .next() + .unwrap_or(module_name) + .to_string() +} From 04aed3917992f4bab6ff8db32842694284130a4d Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sat, 9 Mar 2024 14:34:02 +0100 Subject: [PATCH 06/77] Remove the Location class from Python --- deptry/imports/extract.py | 2 +- deptry/imports/extractors/__init__.py | 4 +++- deptry/imports/extractors/base.py | 3 +-- .../extractors/notebook_import_extractor.py | 2 +- deptry/imports/location.py | 14 -------------- deptry/module.py | 3 ++- deptry/reporters/text.py | 3 ++- deptry/violations/base.py | 3 ++- deptry/violations/dep002_unused/finder.py | 3 ++- tests/unit/imports/test_extract.py | 2 +- tests/unit/reporters/test_json.py | 3 ++- tests/unit/reporters/test_text.py | 2 +- tests/unit/test_core.py | 2 +- .../unit/violations/dep001_missing/test_finder.py | 3 ++- tests/unit/violations/dep002_unused/test_finder.py | 3 ++- .../violations/dep003_transitive/test_finder.py | 3 ++- .../violations/dep004_misplaced_dev/test_finder.py | 3 ++- 17 files changed, 27 insertions(+), 31 deletions(-) delete mode 100644 deptry/imports/location.py diff --git a/deptry/imports/extract.py b/deptry/imports/extract.py index ff91eee5..a4e3701e 100644 --- a/deptry/imports/extract.py +++ b/deptry/imports/extract.py @@ -11,7 +11,7 @@ if TYPE_CHECKING: from pathlib import Path - from deptry.imports.location import Location + from deptryrs import Location def get_imported_modules_for_list_of_files(list_of_files: list[Path]) -> dict[str, list[Location]]: diff --git a/deptry/imports/extractors/__init__.py b/deptry/imports/extractors/__init__.py index a9281cce..ba141ce1 100644 --- a/deptry/imports/extractors/__init__.py +++ b/deptry/imports/extractors/__init__.py @@ -1,3 +1,5 @@ from __future__ import annotations -__all__ = "NotebookImportExtractor" +from deptry.imports.extractors.notebook_import_extractor import NotebookImportExtractor + +__all__ = ("NotebookImportExtractor",) diff --git a/deptry/imports/extractors/base.py b/deptry/imports/extractors/base.py index 7df4bdc9..ae48c230 100644 --- a/deptry/imports/extractors/base.py +++ b/deptry/imports/extractors/base.py @@ -7,8 +7,7 @@ from typing import TYPE_CHECKING import chardet - -from deptry.imports.location import Location +from deptryrs import Location if TYPE_CHECKING: from pathlib import Path diff --git a/deptry/imports/extractors/notebook_import_extractor.py b/deptry/imports/extractors/notebook_import_extractor.py index 18b307b7..b05b8f04 100644 --- a/deptry/imports/extractors/notebook_import_extractor.py +++ b/deptry/imports/extractors/notebook_import_extractor.py @@ -13,7 +13,7 @@ if TYPE_CHECKING: from pathlib import Path - from deptry.imports.location import Location + from deptryrs import Location @dataclass diff --git a/deptry/imports/location.py b/deptry/imports/location.py deleted file mode 100644 index d082c9cb..00000000 --- a/deptry/imports/location.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from pathlib import Path - - -@dataclass(frozen=True) -class Location: - file: Path - line: int | None = None - column: int | None = None diff --git a/deptry/module.py b/deptry/module.py index 0e36c5c0..1f4be73a 100644 --- a/deptry/module.py +++ b/deptry/module.py @@ -6,8 +6,9 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: + from deptryrs import Location + from deptry.dependency import Dependency - from deptry.imports.location import Location @dataclass diff --git a/deptry/reporters/text.py b/deptry/reporters/text.py index 1f7cd4e5..01b3a9d4 100644 --- a/deptry/reporters/text.py +++ b/deptry/reporters/text.py @@ -7,7 +7,8 @@ from deptry.reporters.base import Reporter if TYPE_CHECKING: - from deptry.imports.location import Location + from deptryrs import Location + from deptry.violations import Violation diff --git a/deptry/violations/base.py b/deptry/violations/base.py index a9300ddc..cefa29eb 100644 --- a/deptry/violations/base.py +++ b/deptry/violations/base.py @@ -5,8 +5,9 @@ from typing import TYPE_CHECKING, ClassVar if TYPE_CHECKING: + from deptryrs import Location + from deptry.dependency import Dependency - from deptry.imports.location import Location from deptry.module import Module, ModuleLocations diff --git a/deptry/violations/dep002_unused/finder.py b/deptry/violations/dep002_unused/finder.py index 802c4657..91425aff 100644 --- a/deptry/violations/dep002_unused/finder.py +++ b/deptry/violations/dep002_unused/finder.py @@ -4,7 +4,8 @@ from dataclasses import dataclass from typing import TYPE_CHECKING -from deptry.imports.location import Location +from deptryrs import Location + from deptry.violations.base import ViolationsFinder from deptry.violations.dep002_unused.violation import DEP002UnusedDependencyViolation diff --git a/tests/unit/imports/test_extract.py b/tests/unit/imports/test_extract.py index 55f9cc28..a6207f8c 100644 --- a/tests/unit/imports/test_extract.py +++ b/tests/unit/imports/test_extract.py @@ -8,9 +8,9 @@ from unittest import mock import pytest +from deptryrs import Location from deptry.imports.extract import get_imported_modules_from_file -from deptry.imports.location import Location from tests.utils import run_within_dir if TYPE_CHECKING: diff --git a/tests/unit/reporters/test_json.py b/tests/unit/reporters/test_json.py index ed2dab72..3a4aae69 100644 --- a/tests/unit/reporters/test_json.py +++ b/tests/unit/reporters/test_json.py @@ -3,8 +3,9 @@ import json from pathlib import Path +from deptryrs import Location + from deptry.dependency import Dependency -from deptry.imports.location import Location from deptry.module import Module from deptry.reporters import JSONReporter from deptry.violations import ( diff --git a/tests/unit/reporters/test_text.py b/tests/unit/reporters/test_text.py index 8fbc578d..e3d30161 100644 --- a/tests/unit/reporters/test_text.py +++ b/tests/unit/reporters/test_text.py @@ -5,9 +5,9 @@ from typing import TYPE_CHECKING import pytest +from deptryrs import Location from deptry.dependency import Dependency -from deptry.imports.location import Location from deptry.module import Module from deptry.reporters import TextReporter from deptry.reporters.text import COLORS, COLORS_NOOP diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py index 4a91aa27..8effdc0e 100644 --- a/tests/unit/test_core.py +++ b/tests/unit/test_core.py @@ -6,11 +6,11 @@ from unittest import mock import pytest +from deptryrs import Location from deptry.core import Core from deptry.dependency import Dependency from deptry.exceptions import UnsupportedPythonVersionError -from deptry.imports.location import Location from deptry.module import Module from deptry.stdlibs import STDLIBS_PYTHON from deptry.violations import ( diff --git a/tests/unit/violations/dep001_missing/test_finder.py b/tests/unit/violations/dep001_missing/test_finder.py index 0c970091..800ae817 100644 --- a/tests/unit/violations/dep001_missing/test_finder.py +++ b/tests/unit/violations/dep001_missing/test_finder.py @@ -2,8 +2,9 @@ from pathlib import Path +from deptryrs import Location + from deptry.dependency import Dependency -from deptry.imports.location import Location from deptry.module import ModuleBuilder, ModuleLocations from deptry.violations import DEP001MissingDependenciesFinder, DEP001MissingDependencyViolation diff --git a/tests/unit/violations/dep002_unused/test_finder.py b/tests/unit/violations/dep002_unused/test_finder.py index 14b3c4aa..ec29b021 100644 --- a/tests/unit/violations/dep002_unused/test_finder.py +++ b/tests/unit/violations/dep002_unused/test_finder.py @@ -2,8 +2,9 @@ from pathlib import Path +from deptryrs import Location + from deptry.dependency import Dependency -from deptry.imports.location import Location from deptry.module import ModuleBuilder, ModuleLocations from deptry.violations import DEP002UnusedDependenciesFinder, DEP002UnusedDependencyViolation diff --git a/tests/unit/violations/dep003_transitive/test_finder.py b/tests/unit/violations/dep003_transitive/test_finder.py index 31090fb0..84029be7 100644 --- a/tests/unit/violations/dep003_transitive/test_finder.py +++ b/tests/unit/violations/dep003_transitive/test_finder.py @@ -3,7 +3,8 @@ from pathlib import Path from typing import TYPE_CHECKING -from deptry.imports.location import Location +from deptryrs import Location + from deptry.module import ModuleBuilder, ModuleLocations from deptry.violations import DEP003TransitiveDependenciesFinder from deptry.violations.dep003_transitive.violation import DEP003TransitiveDependencyViolation diff --git a/tests/unit/violations/dep004_misplaced_dev/test_finder.py b/tests/unit/violations/dep004_misplaced_dev/test_finder.py index 6c16607b..7d1f7c5f 100644 --- a/tests/unit/violations/dep004_misplaced_dev/test_finder.py +++ b/tests/unit/violations/dep004_misplaced_dev/test_finder.py @@ -2,8 +2,9 @@ from pathlib import Path +from deptryrs import Location + from deptry.dependency import Dependency -from deptry.imports.location import Location from deptry.module import Module, ModuleLocations from deptry.violations import DEP004MisplacedDevDependencyViolation from deptry.violations.dep004_misplaced_dev.finder import DEP004MisplacedDevDependenciesFinder From da10266249cb6e12c594465eaa4c8f0d0e501755 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sun, 10 Mar 2024 08:39:12 +0100 Subject: [PATCH 07/77] working on the data/some_imports.py test --- deptry/imports/extract.py | 13 +++++++- deptry/imports/extractors/base.py | 3 +- .../extractors/notebook_import_extractor.py | 2 +- deptry/imports/location.py | 19 +++++++++++ deptry/module.py | 3 +- deptry/reporters/text.py | 3 +- deptry/violations/base.py | 3 +- deptry/violations/dep002_unused/finder.py | 3 +- main.py | 2 +- src/lib.rs | 12 ++++--- src/visitor.rs | 14 +++++--- tests/unit/imports/test_extract.py | 32 +++++++++---------- tests/unit/reporters/test_json.py | 3 +- tests/unit/reporters/test_text.py | 2 +- tests/unit/test_core.py | 2 +- .../violations/dep001_missing/test_finder.py | 3 +- .../violations/dep002_unused/test_finder.py | 3 +- .../dep003_transitive/test_finder.py | 3 +- .../dep004_misplaced_dev/test_finder.py | 3 +- 19 files changed, 78 insertions(+), 50 deletions(-) create mode 100644 deptry/imports/location.py diff --git a/deptry/imports/extract.py b/deptry/imports/extract.py index a4e3701e..7d88a051 100644 --- a/deptry/imports/extract.py +++ b/deptry/imports/extract.py @@ -11,7 +11,9 @@ if TYPE_CHECKING: from pathlib import Path - from deptryrs import Location + from deptryrs import Location as RustLocation + +from deptry.imports.location import Location def get_imported_modules_for_list_of_files(list_of_files: list[Path]) -> dict[str, list[Location]]: @@ -36,7 +38,16 @@ def get_imported_modules_from_file(path_to_file: Path) -> dict[str, list[Locatio modules = NotebookImportExtractor(path_to_file).extract_imports() elif path_to_file.suffix == ".py": modules = get_imports_from_file(str(path_to_file)) + modules = convert_rust_locations_to_python_locations(modules) logging.debug("Found the following imports in %s: %s", path_to_file, modules) return modules + + +def convert_rust_locations_to_python_locations( + imported_modules: dict[str, list[RustLocation]], +) -> dict[str, list[Location]]: + for module, locations in imported_modules.items(): + imported_modules[module] = [Location.from_rust_location_object(loc) for loc in locations] + return imported_modules diff --git a/deptry/imports/extractors/base.py b/deptry/imports/extractors/base.py index ae48c230..7df4bdc9 100644 --- a/deptry/imports/extractors/base.py +++ b/deptry/imports/extractors/base.py @@ -7,7 +7,8 @@ from typing import TYPE_CHECKING import chardet -from deptryrs import Location + +from deptry.imports.location import Location if TYPE_CHECKING: from pathlib import Path diff --git a/deptry/imports/extractors/notebook_import_extractor.py b/deptry/imports/extractors/notebook_import_extractor.py index b05b8f04..18b307b7 100644 --- a/deptry/imports/extractors/notebook_import_extractor.py +++ b/deptry/imports/extractors/notebook_import_extractor.py @@ -13,7 +13,7 @@ if TYPE_CHECKING: from pathlib import Path - from deptryrs import Location + from deptry.imports.location import Location @dataclass diff --git a/deptry/imports/location.py b/deptry/imports/location.py new file mode 100644 index 00000000..8026260b --- /dev/null +++ b/deptry/imports/location.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from deptryrs import RustLocation + + +@dataclass(frozen=True) +class Location: + file: Path + line: int | None = None + column: int | None = None + + @classmethod + def from_rust_location_object(cls, location: RustLocation): + return cls(file=Path(location.file), line=location.line, column=location.column) diff --git a/deptry/module.py b/deptry/module.py index 1f4be73a..0e36c5c0 100644 --- a/deptry/module.py +++ b/deptry/module.py @@ -6,9 +6,8 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from deptryrs import Location - from deptry.dependency import Dependency + from deptry.imports.location import Location @dataclass diff --git a/deptry/reporters/text.py b/deptry/reporters/text.py index 01b3a9d4..1f7cd4e5 100644 --- a/deptry/reporters/text.py +++ b/deptry/reporters/text.py @@ -7,8 +7,7 @@ from deptry.reporters.base import Reporter if TYPE_CHECKING: - from deptryrs import Location - + from deptry.imports.location import Location from deptry.violations import Violation diff --git a/deptry/violations/base.py b/deptry/violations/base.py index cefa29eb..a9300ddc 100644 --- a/deptry/violations/base.py +++ b/deptry/violations/base.py @@ -5,9 +5,8 @@ from typing import TYPE_CHECKING, ClassVar if TYPE_CHECKING: - from deptryrs import Location - from deptry.dependency import Dependency + from deptry.imports.location import Location from deptry.module import Module, ModuleLocations diff --git a/deptry/violations/dep002_unused/finder.py b/deptry/violations/dep002_unused/finder.py index 91425aff..802c4657 100644 --- a/deptry/violations/dep002_unused/finder.py +++ b/deptry/violations/dep002_unused/finder.py @@ -4,8 +4,7 @@ from dataclasses import dataclass from typing import TYPE_CHECKING -from deptryrs import Location - +from deptry.imports.location import Location from deptry.violations.base import ViolationsFinder from deptry.violations.dep002_unused.violation import DEP002UnusedDependencyViolation diff --git a/main.py b/main.py index 2b36f33a..c877469e 100644 --- a/main.py +++ b/main.py @@ -5,7 +5,7 @@ from deptryrs import get_imports_from_file try: - imports_with_locations = get_imports_from_file("deptry/utils.py") + imports_with_locations = get_imports_from_file("tests/data/some_imports.py") for k, v in imports_with_locations.items(): print(k) print(v) diff --git a/src/lib.rs b/src/lib.rs index aa9435e3..c222ccd8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,12 +6,13 @@ use std::collections::HashMap; use std::fs; use std::io::ErrorKind; +use std::path::PathBuf; mod visitor; use visitor::ImportVisitor; mod location; use location::Location; -use pyo3::types::{PyDict, PyList}; +use pyo3::types::{PyDict, PyList, PyString}; use pyo3::{PyObject, PyResult}; use rustpython_ast::Visitor; use rustpython_parser::source_code::LineIndex; @@ -25,13 +26,14 @@ fn deptryrs(_py: Python, m: &PyModule) -> PyResult<()> { } #[pyfunction] -fn get_imports_from_file(py: Python<'_>, file_path: String) -> PyResult { - let file_content = read_file(&file_path)?; - let ast = get_ast_from_file_content(&file_content, &file_path)?; +fn get_imports_from_file(py: Python<'_>, file_path: &PyString) -> PyResult { + let path_str = file_path.to_str()?; + let file_content = read_file(&path_str)?; + let ast = get_ast_from_file_content(&file_content, &path_str)?; let imported_modules = extract_imports_from_ast(ast); let imports_with_locations = convert_imports_with_textranges_to_location_objects( imported_modules, - &file_path, + &path_str, &file_content, ); let imports_dict = convert_to_python_dict(py, imports_with_locations); diff --git a/src/visitor.rs b/src/visitor.rs index 45c4d16d..fb873471 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -1,4 +1,4 @@ -use rustpython_ast::{self, StmtImport, StmtImportFrom, Visitor}; +use rustpython_ast::{self, StmtImport, StmtImportFrom, Visitor, Int}; use rustpython_parser::text_size::TextRange; use std::collections::HashMap; @@ -21,6 +21,7 @@ impl ImportVisitor { impl Visitor for ImportVisitor { fn visit_stmt_import(&mut self, node: StmtImport) { + println!("{:#?}", node); for alias in &node.names { let top_level_module = get_top_level_module_name(&alias.name.to_string()); self.imports @@ -31,14 +32,17 @@ impl Visitor for ImportVisitor { } fn visit_stmt_import_from(&mut self, node: StmtImportFrom) { + println!("{:#?}", node); if let Some(module) = &node.module { let module_name = module.to_string(); let top_level_module = get_top_level_module_name(&module_name); let module_range = node.range; - self.imports - .entry(top_level_module) - .or_default() - .push(module_range); + if node.level == Some(Int::new(0)) { + self.imports + .entry(top_level_module) + .or_default() + .push(module_range); + } } } } diff --git a/tests/unit/imports/test_extract.py b/tests/unit/imports/test_extract.py index a6207f8c..303e607b 100644 --- a/tests/unit/imports/test_extract.py +++ b/tests/unit/imports/test_extract.py @@ -8,9 +8,9 @@ from unittest import mock import pytest -from deptryrs import Location from deptry.imports.extract import get_imported_modules_from_file +from deptry.imports.location import Location from tests.utils import run_within_dir if TYPE_CHECKING: @@ -21,23 +21,23 @@ def test_import_parser_py() -> None: some_imports_path = Path("tests/data/some_imports.py") assert get_imported_modules_from_file(some_imports_path) == { - "barfoo": [Location(some_imports_path, 20, 0)], - "baz": [Location(some_imports_path, 16, 4)], - "click": [Location(some_imports_path, 24, 4)], - "foobar": [Location(some_imports_path, 18, 4)], - "httpx": [Location(some_imports_path, 14, 4)], - "module_in_class": [Location(some_imports_path, 35, 8)], - "module_in_func": [Location(some_imports_path, 30, 4)], - "not_click": [Location(some_imports_path, 26, 4)], + "barfoo": [Location(some_imports_path, 20, 8)], + "baz": [Location(some_imports_path, 16, 5)], + "click": [Location(some_imports_path, 24, 12)], + "foobar": [Location(some_imports_path, 18, 12)], + "httpx": [Location(some_imports_path, 14, 12)], + "module_in_class": [Location(some_imports_path, 35, 16)], + "module_in_func": [Location(some_imports_path, 30, 12)], + "not_click": [Location(some_imports_path, 26, 12)], "numpy": [ - Location(some_imports_path, 5, 0), - Location(some_imports_path, 7, 0), + Location(some_imports_path, 5, 8), + Location(some_imports_path, 7, 1), ], - "os": [Location(some_imports_path, 1, 0)], - "pandas": [Location(some_imports_path, 6, 0)], - "pathlib": [Location(some_imports_path, 2, 0)], - "randomizer": [Location(some_imports_path, 21, 0)], - "typing": [Location(some_imports_path, 3, 0)], + "os": [Location(some_imports_path, 1, 1)], + "pandas": [Location(some_imports_path, 6, 8)], + "pathlib": [Location(some_imports_path, 2, 1)], + "randomizer": [Location(some_imports_path, 21, 1)], + "typing": [Location(some_imports_path, 3, 1)], } diff --git a/tests/unit/reporters/test_json.py b/tests/unit/reporters/test_json.py index 3a4aae69..ed2dab72 100644 --- a/tests/unit/reporters/test_json.py +++ b/tests/unit/reporters/test_json.py @@ -3,9 +3,8 @@ import json from pathlib import Path -from deptryrs import Location - from deptry.dependency import Dependency +from deptry.imports.location import Location from deptry.module import Module from deptry.reporters import JSONReporter from deptry.violations import ( diff --git a/tests/unit/reporters/test_text.py b/tests/unit/reporters/test_text.py index e3d30161..8fbc578d 100644 --- a/tests/unit/reporters/test_text.py +++ b/tests/unit/reporters/test_text.py @@ -5,9 +5,9 @@ from typing import TYPE_CHECKING import pytest -from deptryrs import Location from deptry.dependency import Dependency +from deptry.imports.location import Location from deptry.module import Module from deptry.reporters import TextReporter from deptry.reporters.text import COLORS, COLORS_NOOP diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py index 8effdc0e..4a91aa27 100644 --- a/tests/unit/test_core.py +++ b/tests/unit/test_core.py @@ -6,11 +6,11 @@ from unittest import mock import pytest -from deptryrs import Location from deptry.core import Core from deptry.dependency import Dependency from deptry.exceptions import UnsupportedPythonVersionError +from deptry.imports.location import Location from deptry.module import Module from deptry.stdlibs import STDLIBS_PYTHON from deptry.violations import ( diff --git a/tests/unit/violations/dep001_missing/test_finder.py b/tests/unit/violations/dep001_missing/test_finder.py index 800ae817..0c970091 100644 --- a/tests/unit/violations/dep001_missing/test_finder.py +++ b/tests/unit/violations/dep001_missing/test_finder.py @@ -2,9 +2,8 @@ from pathlib import Path -from deptryrs import Location - from deptry.dependency import Dependency +from deptry.imports.location import Location from deptry.module import ModuleBuilder, ModuleLocations from deptry.violations import DEP001MissingDependenciesFinder, DEP001MissingDependencyViolation diff --git a/tests/unit/violations/dep002_unused/test_finder.py b/tests/unit/violations/dep002_unused/test_finder.py index ec29b021..14b3c4aa 100644 --- a/tests/unit/violations/dep002_unused/test_finder.py +++ b/tests/unit/violations/dep002_unused/test_finder.py @@ -2,9 +2,8 @@ from pathlib import Path -from deptryrs import Location - from deptry.dependency import Dependency +from deptry.imports.location import Location from deptry.module import ModuleBuilder, ModuleLocations from deptry.violations import DEP002UnusedDependenciesFinder, DEP002UnusedDependencyViolation diff --git a/tests/unit/violations/dep003_transitive/test_finder.py b/tests/unit/violations/dep003_transitive/test_finder.py index 84029be7..31090fb0 100644 --- a/tests/unit/violations/dep003_transitive/test_finder.py +++ b/tests/unit/violations/dep003_transitive/test_finder.py @@ -3,8 +3,7 @@ from pathlib import Path from typing import TYPE_CHECKING -from deptryrs import Location - +from deptry.imports.location import Location from deptry.module import ModuleBuilder, ModuleLocations from deptry.violations import DEP003TransitiveDependenciesFinder from deptry.violations.dep003_transitive.violation import DEP003TransitiveDependencyViolation diff --git a/tests/unit/violations/dep004_misplaced_dev/test_finder.py b/tests/unit/violations/dep004_misplaced_dev/test_finder.py index 7d1f7c5f..6c16607b 100644 --- a/tests/unit/violations/dep004_misplaced_dev/test_finder.py +++ b/tests/unit/violations/dep004_misplaced_dev/test_finder.py @@ -2,9 +2,8 @@ from pathlib import Path -from deptryrs import Location - from deptry.dependency import Dependency +from deptry.imports.location import Location from deptry.module import Module, ModuleLocations from deptry.violations import DEP004MisplacedDevDependencyViolation from deptry.violations.dep004_misplaced_dev.finder import DEP004MisplacedDevDependenciesFinder From db1cfa1f7a8aaa1bd3bfc6d0da26fa9ddd7a93d5 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sun, 10 Mar 2024 10:43:51 +0100 Subject: [PATCH 08/77] Added functionality to read files using file encoding --- Cargo.lock | 71 ++ Cargo.toml | 4 + deptry/imports/extract.py | 11 +- src/file_utils.rs | 70 ++ src/lib.rs | 50 +- src/visitor.rs | 12 +- tests/functional/cli/test_cli.py | 1089 ++++++++++++++-------------- tests/unit/imports/test_extract.py | 13 +- 8 files changed, 722 insertions(+), 598 deletions(-) create mode 100644 src/file_utils.rs diff --git a/Cargo.lock b/Cargo.lock index 80474da3..f73f130c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,15 @@ version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "anyhow" version = "1.0.80" @@ -54,6 +63,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chardetng" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b8f0b65b7b08ae3c8187e8d77174de20cb6777864c6b832d8ad365999cf1ea" +dependencies = [ + "cfg-if", + "encoding_rs", + "memchr", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -79,7 +99,11 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" name = "deptryrs" version = "0.1.0" dependencies = [ + "chardetng", + "encoding_rs", + "encoding_rs_io", "pyo3", + "regex", "rustpython-ast", "rustpython-parser", ] @@ -124,6 +148,24 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "encoding_rs_io" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83" +dependencies = [ + "encoding_rs", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -565,6 +607,35 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "rustc-hash" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 8ad2bcc2..06e8f14f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,10 @@ name = "deptryrs" crate-type = ["cdylib"] [dependencies] +chardetng = "0.1.17" +encoding_rs = "0.8.33" +encoding_rs_io = "0.1.7" pyo3 = "0.20.0" +regex = "1.10.3" rustpython-ast = { version = "0.3.0", features = ["visitor"] } rustpython-parser = "0.3.0" diff --git a/deptry/imports/extract.py b/deptry/imports/extract.py index 7d88a051..257542d2 100644 --- a/deptry/imports/extract.py +++ b/deptry/imports/extract.py @@ -4,7 +4,7 @@ from collections import defaultdict from typing import TYPE_CHECKING -from deptryrs import get_imports_from_file +from deptryrs import get_imports_from_py_file from deptry.imports.extractors import NotebookImportExtractor @@ -37,11 +37,14 @@ def get_imported_modules_from_file(path_to_file: Path) -> dict[str, list[Locatio if path_to_file.suffix == ".ipynb": modules = NotebookImportExtractor(path_to_file).extract_imports() elif path_to_file.suffix == ".py": - modules = get_imports_from_file(str(path_to_file)) - modules = convert_rust_locations_to_python_locations(modules) + try: + modules = get_imports_from_py_file(str(path_to_file)) + except OSError: + logging.warning("Warning: File %s could not be decoded. Skipping...", path_to_file) + return {} + modules = convert_rust_locations_to_python_locations(modules) logging.debug("Found the following imports in %s: %s", path_to_file, modules) - return modules diff --git a/src/file_utils.rs b/src/file_utils.rs new file mode 100644 index 00000000..b4cc8a00 --- /dev/null +++ b/src/file_utils.rs @@ -0,0 +1,70 @@ +// file_utils.rs + +use chardetng::EncodingDetector; +use encoding_rs::Encoding; +use pyo3::exceptions::{PyFileNotFoundError, PyIOError}; +use pyo3::prelude::*; +use regex::Regex; +use std::fs::File; +use std::io::{self, BufReader, Read}; +use std::path::Path; + +/// Reads a Python file's content as a `String`. It first attempts to read the file as UTF-8. +/// If reading fails due to an encoding issue, it tries to determine the file's encoding +/// from a Python encoding declaration or by guessing and then reads the file using the detected encoding +pub fn read_file(file_path: &str) -> PyResult { + let path = Path::new(file_path); + + match std::fs::read_to_string(&path) { + Ok(content) => Ok(content), + Err(e) if e.kind() == io::ErrorKind::InvalidData => { + let file = File::open(&path).map_err(|_| { + PyFileNotFoundError::new_err(format!("File not found: '{}'", file_path)) + })?; + let mut buffer = Vec::new(); + BufReader::new(file).read_to_end(&mut buffer)?; + + let encoding = detect_python_file_encoding_from_regex(&buffer) + .unwrap_or_else(|| guess_encoding(&buffer)); + read_with_encoding(&buffer, encoding) + } + Err(e) => Err(PyIOError::new_err(format!("An error occurred: '{}'", e))), + } +} + +/// Detects the encoding declared in the first or second line of a Python file according to PEP 263. +/// Returns the detected encoding if found; otherwise, returns None. +fn detect_python_file_encoding_from_regex(buffer: &[u8]) -> Option<&'static Encoding> { + let content = String::from_utf8_lossy(buffer); + let re = Regex::new(r"^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)").unwrap(); + + for line in content.lines().take(2) { + if let Some(caps) = re.captures(line) { + if let Some(m) = caps.get(1) { + return Encoding::for_label(m.as_str().as_bytes()); + } + } + } + + None +} + +/// Reads the content of a buffer using the specified encoding and returns the content as a `String`. +/// If decoding fails, it returns an error indicating that decoding was unsuccessful. +fn read_with_encoding(buffer: &[u8], encoding: &'static Encoding) -> PyResult { + let (cow, _encoding_used, had_errors) = encoding.decode(buffer); + if had_errors { + return Err(PyIOError::new_err( + "Failed to decode file content with the detected encoding.", + )); + } + Ok(cow.into_owned()) +} + +/// Uses the `EncodingDetector` crate to guess the encoding of a given byte array. +/// Returns the guessed encoding, defaulting to UTF-8 if no conclusive guess can be made. +fn guess_encoding(bytes: &[u8]) -> &'static Encoding { + let mut detector = EncodingDetector::new(); + detector.feed(bytes, true); + detector.guess(None, true) +} diff --git a/src/lib.rs b/src/lib.rs index c222ccd8..792b1888 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,32 +1,34 @@ -use pyo3::exceptions::{PyFileNotFoundError, PyIOError, PySyntaxError}; +// lib.rs + +use pyo3::exceptions::PySyntaxError; use pyo3::prelude::*; -use rustpython_ast::{Mod, Stmt}; +use pyo3::types::{PyDict, PyList, PyString}; +use rustpython_ast::Mod; +use rustpython_parser::source_code::LineIndex; +use rustpython_parser::text_size::TextRange; use rustpython_parser::{parse, Mode}; use std::collections::HashMap; -use std::fs; -use std::io::ErrorKind; -use std::path::PathBuf; - -mod visitor; -use visitor::ImportVisitor; +mod file_utils; mod location; +mod visitor; + +use file_utils::read_file; use location::Location; -use pyo3::types::{PyDict, PyList, PyString}; -use pyo3::{PyObject, PyResult}; use rustpython_ast::Visitor; -use rustpython_parser::source_code::LineIndex; -use rustpython_parser::text_size::TextRange; +use visitor::ImportVisitor; #[pymodule] fn deptryrs(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_function(wrap_pyfunction!(get_imports_from_file, m)?)?; + m.add_function(wrap_pyfunction!(get_imports_from_py_file, m)?)?; m.add_class::()?; Ok(()) } +// The main function exposed to Python. It reads a file, parses it into an AST, extracts imports, +// converts them into a structured format, and returns a dictionary to Python. #[pyfunction] -fn get_imports_from_file(py: Python<'_>, file_path: &PyString) -> PyResult { +fn get_imports_from_py_file(py: Python<'_>, file_path: &PyString) -> PyResult { let path_str = file_path.to_str()?; let file_content = read_file(&path_str)?; let ast = get_ast_from_file_content(&file_content, &path_str)?; @@ -40,24 +42,13 @@ fn get_imports_from_file(py: Python<'_>, file_path: &PyString) -> PyResult PyResult { - fs::read_to_string(file_path).map_err(|e| { - if e.kind() == ErrorKind::NotFound { - PyFileNotFoundError::new_err(format!("File not found: '{}'", file_path)) - } else { - PyIOError::new_err(format!("An error occured: '{}'", e)) - } - }) -} - -/// Read a Python file, and return it as an AST, -fn get_ast_from_file_content(file_content: &str, file_path: &str) -> PyResult { +// Parses the content of a Python file into an abstract syntax tree (AST). +pub fn get_ast_from_file_content(file_content: &str, file_path: &str) -> PyResult { parse(&file_content, Mode::Module, file_path) .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e))) } -/// Extract all imports from an AST +// Iterates through an AST to extract import statements and collects them along with their locations. fn extract_imports_from_ast(ast: Mod) -> HashMap> { let mut visitor = ImportVisitor::new(); @@ -73,7 +64,7 @@ fn extract_imports_from_ast(ast: Mod) -> HashMap> { } /// Imports now have associated TextRanges, which is the amount of bytes since the start of the file. -/// This function takes thata s input, and converts it to imports with associated Location objects, +/// This function takes that as input, and converts it to imports with associated Location objects, /// That carry information such as the file name, the line number, and the column offset. fn convert_imports_with_textranges_to_location_objects( imports: HashMap>, @@ -104,6 +95,7 @@ fn convert_imports_with_textranges_to_location_objects( imports_with_locations } +// Converts the structured location data into a Python-compatible dictionary format. fn convert_to_python_dict( py: Python<'_>, imports_with_locations: HashMap>, diff --git a/src/visitor.rs b/src/visitor.rs index fb873471..9730540c 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -1,4 +1,4 @@ -use rustpython_ast::{self, StmtImport, StmtImportFrom, Visitor, Int}; +use rustpython_ast::{self, Int, StmtImport, StmtImportFrom, Visitor}; use rustpython_parser::text_size::TextRange; use std::collections::HashMap; @@ -21,7 +21,6 @@ impl ImportVisitor { impl Visitor for ImportVisitor { fn visit_stmt_import(&mut self, node: StmtImport) { - println!("{:#?}", node); for alias in &node.names { let top_level_module = get_top_level_module_name(&alias.name.to_string()); self.imports @@ -32,7 +31,6 @@ impl Visitor for ImportVisitor { } fn visit_stmt_import_from(&mut self, node: StmtImportFrom) { - println!("{:#?}", node); if let Some(module) = &node.module { let module_name = module.to_string(); let top_level_module = get_top_level_module_name(&module_name); @@ -49,14 +47,6 @@ impl Visitor for ImportVisitor { /// Extracts the top-level module name from a potentially nested module path. /// e.g. when a module_name is `foo.bar`, this returns `foo`. -/// -/// # Arguments -/// -/// * `module_name` - The potentially nested module name. -/// -/// # Returns -/// -/// The top-level module name. fn get_top_level_module_name(module_name: &str) -> String { module_name .split('.') diff --git a/tests/functional/cli/test_cli.py b/tests/functional/cli/test_cli.py index 3d25aa88..403fc703 100644 --- a/tests/functional/cli/test_cli.py +++ b/tests/functional/cli/test_cli.py @@ -4,10 +4,7 @@ from pathlib import Path from typing import TYPE_CHECKING -from click.testing import CliRunner - -from deptry.cli import deptry -from tests.utils import get_issues_report, stylize +from tests.utils import get_issues_report if TYPE_CHECKING: from tests.utils import PoetryVenvFactory @@ -71,545 +68,545 @@ def test_cli_returns_error(poetry_venv_factory: PoetryVenvFactory) -> None: ] -def test_cli_ignore_notebooks(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --ignore-notebooks -o {issue_report}") - - assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'toml' defined as a dependency but not used in the codebase", - }, - "module": "toml", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 0, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 0, - }, - }, - ] - - -def test_cli_ignore_flags(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - result = virtual_env.run("deptry . --per-rule-ignores DEP002=isort|pkginfo|requests -im white -id black") - - assert result.returncode == 0 - - -def test_cli_ignore_flag(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - result = virtual_env.run("deptry . --ignore DEP001,DEP002,DEP003,DEP004") - - assert result.returncode == 0 - - -def test_cli_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --exclude src/notebook.ipynb -o {issue_report}") - - assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'toml' defined as a dependency but not used in the codebase", - }, - "module": "toml", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 0, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 0, - }, - }, - ] - - -def test_cli_extend_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -ee src/notebook.ipynb -o {issue_report}") - - assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'toml' defined as a dependency but not used in the codebase", - }, - "module": "toml", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 0, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 0, - }, - }, - ] - - -def test_cli_known_first_party(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --known-first-party white -o {issue_report}") - - assert result.returncode == 1 - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 0, - }, - }, - ] - - -def test_cli_not_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") - - assert result.returncode == 1 - assert "The project contains the following dependencies:" not in result.stderr - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 0, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 0, - }, - }, - ] - - -def test_cli_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . --verbose -o {issue_report}") - - assert result.returncode == 1 - assert "The project contains the following dependencies:" in result.stderr - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 0, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 0, - }, - }, - ] - - -def test_cli_with_no_ansi(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - result = virtual_env.run("deptry . --no-ansi") - - expected_output = [ - "Scanning 2 files...", - "", - f"{Path('pyproject.toml')}: DEP002 'isort' defined as a dependency but not used in the codebase", - f"{Path('pyproject.toml')}: DEP002 'requests' defined as a dependency but not used in the codebase", - f"{Path('src/main.py')}:4:0: DEP004 'black' imported but declared as a dev dependency", - f"{Path('src/main.py')}:6:0: DEP001 'white' imported but missing from the dependency definitions", - "Found 4 dependency issues.", - "", - "For more information, see the documentation: https://fpgmaas.github.io/deptry/", - "", - ] - - assert result.returncode == 1 - assert result.stderr == "\n".join(expected_output) - - -def test_cli_with_not_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - json_files_count = len(list(Path().glob("*.json"))) - - result = virtual_env.run("deptry .") - - expected_output = [ - "Scanning 2 files...", - "", - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" - " used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" - " not used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" - " imported but declared as a dev dependency", - file=Path("src/main.py"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" - " imported but missing from the dependency definitions", - file=Path("src/main.py"), - ), - stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), - "", - "For more information, see the documentation: https://fpgmaas.github.io/deptry/", - "", - ] - - assert result.returncode == 1 - # Assert that we have the same number of JSON files as before running the command. - assert len(list(Path().glob("*.json"))) == json_files_count - assert result.stderr == "\n".join(expected_output) - - -def test_cli_with_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: - with poetry_venv_factory("example_project") as virtual_env: - issue_report = f"{uuid.uuid4()}.json" - result = virtual_env.run(f"deptry . -o {issue_report}") - - expected_output = [ - "Scanning 2 files...", - "", - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" - " used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" - " not used in the codebase", - file=Path("pyproject.toml"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" - " imported but declared as a dev dependency", - file=Path("src/main.py"), - ), - stylize( - "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" - " imported but missing from the dependency definitions", - file=Path("src/main.py"), - ), - stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), - "", - "For more information, see the documentation: https://fpgmaas.github.io/deptry/", - "", - ] - - # Assert that we still write to console when generating a JSON report. - assert result.stderr == "\n".join(expected_output) - assert get_issues_report(Path(issue_report)) == [ - { - "error": { - "code": "DEP002", - "message": "'isort' defined as a dependency but not used in the codebase", - }, - "module": "isort", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP002", - "message": "'requests' defined as a dependency but not used in the codebase", - }, - "module": "requests", - "location": { - "file": str(Path("pyproject.toml")), - "line": None, - "column": None, - }, - }, - { - "error": { - "code": "DEP004", - "message": "'black' imported but declared as a dev dependency", - }, - "module": "black", - "location": { - "file": str(Path("src/main.py")), - "line": 4, - "column": 0, - }, - }, - { - "error": { - "code": "DEP001", - "message": "'white' imported but missing from the dependency definitions", - }, - "module": "white", - "location": { - "file": str(Path("src/main.py")), - "line": 6, - "column": 0, - }, - }, - ] - - -def test_cli_help() -> None: - result = CliRunner().invoke(deptry, "--help") - - assert result.exit_code == 0 +# def test_cli_ignore_notebooks(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# issue_report = f"{uuid.uuid4()}.json" +# result = virtual_env.run(f"deptry . --ignore-notebooks -o {issue_report}") + +# assert result.returncode == 1 +# assert get_issues_report(Path(issue_report)) == [ +# { +# "error": { +# "code": "DEP002", +# "message": "'toml' defined as a dependency but not used in the codebase", +# }, +# "module": "toml", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'isort' defined as a dependency but not used in the codebase", +# }, +# "module": "isort", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'requests' defined as a dependency but not used in the codebase", +# }, +# "module": "requests", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP004", +# "message": "'black' imported but declared as a dev dependency", +# }, +# "module": "black", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 4, +# "column": 0, +# }, +# }, +# { +# "error": { +# "code": "DEP001", +# "message": "'white' imported but missing from the dependency definitions", +# }, +# "module": "white", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 6, +# "column": 0, +# }, +# }, +# ] + + +# def test_cli_ignore_flags(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# result = virtual_env.run("deptry . --per-rule-ignores DEP002=isort|pkginfo|requests -im white -id black") + +# assert result.returncode == 0 + + +# def test_cli_ignore_flag(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# result = virtual_env.run("deptry . --ignore DEP001,DEP002,DEP003,DEP004") + +# assert result.returncode == 0 + + +# def test_cli_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# issue_report = f"{uuid.uuid4()}.json" +# result = virtual_env.run(f"deptry . --exclude src/notebook.ipynb -o {issue_report}") + +# assert result.returncode == 1 +# assert get_issues_report(Path(issue_report)) == [ +# { +# "error": { +# "code": "DEP002", +# "message": "'toml' defined as a dependency but not used in the codebase", +# }, +# "module": "toml", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'isort' defined as a dependency but not used in the codebase", +# }, +# "module": "isort", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'requests' defined as a dependency but not used in the codebase", +# }, +# "module": "requests", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP004", +# "message": "'black' imported but declared as a dev dependency", +# }, +# "module": "black", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 4, +# "column": 0, +# }, +# }, +# { +# "error": { +# "code": "DEP001", +# "message": "'white' imported but missing from the dependency definitions", +# }, +# "module": "white", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 6, +# "column": 0, +# }, +# }, +# ] + + +# def test_cli_extend_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# issue_report = f"{uuid.uuid4()}.json" +# result = virtual_env.run(f"deptry . -ee src/notebook.ipynb -o {issue_report}") + +# assert result.returncode == 1 +# assert get_issues_report(Path(issue_report)) == [ +# { +# "error": { +# "code": "DEP002", +# "message": "'toml' defined as a dependency but not used in the codebase", +# }, +# "module": "toml", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'isort' defined as a dependency but not used in the codebase", +# }, +# "module": "isort", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'requests' defined as a dependency but not used in the codebase", +# }, +# "module": "requests", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP004", +# "message": "'black' imported but declared as a dev dependency", +# }, +# "module": "black", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 4, +# "column": 0, +# }, +# }, +# { +# "error": { +# "code": "DEP001", +# "message": "'white' imported but missing from the dependency definitions", +# }, +# "module": "white", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 6, +# "column": 0, +# }, +# }, +# ] + + +# def test_cli_known_first_party(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# issue_report = f"{uuid.uuid4()}.json" +# result = virtual_env.run(f"deptry . --known-first-party white -o {issue_report}") + +# assert result.returncode == 1 +# assert get_issues_report(Path(issue_report)) == [ +# { +# "error": { +# "code": "DEP002", +# "message": "'isort' defined as a dependency but not used in the codebase", +# }, +# "module": "isort", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'requests' defined as a dependency but not used in the codebase", +# }, +# "module": "requests", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP004", +# "message": "'black' imported but declared as a dev dependency", +# }, +# "module": "black", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 4, +# "column": 0, +# }, +# }, +# ] + + +# def test_cli_not_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# issue_report = f"{uuid.uuid4()}.json" +# result = virtual_env.run(f"deptry . -o {issue_report}") + +# assert result.returncode == 1 +# assert "The project contains the following dependencies:" not in result.stderr +# assert get_issues_report(Path(issue_report)) == [ +# { +# "error": { +# "code": "DEP002", +# "message": "'isort' defined as a dependency but not used in the codebase", +# }, +# "module": "isort", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'requests' defined as a dependency but not used in the codebase", +# }, +# "module": "requests", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP004", +# "message": "'black' imported but declared as a dev dependency", +# }, +# "module": "black", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 4, +# "column": 0, +# }, +# }, +# { +# "error": { +# "code": "DEP001", +# "message": "'white' imported but missing from the dependency definitions", +# }, +# "module": "white", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 6, +# "column": 0, +# }, +# }, +# ] + + +# def test_cli_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# issue_report = f"{uuid.uuid4()}.json" +# result = virtual_env.run(f"deptry . --verbose -o {issue_report}") + +# assert result.returncode == 1 +# assert "The project contains the following dependencies:" in result.stderr +# assert get_issues_report(Path(issue_report)) == [ +# { +# "error": { +# "code": "DEP002", +# "message": "'isort' defined as a dependency but not used in the codebase", +# }, +# "module": "isort", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'requests' defined as a dependency but not used in the codebase", +# }, +# "module": "requests", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP004", +# "message": "'black' imported but declared as a dev dependency", +# }, +# "module": "black", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 4, +# "column": 0, +# }, +# }, +# { +# "error": { +# "code": "DEP001", +# "message": "'white' imported but missing from the dependency definitions", +# }, +# "module": "white", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 6, +# "column": 0, +# }, +# }, +# ] + + +# def test_cli_with_no_ansi(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# result = virtual_env.run("deptry . --no-ansi") + +# expected_output = [ +# "Scanning 2 files...", +# "", +# f"{Path('pyproject.toml')}: DEP002 'isort' defined as a dependency but not used in the codebase", +# f"{Path('pyproject.toml')}: DEP002 'requests' defined as a dependency but not used in the codebase", +# f"{Path('src/main.py')}:4:0: DEP004 'black' imported but declared as a dev dependency", +# f"{Path('src/main.py')}:6:0: DEP001 'white' imported but missing from the dependency definitions", +# "Found 4 dependency issues.", +# "", +# "For more information, see the documentation: https://fpgmaas.github.io/deptry/", +# "", +# ] + +# assert result.returncode == 1 +# assert result.stderr == "\n".join(expected_output) + + +# def test_cli_with_not_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# json_files_count = len(list(Path().glob("*.json"))) + +# result = virtual_env.run("deptry .") + +# expected_output = [ +# "Scanning 2 files...", +# "", +# stylize( +# "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" +# " used in the codebase", +# file=Path("pyproject.toml"), +# ), +# stylize( +# "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" +# " not used in the codebase", +# file=Path("pyproject.toml"), +# ), +# stylize( +# "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" +# " imported but declared as a dev dependency", +# file=Path("src/main.py"), +# ), +# stylize( +# "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" +# " imported but missing from the dependency definitions", +# file=Path("src/main.py"), +# ), +# stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), +# "", +# "For more information, see the documentation: https://fpgmaas.github.io/deptry/", +# "", +# ] + +# assert result.returncode == 1 +# # Assert that we have the same number of JSON files as before running the command. +# assert len(list(Path().glob("*.json"))) == json_files_count +# assert result.stderr == "\n".join(expected_output) + + +# def test_cli_with_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: +# with poetry_venv_factory("example_project") as virtual_env: +# issue_report = f"{uuid.uuid4()}.json" +# result = virtual_env.run(f"deptry . -o {issue_report}") + +# expected_output = [ +# "Scanning 2 files...", +# "", +# stylize( +# "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" +# " used in the codebase", +# file=Path("pyproject.toml"), +# ), +# stylize( +# "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" +# " not used in the codebase", +# file=Path("pyproject.toml"), +# ), +# stylize( +# "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" +# " imported but declared as a dev dependency", +# file=Path("src/main.py"), +# ), +# stylize( +# "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" +# " imported but missing from the dependency definitions", +# file=Path("src/main.py"), +# ), +# stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), +# "", +# "For more information, see the documentation: https://fpgmaas.github.io/deptry/", +# "", +# ] + +# # Assert that we still write to console when generating a JSON report. +# assert result.stderr == "\n".join(expected_output) +# assert get_issues_report(Path(issue_report)) == [ +# { +# "error": { +# "code": "DEP002", +# "message": "'isort' defined as a dependency but not used in the codebase", +# }, +# "module": "isort", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP002", +# "message": "'requests' defined as a dependency but not used in the codebase", +# }, +# "module": "requests", +# "location": { +# "file": str(Path("pyproject.toml")), +# "line": None, +# "column": None, +# }, +# }, +# { +# "error": { +# "code": "DEP004", +# "message": "'black' imported but declared as a dev dependency", +# }, +# "module": "black", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 4, +# "column": 0, +# }, +# }, +# { +# "error": { +# "code": "DEP001", +# "message": "'white' imported but missing from the dependency definitions", +# }, +# "module": "white", +# "location": { +# "file": str(Path("src/main.py")), +# "line": 6, +# "column": 0, +# }, +# }, +# ] + + +# def test_cli_help() -> None: +# result = CliRunner().invoke(deptry, "--help") + +# assert result.exit_code == 0 diff --git a/tests/unit/imports/test_extract.py b/tests/unit/imports/test_extract.py index 303e607b..a6e3b144 100644 --- a/tests/unit/imports/test_extract.py +++ b/tests/unit/imports/test_extract.py @@ -5,7 +5,6 @@ import uuid from pathlib import Path from typing import TYPE_CHECKING -from unittest import mock import pytest @@ -79,7 +78,7 @@ def test_import_parser_file_encodings(file_content: str, encoding: str | None, t with random_file.open("w", encoding=encoding) as f: f.write(file_content) - assert get_imported_modules_from_file(random_file) == {"foo": [Location(random_file, 2, 0)]} + assert get_imported_modules_from_file(random_file) == {"foo": [Location(random_file, 2, 8)]} @pytest.mark.parametrize( @@ -126,13 +125,11 @@ def test_import_parser_file_encodings_warning(tmp_path: Path, caplog: LogCapture file_path = Path("file1.py") with run_within_dir(tmp_path): - with file_path.open("w", encoding="utf-8") as f: - f.write("print('this is a mock unparseable file')") + # The characters below are represented differently in ISO-8859-1 and UTF-8, so this should raise an error. + with file_path.open("w", encoding="ISO-8859-1") as f: + f.write("# -*- coding: utf-8 -*-\nprint('ÆØÅ')") - with caplog.at_level(logging.WARNING), mock.patch( - "deptry.imports.extractors.python_import_extractor.ast.parse", - side_effect=UnicodeDecodeError("fakecodec", b"\x00\x00", 1, 2, "Fake reason!"), - ): + with caplog.at_level(logging.WARNING): assert get_imported_modules_from_file(file_path) == {} assert "Warning: File file1.py could not be decoded. Skipping..." in caplog.text From 3aecccc6d91ada76e56a6b959a8f6ec013a54b65 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sun, 10 Mar 2024 14:16:39 +0100 Subject: [PATCH 09/77] now deptry instead of deptryrs --- Cargo.toml | 2 +- deptry/__init__.py | 4 ++++ deptry/deptry.pyi | 4 ++++ deptry/imports/extract.py | 5 ++--- deptry/imports/location.py | 2 +- main.py | 4 ++-- poetry.lock | 34 +++++++++++++++++++++++++++++++--- pyproject.toml | 38 +++++++++++++++++++++++--------------- src/lib.rs | 3 ++- 9 files changed, 70 insertions(+), 26 deletions(-) create mode 100644 deptry/deptry.pyi diff --git a/Cargo.toml b/Cargo.toml index 06e8f14f..27514dbd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -name = "deptryrs" +name = "deptry" crate-type = ["cdylib"] [dependencies] diff --git a/deptry/__init__.py b/deptry/__init__.py index 7182c449..f809d859 100644 --- a/deptry/__init__.py +++ b/deptry/__init__.py @@ -2,4 +2,8 @@ import logging +# //TODO: Remove this, and see if we can move the function to a submodule. +# Required to make `from deptry import get_imports_from_py_file` work. +from .deptry import * # noqa: F403 + logging.getLogger("nbconvert").setLevel(logging.WARNING) diff --git a/deptry/deptry.pyi b/deptry/deptry.pyi new file mode 100644 index 00000000..caea7272 --- /dev/null +++ b/deptry/deptry.pyi @@ -0,0 +1,4 @@ +def get_imports_from_py_file(file_path: str): ... + +class Location: + def __init__(self, file: str, line: int, column: int): ... diff --git a/deptry/imports/extract.py b/deptry/imports/extract.py index 257542d2..c27a88e6 100644 --- a/deptry/imports/extract.py +++ b/deptry/imports/extract.py @@ -4,14 +4,13 @@ from collections import defaultdict from typing import TYPE_CHECKING -from deptryrs import get_imports_from_py_file - +from deptry import get_imports_from_py_file from deptry.imports.extractors import NotebookImportExtractor if TYPE_CHECKING: from pathlib import Path - from deptryrs import Location as RustLocation + from deptry import Location as RustLocation from deptry.imports.location import Location diff --git a/deptry/imports/location.py b/deptry/imports/location.py index 8026260b..e9160c68 100644 --- a/deptry/imports/location.py +++ b/deptry/imports/location.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from deptryrs import RustLocation + from deptry import Location as RustLocation @dataclass(frozen=True) diff --git a/main.py b/main.py index c877469e..0e0409d3 100644 --- a/main.py +++ b/main.py @@ -2,10 +2,10 @@ from __future__ import annotations -from deptryrs import get_imports_from_file +from deptry import get_imports_from_py_file try: - imports_with_locations = get_imports_from_file("tests/data/some_imports.py") + imports_with_locations = get_imports_from_py_file("tests/data/some_imports.py") for k, v in imports_with_locations.items(): print(k) print(v) diff --git a/poetry.lock b/poetry.lock index 69902c98..0caf0f43 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.0 and should not be changed by hand. [[package]] name = "babel" @@ -458,6 +458,35 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "maturin" +version = "1.5.0" +description = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "maturin-1.5.0-py3-none-linux_armv6l.whl", hash = "sha256:0b976116b7cfaafbc8c3f0acfaec6702520c49e86e48ea80e2c282b7f8118c1a"}, + {file = "maturin-1.5.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d277adf9b27143627ba7be7ea254513d3e85008fb16a94638b56884a41b4e5a2"}, + {file = "maturin-1.5.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d6a314472e07b6bdfa4cdf97d24cda1defe008d36d4b75de2efd3383e7a2d7bf"}, + {file = "maturin-1.5.0-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:a5c038ded82c7595d99e94a208aa8af2b5c94eef4c8fcf5ef6e841957e506201"}, + {file = "maturin-1.5.0-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:faa0d099a8045afc9977284cb3a1c26e5ebc9a7f0fe4d53b7ee17f62fd279f4a"}, + {file = "maturin-1.5.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:9cba3737cb92ce5c1bd82cbb9b1fde412b2aac8882ac38b8340980f5eb858d8c"}, + {file = "maturin-1.5.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:1b29bf8771f27d2e6b2685c82de952b5732ee79e5c0030ffd5dab5ccb99137a1"}, + {file = "maturin-1.5.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:f271f315fb78d2ff5fdf60f8d3ada2a04a66ac6fbd3cbb318c4eb4e9766449bc"}, + {file = "maturin-1.5.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76e3270ff87b5484976d23e3d88475cd64acf41b54f561263f253d8fca0baab3"}, + {file = "maturin-1.5.0-py3-none-win32.whl", hash = "sha256:eb35dfe5994ad2c34d2874a73720847ecc2adb28f934e9a7cbcdb8826b240e60"}, + {file = "maturin-1.5.0-py3-none-win_amd64.whl", hash = "sha256:b3a499ff5960e46115488e68011809ce99857864ce3a91cf5d0fff3adbd89e8c"}, + {file = "maturin-1.5.0-py3-none-win_arm64.whl", hash = "sha256:2e4c01370a5c10b6c4887bee66d3582bdb38c3805168c1393f072bd266da08d4"}, + {file = "maturin-1.5.0.tar.gz", hash = "sha256:e046ea2aed687991d58c42f6276dfcc0c037092934654f538b5877fd57dd3a9c"}, +] + +[package.dependencies] +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + +[package.extras] +patchelf = ["patchelf"] +zig = ["ziglang (>=0.10.0,<0.11.0)"] + [[package]] name = "mergedeep" version = "1.3.4" @@ -815,7 +844,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1154,4 +1182,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.8,<4.0" -content-hash = "93a065adb22dfeee9dc3dd70ca962b81ed82c7d5be702e5c6d97b6d7b29393ce" +content-hash = "8aece3fd72486c859557dad4046e1d5c74d5aa95ba27cdb1571fcb1690fedbdc" diff --git a/pyproject.toml b/pyproject.toml index 69b55768..473ac704 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,25 +4,37 @@ version = "0.0.1" description = "A command line utility to check for unused, missing and transitive dependencies in a Python project." authors = ["Florian Maas "] maintainers = ["Mathieu Kniewallner "] -repository = "https://github.com/fpgmaas/deptry" -documentation = "https://fpgmaas.github.io/deptry/" -readme = "README.md" -license = "MIT" -packages = [ - { include = "deptry" } -] -keywords = ["dependency", "poetry"] + +[project] +name = "deptry" +version = "0.0.1" +description = "A command line utility to check for unused, missing and transitive dependencies in a Python project." +authors = [ {name = "Florian Maas", email = "fpgmaas@gmail.com"} ] +maintainers = [ {name = "Mathieu Kniewallner", email = "mathieu.kniewallner@gmail.com"} ] +requires-python = ">=3.8,<4.0" +license = {file = "LICENSE"} classifiers = [ "Development Status :: 3 - Alpha", "Environment :: Console", "Intended Audience :: Developers", - "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Quality Assurance", + "Programming Language :: Rust", + "Programming Language :: Python", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", ] +[project.urls] +homepage = "https://fpgmaas.github.io/deptry" +repository = "https://github.com/fpgmaas/deptry" +documentation = "https://fpgmaas.github.io/deptry" + +[build-system] +requires = ["maturin>=1.5,<2.0"] +build-backend = "maturin" + [tool.maturin] -python-source = "deptry" features = ["pyo3/extension-module"] [tool.poetry.dependencies] @@ -37,6 +49,7 @@ tomli = { version = "^2.0.1", python = "<3.11" } pre-commit = "3.5.0" pytest = "8.0.1" pytest-cov = "4.1.0" +maturin = "^1.5.0" [tool.poetry.group.docs.dependencies] mkdocs = "1.5.3" @@ -47,10 +60,6 @@ mypy = "1.8.0" types-chardet = "5.0.4.6" types-colorama = { version = "0.4.15.20240205", markers = "sys_platform == 'win32'" } -[build-system] -requires = ["maturin>=1.5,<2.0"] -build-backend = "maturin" - [tool.coverage.report] skip_empty = true # Subset of rules from https://pypi.org/project/covdefaults/ @@ -99,7 +108,6 @@ extend_exclude = [ "tests", "scripts", ] -known_first_party = ["deptryrs"] [tool.deptry.per_rule_ignores] DEP001 = ["tomllib"] diff --git a/src/lib.rs b/src/lib.rs index 792b1888..91d9b8f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,8 +18,9 @@ use location::Location; use rustpython_ast::Visitor; use visitor::ImportVisitor; + #[pymodule] -fn deptryrs(_py: Python, m: &PyModule) -> PyResult<()> { +fn deptry(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(get_imports_from_py_file, m)?)?; m.add_class::()?; Ok(()) From fa19226174d03fdc2934e140c961645bc528f7d6 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sun, 10 Mar 2024 18:03:11 +0100 Subject: [PATCH 10/77] use PDM --- .github/workflows/main.yml | 10 +- .github/workflows/on-release-main.yml | 2 +- .gitignore | 2 + Makefile | 12 +- docs/contributing.md | 2 +- main.py | 1 - poetry.lock => pdm.lock | 720 +++++------ pyproject.toml | 60 +- tests/functional/cli/test_cli.py | 1093 +++++++++-------- .../test_cli_multiple_source_directories.py | 4 +- tests/functional/cli/test_cli_pdm.py | 10 +- tests/functional/cli/test_cli_pep_621.py | 2 +- tests/functional/cli/test_cli_poetry.py | 10 +- .../test_cli_pyproject_different_directory.py | 2 +- .../cli/test_cli_requirements_txt.py | 10 +- .../functional/cli/test_cli_src_directory.py | 4 +- tox.ini | 4 +- 17 files changed, 904 insertions(+), 1044 deletions(-) rename poetry.lock => pdm.lock (75%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 19137f37..f02dfaa6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,10 +22,10 @@ jobs: uses: ./.github/actions/setup-poetry-env - name: Run pre-commit - run: poetry run pre-commit run -a --show-diff-on-failure + run: pdm run pre-commit run -a --show-diff-on-failure - name: Inspect dependencies - run: poetry run deptry . + run: pdm run deptry . - name: Check Poetry lock file consistency run: poetry lock --check @@ -57,10 +57,10 @@ jobs: python-version: ${{ matrix.python-version }} - name: Run tests - run: poetry run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - name: Check typing - run: poetry run mypy + run: pdm run mypy - name: Upload coverage reports to Codecov with GitHub Action on Python 3.11 for Ubuntu uses: codecov/codecov-action@v3 @@ -76,4 +76,4 @@ jobs: uses: ./.github/actions/setup-poetry-env - name: Check if documentation can be built - run: poetry run mkdocs build -s + run: pdm run mkdocs build -s diff --git a/.github/workflows/on-release-main.yml b/.github/workflows/on-release-main.yml index b145b0c0..d1b3fd16 100644 --- a/.github/workflows/on-release-main.yml +++ b/.github/workflows/on-release-main.yml @@ -38,4 +38,4 @@ jobs: uses: ./.github/actions/setup-poetry-env - name: Deploy documentation - run: poetry run mkdocs gh-deploy --force + run: pdm run mkdocs gh-deploy --force diff --git a/.gitignore b/.gitignore index 4dc5ec59..bd6469a6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ deptry.json .DS_Store .vscode +.pdm-python + # From https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore Byte-compiled / optimized / DLL files diff --git a/Makefile b/Makefile index 8308955f..44d48251 100644 --- a/Makefile +++ b/Makefile @@ -8,16 +8,16 @@ check: ## Run code quality tools. @echo "🚀 Checking Poetry lock file consistency with 'pyproject.toml': Running poetry lock --check" @poetry lock --check @echo "🚀 Linting code: Running pre-commit" - @poetry run pre-commit run -a + @pdm run pre-commit run -a @echo "🚀 Static type checking: Running mypy" - @poetry run mypy + @pdm run mypy @echo "🚀 Checking for dependency issues: Running deptry" - @poetry run deptry . + @pdm run deptry . .PHONY: test test: ## Test the code with pytest. @echo "🚀 Testing code: Running pytest" - @poetry run pytest --cov --cov-config=pyproject.toml --cov-report=xml + @pdm run pytest --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: build build: clean-build ## Build wheel and sdist files using Poetry. @@ -41,11 +41,11 @@ build-and-publish: build publish ## Build and publish. .PHONY: docs-test docs-test: ## Test if documentation can be built without warnings or errors. - @poetry run mkdocs build -s + @pdm run mkdocs build -s .PHONY: docs docs: ## Build and serve the documentation. - @poetry run mkdocs serve + @pdm run mkdocs serve .PHONY: help help: ## Show help for the commands. diff --git a/docs/contributing.md b/docs/contributing.md index b892fa62..f34b4626 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -67,7 +67,7 @@ Ready to contribute? Here's how to set up _deptry_ for local development. Please 4. Install [pre-commit](https://pre-commit.com/) to run linters/formatters at commit time: ```bash - poetry run pre-commit install + pdm run pre-commit install ``` 5. Create a branch for local development: diff --git a/main.py b/main.py index 0e0409d3..b4bc1395 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,6 @@ for k, v in imports_with_locations.items(): print(k) print(v) - print(v[0].line + 1) except Exception as e: # It will catch the PyIOError thrown by Rust print(type(e)) print(e) diff --git a/poetry.lock b/pdm.lock similarity index 75% rename from poetry.lock rename to pdm.lock index 0caf0f43..90208d05 100644 --- a/poetry.lock +++ b/pdm.lock @@ -1,28 +1,31 @@ -# This file is automatically @generated by Poetry 1.5.0 and should not be changed by hand. +# This file is @generated by PDM. +# It is not intended for manual editing. + +[metadata] +groups = ["default", "dev", "docs", "typing"] +cross_platform = true +static_urls = false +lock_version = "4.3" +content_hash = "sha256:5f1735071095c166db7483350395fa16219910cfb61ad973163ee21df5bb1648" [[package]] name = "babel" version = "2.14.0" -description = "Internationalization utilities" -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Internationalization utilities" +dependencies = [ + "pytz>=2015.7; python_version < \"3.9\"", +] files = [ {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, ] -[package.dependencies] -pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} - -[package.extras] -dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] - [[package]] name = "certifi" version = "2024.2.2" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.6" +requires_python = ">=3.6" +summary = "Python package for providing Mozilla's CA Bundle." files = [ {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, @@ -31,9 +34,8 @@ files = [ [[package]] name = "cfgv" version = "3.4.0" -description = "Validate configuration and produce human readable error messages." -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Validate configuration and produce human readable error messages." files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -41,21 +43,19 @@ files = [ [[package]] name = "chardet" -version = "5.2.0" -description = "Universal encoding detector for Python 3" -optional = false -python-versions = ">=3.7" +version = "4.0.0" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +summary = "Universal encoding detector for Python 2 and 3" files = [ - {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, - {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, + {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, + {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] [[package]] name = "charset-normalizer" version = "3.3.2" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7.0" +requires_python = ">=3.7.0" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, @@ -103,19 +103,6 @@ files = [ {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, @@ -152,23 +139,21 @@ files = [ [[package]] name = "click" version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +dependencies = [ + "colorama; platform_system == \"Windows\"", +] files = [ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - [[package]] name = "colorama" version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -177,9 +162,8 @@ files = [ [[package]] name = "coverage" version = "7.4.3" -description = "Code coverage measurement for Python" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Code coverage measurement for Python" files = [ {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, @@ -235,18 +219,75 @@ files = [ {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, ] -[package.dependencies] -tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} - -[package.extras] -toml = ["tomli"] +[[package]] +name = "coverage" +version = "7.4.3" +extras = ["toml"] +requires_python = ">=3.8" +summary = "Code coverage measurement for Python" +dependencies = [ + "coverage==7.4.3", + "tomli; python_full_version <= \"3.11.0a6\"", +] +files = [ + {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, + {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, + {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"}, + {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"}, + {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"}, + {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"}, + {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"}, + {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"}, + {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"}, + {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"}, + {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"}, + {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"}, + {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"}, + {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"}, + {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"}, + {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"}, + {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"}, + {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"}, + {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"}, + {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"}, + {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"}, + {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"}, + {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"}, + {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"}, + {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"}, + {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"}, + {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"}, + {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"}, + {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"}, + {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"}, + {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"}, + {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"}, + {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"}, + {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"}, + {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"}, + {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"}, + {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"}, + {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"}, + {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"}, + {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"}, + {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"}, + {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"}, + {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"}, + {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"}, + {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"}, + {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"}, + {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"}, + {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"}, + {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"}, + {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"}, + {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"}, + {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, +] [[package]] name = "distlib" version = "0.3.8" -description = "Distribution utilities" -optional = false -python-versions = "*" +summary = "Distribution utilities" files = [ {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, @@ -255,70 +296,50 @@ files = [ [[package]] name = "exceptiongroup" version = "1.2.0" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Backport of PEP 654 (exception groups)" files = [ {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "filelock" version = "3.13.1" -description = "A platform independent file lock." -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "A platform independent file lock." files = [ {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] -[package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] - [[package]] name = "ghp-import" version = "2.1.0" -description = "Copy your docs directly to the gh-pages branch." -optional = false -python-versions = "*" +summary = "Copy your docs directly to the gh-pages branch." +dependencies = [ + "python-dateutil>=2.8.1", +] files = [ {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, ] -[package.dependencies] -python-dateutil = ">=2.8.1" - -[package.extras] -dev = ["flake8", "markdown", "twine", "wheel"] - [[package]] name = "identify" version = "2.5.35" -description = "File identification library for Python" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "File identification library for Python" files = [ {file = "identify-2.5.35-py2.py3-none-any.whl", hash = "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e"}, {file = "identify-2.5.35.tar.gz", hash = "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791"}, ] -[package.extras] -license = ["ukkonen"] - [[package]] name = "idna" version = "3.6" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.5" +requires_python = ">=3.5" +summary = "Internationalized Domain Names in Applications (IDNA)" files = [ {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, @@ -326,29 +347,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.1" -description = "Read metadata from Python packages" -optional = false -python-versions = ">=3.8" +version = "7.0.2" +requires_python = ">=3.8" +summary = "Read metadata from Python packages" +dependencies = [ + "zipp>=0.5", +] files = [ - {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, - {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, + {file = "importlib_metadata-7.0.2-py3-none-any.whl", hash = "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100"}, + {file = "importlib_metadata-7.0.2.tar.gz", hash = "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792"}, ] -[package.dependencies] -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] - [[package]] name = "iniconfig" version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "brain-dead simple config-ini parsing" files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -357,44 +371,34 @@ files = [ [[package]] name = "jinja2" version = "3.1.3" -description = "A very fast and expressive template engine." -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "A very fast and expressive template engine." +dependencies = [ + "MarkupSafe>=2.0", +] files = [ {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, ] -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - [[package]] name = "markdown" version = "3.5.2" -description = "Python implementation of John Gruber's Markdown." -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Python implementation of John Gruber's Markdown." +dependencies = [ + "importlib-metadata>=4.4; python_version < \"3.10\"", +] files = [ {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"}, {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"}, ] -[package.dependencies] -importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} - -[package.extras] -docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] -testing = ["coverage", "pyyaml"] - [[package]] name = "markupsafe" version = "2.1.5" -description = "Safely add untrusted strings to HTML/XML markup." -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Safely add untrusted strings to HTML/XML markup." files = [ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, @@ -426,15 +430,6 @@ files = [ {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, @@ -461,9 +456,11 @@ files = [ [[package]] name = "maturin" version = "1.5.0" -description = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages" -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages" +dependencies = [ + "tomli>=1.1.0; python_version < \"3.11\"", +] files = [ {file = "maturin-1.5.0-py3-none-linux_armv6l.whl", hash = "sha256:0b976116b7cfaafbc8c3f0acfaec6702520c49e86e48ea80e2c282b7f8118c1a"}, {file = "maturin-1.5.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d277adf9b27143627ba7be7ea254513d3e85008fb16a94638b56884a41b4e5a2"}, @@ -480,19 +477,11 @@ files = [ {file = "maturin-1.5.0.tar.gz", hash = "sha256:e046ea2aed687991d58c42f6276dfcc0c037092934654f538b5877fd57dd3a9c"}, ] -[package.dependencies] -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} - -[package.extras] -patchelf = ["patchelf"] -zig = ["ziglang (>=0.10.0,<0.11.0)"] - [[package]] name = "mergedeep" version = "1.3.4" -description = "A deep merge function for 🐍." -optional = false -python-versions = ">=3.6" +requires_python = ">=3.6" +summary = "A deep merge function for 🐍." files = [ {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, @@ -501,69 +490,57 @@ files = [ [[package]] name = "mkdocs" version = "1.5.3" -description = "Project documentation with Markdown." -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Project documentation with Markdown." +dependencies = [ + "click>=7.0", + "colorama>=0.4; platform_system == \"Windows\"", + "ghp-import>=1.0", + "importlib-metadata>=4.3; python_version < \"3.10\"", + "jinja2>=2.11.1", + "markdown>=3.2.1", + "markupsafe>=2.0.1", + "mergedeep>=1.3.4", + "packaging>=20.5", + "pathspec>=0.11.1", + "platformdirs>=2.2.0", + "pyyaml-env-tag>=0.1", + "pyyaml>=5.1", + "watchdog>=2.0", +] files = [ {file = "mkdocs-1.5.3-py3-none-any.whl", hash = "sha256:3b3a78e736b31158d64dbb2f8ba29bd46a379d0c6e324c2246c3bc3d2189cfc1"}, {file = "mkdocs-1.5.3.tar.gz", hash = "sha256:eb7c99214dcb945313ba30426c2451b735992c73c2e10838f76d09e39ff4d0e2"}, ] -[package.dependencies] -click = ">=7.0" -colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} -ghp-import = ">=1.0" -importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""} -jinja2 = ">=2.11.1" -markdown = ">=3.2.1" -markupsafe = ">=2.0.1" -mergedeep = ">=1.3.4" -packaging = ">=20.5" -pathspec = ">=0.11.1" -platformdirs = ">=2.2.0" -pyyaml = ">=5.1" -pyyaml-env-tag = ">=0.1" -watchdog = ">=2.0" - -[package.extras] -i18n = ["babel (>=2.9.0)"] -min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pathspec (==0.11.1)", "platformdirs (==2.2.0)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] - [[package]] name = "mkdocs-material" version = "9.5.10" -description = "Documentation that simply works" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Documentation that simply works" +dependencies = [ + "babel~=2.10", + "colorama~=0.4", + "jinja2~=3.0", + "markdown~=3.2", + "mkdocs-material-extensions~=1.3", + "mkdocs~=1.5.3", + "paginate~=0.5", + "pygments~=2.16", + "pymdown-extensions~=10.2", + "regex>=2022.4", + "requests~=2.26", +] files = [ {file = "mkdocs_material-9.5.10-py3-none-any.whl", hash = "sha256:3c6c46b57d2ee3c8890e6e0406e68b6863cf65768f0f436990a742702d198442"}, {file = "mkdocs_material-9.5.10.tar.gz", hash = "sha256:6ad626dbb31070ebbaedff813323a16a406629620e04b96458f16e6e9c7008fe"}, ] -[package.dependencies] -babel = ">=2.10,<3.0" -colorama = ">=0.4,<1.0" -jinja2 = ">=3.0,<4.0" -markdown = ">=3.2,<4.0" -mkdocs = ">=1.5.3,<1.6.0" -mkdocs-material-extensions = ">=1.3,<2.0" -paginate = ">=0.5,<1.0" -pygments = ">=2.16,<3.0" -pymdown-extensions = ">=10.2,<11.0" -regex = ">=2022.4" -requests = ">=2.26,<3.0" - -[package.extras] -git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"] -imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"] -recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"] - [[package]] name = "mkdocs-material-extensions" version = "1.3.1" -description = "Extension pack for Python Markdown and MkDocs Material." -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Extension pack for Python Markdown and MkDocs Material." files = [ {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, @@ -572,9 +549,13 @@ files = [ [[package]] name = "mypy" version = "1.8.0" -description = "Optional static typing for Python" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Optional static typing for Python" +dependencies = [ + "mypy-extensions>=1.0.0", + "tomli>=1.1.0; python_version < \"3.11\"", + "typing-extensions>=4.1.0", +] files = [ {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, @@ -605,23 +586,11 @@ files = [ {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, ] -[package.dependencies] -mypy-extensions = ">=1.0.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.1.0" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -install-types = ["pip"] -mypyc = ["setuptools (>=50)"] -reports = ["lxml"] - [[package]] name = "mypy-extensions" version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -630,34 +599,30 @@ files = [ [[package]] name = "nodeenv" version = "1.8.0" -description = "Node.js virtual environment builder" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +requires_python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +summary = "Node.js virtual environment builder" +dependencies = [ + "setuptools", +] files = [ {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "packaging" -version = "23.2" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.7" +version = "24.0" +requires_python = ">=3.7" +summary = "Core utilities for Python packages" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] name = "paginate" version = "0.5.6" -description = "Divides large result sets into pages for easier browsing" -optional = false -python-versions = "*" +summary = "Divides large result sets into pages for easier browsing" files = [ {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, ] @@ -665,9 +630,8 @@ files = [ [[package]] name = "pathspec" version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Utility library for gitignore style pattern matching of file paths." files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -676,144 +640,113 @@ files = [ [[package]] name = "platformdirs" version = "4.2.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." files = [ {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] -[package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] - [[package]] name = "pluggy" version = "1.4.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "plugin and hook calling mechanisms for python" files = [ {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - [[package]] name = "pre-commit" version = "3.5.0" -description = "A framework for managing and maintaining multi-language pre-commit hooks." -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "A framework for managing and maintaining multi-language pre-commit hooks." +dependencies = [ + "cfgv>=2.0.0", + "identify>=1.0.0", + "nodeenv>=0.11.1", + "pyyaml>=5.1", + "virtualenv>=20.10.0", +] files = [ {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, ] -[package.dependencies] -cfgv = ">=2.0.0" -identify = ">=1.0.0" -nodeenv = ">=0.11.1" -pyyaml = ">=5.1" -virtualenv = ">=20.10.0" - [[package]] name = "pygments" version = "2.17.2" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Pygments is a syntax highlighting package written in Python." files = [ {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] -[package.extras] -plugins = ["importlib-metadata"] -windows-terminal = ["colorama (>=0.4.6)"] - [[package]] name = "pymdown-extensions" -version = "10.7" -description = "Extension pack for Python Markdown." -optional = false -python-versions = ">=3.8" +version = "10.7.1" +requires_python = ">=3.8" +summary = "Extension pack for Python Markdown." +dependencies = [ + "markdown>=3.5", + "pyyaml", +] files = [ - {file = "pymdown_extensions-10.7-py3-none-any.whl", hash = "sha256:6ca215bc57bc12bf32b414887a68b810637d039124ed9b2e5bd3325cbb2c050c"}, - {file = "pymdown_extensions-10.7.tar.gz", hash = "sha256:c0d64d5cf62566f59e6b2b690a4095c931107c250a8c8e1351c1de5f6b036deb"}, + {file = "pymdown_extensions-10.7.1-py3-none-any.whl", hash = "sha256:f5cc7000d7ff0d1ce9395d216017fa4df3dde800afb1fb72d1c7d3fd35e710f4"}, + {file = "pymdown_extensions-10.7.1.tar.gz", hash = "sha256:c70e146bdd83c744ffc766b4671999796aba18842b268510a329f7f64700d584"}, ] -[package.dependencies] -markdown = ">=3.5" -pyyaml = "*" - -[package.extras] -extra = ["pygments (>=2.12)"] - [[package]] name = "pytest" version = "8.0.1" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "pytest: simple powerful testing with Python" +dependencies = [ + "colorama; sys_platform == \"win32\"", + "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", + "iniconfig", + "packaging", + "pluggy<2.0,>=1.3.0", + "tomli>=1.0.0; python_version < \"3.11\"", +] files = [ {file = "pytest-8.0.1-py3-none-any.whl", hash = "sha256:3e4f16fe1c0a9dc9d9389161c127c3edc5d810c38d6793042fb81d9f48a59fca"}, {file = "pytest-8.0.1.tar.gz", hash = "sha256:267f6563751877d772019b13aacbe4e860d73fe8f651f28112e9ac37de7513ae"}, ] -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=1.3.0,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} - -[package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - [[package]] name = "pytest-cov" version = "4.1.0" -description = "Pytest plugin for measuring coverage." -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Pytest plugin for measuring coverage." +dependencies = [ + "coverage[toml]>=5.2.1", + "pytest>=4.6", +] files = [ {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, ] -[package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} -pytest = ">=4.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] - [[package]] name = "python-dateutil" -version = "2.8.2" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +version = "2.9.0.post0" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +summary = "Extensions to the standard Python datetime module" +dependencies = [ + "six>=1.5", +] files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] -[package.dependencies] -six = ">=1.5" - [[package]] name = "pytz" version = "2024.1" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" +summary = "World timezone definitions, modern and historical" files = [ {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, @@ -822,9 +755,8 @@ files = [ [[package]] name = "pyyaml" version = "6.0.1" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.6" +requires_python = ">=3.6" +summary = "YAML parser and emitter for Python" files = [ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, @@ -844,22 +776,11 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, @@ -881,23 +802,21 @@ files = [ [[package]] name = "pyyaml-env-tag" version = "0.1" -description = "A custom YAML tag for referencing environment variables in YAML files. " -optional = false -python-versions = ">=3.6" +requires_python = ">=3.6" +summary = "A custom YAML tag for referencing environment variables in YAML files. " +dependencies = [ + "pyyaml", +] files = [ {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, ] -[package.dependencies] -pyyaml = "*" - [[package]] name = "regex" version = "2023.12.25" -description = "Alternative regular expression module, to replace re." -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Alternative regular expression module, to replace re." files = [ {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5"}, {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8"}, @@ -945,20 +864,6 @@ files = [ {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d"}, {file = "regex-2023.12.25-cp312-cp312-win32.whl", hash = "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5"}, {file = "regex-2023.12.25-cp312-cp312-win_amd64.whl", hash = "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232"}, - {file = "regex-2023.12.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39"}, - {file = "regex-2023.12.25-cp37-cp37m-win32.whl", hash = "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c"}, - {file = "regex-2023.12.25-cp37-cp37m-win_amd64.whl", hash = "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445"}, {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53"}, {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64"}, {file = "regex-2023.12.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415"}, @@ -997,46 +902,34 @@ files = [ [[package]] name = "requests" version = "2.31.0" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Python HTTP for Humans." +dependencies = [ + "certifi>=2017.4.17", + "charset-normalizer<4,>=2", + "idna<4,>=2.5", + "urllib3<3,>=1.21.1", +] files = [ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, ] -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - [[package]] name = "setuptools" version = "69.1.1" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Easily download, build, install, upgrade, and uninstall Python packages" files = [ {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, ] -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "six" version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +summary = "Python 2 and 3 compatibility utilities" files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -1045,9 +938,8 @@ files = [ [[package]] name = "tomli" version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "A lil' TOML parser" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, @@ -1056,9 +948,7 @@ files = [ [[package]] name = "types-chardet" version = "5.0.4.6" -description = "Typing stubs for chardet" -optional = false -python-versions = "*" +summary = "Typing stubs for chardet" files = [ {file = "types-chardet-5.0.4.6.tar.gz", hash = "sha256:caf4c74cd13ccfd8b3313c314aba943b159de562a2573ed03137402b2bb37818"}, {file = "types_chardet-5.0.4.6-py3-none-any.whl", hash = "sha256:ea832d87e798abf1e4dfc73767807c2b7fee35d0003ae90348aea4ae00fb004d"}, @@ -1067,9 +957,8 @@ files = [ [[package]] name = "types-colorama" version = "0.4.15.20240205" -description = "Typing stubs for colorama" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Typing stubs for colorama" files = [ {file = "types-colorama-0.4.15.20240205.tar.gz", hash = "sha256:7ae4f58d407d387f4f98b24d81e1b7657ec754ea1dc4619ae5bd27f0c367637e"}, {file = "types_colorama-0.4.15.20240205-py3-none-any.whl", hash = "sha256:3ab26dcd76d2f13b1b795ed5c87a1a1a29331ea64cf614bb6ae958a3cebc3a53"}, @@ -1077,58 +966,44 @@ files = [ [[package]] name = "typing-extensions" -version = "4.9.0" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" +version = "4.10.0" +requires_python = ">=3.8" +summary = "Backported and Experimental Type Hints for Python 3.8+" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, + {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, ] [[package]] name = "urllib3" version = "2.2.1" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "HTTP library with thread-safe connection pooling, file post, and more." files = [ {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - [[package]] name = "virtualenv" version = "20.25.1" -description = "Virtual Python Environment builder" -optional = false -python-versions = ">=3.7" +requires_python = ">=3.7" +summary = "Virtual Python Environment builder" +dependencies = [ + "distlib<1,>=0.3.7", + "filelock<4,>=3.12.2", + "platformdirs<5,>=3.9.1", +] files = [ {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, ] -[package.dependencies] -distlib = ">=0.3.7,<1" -filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<5" - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] - [[package]] name = "watchdog" version = "4.0.0" -description = "Filesystem events monitoring" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Filesystem events monitoring" files = [ {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, @@ -1161,25 +1036,12 @@ files = [ {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, ] -[package.extras] -watchmedo = ["PyYAML (>=3.10)"] - [[package]] name = "zipp" version = "3.17.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -optional = false -python-versions = ">=3.8" +requires_python = ">=3.8" +summary = "Backport of pathlib-compatible object wrapper for zip files" files = [ {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, ] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] - -[metadata] -lock-version = "2.0" -python-versions = ">=3.8,<4.0" -content-hash = "8aece3fd72486c859557dad4046e1d5c74d5aa95ba27cdb1571fcb1690fedbdc" diff --git a/pyproject.toml b/pyproject.toml index 473ac704..2975db3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,3 @@ -[tool.poetry] -name = "deptry" -version = "0.0.1" -description = "A command line utility to check for unused, missing and transitive dependencies in a Python project." -authors = ["Florian Maas "] -maintainers = ["Mathieu Kniewallner "] - [project] name = "deptry" version = "0.0.1" @@ -24,12 +17,39 @@ classifiers = [ "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", ] +dependencies = [ + "chardet>=4.0.0", + "click>=8.0.0,<9", + "pathspec>=0.9.0", + "colorama>=0.4.6; sys_platform == 'win32'", + "tomli>=2.0.1; python_version < '3.11'" +] + +[tool.pdm.dev-dependencies] +dev = [ + "pre-commit == 3.5.0", + "pytest == 8.0.1", + "pytest-cov == 4.1.0", + "maturin == 1.5.0", +] +typing = [ + "mypy == 1.8.0", + "types-chardet == 5.0.4.6", + "types-colorama == 0.4.15.20240205; sys_platform == 'win32'", +] +docs = [ + "mkdocs == 1.5.3", + "mkdocs-material == 9.5.10", +] [project.urls] homepage = "https://fpgmaas.github.io/deptry" repository = "https://github.com/fpgmaas/deptry" documentation = "https://fpgmaas.github.io/deptry" +[project.scripts] +deptry = "deptry.cli:deptry" + [build-system] requires = ["maturin>=1.5,<2.0"] build-backend = "maturin" @@ -37,29 +57,6 @@ build-backend = "maturin" [tool.maturin] features = ["pyo3/extension-module"] -[tool.poetry.dependencies] -python = ">=3.8,<4.0" -chardet = ">=4.0.0" -click = "^8.0.0" -colorama = { version = ">=0.4.6", markers = "sys_platform == 'win32'" } -pathspec = ">=0.9.0" -tomli = { version = "^2.0.1", python = "<3.11" } - -[tool.poetry.group.dev.dependencies] -pre-commit = "3.5.0" -pytest = "8.0.1" -pytest-cov = "4.1.0" -maturin = "^1.5.0" - -[tool.poetry.group.docs.dependencies] -mkdocs = "1.5.3" -mkdocs-material = "9.5.10" - -[tool.poetry.group.typing.dependencies] -mypy = "1.8.0" -types-chardet = "5.0.4.6" -types-colorama = { version = "0.4.15.20240205", markers = "sys_platform == 'win32'" } - [tool.coverage.report] skip_empty = true # Subset of rules from https://pypi.org/project/covdefaults/ @@ -112,9 +109,6 @@ extend_exclude = [ [tool.deptry.per_rule_ignores] DEP001 = ["tomllib"] -[tool.poetry.scripts] -deptry = "deptry.cli:deptry" - [tool.pytest.ini_options] addopts = "--doctest-modules" filterwarnings = ["error"] diff --git a/tests/functional/cli/test_cli.py b/tests/functional/cli/test_cli.py index 403fc703..d3d581ec 100644 --- a/tests/functional/cli/test_cli.py +++ b/tests/functional/cli/test_cli.py @@ -4,7 +4,10 @@ from pathlib import Path from typing import TYPE_CHECKING -from tests.utils import get_issues_report +from click.testing import CliRunner + +from deptry.cli import deptry +from tests.utils import get_issues_report, stylize if TYPE_CHECKING: from tests.utils import PoetryVenvFactory @@ -50,7 +53,336 @@ def test_cli_returns_error(poetry_venv_factory: PoetryVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 4, - "column": 0, + "column": 8, + }, + }, + { + "error": { + "code": "DEP001", + "message": "'white' imported but missing from the dependency definitions", + }, + "module": "white", + "location": { + "file": str(Path("src/main.py")), + "line": 6, + "column": 8, + }, + }, + ] + + +def test_cli_ignore_notebooks(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + issue_report = f"{uuid.uuid4()}.json" + result = virtual_env.run(f"deptry . --ignore-notebooks -o {issue_report}") + + assert result.returncode == 1 + assert get_issues_report(Path(issue_report)) == [ + { + "error": { + "code": "DEP002", + "message": "'toml' defined as a dependency but not used in the codebase", + }, + "module": "toml", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'isort' defined as a dependency but not used in the codebase", + }, + "module": "isort", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'requests' defined as a dependency but not used in the codebase", + }, + "module": "requests", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP004", + "message": "'black' imported but declared as a dev dependency", + }, + "module": "black", + "location": { + "file": str(Path("src/main.py")), + "line": 4, + "column": 8, + }, + }, + { + "error": { + "code": "DEP001", + "message": "'white' imported but missing from the dependency definitions", + }, + "module": "white", + "location": { + "file": str(Path("src/main.py")), + "line": 6, + "column": 8, + }, + }, + ] + + +def test_cli_ignore_flags(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + result = virtual_env.run("deptry . --per-rule-ignores DEP002=isort|pkginfo|requests -im white -id black") + + assert result.returncode == 0 + + +def test_cli_ignore_flag(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + result = virtual_env.run("deptry . --ignore DEP001,DEP002,DEP003,DEP004") + + assert result.returncode == 0 + + +def test_cli_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + issue_report = f"{uuid.uuid4()}.json" + result = virtual_env.run(f"deptry . --exclude src/notebook.ipynb -o {issue_report}") + + assert result.returncode == 1 + assert get_issues_report(Path(issue_report)) == [ + { + "error": { + "code": "DEP002", + "message": "'toml' defined as a dependency but not used in the codebase", + }, + "module": "toml", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'isort' defined as a dependency but not used in the codebase", + }, + "module": "isort", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'requests' defined as a dependency but not used in the codebase", + }, + "module": "requests", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP004", + "message": "'black' imported but declared as a dev dependency", + }, + "module": "black", + "location": { + "file": str(Path("src/main.py")), + "line": 4, + "column": 8, + }, + }, + { + "error": { + "code": "DEP001", + "message": "'white' imported but missing from the dependency definitions", + }, + "module": "white", + "location": { + "file": str(Path("src/main.py")), + "line": 6, + "column": 8, + }, + }, + ] + + +def test_cli_extend_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + issue_report = f"{uuid.uuid4()}.json" + result = virtual_env.run(f"deptry . -ee src/notebook.ipynb -o {issue_report}") + + assert result.returncode == 1 + assert get_issues_report(Path(issue_report)) == [ + { + "error": { + "code": "DEP002", + "message": "'toml' defined as a dependency but not used in the codebase", + }, + "module": "toml", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'isort' defined as a dependency but not used in the codebase", + }, + "module": "isort", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'requests' defined as a dependency but not used in the codebase", + }, + "module": "requests", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP004", + "message": "'black' imported but declared as a dev dependency", + }, + "module": "black", + "location": { + "file": str(Path("src/main.py")), + "line": 4, + "column": 8, + }, + }, + { + "error": { + "code": "DEP001", + "message": "'white' imported but missing from the dependency definitions", + }, + "module": "white", + "location": { + "file": str(Path("src/main.py")), + "line": 6, + "column": 8, + }, + }, + ] + + +def test_cli_known_first_party(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + issue_report = f"{uuid.uuid4()}.json" + result = virtual_env.run(f"deptry . --known-first-party white -o {issue_report}") + + assert result.returncode == 1 + assert get_issues_report(Path(issue_report)) == [ + { + "error": { + "code": "DEP002", + "message": "'isort' defined as a dependency but not used in the codebase", + }, + "module": "isort", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'requests' defined as a dependency but not used in the codebase", + }, + "module": "requests", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP004", + "message": "'black' imported but declared as a dev dependency", + }, + "module": "black", + "location": { + "file": str(Path("src/main.py")), + "line": 4, + "column": 8, + }, + }, + ] + + +def test_cli_not_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + issue_report = f"{uuid.uuid4()}.json" + result = virtual_env.run(f"deptry . -o {issue_report}") + + assert result.returncode == 1 + assert "The project contains the following dependencies:" not in result.stderr + assert get_issues_report(Path(issue_report)) == [ + { + "error": { + "code": "DEP002", + "message": "'isort' defined as a dependency but not used in the codebase", + }, + "module": "isort", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'requests' defined as a dependency but not used in the codebase", + }, + "module": "requests", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP004", + "message": "'black' imported but declared as a dev dependency", + }, + "module": "black", + "location": { + "file": str(Path("src/main.py")), + "line": 4, + "column": 8, }, }, { @@ -62,551 +394,222 @@ def test_cli_returns_error(poetry_venv_factory: PoetryVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 6, - "column": 0, + "column": 8, }, }, ] -# def test_cli_ignore_notebooks(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# issue_report = f"{uuid.uuid4()}.json" -# result = virtual_env.run(f"deptry . --ignore-notebooks -o {issue_report}") - -# assert result.returncode == 1 -# assert get_issues_report(Path(issue_report)) == [ -# { -# "error": { -# "code": "DEP002", -# "message": "'toml' defined as a dependency but not used in the codebase", -# }, -# "module": "toml", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'isort' defined as a dependency but not used in the codebase", -# }, -# "module": "isort", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'requests' defined as a dependency but not used in the codebase", -# }, -# "module": "requests", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP004", -# "message": "'black' imported but declared as a dev dependency", -# }, -# "module": "black", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 4, -# "column": 0, -# }, -# }, -# { -# "error": { -# "code": "DEP001", -# "message": "'white' imported but missing from the dependency definitions", -# }, -# "module": "white", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 6, -# "column": 0, -# }, -# }, -# ] - - -# def test_cli_ignore_flags(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# result = virtual_env.run("deptry . --per-rule-ignores DEP002=isort|pkginfo|requests -im white -id black") - -# assert result.returncode == 0 - - -# def test_cli_ignore_flag(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# result = virtual_env.run("deptry . --ignore DEP001,DEP002,DEP003,DEP004") - -# assert result.returncode == 0 - - -# def test_cli_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# issue_report = f"{uuid.uuid4()}.json" -# result = virtual_env.run(f"deptry . --exclude src/notebook.ipynb -o {issue_report}") - -# assert result.returncode == 1 -# assert get_issues_report(Path(issue_report)) == [ -# { -# "error": { -# "code": "DEP002", -# "message": "'toml' defined as a dependency but not used in the codebase", -# }, -# "module": "toml", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'isort' defined as a dependency but not used in the codebase", -# }, -# "module": "isort", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'requests' defined as a dependency but not used in the codebase", -# }, -# "module": "requests", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP004", -# "message": "'black' imported but declared as a dev dependency", -# }, -# "module": "black", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 4, -# "column": 0, -# }, -# }, -# { -# "error": { -# "code": "DEP001", -# "message": "'white' imported but missing from the dependency definitions", -# }, -# "module": "white", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 6, -# "column": 0, -# }, -# }, -# ] - - -# def test_cli_extend_exclude(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# issue_report = f"{uuid.uuid4()}.json" -# result = virtual_env.run(f"deptry . -ee src/notebook.ipynb -o {issue_report}") - -# assert result.returncode == 1 -# assert get_issues_report(Path(issue_report)) == [ -# { -# "error": { -# "code": "DEP002", -# "message": "'toml' defined as a dependency but not used in the codebase", -# }, -# "module": "toml", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'isort' defined as a dependency but not used in the codebase", -# }, -# "module": "isort", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'requests' defined as a dependency but not used in the codebase", -# }, -# "module": "requests", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP004", -# "message": "'black' imported but declared as a dev dependency", -# }, -# "module": "black", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 4, -# "column": 0, -# }, -# }, -# { -# "error": { -# "code": "DEP001", -# "message": "'white' imported but missing from the dependency definitions", -# }, -# "module": "white", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 6, -# "column": 0, -# }, -# }, -# ] - - -# def test_cli_known_first_party(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# issue_report = f"{uuid.uuid4()}.json" -# result = virtual_env.run(f"deptry . --known-first-party white -o {issue_report}") - -# assert result.returncode == 1 -# assert get_issues_report(Path(issue_report)) == [ -# { -# "error": { -# "code": "DEP002", -# "message": "'isort' defined as a dependency but not used in the codebase", -# }, -# "module": "isort", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'requests' defined as a dependency but not used in the codebase", -# }, -# "module": "requests", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP004", -# "message": "'black' imported but declared as a dev dependency", -# }, -# "module": "black", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 4, -# "column": 0, -# }, -# }, -# ] - - -# def test_cli_not_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# issue_report = f"{uuid.uuid4()}.json" -# result = virtual_env.run(f"deptry . -o {issue_report}") - -# assert result.returncode == 1 -# assert "The project contains the following dependencies:" not in result.stderr -# assert get_issues_report(Path(issue_report)) == [ -# { -# "error": { -# "code": "DEP002", -# "message": "'isort' defined as a dependency but not used in the codebase", -# }, -# "module": "isort", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'requests' defined as a dependency but not used in the codebase", -# }, -# "module": "requests", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP004", -# "message": "'black' imported but declared as a dev dependency", -# }, -# "module": "black", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 4, -# "column": 0, -# }, -# }, -# { -# "error": { -# "code": "DEP001", -# "message": "'white' imported but missing from the dependency definitions", -# }, -# "module": "white", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 6, -# "column": 0, -# }, -# }, -# ] - - -# def test_cli_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# issue_report = f"{uuid.uuid4()}.json" -# result = virtual_env.run(f"deptry . --verbose -o {issue_report}") - -# assert result.returncode == 1 -# assert "The project contains the following dependencies:" in result.stderr -# assert get_issues_report(Path(issue_report)) == [ -# { -# "error": { -# "code": "DEP002", -# "message": "'isort' defined as a dependency but not used in the codebase", -# }, -# "module": "isort", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'requests' defined as a dependency but not used in the codebase", -# }, -# "module": "requests", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP004", -# "message": "'black' imported but declared as a dev dependency", -# }, -# "module": "black", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 4, -# "column": 0, -# }, -# }, -# { -# "error": { -# "code": "DEP001", -# "message": "'white' imported but missing from the dependency definitions", -# }, -# "module": "white", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 6, -# "column": 0, -# }, -# }, -# ] - - -# def test_cli_with_no_ansi(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# result = virtual_env.run("deptry . --no-ansi") - -# expected_output = [ -# "Scanning 2 files...", -# "", -# f"{Path('pyproject.toml')}: DEP002 'isort' defined as a dependency but not used in the codebase", -# f"{Path('pyproject.toml')}: DEP002 'requests' defined as a dependency but not used in the codebase", -# f"{Path('src/main.py')}:4:0: DEP004 'black' imported but declared as a dev dependency", -# f"{Path('src/main.py')}:6:0: DEP001 'white' imported but missing from the dependency definitions", -# "Found 4 dependency issues.", -# "", -# "For more information, see the documentation: https://fpgmaas.github.io/deptry/", -# "", -# ] - -# assert result.returncode == 1 -# assert result.stderr == "\n".join(expected_output) - - -# def test_cli_with_not_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# json_files_count = len(list(Path().glob("*.json"))) - -# result = virtual_env.run("deptry .") - -# expected_output = [ -# "Scanning 2 files...", -# "", -# stylize( -# "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" -# " used in the codebase", -# file=Path("pyproject.toml"), -# ), -# stylize( -# "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" -# " not used in the codebase", -# file=Path("pyproject.toml"), -# ), -# stylize( -# "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" -# " imported but declared as a dev dependency", -# file=Path("src/main.py"), -# ), -# stylize( -# "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" -# " imported but missing from the dependency definitions", -# file=Path("src/main.py"), -# ), -# stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), -# "", -# "For more information, see the documentation: https://fpgmaas.github.io/deptry/", -# "", -# ] - -# assert result.returncode == 1 -# # Assert that we have the same number of JSON files as before running the command. -# assert len(list(Path().glob("*.json"))) == json_files_count -# assert result.stderr == "\n".join(expected_output) - - -# def test_cli_with_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: -# with poetry_venv_factory("example_project") as virtual_env: -# issue_report = f"{uuid.uuid4()}.json" -# result = virtual_env.run(f"deptry . -o {issue_report}") - -# expected_output = [ -# "Scanning 2 files...", -# "", -# stylize( -# "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" -# " used in the codebase", -# file=Path("pyproject.toml"), -# ), -# stylize( -# "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" -# " not used in the codebase", -# file=Path("pyproject.toml"), -# ), -# stylize( -# "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" -# " imported but declared as a dev dependency", -# file=Path("src/main.py"), -# ), -# stylize( -# "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}0{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" -# " imported but missing from the dependency definitions", -# file=Path("src/main.py"), -# ), -# stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), -# "", -# "For more information, see the documentation: https://fpgmaas.github.io/deptry/", -# "", -# ] - -# # Assert that we still write to console when generating a JSON report. -# assert result.stderr == "\n".join(expected_output) -# assert get_issues_report(Path(issue_report)) == [ -# { -# "error": { -# "code": "DEP002", -# "message": "'isort' defined as a dependency but not used in the codebase", -# }, -# "module": "isort", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP002", -# "message": "'requests' defined as a dependency but not used in the codebase", -# }, -# "module": "requests", -# "location": { -# "file": str(Path("pyproject.toml")), -# "line": None, -# "column": None, -# }, -# }, -# { -# "error": { -# "code": "DEP004", -# "message": "'black' imported but declared as a dev dependency", -# }, -# "module": "black", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 4, -# "column": 0, -# }, -# }, -# { -# "error": { -# "code": "DEP001", -# "message": "'white' imported but missing from the dependency definitions", -# }, -# "module": "white", -# "location": { -# "file": str(Path("src/main.py")), -# "line": 6, -# "column": 0, -# }, -# }, -# ] - - -# def test_cli_help() -> None: -# result = CliRunner().invoke(deptry, "--help") - -# assert result.exit_code == 0 +def test_cli_verbose(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + issue_report = f"{uuid.uuid4()}.json" + result = virtual_env.run(f"deptry . --verbose -o {issue_report}") + + assert result.returncode == 1 + assert "The project contains the following dependencies:" in result.stderr + assert get_issues_report(Path(issue_report)) == [ + { + "error": { + "code": "DEP002", + "message": "'isort' defined as a dependency but not used in the codebase", + }, + "module": "isort", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'requests' defined as a dependency but not used in the codebase", + }, + "module": "requests", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP004", + "message": "'black' imported but declared as a dev dependency", + }, + "module": "black", + "location": { + "file": str(Path("src/main.py")), + "line": 4, + "column": 8, + }, + }, + { + "error": { + "code": "DEP001", + "message": "'white' imported but missing from the dependency definitions", + }, + "module": "white", + "location": { + "file": str(Path("src/main.py")), + "line": 6, + "column": 8, + }, + }, + ] + + +def test_cli_with_no_ansi(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + result = virtual_env.run("deptry . --no-ansi") + + expected_output = [ + "Scanning 2 files...", + "", + f"{Path('pyproject.toml')}: DEP002 'isort' defined as a dependency but not used in the codebase", + f"{Path('pyproject.toml')}: DEP002 'requests' defined as a dependency but not used in the codebase", + f"{Path('src/main.py')}:4:8: DEP004 'black' imported but declared as a dev dependency", + f"{Path('src/main.py')}:6:8: DEP001 'white' imported but missing from the dependency definitions", + "Found 4 dependency issues.", + "", + "For more information, see the documentation: https://fpgmaas.github.io/deptry/", + "", + ] + + assert result.returncode == 1 + assert result.stderr == "\n".join(expected_output) + + +def test_cli_with_not_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + json_files_count = len(list(Path().glob("*.json"))) + + result = virtual_env.run("deptry .") + + expected_output = [ + "Scanning 2 files...", + "", + stylize( + "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" + " used in the codebase", + file=Path("pyproject.toml"), + ), + stylize( + "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" + " not used in the codebase", + file=Path("pyproject.toml"), + ), + stylize( + "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" + " imported but declared as a dev dependency", + file=Path("src/main.py"), + ), + stylize( + "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" + " imported but missing from the dependency definitions", + file=Path("src/main.py"), + ), + stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), + "", + "For more information, see the documentation: https://fpgmaas.github.io/deptry/", + "", + ] + + assert result.returncode == 1 + # Assert that we have the same number of JSON files as before running the command. + assert len(list(Path().glob("*.json"))) == json_files_count + assert result.stderr == "\n".join(expected_output) + + +def test_cli_with_json_output(poetry_venv_factory: PoetryVenvFactory) -> None: + with poetry_venv_factory("example_project") as virtual_env: + issue_report = f"{uuid.uuid4()}.json" + result = virtual_env.run(f"deptry . -o {issue_report}") + + expected_output = [ + "Scanning 2 files...", + "", + stylize( + "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'isort' defined as a dependency but not" + " used in the codebase", + file=Path("pyproject.toml"), + ), + stylize( + "{BOLD}{file}{RESET}{CYAN}:{RESET} {BOLD}{RED}DEP002{RESET} 'requests' defined as a dependency but" + " not used in the codebase", + file=Path("pyproject.toml"), + ), + stylize( + "{BOLD}{file}{RESET}{CYAN}:{RESET}4{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP004{RESET} 'black'" + " imported but declared as a dev dependency", + file=Path("src/main.py"), + ), + stylize( + "{BOLD}{file}{RESET}{CYAN}:{RESET}6{CYAN}:{RESET}8{CYAN}:{RESET} {BOLD}{RED}DEP001{RESET} 'white'" + " imported but missing from the dependency definitions", + file=Path("src/main.py"), + ), + stylize("{BOLD}{RED}Found 4 dependency issues.{RESET}"), + "", + "For more information, see the documentation: https://fpgmaas.github.io/deptry/", + "", + ] + + # Assert that we still write to console when generating a JSON report. + assert result.stderr == "\n".join(expected_output) + assert get_issues_report(Path(issue_report)) == [ + { + "error": { + "code": "DEP002", + "message": "'isort' defined as a dependency but not used in the codebase", + }, + "module": "isort", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP002", + "message": "'requests' defined as a dependency but not used in the codebase", + }, + "module": "requests", + "location": { + "file": str(Path("pyproject.toml")), + "line": None, + "column": None, + }, + }, + { + "error": { + "code": "DEP004", + "message": "'black' imported but declared as a dev dependency", + }, + "module": "black", + "location": { + "file": str(Path("src/main.py")), + "line": 4, + "column": 8, + }, + }, + { + "error": { + "code": "DEP001", + "message": "'white' imported but missing from the dependency definitions", + }, + "module": "white", + "location": { + "file": str(Path("src/main.py")), + "line": 6, + "column": 8, + }, + }, + ] + + +def test_cli_help() -> None: + result = CliRunner().invoke(deptry, "--help") + + assert result.exit_code == 0 diff --git a/tests/functional/cli/test_cli_multiple_source_directories.py b/tests/functional/cli/test_cli_multiple_source_directories.py index 701c59b3..a33e64f5 100644 --- a/tests/functional/cli/test_cli_multiple_source_directories.py +++ b/tests/functional/cli/test_cli_multiple_source_directories.py @@ -25,11 +25,11 @@ def test_cli_with_multiple_source_directories(pip_venv_factory: PipVenvFactory) { "error": {"code": "DEP001", "message": "'httpx' imported but missing from the dependency definitions"}, "module": "httpx", - "location": {"file": str(Path("src/foo.py")), "line": 1, "column": 0}, + "location": {"file": str(Path("src/foo.py")), "line": 1, "column": 8}, }, { "error": {"code": "DEP001", "message": "'celery' imported but missing from the dependency definitions"}, "module": "celery", - "location": {"file": str(Path("worker/foo.py")), "line": 1, "column": 0}, + "location": {"file": str(Path("worker/foo.py")), "line": 1, "column": 8}, }, ] diff --git a/tests/functional/cli/test_cli_pdm.py b/tests/functional/cli/test_cli_pdm.py index 5b3a35b2..6c6a398f 100644 --- a/tests/functional/cli/test_cli_pdm.py +++ b/tests/functional/cli/test_cli_pdm.py @@ -50,7 +50,7 @@ def test_cli_with_pdm(pdm_venv_factory: PDMVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 4, - "column": 0, + "column": 8, }, }, { @@ -62,7 +62,7 @@ def test_cli_with_pdm(pdm_venv_factory: PDMVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 6, - "column": 0, + "column": 8, }, }, { @@ -74,7 +74,7 @@ def test_cli_with_pdm(pdm_venv_factory: PDMVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 7, - "column": 0, + "column": 8, }, }, { @@ -86,7 +86,7 @@ def test_cli_with_pdm(pdm_venv_factory: PDMVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 8, - "column": 0, + "column": 8, }, }, { @@ -98,7 +98,7 @@ def test_cli_with_pdm(pdm_venv_factory: PDMVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 9, - "column": 0, + "column": 8, }, }, ] diff --git a/tests/functional/cli/test_cli_pep_621.py b/tests/functional/cli/test_cli_pep_621.py index d7a98514..15ab5d13 100644 --- a/tests/functional/cli/test_cli_pep_621.py +++ b/tests/functional/cli/test_cli_pep_621.py @@ -74,7 +74,7 @@ def test_cli_with_pep_621(pip_venv_factory: PipVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 6, - "column": 0, + "column": 8, }, }, ] diff --git a/tests/functional/cli/test_cli_poetry.py b/tests/functional/cli/test_cli_poetry.py index 7d7872a6..42c7216a 100644 --- a/tests/functional/cli/test_cli_poetry.py +++ b/tests/functional/cli/test_cli_poetry.py @@ -50,7 +50,7 @@ def test_cli_with_poetry(poetry_venv_factory: PoetryVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 4, - "column": 0, + "column": 8, }, }, { @@ -62,7 +62,7 @@ def test_cli_with_poetry(poetry_venv_factory: PoetryVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 6, - "column": 0, + "column": 8, }, }, { @@ -74,7 +74,7 @@ def test_cli_with_poetry(poetry_venv_factory: PoetryVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 7, - "column": 0, + "column": 8, }, }, { @@ -86,7 +86,7 @@ def test_cli_with_poetry(poetry_venv_factory: PoetryVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 8, - "column": 0, + "column": 8, }, }, { @@ -98,7 +98,7 @@ def test_cli_with_poetry(poetry_venv_factory: PoetryVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 9, - "column": 0, + "column": 8, }, }, ] diff --git a/tests/functional/cli/test_cli_pyproject_different_directory.py b/tests/functional/cli/test_cli_pyproject_different_directory.py index 00af98ad..c608e668 100644 --- a/tests/functional/cli/test_cli_pyproject_different_directory.py +++ b/tests/functional/cli/test_cli_pyproject_different_directory.py @@ -76,7 +76,7 @@ def test_cli_with_pyproject_different_directory(pip_venv_factory: PipVenvFactory "location": { "file": str(Path("src/project_with_src_directory/foo.py")), "line": 6, - "column": 0, + "column": 8, }, }, ] diff --git a/tests/functional/cli/test_cli_requirements_txt.py b/tests/functional/cli/test_cli_requirements_txt.py index d3e456d9..2e275a01 100644 --- a/tests/functional/cli/test_cli_requirements_txt.py +++ b/tests/functional/cli/test_cli_requirements_txt.py @@ -58,7 +58,7 @@ def test_cli_single_requirements_txt(pip_venv_factory: PipVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 4, - "column": 0, + "column": 8, }, }, { @@ -70,7 +70,7 @@ def test_cli_single_requirements_txt(pip_venv_factory: PipVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 6, - "column": 0, + "column": 8, }, }, { @@ -82,7 +82,7 @@ def test_cli_single_requirements_txt(pip_venv_factory: PipVenvFactory) -> None: "location": { "file": str(Path("src/main.py")), "line": 7, - "column": 0, + "column": 1, }, }, { @@ -148,7 +148,7 @@ def test_cli_multiple_requirements_txt(pip_venv_factory: PipVenvFactory) -> None "location": { "file": str(Path("src/main.py")), "line": 4, - "column": 0, + "column": 8, }, }, { @@ -160,7 +160,7 @@ def test_cli_multiple_requirements_txt(pip_venv_factory: PipVenvFactory) -> None "location": { "file": str(Path("src/main.py")), "line": 6, - "column": 0, + "column": 8, }, }, ] diff --git a/tests/functional/cli/test_cli_src_directory.py b/tests/functional/cli/test_cli_src_directory.py index ccf165c2..da6056ff 100644 --- a/tests/functional/cli/test_cli_src_directory.py +++ b/tests/functional/cli/test_cli_src_directory.py @@ -74,7 +74,7 @@ def test_cli_with_src_directory(pip_venv_factory: PipVenvFactory) -> None: "location": { "file": str(Path("src/foobar.py")), "line": 1, - "column": 0, + "column": 8, }, }, { @@ -86,7 +86,7 @@ def test_cli_with_src_directory(pip_venv_factory: PipVenvFactory) -> None: "location": { "file": str(Path("src/project_with_src_directory/foo.py")), "line": 6, - "column": 0, + "column": 8, }, }, ] diff --git a/tox.ini b/tox.ini index b3dc5c79..ddc09bd9 100644 --- a/tox.ini +++ b/tox.ini @@ -7,5 +7,5 @@ allowlist_externals = poetry skip_install = true commands_pre = poetry install commands = - poetry run pytest - poetry run mypy + pdm run pytest + pdm run mypy From 7150ab7d720cead187f3679c3bc06abb49742ff2 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Sun, 10 Mar 2024 20:00:20 +0100 Subject: [PATCH 11/77] parallel processing attempt --- Cargo.lock | 46 ++++++++++++++++++++++++++++++++ Cargo.toml | 1 + deptry/imports/extract.py | 23 +++++++++------- src/lib.rs | 55 +++++++++++++++++++++++++++------------ 4 files changed, 99 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f73f130c..365a2f54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,6 +89,31 @@ dependencies = [ "libc", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crunchy" version = "0.2.2" @@ -103,6 +128,7 @@ dependencies = [ "encoding_rs", "encoding_rs_io", "pyo3", + "rayon", "regex", "rustpython-ast", "rustpython-parser", @@ -598,6 +624,26 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rayon" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index 27514dbd..40907460 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ chardetng = "0.1.17" encoding_rs = "0.8.33" encoding_rs_io = "0.1.7" pyo3 = "0.20.0" +rayon = "1.9.0" regex = "1.10.3" rustpython-ast = { version = "0.3.0", features = ["visitor"] } rustpython-parser = "0.3.0" diff --git a/deptry/imports/extract.py b/deptry/imports/extract.py index c27a88e6..30fffa2f 100644 --- a/deptry/imports/extract.py +++ b/deptry/imports/extract.py @@ -4,7 +4,7 @@ from collections import defaultdict from typing import TYPE_CHECKING -from deptry import get_imports_from_py_file +from deptry import get_imports_from_py_files from deptry.imports.extractors import NotebookImportExtractor if TYPE_CHECKING: @@ -18,12 +18,21 @@ def get_imported_modules_for_list_of_files(list_of_files: list[Path]) -> dict[str, list[Location]]: logging.info("Scanning %d %s...", len(list_of_files), "files" if len(list_of_files) > 1 else "file") + py_files = [str(file) for file in list_of_files if file.suffix == ".py"] + ipynb_files = [file for file in list_of_files if file.suffix == ".ipynb"] + modules: dict[str, list[Location]] = defaultdict(list) - for file in list_of_files: + # Process all .py files in parallel using Rust + if py_files: + rust_result = get_imports_from_py_files(py_files) + for module, locations in convert_rust_locations_to_python_locations(rust_result).items(): + modules[module].extend(locations) + + # Process each .ipynb file individually + for file in ipynb_files: for module, locations in get_imported_modules_from_file(file).items(): - for location in locations: - modules[module].append(location) + modules[module].extend(locations) logging.debug("All imported modules: %s\n", modules) @@ -35,12 +44,6 @@ def get_imported_modules_from_file(path_to_file: Path) -> dict[str, list[Locatio if path_to_file.suffix == ".ipynb": modules = NotebookImportExtractor(path_to_file).extract_imports() - elif path_to_file.suffix == ".py": - try: - modules = get_imports_from_py_file(str(path_to_file)) - except OSError: - logging.warning("Warning: File %s could not be decoded. Skipping...", path_to_file) - return {} modules = convert_rust_locations_to_python_locations(modules) logging.debug("Found the following imports in %s: %s", path_to_file, modules) diff --git a/src/lib.rs b/src/lib.rs index 91d9b8f9..90ae81de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,32 +17,55 @@ use file_utils::read_file; use location::Location; use rustpython_ast::Visitor; use visitor::ImportVisitor; - +use rayon::prelude::*; #[pymodule] fn deptry(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_function(wrap_pyfunction!(get_imports_from_py_file, m)?)?; + m.add_function(wrap_pyfunction!(get_imports_from_py_files, m)?)?; m.add_class::()?; Ok(()) } -// The main function exposed to Python. It reads a file, parses it into an AST, extracts imports, -// converts them into a structured format, and returns a dictionary to Python. #[pyfunction] -fn get_imports_from_py_file(py: Python<'_>, file_path: &PyString) -> PyResult { - let path_str = file_path.to_str()?; - let file_content = read_file(&path_str)?; - let ast = get_ast_from_file_content(&file_content, &path_str)?; - let imported_modules = extract_imports_from_ast(ast); - let imports_with_locations = convert_imports_with_textranges_to_location_objects( - imported_modules, - &path_str, - &file_content, - ); - let imports_dict = convert_to_python_dict(py, imports_with_locations); - Ok(imports_dict) +fn get_imports_from_py_files(py: Python, file_paths: Vec<&PyString>) -> PyResult { + // Convert PyString references to Rust-owned String objects. + let rust_file_paths: Vec = file_paths + .iter() + .map(|py_str| py_str.to_str().unwrap().to_owned()) + .collect(); + + // Now, you can use Rayon to process these paths in parallel. + let results: Vec<_> = rust_file_paths + .par_iter() + .map(|path_str| { + let file_content = read_file(path_str).unwrap(); + let ast = get_ast_from_file_content(&file_content, path_str).unwrap(); + let imported_modules = extract_imports_from_ast(ast); + convert_imports_with_textranges_to_location_objects( + imported_modules, + path_str, + &file_content, + ) + }) + .collect(); + + // Rest of the function to prepare the Python dictionary... + let combined_result = PyDict::new(py); + for result in results { + for (module, locations) in result { + let py_locations: Vec = locations + .into_iter() + .map(|location| location.into_py(py)) + .collect(); + let locations_list = PyList::new(py, &py_locations); + combined_result.set_item(module, locations_list).unwrap(); + } + } + + Ok(combined_result.into()) } + // Parses the content of a Python file into an abstract syntax tree (AST). pub fn get_ast_from_file_content(file_content: &str, file_path: &str) -> PyResult { parse(&file_content, Mode::Module, file_path) From fbc658dd8a3b10343a38cec1dc4ed481fafd431e Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 07:45:48 +0100 Subject: [PATCH 12/77] improved parallel running --- Cargo.lock | 19 ++++++++ Cargo.toml | 2 + deptry/core.py | 4 +- deptry/deptry.pyi | 1 + deptry/imports/extract.py | 9 ++-- src/lib.rs | 76 ++++++++++++++++++------------ tests/unit/imports/test_extract.py | 17 ++++--- 7 files changed, 83 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 365a2f54..3e7f2bbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,12 @@ version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +[[package]] +name = "arc-swap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" + [[package]] name = "autocfg" version = "1.1.0" @@ -127,7 +133,9 @@ dependencies = [ "chardetng", "encoding_rs", "encoding_rs_io", + "log", "pyo3", + "pyo3-log", "rayon", "regex", "rustpython-ast", @@ -534,6 +542,17 @@ dependencies = [ "pyo3-build-config", ] +[[package]] +name = "pyo3-log" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c10808ee7250403bedb24bc30c32493e93875fef7ba3e4292226fe924f398bd" +dependencies = [ + "arc-swap", + "log", + "pyo3", +] + [[package]] name = "pyo3-macros" version = "0.20.3" diff --git a/Cargo.toml b/Cargo.toml index 40907460..2d680c8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,9 @@ crate-type = ["cdylib"] chardetng = "0.1.17" encoding_rs = "0.8.33" encoding_rs_io = "0.1.7" +log = "0.4.21" pyo3 = "0.20.0" +pyo3-log = "0.9.0" rayon = "1.9.0" regex = "1.10.3" rustpython-ast = { version = "0.3.0", features = ["visitor"] } diff --git a/deptry/core.py b/deptry/core.py index 731c30bc..ff8b0ec1 100644 --- a/deptry/core.py +++ b/deptry/core.py @@ -12,7 +12,7 @@ from deptry.dependency_getter.requirements_txt import RequirementsTxtDependencyGetter from deptry.dependency_specification_detector import DependencyManagementFormat, DependencySpecificationDetector from deptry.exceptions import IncorrectDependencyFormatError, UnsupportedPythonVersionError -from deptry.imports.extract import get_imported_modules_for_list_of_files +from deptry.imports.extract import get_imported_modules_from_list_of_files from deptry.module import ModuleBuilder, ModuleLocations from deptry.python_file_finder import PythonFileFinder from deptry.reporters import JSONReporter, TextReporter @@ -80,7 +80,7 @@ def run(self) -> None: ).build(), locations, ) - for module, locations in get_imported_modules_for_list_of_files(all_python_files).items() + for module, locations in get_imported_modules_from_list_of_files(all_python_files).items() ] imported_modules_with_locations = [ module_with_locations diff --git a/deptry/deptry.pyi b/deptry/deptry.pyi index caea7272..ded64a2b 100644 --- a/deptry/deptry.pyi +++ b/deptry/deptry.pyi @@ -1,3 +1,4 @@ +def get_imports_from_py_files(file_paths: list[str]): ... def get_imports_from_py_file(file_path: str): ... class Location: diff --git a/deptry/imports/extract.py b/deptry/imports/extract.py index 30fffa2f..b857713a 100644 --- a/deptry/imports/extract.py +++ b/deptry/imports/extract.py @@ -15,7 +15,7 @@ from deptry.imports.location import Location -def get_imported_modules_for_list_of_files(list_of_files: list[Path]) -> dict[str, list[Location]]: +def get_imported_modules_from_list_of_files(list_of_files: list[Path]) -> dict[str, list[Location]]: logging.info("Scanning %d %s...", len(list_of_files), "files" if len(list_of_files) > 1 else "file") py_files = [str(file) for file in list_of_files if file.suffix == ".py"] @@ -31,7 +31,7 @@ def get_imported_modules_for_list_of_files(list_of_files: list[Path]) -> dict[st # Process each .ipynb file individually for file in ipynb_files: - for module, locations in get_imported_modules_from_file(file).items(): + for module, locations in get_imported_modules_from_ipynb_file(file).items(): modules[module].extend(locations) logging.debug("All imported modules: %s\n", modules) @@ -39,11 +39,10 @@ def get_imported_modules_for_list_of_files(list_of_files: list[Path]) -> dict[st return modules -def get_imported_modules_from_file(path_to_file: Path) -> dict[str, list[Location]]: +def get_imported_modules_from_ipynb_file(path_to_file: Path) -> dict[str, list[Location]]: logging.debug("Scanning %s...", path_to_file) - if path_to_file.suffix == ".ipynb": - modules = NotebookImportExtractor(path_to_file).extract_imports() + modules = NotebookImportExtractor(path_to_file).extract_imports() modules = convert_rust_locations_to_python_locations(modules) logging.debug("Found the following imports in %s: %s", path_to_file, modules) diff --git a/src/lib.rs b/src/lib.rs index 90ae81de..e43af082 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,57 +15,71 @@ mod visitor; use file_utils::read_file; use location::Location; +use rayon::prelude::*; use rustpython_ast::Visitor; use visitor::ImportVisitor; -use rayon::prelude::*; #[pymodule] -fn deptry(_py: Python, m: &PyModule) -> PyResult<()> { +fn deptry(py: Python, m: &PyModule) -> PyResult<()> { + pyo3_log::init(); // Initialize logging to forward to Python's logger + m.add_function(wrap_pyfunction!(get_imports_from_py_files, m)?)?; + m.add_function(wrap_pyfunction!(get_imports_from_py_file, m)?)?; m.add_class::()?; Ok(()) } #[pyfunction] fn get_imports_from_py_files(py: Python, file_paths: Vec<&PyString>) -> PyResult { - // Convert PyString references to Rust-owned String objects. let rust_file_paths: Vec = file_paths .iter() .map(|py_str| py_str.to_str().unwrap().to_owned()) .collect(); - // Now, you can use Rayon to process these paths in parallel. - let results: Vec<_> = rust_file_paths - .par_iter() - .map(|path_str| { - let file_content = read_file(path_str).unwrap(); - let ast = get_ast_from_file_content(&file_content, path_str).unwrap(); - let imported_modules = extract_imports_from_ast(ast); - convert_imports_with_textranges_to_location_objects( - imported_modules, - path_str, - &file_content, - ) - }) - .collect(); + // This will hold the merged results from all files + let mut all_imports = HashMap::new(); - // Rest of the function to prepare the Python dictionary... - let combined_result = PyDict::new(py); - for result in results { - for (module, locations) in result { - let py_locations: Vec = locations - .into_iter() - .map(|location| location.into_py(py)) - .collect(); - let locations_list = PyList::new(py, &py_locations); - combined_result.set_item(module, locations_list).unwrap(); + // Iterate over file paths, process each, and merge the results + for path_str in rust_file_paths.iter() { + let file_result = _get_imports_from_py_file(path_str)?; + for (module, locations) in file_result { + all_imports.entry(module).or_insert_with(Vec::new).extend(locations); } } - Ok(combined_result.into()) + // Now convert the merged results to a Python dictionary + convert_to_python_dict(py, all_imports) } +#[pyfunction] +fn get_imports_from_py_file(py: Python, file_path: &PyString) -> PyResult { + let path_str = file_path.to_str()?; + let result = _get_imports_from_py_file(path_str)?; + + convert_to_python_dict(py, result) +} + +fn _get_imports_from_py_file(path_str: &str) -> PyResult>> { + let file_content = match read_file(path_str) { + Ok(content) => content, + Err(_) => { + log::warn!("Warning: File {} could not be read. Skipping...", path_str); + return Ok(HashMap::new()); + } + }; + + let ast = get_ast_from_file_content(&file_content, path_str) + .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", path_str, e)))?; + + let imported_modules = extract_imports_from_ast(ast); + Ok(convert_imports_with_textranges_to_location_objects( + imported_modules, + path_str, + &file_content, + )) +} + // Parses the content of a Python file into an abstract syntax tree (AST). pub fn get_ast_from_file_content(file_content: &str, file_path: &str) -> PyResult { parse(&file_content, Mode::Module, file_path) @@ -123,7 +137,7 @@ fn convert_imports_with_textranges_to_location_objects( fn convert_to_python_dict( py: Python<'_>, imports_with_locations: HashMap>, -) -> PyObject { +) -> PyResult { let imports_dict = PyDict::new(py); for (module, locations) in imports_with_locations { @@ -132,8 +146,8 @@ fn convert_to_python_dict( .map(|location| location.into_py(py)) .collect(); let locations_list = PyList::new(py, &py_locations); - imports_dict.set_item(module, locations_list).unwrap(); + imports_dict.set_item(module, locations_list)?; } - imports_dict.into() + Ok(imports_dict.into()) } diff --git a/tests/unit/imports/test_extract.py b/tests/unit/imports/test_extract.py index a6e3b144..4991ad2f 100644 --- a/tests/unit/imports/test_extract.py +++ b/tests/unit/imports/test_extract.py @@ -2,13 +2,14 @@ import json import logging +import re import uuid from pathlib import Path from typing import TYPE_CHECKING import pytest -from deptry.imports.extract import get_imported_modules_from_file +from deptry.imports.extract import get_imported_modules_from_ipynb_file, get_imported_modules_from_list_of_files from deptry.imports.location import Location from tests.utils import run_within_dir @@ -19,7 +20,7 @@ def test_import_parser_py() -> None: some_imports_path = Path("tests/data/some_imports.py") - assert get_imported_modules_from_file(some_imports_path) == { + assert get_imported_modules_from_list_of_files([some_imports_path]) == { "barfoo": [Location(some_imports_path, 20, 8)], "baz": [Location(some_imports_path, 16, 5)], "click": [Location(some_imports_path, 24, 12)], @@ -43,7 +44,7 @@ def test_import_parser_py() -> None: def test_import_parser_ipynb() -> None: notebook_path = Path("tests/data/example_project/src/notebook.ipynb") - assert get_imported_modules_from_file(notebook_path) == { + assert get_imported_modules_from_ipynb_file(notebook_path) == { "click": [Location(notebook_path, 1, 0)], "toml": [Location(notebook_path, 5, 0)], "urllib3": [Location(notebook_path, 3, 0)], @@ -78,7 +79,7 @@ def test_import_parser_file_encodings(file_content: str, encoding: str | None, t with random_file.open("w", encoding=encoding) as f: f.write(file_content) - assert get_imported_modules_from_file(random_file) == {"foo": [Location(random_file, 2, 8)]} + assert get_imported_modules_from_list_of_files([random_file]) == {"foo": [Location(random_file, 2, 8)]} @pytest.mark.parametrize( @@ -118,7 +119,7 @@ def test_import_parser_file_encodings_ipynb(code_cell_content: list[str], encodi } f.write(json.dumps(file_content)) - assert get_imported_modules_from_file(random_file) == {"foo": [Location(random_file, 1, 0)]} + assert get_imported_modules_from_list_of_files([random_file]) == {"foo": [Location(random_file, 1, 0)]} def test_import_parser_file_encodings_warning(tmp_path: Path, caplog: LogCaptureFixture) -> None: @@ -130,6 +131,8 @@ def test_import_parser_file_encodings_warning(tmp_path: Path, caplog: LogCapture f.write("# -*- coding: utf-8 -*-\nprint('ÆØÅ')") with caplog.at_level(logging.WARNING): - assert get_imported_modules_from_file(file_path) == {} + assert get_imported_modules_from_list_of_files([file_path]) == {} - assert "Warning: File file1.py could not be decoded. Skipping..." in caplog.text + # //TODO logging from Rust still includes it's own warning and file + line number. Can we get rid of that? + pattern = re.compile(r"WARNING deptry:lib.rs:\d+ Warning: File file1.py could not be read. Skipping...\n") + assert pattern.search(caplog.text) is not None From a0998a9fa9a1e7d70ffaad7d276d342e253886e3 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 07:48:14 +0100 Subject: [PATCH 13/77] improved parallel running --- src/lib.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e43af082..f43923f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,12 +36,20 @@ fn get_imports_from_py_files(py: Python, file_paths: Vec<&PyString>) -> PyResult .map(|py_str| py_str.to_str().unwrap().to_owned()) .collect(); + // Process each file in parallel and collect results + let results: PyResult> = rust_file_paths + .par_iter() + .map(|path_str| _get_imports_from_py_file(path_str)) + .collect(); + + // Check if there was any error during processing + let results = results?; + // This will hold the merged results from all files let mut all_imports = HashMap::new(); - // Iterate over file paths, process each, and merge the results - for path_str in rust_file_paths.iter() { - let file_result = _get_imports_from_py_file(path_str)?; + // Merge results from each thread + for file_result in results { for (module, locations) in file_result { all_imports.entry(module).or_insert_with(Vec::new).extend(locations); } @@ -52,6 +60,7 @@ fn get_imports_from_py_files(py: Python, file_paths: Vec<&PyString>) -> PyResult } + #[pyfunction] fn get_imports_from_py_file(py: Python, file_path: &PyString) -> PyResult { let path_str = file_path.to_str()?; From 9fe6dda3ddadb8cfb7b32c98a731a00b4c43144c Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 07:56:47 +0100 Subject: [PATCH 14/77] docstrings and formatting --- src/lib.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f43923f1..f6f23b3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,8 @@ fn deptry(py: Python, m: &PyModule) -> PyResult<()> { Ok(()) } +/// Processes multiple Python files in parallel to extract import statements and their locations. +/// Accepts a list of file paths and returns a dictionary mapping module names to their import locations. #[pyfunction] fn get_imports_from_py_files(py: Python, file_paths: Vec<&PyString>) -> PyResult { let rust_file_paths: Vec = file_paths @@ -42,25 +44,24 @@ fn get_imports_from_py_files(py: Python, file_paths: Vec<&PyString>) -> PyResult .map(|path_str| _get_imports_from_py_file(path_str)) .collect(); - // Check if there was any error during processing let results = results?; - // This will hold the merged results from all files - let mut all_imports = HashMap::new(); - // Merge results from each thread + let mut all_imports = HashMap::new(); for file_result in results { for (module, locations) in file_result { - all_imports.entry(module).or_insert_with(Vec::new).extend(locations); + all_imports + .entry(module) + .or_insert_with(Vec::new) + .extend(locations); } } - // Now convert the merged results to a Python dictionary convert_to_python_dict(py, all_imports) } - - +/// Processes a single Python file to extract import statements and their locations. +/// Accepts a single file path and returns a dictionary mapping module names to their import locations. #[pyfunction] fn get_imports_from_py_file(py: Python, file_path: &PyString) -> PyResult { let path_str = file_path.to_str()?; @@ -69,6 +70,8 @@ fn get_imports_from_py_file(py: Python, file_path: &PyString) -> PyResult PyResult>> { let file_content = match read_file(path_str) { Ok(content) => content, @@ -89,13 +92,14 @@ fn _get_imports_from_py_file(path_str: &str) -> PyResult PyResult { parse(&file_content, Mode::Module, file_path) .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e))) } -// Iterates through an AST to extract import statements and collects them along with their locations. +/// Iterates through an AST to identify and collect import statements, and returns them together with their +/// a TextRange for each occurence. fn extract_imports_from_ast(ast: Mod) -> HashMap> { let mut visitor = ImportVisitor::new(); @@ -110,9 +114,8 @@ fn extract_imports_from_ast(ast: Mod) -> HashMap> { visitor.get_imports() } -/// Imports now have associated TextRanges, which is the amount of bytes since the start of the file. -/// This function takes that as input, and converts it to imports with associated Location objects, -/// That carry information such as the file name, the line number, and the column offset. +/// Converts textual ranges of import statements into structured location objects. +/// Facilitates the mapping of imports to detailed, file-specific location data (file, line, column). fn convert_imports_with_textranges_to_location_objects( imports: HashMap>, file_path: &str, @@ -142,7 +145,7 @@ fn convert_imports_with_textranges_to_location_objects( imports_with_locations } -// Converts the structured location data into a Python-compatible dictionary format. +/// Transforms a Rust HashMap containing import data into a Python dictionary suitable for Python-side consumption. fn convert_to_python_dict( py: Python<'_>, imports_with_locations: HashMap>, From a732b67702651a836a83ccc0e0783ee06e28ffaf Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 08:35:14 +0100 Subject: [PATCH 15/77] fix CI/CD pipeline --- .github/actions/setup-pdm-env/action.yml | 36 +++++++++++++++ .github/actions/setup-poetry-env/action.yml | 49 --------------------- .github/workflows/main.yml | 10 ++--- .github/workflows/on-release-main.yml | 16 +++++-- Makefile | 19 ++++---- pdm.lock | 15 +++---- tox.ini | 4 +- 7 files changed, 72 insertions(+), 77 deletions(-) create mode 100644 .github/actions/setup-pdm-env/action.yml delete mode 100644 .github/actions/setup-poetry-env/action.yml diff --git a/.github/actions/setup-pdm-env/action.yml b/.github/actions/setup-pdm-env/action.yml new file mode 100644 index 00000000..bd6e441d --- /dev/null +++ b/.github/actions/setup-pdm-env/action.yml @@ -0,0 +1,36 @@ +name: "setup-pdm-env" +description: "Composite action to setup the Python and PDM environment." + +inputs: + python-version: + required: false + description: "The python version to use" + default: "3.11" + +runs: + using: "composite" + steps: + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python-version }} + + - name: Install PDM + run: pip install pdm==2.2.1 + shell: bash + + - name: Configure PDM to use PEP 582 packages + run: pdm config python.use_venv true + shell: bash + + - name: Load cached pdm environment + id: cached-pdm-dependencies + uses: actions/cache@v4 + with: + path: .venv + key: pdm-${{ runner.os }}-${{ inputs.python-version }}-${{ hashFiles('pdm.lock') }} + + - name: Install dependencies + if: steps.cached-pdm-dependencies.outputs.cache-hit != 'true' + run: pdm install --no-lock --no-editable + shell: bash diff --git a/.github/actions/setup-poetry-env/action.yml b/.github/actions/setup-poetry-env/action.yml deleted file mode 100644 index 5683f0dd..00000000 --- a/.github/actions/setup-poetry-env/action.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: "setup-poetry-env" -description: "Composite action to setup the Python and poetry environment." - -inputs: - python-version: - required: false - description: "The python version to use" - default: "3.11" - -runs: - using: "composite" - steps: - - name: Set up python - uses: actions/setup-python@v5 - with: - python-version: ${{ inputs.python-version }} - - - name: Install Poetry - env: - # renovate: datasource=pypi depName=poetry - POETRY_VERSION: "1.8.2" - run: curl -sSL https://install.python-poetry.org | python - -y - shell: bash - - - name: Add Poetry to Path - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - if: ${{ matrix.os != 'Windows' }} - shell: bash - - - name: Add Poetry to Path - run: echo "$APPDATA\Python\Scripts" >> $GITHUB_PATH - if: ${{ matrix.os == 'Windows' }} - shell: bash - - - name: Configure Poetry virtual environment in project - run: poetry config virtualenvs.in-project true - shell: bash - - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v4 - with: - path: .venv - key: venv-${{ runner.os }}-${{ inputs.python-version }}-${{ hashFiles('poetry.lock') }} - - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' - run: poetry install --no-interaction - shell: bash diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f02dfaa6..6b403e76 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,7 +19,7 @@ jobs: key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} - name: Set up the environment - uses: ./.github/actions/setup-poetry-env + uses: ./.github/actions/setup-pdm-env - name: Run pre-commit run: pdm run pre-commit run -a --show-diff-on-failure @@ -27,8 +27,8 @@ jobs: - name: Inspect dependencies run: pdm run deptry . - - name: Check Poetry lock file consistency - run: poetry lock --check + - name: Check PDM lock file consistency + run: pdm lock --check tests-and-type-check: runs-on: ${{ matrix.image }} @@ -52,7 +52,7 @@ jobs: uses: actions/checkout@v4 - name: Set up the environment - uses: ./.github/actions/setup-poetry-env + uses: ./.github/actions/setup-pdm-env with: python-version: ${{ matrix.python-version }} @@ -73,7 +73,7 @@ jobs: uses: actions/checkout@v4 - name: Set up the environment - uses: ./.github/actions/setup-poetry-env + uses: ./.github/actions/setup-pdm-env - name: Check if documentation can be built run: pdm run mkdocs build -s diff --git a/.github/workflows/on-release-main.yml b/.github/workflows/on-release-main.yml index d1b3fd16..f3e17a7e 100644 --- a/.github/workflows/on-release-main.yml +++ b/.github/workflows/on-release-main.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v4 - name: Set up the environment - uses: ./.github/actions/setup-poetry-env + uses: ./.github/actions/setup-pdm-env - name: Export tag id: vars @@ -21,12 +21,22 @@ jobs: - name: Build and publish run: | - poetry version $RELEASE_VERSION + # Set version in pyproject.toml + sed -i "s/^version = \".*\"/version = \"$RELEASE_VERSION\"/" pyproject.toml + + # Verify that the version has been updated correctly in pyproject.toml + VERSION_FROM_TOML=$(python -c "import tomllib; print(tomllib.loads(open('pyproject.toml', 'rb').read())['project']['version'])") + if [ "$VERSION_FROM_TOML" != "$RELEASE_VERSION" ]; then + echo "Version mismatch: Expected $RELEASE_VERSION, got $VERSION_FROM_TOML" + exit 1 + fi + make build-and-publish env: PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} RELEASE_VERSION: ${{ steps.vars.outputs.tag }} + deploy-docs: runs-on: ubuntu-latest needs: publish @@ -35,7 +45,7 @@ jobs: uses: actions/checkout@v4 - name: Set up the environment - uses: ./.github/actions/setup-poetry-env + uses: ./.github/actions/setup-pdm-env - name: Deploy documentation run: pdm run mkdocs gh-deploy --force diff --git a/Makefile b/Makefile index 44d48251..c0e19417 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,12 @@ .PHONY: install -install: ## Install the Poetry environment. - @echo "🚀 Creating virtual environment using Poetry" - @poetry install +install: ## Install the PDM environment. + @echo "🚀 Creating virtual environment using PDM" + @pdm install .PHONY: check check: ## Run code quality tools. - @echo "🚀 Checking Poetry lock file consistency with 'pyproject.toml': Running poetry lock --check" - @poetry lock --check + @echo "🚀 Checking PDM lock file consistency with 'pyproject.toml': Running pdm lock --check" + @pdm lock --check @echo "🚀 Linting code: Running pre-commit" @pdm run pre-commit run -a @echo "🚀 Static type checking: Running mypy" @@ -20,9 +20,9 @@ test: ## Test the code with pytest. @pdm run pytest --cov --cov-config=pyproject.toml --cov-report=xml .PHONY: build -build: clean-build ## Build wheel and sdist files using Poetry. +build: clean-build ## Build wheel and sdist files using PDM. @echo "🚀 Creating wheel and sdist files" - @poetry build + @pdm build .PHONY: clean-build clean-build: ## clean build artifacts @@ -31,10 +31,9 @@ clean-build: ## clean build artifacts .PHONY: publish publish: ## Publish a release to PyPI. @echo "🚀 Publishing: Dry run." - @poetry config pypi-token.pypi $(PYPI_TOKEN) - @poetry publish --dry-run + @PDM_PYPI_TOKEN=$(PYPI_TOKEN) pdm publish --dry-run @echo "🚀 Publishing." - @poetry publish + @PDM_PYPI_TOKEN=$(PYPI_TOKEN) pdm publish .PHONY: build-and-publish build-and-publish: build publish ## Build and publish. diff --git a/pdm.lock b/pdm.lock index 90208d05..38b3ba29 100644 --- a/pdm.lock +++ b/pdm.lock @@ -3,9 +3,8 @@ [metadata] groups = ["default", "dev", "docs", "typing"] -cross_platform = true -static_urls = false -lock_version = "4.3" +strategy = ["cross_platform"] +lock_version = "4.4.1" content_hash = "sha256:5f1735071095c166db7483350395fa16219910cfb61ad973163ee21df5bb1648" [[package]] @@ -43,12 +42,12 @@ files = [ [[package]] name = "chardet" -version = "4.0.0" -requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -summary = "Universal encoding detector for Python 2 and 3" +version = "5.2.0" +requires_python = ">=3.7" +summary = "Universal encoding detector for Python 3" files = [ - {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, - {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, ] [[package]] diff --git a/tox.ini b/tox.ini index ddc09bd9..8c9ebeb8 100644 --- a/tox.ini +++ b/tox.ini @@ -3,9 +3,9 @@ skipsdist = true envlist = py38, py39, py310, py311, py312 [testenv] -allowlist_externals = poetry +allowlist_externals = pdm skip_install = true -commands_pre = poetry install +commands_pre = pdm install commands = pdm run pytest pdm run mypy From f272882213fd7b012d0511722aa5e6b19b52d741 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 08:41:04 +0100 Subject: [PATCH 16/77] lock file version --- .github/actions/setup-pdm-env/action.yml | 2 +- main.py | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 main.py diff --git a/.github/actions/setup-pdm-env/action.yml b/.github/actions/setup-pdm-env/action.yml index bd6e441d..8b871764 100644 --- a/.github/actions/setup-pdm-env/action.yml +++ b/.github/actions/setup-pdm-env/action.yml @@ -16,7 +16,7 @@ runs: python-version: ${{ inputs.python-version }} - name: Install PDM - run: pip install pdm==2.2.1 + run: pip install pdm==2.12.4 shell: bash - name: Configure PDM to use PEP 582 packages diff --git a/main.py b/main.py deleted file mode 100644 index b4bc1395..00000000 --- a/main.py +++ /dev/null @@ -1,14 +0,0 @@ -# ruff: noqa - -from __future__ import annotations - -from deptry import get_imports_from_py_file - -try: - imports_with_locations = get_imports_from_py_file("tests/data/some_imports.py") - for k, v in imports_with_locations.items(): - print(k) - print(v) -except Exception as e: # It will catch the PyIOError thrown by Rust - print(type(e)) - print(e) From 6c4d83d6cb7e539d98d4b9ebc6588accaed153e6 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 16:45:17 +0100 Subject: [PATCH 17/77] new dev cicd pipeline --- .github/workflows/dev.yml | 34 +++++++++ .github/workflows/main.yml | 137 ++++++++++++++++++++----------------- 2 files changed, 107 insertions(+), 64 deletions(-) create mode 100644 .github/workflows/dev.yml diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml new file mode 100644 index 00000000..3318ba48 --- /dev/null +++ b/.github/workflows/dev.yml @@ -0,0 +1,34 @@ +name: Main + +on: workflow_dispatch + +jobs: + linux: + runs-on: ubuntu-latest + strategy: + matrix: + target: [x86_64, i686] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: 3.9 + architecture: x64 + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + rust-toolchain: nightly + target: ${{ matrix.target }} + manylinux: auto + args: --release --out dist + - name: Install built wheel + if: matrix.target == 'x86_64' + run: | + pip install rjmespath --no-index --find-links dist --force-reinstall + pip install pytest + cd tests && pytest + - name: Upload wheels + uses: actions/upload-artifact@v3 + with: + name: wheels + path: dist diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6b403e76..4892d0e2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,79 +1,88 @@ -name: Main +name: CI -on: - pull_request: - types: [opened, synchronize, reopened] - push: - branches: [main] +on: workflow_dispatch jobs: - quality: + linux: runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + architecture: [x64, aarch64] steps: - - name: Check out - uses: actions/checkout@v4 - - - uses: actions/cache@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: - path: ~/.cache/pre-commit - key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} - - - name: Set up the environment - uses: ./.github/actions/setup-pdm-env - - - name: Run pre-commit - run: pdm run pre-commit run -a --show-diff-on-failure - - - name: Inspect dependencies - run: pdm run deptry . - - - name: Check PDM lock file consistency - run: pdm lock --check + python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.architecture }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip pdm + pdm install + - name: Build and install the project + uses: PyO3/maturin-action@v1 + with: + python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.architecture }} + command: develop + sccache: 'true' + - name: Pre-commit hooks and deptry + if: matrix.python-version == '3.11' + run: | + pre-commit run -a --show-diff-on-failure + pdm run deptry . + - name: Run tests + run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - tests-and-type-check: - runs-on: ${{ matrix.image }} + windows: + runs-on: windows-latest strategy: matrix: - os: [macOS, Ubuntu, Windows] - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] - include: - - os: macOS - image: macos-12 - - os: Ubuntu - image: ubuntu-22.04 - - os: Windows - image: windows-2022 - fail-fast: false - defaults: - run: - shell: bash + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + architecture: [x64, x86] steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up the environment - uses: ./.github/actions/setup-pdm-env + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - + architecture: ${{ matrix.architecture }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip pdm + pdm install + - name: Build and install the project + uses: PyO3/maturin-action@v1 + with: + python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.architecture }} + command: develop + sccache: 'true' - name: Run tests - run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - - - name: Check typing - run: pdm run mypy + run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - - name: Upload coverage reports to Codecov with GitHub Action on Python 3.11 for Ubuntu - uses: codecov/codecov-action@v3 - if: ${{ matrix.python-version == '3.11' && matrix.os == 'Ubuntu' }} - - check-docs: - runs-on: ubuntu-latest + macos: + runs-on: macos-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + architecture: [x64] steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up the environment - uses: ./.github/actions/setup-pdm-env - - - name: Check if documentation can be built - run: pdm run mkdocs build -s + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip pdm + pdm install + - name: Build and install the project + uses: PyO3/maturin-action@v1 + with: + python-version: ${{ matrix.python-version }} + command: develop + sccache: 'true' + - name: Run tests + run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml From 0c16f5cb5db206dc04c9b3149132f55d3c429b33 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 16:47:36 +0100 Subject: [PATCH 18/77] new dev cicd pipeline --- .github/workflows/dev.yml | 34 ------------------ .github/workflows/main.yml | 6 +++- .github/workflows/on-release-main.yml | 51 --------------------------- 3 files changed, 5 insertions(+), 86 deletions(-) delete mode 100644 .github/workflows/dev.yml delete mode 100644 .github/workflows/on-release-main.yml diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml deleted file mode 100644 index 3318ba48..00000000 --- a/.github/workflows/dev.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Main - -on: workflow_dispatch - -jobs: - linux: - runs-on: ubuntu-latest - strategy: - matrix: - target: [x86_64, i686] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 - with: - python-version: 3.9 - architecture: x64 - - name: Build wheels - uses: PyO3/maturin-action@v1 - with: - rust-toolchain: nightly - target: ${{ matrix.target }} - manylinux: auto - args: --release --out dist - - name: Install built wheel - if: matrix.target == 'x86_64' - run: | - pip install rjmespath --no-index --find-links dist --force-reinstall - pip install pytest - cd tests && pytest - - name: Upload wheels - uses: actions/upload-artifact@v3 - with: - name: wheels - path: dist diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4892d0e2..32d59f62 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,10 @@ name: CI -on: workflow_dispatch +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: [main] jobs: linux: diff --git a/.github/workflows/on-release-main.yml b/.github/workflows/on-release-main.yml deleted file mode 100644 index f3e17a7e..00000000 --- a/.github/workflows/on-release-main.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: release-main - -on: - release: - types: [published] - branches: [main] - -jobs: - publish: - runs-on: ubuntu-latest - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up the environment - uses: ./.github/actions/setup-pdm-env - - - name: Export tag - id: vars - run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT - - - name: Build and publish - run: | - # Set version in pyproject.toml - sed -i "s/^version = \".*\"/version = \"$RELEASE_VERSION\"/" pyproject.toml - - # Verify that the version has been updated correctly in pyproject.toml - VERSION_FROM_TOML=$(python -c "import tomllib; print(tomllib.loads(open('pyproject.toml', 'rb').read())['project']['version'])") - if [ "$VERSION_FROM_TOML" != "$RELEASE_VERSION" ]; then - echo "Version mismatch: Expected $RELEASE_VERSION, got $VERSION_FROM_TOML" - exit 1 - fi - - make build-and-publish - env: - PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - RELEASE_VERSION: ${{ steps.vars.outputs.tag }} - - - deploy-docs: - runs-on: ubuntu-latest - needs: publish - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up the environment - uses: ./.github/actions/setup-pdm-env - - - name: Deploy documentation - run: pdm run mkdocs gh-deploy --force From ade10a0ddb96aae333f538e5c078065a16da7620 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 16:50:11 +0100 Subject: [PATCH 19/77] new dev cicd pipeline --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 32d59f62..22e50208 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip pdm + pip install pdm pdm install - name: Build and install the project uses: PyO3/maturin-action@v1 @@ -54,7 +54,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip pdm + pip install pdm pdm install - name: Build and install the project uses: PyO3/maturin-action@v1 @@ -80,7 +80,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip pdm + pip install pdm pdm install - name: Build and install the project uses: PyO3/maturin-action@v1 From ee37b73967521934770ce68b77fea18ebf97d3ab Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 16:52:17 +0100 Subject: [PATCH 20/77] new dev cicd pipeline --- .github/workflows/main.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 22e50208..53bf3453 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,13 +12,12 @@ jobs: strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - architecture: [x64, aarch64] + architecture: [x86_64, x86, aarch64] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.architecture }} - name: Install dependencies run: | python -m pip install --upgrade pip @@ -44,7 +43,6 @@ jobs: strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - architecture: [x64, x86] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 @@ -71,7 +69,7 @@ jobs: strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - architecture: [x64] + architecture: [x86_64, aarch64] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 From 25465e77ba841528bd6fbe2cccd06a1ce9f50418 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 16:53:35 +0100 Subject: [PATCH 21/77] remove pdm install --- .github/workflows/main.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 53bf3453..bfc5e77c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,11 +18,6 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pdm - pdm install - name: Build and install the project uses: PyO3/maturin-action@v1 with: @@ -49,11 +44,6 @@ jobs: with: python-version: ${{ matrix.python-version }} architecture: ${{ matrix.architecture }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pdm - pdm install - name: Build and install the project uses: PyO3/maturin-action@v1 with: @@ -75,11 +65,6 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pdm - pdm install - name: Build and install the project uses: PyO3/maturin-action@v1 with: From 4ab1d994f24779e1c473846cc7d13afb78be252f Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 16:58:12 +0100 Subject: [PATCH 22/77] add venv --- .github/workflows/main.yml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bfc5e77c..0f5b489b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,17 +12,20 @@ jobs: strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - architecture: [x86_64, x86, aarch64] + target: [x86_64, x86, aarch64] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + - name: Create and activate virtual environment + run: | + python -m venv .venv + source .venv/bin/activate - name: Build and install the project uses: PyO3/maturin-action@v1 with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.architecture }} + target: ${{ matrix.target }} command: develop sccache: 'true' - name: Pre-commit hooks and deptry @@ -43,12 +46,15 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.architecture }} + target: ${{ matrix.target }} + - name: Create and activate virtual environment + run: | + python -m venv .venv + source .venv/bin/activate - name: Build and install the project uses: PyO3/maturin-action@v1 with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.architecture }} + target: ${{ matrix.target }} command: develop sccache: 'true' - name: Run tests @@ -59,16 +65,20 @@ jobs: strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - architecture: [x86_64, aarch64] + target: [x86_64, aarch64] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + - name: Create and activate virtual environment + run: | + python -m venv .venv + source .venv/bin/activate - name: Build and install the project uses: PyO3/maturin-action@v1 with: - python-version: ${{ matrix.python-version }} + target: ${{ matrix.target }} command: develop sccache: 'true' - name: Run tests From 1d1d11714a31a9f65f8c8d1e0c77e43e625d642f Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:04:05 +0100 Subject: [PATCH 23/77] add rust toolchain --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0f5b489b..59682605 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,6 +22,7 @@ jobs: run: | python -m venv .venv source .venv/bin/activate + - uses: dtolnay/rust-toolchain@stable - name: Build and install the project uses: PyO3/maturin-action@v1 with: @@ -51,6 +52,7 @@ jobs: run: | python -m venv .venv source .venv/bin/activate + - uses: dtolnay/rust-toolchain@stable - name: Build and install the project uses: PyO3/maturin-action@v1 with: @@ -75,6 +77,7 @@ jobs: run: | python -m venv .venv source .venv/bin/activate + - uses: dtolnay/rust-toolchain@stable - name: Build and install the project uses: PyO3/maturin-action@v1 with: From 22bfb3608660ce85c1cbb7d5d70a33e174561c99 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:08:05 +0100 Subject: [PATCH 24/77] 1.75.0 rust --- .github/workflows/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 59682605..e77fd9b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,6 +23,8 @@ jobs: python -m venv .venv source .venv/bin/activate - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.75.0 - name: Build and install the project uses: PyO3/maturin-action@v1 with: @@ -53,6 +55,8 @@ jobs: python -m venv .venv source .venv/bin/activate - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.75.0 - name: Build and install the project uses: PyO3/maturin-action@v1 with: @@ -78,6 +82,8 @@ jobs: python -m venv .venv source .venv/bin/activate - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.75.0 - name: Build and install the project uses: PyO3/maturin-action@v1 with: From a8c9edde73f9faa8ef816345791c0835f4748576 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:14:22 +0100 Subject: [PATCH 25/77] 1.75.0 rust --- .github/workflows/main.yml | 123 ++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 56 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e77fd9b8..cb434f0a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,80 +15,91 @@ jobs: target: [x86_64, x86, aarch64] steps: - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Create and activate virtual environment - run: | - python -m venv .venv - source .venv/bin/activate + - uses: dtolnay/rust-toolchain@stable with: toolchain: 1.75.0 + + - name: Install PDM + run: | + python -m pip install pdm + + - name: Set up Python environment with PDM + run: | + pdm config python.use_venv true + pdm install + - name: Build and install the project uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} command: develop sccache: 'true' + - name: Pre-commit hooks and deptry if: matrix.python-version == '3.11' run: | pre-commit run -a --show-diff-on-failure pdm run deptry . - - name: Run tests - run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - windows: - runs-on: windows-latest - strategy: - matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - target: ${{ matrix.target }} - - name: Create and activate virtual environment - run: | - python -m venv .venv - source .venv/bin/activate - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.75.0 - - name: Build and install the project - uses: PyO3/maturin-action@v1 - with: - target: ${{ matrix.target }} - command: develop - sccache: 'true' - name: Run tests run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - macos: - runs-on: macos-latest - strategy: - matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - target: [x86_64, aarch64] - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - name: Create and activate virtual environment - run: | - python -m venv .venv - source .venv/bin/activate - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.75.0 - - name: Build and install the project - uses: PyO3/maturin-action@v1 - with: - target: ${{ matrix.target }} - command: develop - sccache: 'true' - - name: Run tests - run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + # windows: + # runs-on: windows-latest + # strategy: + # matrix: + # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + # steps: + # - uses: actions/checkout@v4 + # - uses: actions/setup-python@v5 + # with: + # python-version: ${{ matrix.python-version }} + # target: ${{ matrix.target }} + # - name: Create and activate virtual environment + # run: | + # python -m venv .venv + # source .venv/bin/activate + # - uses: dtolnay/rust-toolchain@stable + # with: + # toolchain: 1.75.0 + # - name: Build and install the project + # uses: PyO3/maturin-action@v1 + # with: + # target: ${{ matrix.target }} + # command: develop + # sccache: 'true' + # - name: Run tests + # run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + # macos: + # runs-on: macos-latest + # strategy: + # matrix: + # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + # target: [x86_64, aarch64] + # steps: + # - uses: actions/checkout@v4 + # - uses: actions/setup-python@v5 + # with: + # python-version: ${{ matrix.python-version }} + # - name: Create and activate virtual environment + # run: | + # python -m venv .venv + # source .venv/bin/activate + # - uses: dtolnay/rust-toolchain@stable + # with: + # toolchain: 1.75.0 + # - name: Build and install the project + # uses: PyO3/maturin-action@v1 + # with: + # target: ${{ matrix.target }} + # command: develop + # sccache: 'true' + # - name: Run tests + # run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml From 37cdaf593cd8b5c673337cf4fcca0f2c5acef90c Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:19:39 +0100 Subject: [PATCH 26/77] create venv manually --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cb434f0a..070fe565 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,6 +30,9 @@ jobs: - name: Set up Python environment with PDM run: | + python -m venv .venv + source .venv/bin/activate + python -m pip install --upgrade pip pdm config python.use_venv true pdm install From 7147fbd2e6488bfd89a2f025e3c68d4fe4bfbefe Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:26:11 +0100 Subject: [PATCH 27/77] pdm run --- .github/workflows/main.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 070fe565..2eb6ae4d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,12 +24,9 @@ jobs: with: toolchain: 1.75.0 - - name: Install PDM - run: | - python -m pip install pdm - - name: Set up Python environment with PDM run: | + python -m pip install pdm python -m venv .venv source .venv/bin/activate python -m pip install --upgrade pip @@ -46,7 +43,7 @@ jobs: - name: Pre-commit hooks and deptry if: matrix.python-version == '3.11' run: | - pre-commit run -a --show-diff-on-failure + pdm run pre-commit run -a --show-diff-on-failure pdm run deptry . - name: Run tests From d8d8b504ded7969a4ca2b7d79cae9ce9c41cf9a1 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:29:22 +0100 Subject: [PATCH 28/77] pdm run --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2eb6ae4d..2a1c9117 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -47,7 +47,7 @@ jobs: pdm run deptry . - name: Run tests - run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml # windows: From d4e11dd143719f85c2ac893e5631c83ade62854e Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:46:00 +0100 Subject: [PATCH 29/77] try to make modular --- .github/actions/setup-environment/action.yml | 44 ++++++++ .github/actions/setup-pdm-env/action.yml | 36 ------- .github/workflows/main.yml | 102 +++++-------------- 3 files changed, 72 insertions(+), 110 deletions(-) create mode 100644 .github/actions/setup-environment/action.yml delete mode 100644 .github/actions/setup-pdm-env/action.yml diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml new file mode 100644 index 00000000..88f9d4c4 --- /dev/null +++ b/.github/actions/setup-environment/action.yml @@ -0,0 +1,44 @@ +name: 'Setup Python and Rust Environment' +description: 'Set up Python and Rust for PDM projects with matrix support' +inputs: + python-version: + description: 'Python version for setup-python' + required: true + default: 3.11 + target: + description: 'Target architecture for maturin' + required: true + default: 'x86_64' + +runs: + using: 'composite' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python-version }} + + - name: Install PDM and dependencies + run: | + python -m pip install pdm + python -m venv .venv + source ${{ github.action_path }}/scripts/activate-venv.sh + python -m pip install --upgrade pip + pdm config python.use_venv true + pdm install + shell: bash + + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.75.0 + + - name: Build and install the project using Maturin + uses: PyO3/maturin-action@v1 + with: + target: ${{ inputs.target }} + command: develop + sccache: 'true' diff --git a/.github/actions/setup-pdm-env/action.yml b/.github/actions/setup-pdm-env/action.yml deleted file mode 100644 index 8b871764..00000000 --- a/.github/actions/setup-pdm-env/action.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: "setup-pdm-env" -description: "Composite action to setup the Python and PDM environment." - -inputs: - python-version: - required: false - description: "The python version to use" - default: "3.11" - -runs: - using: "composite" - steps: - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: ${{ inputs.python-version }} - - - name: Install PDM - run: pip install pdm==2.12.4 - shell: bash - - - name: Configure PDM to use PEP 582 packages - run: pdm config python.use_venv true - shell: bash - - - name: Load cached pdm environment - id: cached-pdm-dependencies - uses: actions/cache@v4 - with: - path: .venv - key: pdm-${{ runner.os }}-${{ inputs.python-version }}-${{ hashFiles('pdm.lock') }} - - - name: Install dependencies - if: steps.cached-pdm-dependencies.outputs.cache-hit != 'true' - run: pdm install --no-lock --no-editable - shell: bash diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2a1c9117..09b40d4f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,31 +14,10 @@ jobs: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] target: [x86_64, x86, aarch64] steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v5 + - uses: ./.github/actions/setup-environment with: python-version: ${{ matrix.python-version }} - - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.75.0 - - - name: Set up Python environment with PDM - run: | - python -m pip install pdm - python -m venv .venv - source .venv/bin/activate - python -m pip install --upgrade pip - pdm config python.use_venv true - pdm install - - - name: Build and install the project - uses: PyO3/maturin-action@v1 - with: target: ${{ matrix.target }} - command: develop - sccache: 'true' - name: Pre-commit hooks and deptry if: matrix.python-version == '3.11' @@ -50,56 +29,31 @@ jobs: run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - # windows: - # runs-on: windows-latest - # strategy: - # matrix: - # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - # steps: - # - uses: actions/checkout@v4 - # - uses: actions/setup-python@v5 - # with: - # python-version: ${{ matrix.python-version }} - # target: ${{ matrix.target }} - # - name: Create and activate virtual environment - # run: | - # python -m venv .venv - # source .venv/bin/activate - # - uses: dtolnay/rust-toolchain@stable - # with: - # toolchain: 1.75.0 - # - name: Build and install the project - # uses: PyO3/maturin-action@v1 - # with: - # target: ${{ matrix.target }} - # command: develop - # sccache: 'true' - # - name: Run tests - # run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + windows: + runs-on: windows-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + steps: + - uses: ./.github/actions/setup-environment + with: + python-version: ${{ matrix.python-version }} + target: ${{ matrix.target }} - # macos: - # runs-on: macos-latest - # strategy: - # matrix: - # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - # target: [x86_64, aarch64] - # steps: - # - uses: actions/checkout@v4 - # - uses: actions/setup-python@v5 - # with: - # python-version: ${{ matrix.python-version }} - # - name: Create and activate virtual environment - # run: | - # python -m venv .venv - # source .venv/bin/activate - # - uses: dtolnay/rust-toolchain@stable - # with: - # toolchain: 1.75.0 - # - name: Build and install the project - # uses: PyO3/maturin-action@v1 - # with: - # target: ${{ matrix.target }} - # command: develop - # sccache: 'true' - # - name: Run tests - # run: pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + - name: Run tests + run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + macos: + runs-on: macos-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + target: [x86_64, aarch64] + steps: + - uses: ./.github/actions/setup-environment + with: + python-version: ${{ matrix.python-version }} + target: ${{ matrix.target }} + + - name: Run tests + run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml From 8a0989724b17824273a6caa6d5ce2285e0622a69 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:47:51 +0100 Subject: [PATCH 30/77] try to make modular --- .github/actions/setup-environment/action.yml | 2 -- .github/workflows/main.yml | 10 +++++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml index 88f9d4c4..14a7777b 100644 --- a/.github/actions/setup-environment/action.yml +++ b/.github/actions/setup-environment/action.yml @@ -13,8 +13,6 @@ inputs: runs: using: 'composite' steps: - - name: Checkout code - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 09b40d4f..3be5c8fe 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,9 @@ jobs: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] target: [x86_64, x86, aarch64] steps: + - name: Checkout code + uses: actions/checkout@v4 + - uses: ./.github/actions/setup-environment with: python-version: ${{ matrix.python-version }} @@ -28,13 +31,15 @@ jobs: - name: Run tests run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - windows: runs-on: windows-latest strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] steps: + - name: Checkout code + uses: actions/checkout@v4 + - uses: ./.github/actions/setup-environment with: python-version: ${{ matrix.python-version }} @@ -50,6 +55,9 @@ jobs: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] target: [x86_64, aarch64] steps: + - name: Checkout code + uses: actions/checkout@v4 + - uses: ./.github/actions/setup-environment with: python-version: ${{ matrix.python-version }} From d37c8a1b503102c08710568d3027c44a834673bf Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:51:59 +0100 Subject: [PATCH 31/77] new attempt --- .github/actions/setup-environment/action.yml | 2 +- .github/workflows/main.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-environment/action.yml index 14a7777b..474a31fe 100644 --- a/.github/actions/setup-environment/action.yml +++ b/.github/actions/setup-environment/action.yml @@ -1,5 +1,6 @@ name: 'Setup Python and Rust Environment' description: 'Set up Python and Rust for PDM projects with matrix support' + inputs: python-version: description: 'Python version for setup-python' @@ -13,7 +14,6 @@ inputs: runs: using: 'composite' steps: - - name: Setup Python uses: actions/setup-python@v5 with: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3be5c8fe..5c2e6f6a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] target: [x86_64, x86, aarch64] steps: - - name: Checkout code + - name: Check out uses: actions/checkout@v4 - uses: ./.github/actions/setup-environment @@ -37,7 +37,7 @@ jobs: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] steps: - - name: Checkout code + - name: Check out uses: actions/checkout@v4 - uses: ./.github/actions/setup-environment @@ -55,7 +55,7 @@ jobs: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] target: [x86_64, aarch64] steps: - - name: Checkout code + - name: Check out uses: actions/checkout@v4 - uses: ./.github/actions/setup-environment From 407cd25f0919b77144b37bf9a04dccf91672e5a8 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:54:31 +0100 Subject: [PATCH 32/77] new attempt --- .../actions/{setup-environment => setup-env}/action.yml | 0 .github/workflows/main.yml | 9 ++++++--- 2 files changed, 6 insertions(+), 3 deletions(-) rename .github/actions/{setup-environment => setup-env}/action.yml (100%) diff --git a/.github/actions/setup-environment/action.yml b/.github/actions/setup-env/action.yml similarity index 100% rename from .github/actions/setup-environment/action.yml rename to .github/actions/setup-env/action.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5c2e6f6a..549b69e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,7 +17,8 @@ jobs: - name: Check out uses: actions/checkout@v4 - - uses: ./.github/actions/setup-environment + - name: Set up the environment + uses: ./.github/actions/setup-env with: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} @@ -40,7 +41,8 @@ jobs: - name: Check out uses: actions/checkout@v4 - - uses: ./.github/actions/setup-environment + - name: Set up the environment + uses: ./.github/actions/setup-env with: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} @@ -58,7 +60,8 @@ jobs: - name: Check out uses: actions/checkout@v4 - - uses: ./.github/actions/setup-environment + - name: Set up the environment + uses: ./.github/actions/setup-env with: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} From 6a7f1adfb1b7f4fc4e0954ea8b25588a355f3398 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 17:57:30 +0100 Subject: [PATCH 33/77] new attempt --- .github/actions/setup-env/action.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index 474a31fe..93ad197c 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -23,7 +23,11 @@ runs: run: | python -m pip install pdm python -m venv .venv - source ${{ github.action_path }}/scripts/activate-venv.sh + if [ "${{ runner.os }}" = "Windows" ]; then + .venv\Scripts\Activate + else + source .venv/bin/activate + fi python -m pip install --upgrade pip pdm config python.use_venv true pdm install From f8693404a78a4ebddd2d9ff966e72e1ae095703c Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 18:03:14 +0100 Subject: [PATCH 34/77] change order --- .github/actions/setup-env/action.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index 93ad197c..df9b928d 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -19,6 +19,11 @@ runs: with: python-version: ${{ inputs.python-version }} + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.75.0 + - name: Install PDM and dependencies run: | python -m pip install pdm @@ -33,11 +38,6 @@ runs: pdm install shell: bash - - name: Setup Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.75.0 - - name: Build and install the project using Maturin uses: PyO3/maturin-action@v1 with: From 6a8651f79aad1fe8ff8066f988992c3944b8cecd Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 18:37:55 +0100 Subject: [PATCH 35/77] change order --- .github/actions/setup-env/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index df9b928d..5732fcf3 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -29,7 +29,7 @@ runs: python -m pip install pdm python -m venv .venv if [ "${{ runner.os }}" = "Windows" ]; then - .venv\Scripts\Activate + source .venv/Scripts/Activate else source .venv/bin/activate fi From 33d8dbb882cdebc3c265600673feb9f873504163 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 18:42:35 +0100 Subject: [PATCH 36/77] x64 and x86 for windows --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 549b69e8..244751b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,6 +37,7 @@ jobs: strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + target: [x64, x86] steps: - name: Check out uses: actions/checkout@v4 From 323cf87eb09ead0198dfe9d16b3bf65ac44899ad Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 18:48:22 +0100 Subject: [PATCH 37/77] add quality and docs check --- .github/workflows/main.yml | 47 ++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 244751b8..81f36ef7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,6 +7,27 @@ on: branches: [main] jobs: + + quality: + runs-on: ubuntu-latest + steps: + - name: Check out + uses: actions/checkout@v4 + + - name: Set up the environment + uses: ./.github/actions/setup-env + with: + python-version: '3.11' + target: 'x86_64' + + - name: Run pre-commit + run: | + pdm run pre-commit run -a --show-diff-on-failure + + - name: Inspect dependencies with deptry + run: | + pdm run deptry . + linux: runs-on: ubuntu-latest strategy: @@ -23,15 +44,16 @@ jobs: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} - - name: Pre-commit hooks and deptry - if: matrix.python-version == '3.11' - run: | - pdm run pre-commit run -a --show-diff-on-failure - pdm run deptry . + - name: Check typing + run: pdm run mypy - name: Run tests run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + - name: Upload coverage reports to Codecov with GitHub Action on Python 3.11 and x86_64 + uses: codecov/codecov-action@v3 + if: ${{ matrix.python-version == '3.11' && matrix.target == 'x86_64' }} + windows: runs-on: windows-latest strategy: @@ -69,3 +91,18 @@ jobs: - name: Run tests run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + check-docs: + runs-on: ubuntu-latest + steps: + - name: Check out + uses: actions/checkout@v4 + + - name: Set up the environment + uses: ./.github/actions/setup-env + with: + python-version: '3.11' + target: 'x86_64' + + - name: Check if documentation can be built + run: pdm run mkdocs build -s From 8be7d9314b27ea0ed22e02dbd6605d533a7e6806 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 18:50:49 +0100 Subject: [PATCH 38/77] add quality and docs check --- .github/actions/setup-env/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index 5732fcf3..f1651c8d 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -1,5 +1,5 @@ name: 'Setup Python and Rust Environment' -description: 'Set up Python and Rust for PDM projects with matrix support' +description: 'Set up Python and Rust environment for PDM projects with matrix support' inputs: python-version: From bb24bbed3fffae713dd66bad37110d347b33040e Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 19:35:14 +0100 Subject: [PATCH 39/77] fix mypy --- deptry/deptry.pyi | 11 ++++++++--- deptry/imports/extract.py | 6 +++--- deptry/imports/location.py | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/deptry/deptry.pyi b/deptry/deptry.pyi index ded64a2b..9b49a83b 100644 --- a/deptry/deptry.pyi +++ b/deptry/deptry.pyi @@ -1,5 +1,10 @@ -def get_imports_from_py_files(file_paths: list[str]): ... -def get_imports_from_py_file(file_path: str): ... +from deptry import Location as RustLocation + +def get_imports_from_py_files(file_paths: list[str]) -> dict[str, list[RustLocation]]: ... +def get_imports_from_py_file(file_path: str) -> dict[str, list[RustLocation]]: ... class Location: - def __init__(self, file: str, line: int, column: int): ... + file: str + line: int + column: int + def __init__(self, file: str, line: int, column: int) -> None: ... diff --git a/deptry/imports/extract.py b/deptry/imports/extract.py index b857713a..b366c91c 100644 --- a/deptry/imports/extract.py +++ b/deptry/imports/extract.py @@ -44,7 +44,6 @@ def get_imported_modules_from_ipynb_file(path_to_file: Path) -> dict[str, list[L modules = NotebookImportExtractor(path_to_file).extract_imports() - modules = convert_rust_locations_to_python_locations(modules) logging.debug("Found the following imports in %s: %s", path_to_file, modules) return modules @@ -52,6 +51,7 @@ def get_imported_modules_from_ipynb_file(path_to_file: Path) -> dict[str, list[L def convert_rust_locations_to_python_locations( imported_modules: dict[str, list[RustLocation]], ) -> dict[str, list[Location]]: + converted_modules: dict[str, list[Location]] = {} for module, locations in imported_modules.items(): - imported_modules[module] = [Location.from_rust_location_object(loc) for loc in locations] - return imported_modules + converted_modules[module] = [Location.from_rust_location_object(loc) for loc in locations] + return converted_modules diff --git a/deptry/imports/location.py b/deptry/imports/location.py index e9160c68..e1017443 100644 --- a/deptry/imports/location.py +++ b/deptry/imports/location.py @@ -15,5 +15,5 @@ class Location: column: int | None = None @classmethod - def from_rust_location_object(cls, location: RustLocation): + def from_rust_location_object(cls, location: RustLocation) -> Location: return cls(file=Path(location.file), line=location.line, column=location.column) From f778aa2274b5574ffc9c1e6aca51f7dce22d1abf Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 21:06:51 +0100 Subject: [PATCH 40/77] try to release --- .github/workflows/release.yml | 119 ++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..3dc8759d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,119 @@ +name: Release + +on: + workflow_dispatch: + inputs: + tag: + description: "The version to tag." + +jobs: + +# linux: +# runs-on: ubuntu-latest +# strategy: +# matrix: +# target: [x86_64, x86, aarch64] +# steps: +# - name: Check out +# uses: actions/checkout@v4 + +# - uses: actions/setup-python@v5 +# with: +# python-version: '3.11' + +# - name: Build wheels +# uses: PyO3/maturin-action@v1 +# with: +# target: ${{ matrix.target }} +# args: --release --out dist --find-interpreter +# sccache: 'true' +# manylinux: auto + +# - name: Upload wheels +# uses: actions/upload-artifact@v4 +# with: +# name: wheels-linux-${{ matrix.target }} +# path: dist + +# windows: +# runs-on: windows-latest +# strategy: +# matrix: +# target: [x64, x86] +# steps: +# - name: Check out +# uses: actions/checkout@v4 + +# - uses: actions/setup-python@v5 +# with: +# python-version: '3.11' + +# - name: Build wheels +# uses: PyO3/maturin-action@v1 +# with: +# target: ${{ matrix.target }} +# args: --release --out dist --find-interpreter +# sccache: 'true' + +# - name: Upload wheels +# uses: actions/upload-artifact@v4 +# with: +# name: wheels-windows-${{ matrix.target }} +# path: dist + +# macos: +# runs-on: macos-latest +# strategy: +# matrix: +# target: [x86_64, aarch64] +# steps: +# - name: Check out +# uses: actions/checkout@v4 + +# - uses: actions/setup-python@v5 +# with: +# python-version: '3.11' + +# - name: Build wheels +# uses: PyO3/maturin-action@v1 +# with: +# target: ${{ matrix.target }} +# args: --release --out dist --find-interpreter +# sccache: 'true' + +# - name: Upload wheels +# uses: actions/upload-artifact@v4 +# with: +# name: wheels-macos-${{ matrix.target }} +# path: dist + + sdist: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build sdist + uses: PyO3/maturin-action@v1 + with: + command: sdist + args: --out dist + - name: Upload sdist + uses: actions/upload-artifact@v4 + with: + name: wheels-sdist + path: dist + + release: + name: Release + runs-on: ubuntu-latest + needs: [sdist] + # needs: [linux, windows, macos, sdist] + steps: + - uses: actions/download-artifact@v4 + - name: Publish to Test PyPI + uses: PyO3/maturin-action@v1 + env: + MATURIN_PYPI_TOKEN: ${{ secrets.TEST_PYPI_TOKEN }} + MATURIN_REPOSITORY_URL: https://test.pypi.org/ + with: + command: upload + args: --non-interactive --skip-existing wheels-*/* From 7c078cf50345593b7322067047307801f8b3c9e0 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 21:16:10 +0100 Subject: [PATCH 41/77] try to release --- .github/workflows/main.yml | 10 +++++----- .github/workflows/release.yml | 14 ++++++++++---- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 81f36ef7..ec9805f4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,10 +1,10 @@ name: CI -on: - pull_request: - types: [opened, synchronize, reopened] - push: - branches: [main] +on: workflow_dispatch + # pull_request: + # types: [opened, synchronize, reopened] + # push: + # branches: [main] jobs: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3dc8759d..4106742c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,10 +1,10 @@ name: Release on: - workflow_dispatch: - inputs: - tag: - description: "The version to tag." + pull_request: + types: [opened, synchronize, reopened] + push: + branches: [main] jobs: @@ -91,6 +91,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + + - name: Update project version + run: | + PROJECT_VERSION="0.0.13a1" # Set this to your desired version + sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" Cargo.toml + - name: Build sdist uses: PyO3/maturin-action@v1 with: From 1cdfa2bb09373d814d47d77708dfdaae1b21f6c7 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 21:17:25 +0100 Subject: [PATCH 42/77] try to release --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4106742c..abaf4ee7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -95,7 +95,7 @@ jobs: - name: Update project version run: | PROJECT_VERSION="0.0.13a1" # Set this to your desired version - sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" Cargo.toml + sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml - name: Build sdist uses: PyO3/maturin-action@v1 From 6a08ebee098da4e25d8822dece9e3ec047492976 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 21:19:11 +0100 Subject: [PATCH 43/77] try to release --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index abaf4ee7..1e08d15d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -119,7 +119,7 @@ jobs: uses: PyO3/maturin-action@v1 env: MATURIN_PYPI_TOKEN: ${{ secrets.TEST_PYPI_TOKEN }} - MATURIN_REPOSITORY_URL: https://test.pypi.org/ + MATURIN_REPOSITORY_URL: https://test.pypi.org/legacy/ with: command: upload args: --non-interactive --skip-existing wheels-*/* From 1e8a95b02ade3dd86b3d8355e1b3b2161b92ac84 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 21:20:01 +0100 Subject: [PATCH 44/77] try to release --- .github/workflows/release.yml | 159 +++++++++++++++++----------------- 1 file changed, 79 insertions(+), 80 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1e08d15d..1ed27db5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,84 +8,84 @@ on: jobs: -# linux: -# runs-on: ubuntu-latest -# strategy: -# matrix: -# target: [x86_64, x86, aarch64] -# steps: -# - name: Check out -# uses: actions/checkout@v4 - -# - uses: actions/setup-python@v5 -# with: -# python-version: '3.11' - -# - name: Build wheels -# uses: PyO3/maturin-action@v1 -# with: -# target: ${{ matrix.target }} -# args: --release --out dist --find-interpreter -# sccache: 'true' -# manylinux: auto - -# - name: Upload wheels -# uses: actions/upload-artifact@v4 -# with: -# name: wheels-linux-${{ matrix.target }} -# path: dist - -# windows: -# runs-on: windows-latest -# strategy: -# matrix: -# target: [x64, x86] -# steps: -# - name: Check out -# uses: actions/checkout@v4 - -# - uses: actions/setup-python@v5 -# with: -# python-version: '3.11' - -# - name: Build wheels -# uses: PyO3/maturin-action@v1 -# with: -# target: ${{ matrix.target }} -# args: --release --out dist --find-interpreter -# sccache: 'true' - -# - name: Upload wheels -# uses: actions/upload-artifact@v4 -# with: -# name: wheels-windows-${{ matrix.target }} -# path: dist - -# macos: -# runs-on: macos-latest -# strategy: -# matrix: -# target: [x86_64, aarch64] -# steps: -# - name: Check out -# uses: actions/checkout@v4 - -# - uses: actions/setup-python@v5 -# with: -# python-version: '3.11' - -# - name: Build wheels -# uses: PyO3/maturin-action@v1 -# with: -# target: ${{ matrix.target }} -# args: --release --out dist --find-interpreter -# sccache: 'true' - -# - name: Upload wheels -# uses: actions/upload-artifact@v4 -# with: -# name: wheels-macos-${{ matrix.target }} -# path: dist + linux: + runs-on: ubuntu-latest + strategy: + matrix: + target: [x86_64, x86, aarch64] + steps: + - name: Check out + uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + manylinux: auto + + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-linux-${{ matrix.target }} + path: dist + + windows: + runs-on: windows-latest + strategy: + matrix: + target: [x64, x86] + steps: + - name: Check out + uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-windows-${{ matrix.target }} + path: dist + + macos: + runs-on: macos-latest + strategy: + matrix: + target: [x86_64, aarch64] + steps: + - name: Check out + uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-macos-${{ matrix.target }} + path: dist sdist: runs-on: ubuntu-latest @@ -111,8 +111,7 @@ jobs: release: name: Release runs-on: ubuntu-latest - needs: [sdist] - # needs: [linux, windows, macos, sdist] + needs: [linux, windows, macos, sdist] steps: - uses: actions/download-artifact@v4 - name: Publish to Test PyPI From 340608b859bbaa6ccabbbcc7e02078d5a1d01c2a Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Mon, 11 Mar 2024 21:28:36 +0100 Subject: [PATCH 45/77] try to release --- .github/workflows/release.yml | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1ed27db5..ce579de5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,6 +21,20 @@ jobs: with: python-version: '3.11' + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.75.0 + + - name: Export tag + id: vars + run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT + + - name: Update project version + run: | + PROJECT_VERSION="0.0.13a1" # Set this to your desired version + sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml + - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -48,6 +62,20 @@ jobs: with: python-version: '3.11' + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.75.0 + + - name: Export tag + id: vars + run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT + + - name: Update project version + run: | + PROJECT_VERSION="0.0.13a1" # Set this to your desired version + sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml + - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -74,6 +102,20 @@ jobs: with: python-version: '3.11' + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.75.0 + + - name: Export tag + id: vars + run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT + + - name: Update project version + run: | + PROJECT_VERSION="0.0.13a1" # Set this to your desired version + sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml + - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -92,11 +134,20 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Export tag + id: vars + run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT + - name: Update project version run: | PROJECT_VERSION="0.0.13a1" # Set this to your desired version sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml + - name: Setup Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.75.0 + - name: Build sdist uses: PyO3/maturin-action@v1 with: @@ -108,6 +159,7 @@ jobs: name: wheels-sdist path: dist + # //TODO: Remove the MATURIN_REPOSITORY_URL, change TEST_PYPI_TOKEN to PYPI_TOKEN. release: name: Release runs-on: ubuntu-latest From eb700eab1b5a2c52ea3308ea6fd2a89354f7af6a Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 05:11:18 +0100 Subject: [PATCH 46/77] try to release --- .github/workflows/release.yml | 70 +++++++++++++++++------------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ce579de5..cbd05e71 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,6 +8,22 @@ on: jobs: + set-version: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Update project version + run: | + PROJECT_VERSION="0.0.13a1" + sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml + + - name: Upload updated pyproject.toml + uses: actions/upload-artifact@v4 + with: + name: pyproject-toml + path: pyproject.toml + linux: runs-on: ubuntu-latest strategy: @@ -17,6 +33,11 @@ jobs: - name: Check out uses: actions/checkout@v4 + - name: Download updated pyproject.toml + uses: actions/download-artifact@v4 + with: + name: pyproject-toml + - uses: actions/setup-python@v5 with: python-version: '3.11' @@ -26,15 +47,6 @@ jobs: with: toolchain: 1.75.0 - - name: Export tag - id: vars - run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT - - - name: Update project version - run: | - PROJECT_VERSION="0.0.13a1" # Set this to your desired version - sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml - - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -58,6 +70,11 @@ jobs: - name: Check out uses: actions/checkout@v4 + - name: Download updated pyproject.toml + uses: actions/download-artifact@v4 + with: + name: pyproject-toml + - uses: actions/setup-python@v5 with: python-version: '3.11' @@ -67,15 +84,6 @@ jobs: with: toolchain: 1.75.0 - - name: Export tag - id: vars - run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT - - - name: Update project version - run: | - PROJECT_VERSION="0.0.13a1" # Set this to your desired version - sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml - - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -98,6 +106,11 @@ jobs: - name: Check out uses: actions/checkout@v4 + - name: Download updated pyproject.toml + uses: actions/download-artifact@v4 + with: + name: pyproject-toml + - uses: actions/setup-python@v5 with: python-version: '3.11' @@ -107,15 +120,6 @@ jobs: with: toolchain: 1.75.0 - - name: Export tag - id: vars - run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT - - - name: Update project version - run: | - PROJECT_VERSION="0.0.13a1" # Set this to your desired version - sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml - - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -134,14 +138,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Export tag - id: vars - run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT - - - name: Update project version - run: | - PROJECT_VERSION="0.0.13a1" # Set this to your desired version - sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml + - name: Download updated pyproject.toml + uses: actions/download-artifact@v4 + with: + name: pyproject-toml - name: Setup Rust toolchain uses: dtolnay/rust-toolchain@stable From 1d363baaa753b3c12089e28df482ed01227c9fe9 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 05:13:25 +0100 Subject: [PATCH 47/77] try to release --- .github/workflows/release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cbd05e71..44539e8c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,6 +26,7 @@ jobs: linux: runs-on: ubuntu-latest + needs: [set-version] strategy: matrix: target: [x86_64, x86, aarch64] @@ -63,6 +64,7 @@ jobs: windows: runs-on: windows-latest + needs: [set-version] strategy: matrix: target: [x64, x86] @@ -99,6 +101,7 @@ jobs: macos: runs-on: macos-latest + needs: [set-version] strategy: matrix: target: [x86_64, aarch64] @@ -135,6 +138,7 @@ jobs: sdist: runs-on: ubuntu-latest + needs: [set-version] steps: - uses: actions/checkout@v4 From f6d5db6dbd8212500e1fa4b59e4ab7b811b80a9d Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 05:17:02 +0100 Subject: [PATCH 48/77] try to release --- .github/workflows/release.yml | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 44539e8c..880c9595 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,20 +9,20 @@ on: jobs: set-version: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 - - name: Update project version - run: | - PROJECT_VERSION="0.0.13a1" - sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml + - name: Update project version + run: | + PROJECT_VERSION="0.0.13a1" + sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml - - name: Upload updated pyproject.toml - uses: actions/upload-artifact@v4 - with: - name: pyproject-toml - path: pyproject.toml + - name: Upload updated pyproject.toml + uses: actions/upload-artifact@v4 + with: + name: pyproject-toml + path: pyproject.toml linux: runs-on: ubuntu-latest @@ -43,11 +43,6 @@ jobs: with: python-version: '3.11' - - name: Setup Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.75.0 - - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -55,6 +50,7 @@ jobs: args: --release --out dist --find-interpreter sccache: 'true' manylinux: auto + rust-toolchain: 1.75.0 - name: Upload wheels uses: actions/upload-artifact@v4 From 0b63d5a7bf498d26c135a1c7e2b2cb5da46bc5a0 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 05:19:57 +0100 Subject: [PATCH 49/77] try to release --- .github/workflows/release.yml | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 880c9595..71fc6764 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,17 +77,13 @@ jobs: with: python-version: '3.11' - - name: Setup Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.75.0 - - name: Build wheels uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} args: --release --out dist --find-interpreter sccache: 'true' + rust-toolchain: 1.75.0 - name: Upload wheels uses: actions/upload-artifact@v4 @@ -114,17 +110,13 @@ jobs: with: python-version: '3.11' - - name: Setup Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.75.0 - - name: Build wheels uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} args: --release --out dist --find-interpreter sccache: 'true' + rust-toolchain: 1.75.0 - name: Upload wheels uses: actions/upload-artifact@v4 @@ -143,16 +135,13 @@ jobs: with: name: pyproject-toml - - name: Setup Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.75.0 - - name: Build sdist uses: PyO3/maturin-action@v1 with: command: sdist args: --out dist + rust-toolchain: 1.75.0 + - name: Upload sdist uses: actions/upload-artifact@v4 with: From e434f4bf59c8f86130cb12cbb9392966907d756c Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 05:31:28 +0100 Subject: [PATCH 50/77] try to release --- .github/workflows/release.yml | 2 +- .pre-commit-config.yaml | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 71fc6764..ffa4c007 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,7 +15,7 @@ jobs: - name: Update project version run: | - PROJECT_VERSION="0.0.13a1" + PROJECT_VERSION="0.0.13a2" sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml - name: Upload updated pyproject.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ee4befb4..1f7b899f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,3 +15,9 @@ repos: - id: ruff args: [--exit-non-zero-on-fix] - id: ruff-format + + - repo: https://github.com/doublify/pre-commit-rust + rev: master + hooks: + - id: fmt + - id: cargo-check From 3e857600fef45a5e07db9b548eba22089f7f552c Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 05:49:24 +0100 Subject: [PATCH 51/77] build for more python versions --- .github/workflows/release.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ffa4c007..335b6e1c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,6 @@ name: Release +# //TODO: Change to on 'tag' on: pull_request: types: [opened, synchronize, reopened] @@ -13,9 +14,10 @@ jobs: steps: - uses: actions/checkout@v4 + # //TODO: Change to fetch version from tag. - name: Update project version run: | - PROJECT_VERSION="0.0.13a2" + PROJECT_VERSION="0.0.13a3" sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml - name: Upload updated pyproject.toml @@ -47,7 +49,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist --find-interpreter + args: --release --out dist -i 3.8 3.9 3.10 3.11 3.12 sccache: 'true' manylinux: auto rust-toolchain: 1.75.0 @@ -81,7 +83,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist --find-interpreter + args: --release --out dist -i 3.8 3.9 3.10 3.11 3.12 sccache: 'true' rust-toolchain: 1.75.0 @@ -114,7 +116,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist --find-interpreter + args: --release --out dist -i 3.8 3.9 3.10 3.11 3.12 sccache: 'true' rust-toolchain: 1.75.0 From 3ce59f12655b4e8910d935da763c66ffb096e29b Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 05:57:36 +0100 Subject: [PATCH 52/77] try abi3 --- .github/workflows/release.yml | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 335b6e1c..d169be9f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist -i 3.8 3.9 3.10 3.11 3.12 + args: --release --out dist sccache: 'true' manylinux: auto rust-toolchain: 1.75.0 @@ -83,7 +83,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist -i 3.8 3.9 3.10 3.11 3.12 + args: --release --out dist sccache: 'true' rust-toolchain: 1.75.0 @@ -116,7 +116,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist -i 3.8 3.9 3.10 3.11 3.12 + args: --release --out dist sccache: 'true' rust-toolchain: 1.75.0 diff --git a/Cargo.toml b/Cargo.toml index 2d680c8a..381201d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ chardetng = "0.1.17" encoding_rs = "0.8.33" encoding_rs_io = "0.1.7" log = "0.4.21" -pyo3 = "0.20.0" +pyo3 = { version = "0.20.0", features = ["abi3-py38"] } pyo3-log = "0.9.0" rayon = "1.9.0" regex = "1.10.3" From 945891bca4e09233ef652d44f2d2717580d3e954 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 05:58:16 +0100 Subject: [PATCH 53/77] try abi3 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d169be9f..9a1f0ddb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: # //TODO: Change to fetch version from tag. - name: Update project version run: | - PROJECT_VERSION="0.0.13a3" + PROJECT_VERSION="0.0.13a4" sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml - name: Upload updated pyproject.toml From 995b227f0c3da5b328b1bb3895f17372881a8b67 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 06:01:36 +0100 Subject: [PATCH 54/77] try abi3 --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9a1f0ddb..437946df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist + args: --release --out dist --find-interpreter sccache: 'true' manylinux: auto rust-toolchain: 1.75.0 @@ -83,7 +83,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist + args: --release --out dist --find-interpreter sccache: 'true' rust-toolchain: 1.75.0 @@ -116,7 +116,7 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} - args: --release --out dist + args: --release --out dist --find-interpreter sccache: 'true' rust-toolchain: 1.75.0 From bff16deda477e8e71775444c9af2ed96fe003a20 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 06:07:43 +0100 Subject: [PATCH 55/77] try abi3 --- .github/actions/setup-env/action.yml | 1 + .github/workflows/release.yml | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index f1651c8d..e04bf29c 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -18,6 +18,7 @@ runs: uses: actions/setup-python@v5 with: python-version: ${{ inputs.python-version }} + architecture: ${{ matrix.target }} - name: Setup Rust toolchain uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 437946df..5d5ed947 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: # //TODO: Change to fetch version from tag. - name: Update project version run: | - PROJECT_VERSION="0.0.13a4" + PROJECT_VERSION="0.0.13a5" sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml - name: Upload updated pyproject.toml @@ -44,6 +44,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.11' + architecture: ${{ matrix.target }} - name: Build wheels uses: PyO3/maturin-action@v1 @@ -78,6 +79,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.11' + architecture: ${{ matrix.target }} - name: Build wheels uses: PyO3/maturin-action@v1 @@ -111,6 +113,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.11' + architecture: ${{ matrix.target }} - name: Build wheels uses: PyO3/maturin-action@v1 From c824adec27b1610efe9d05146d4ab5369d63181c Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 06:22:20 +0100 Subject: [PATCH 56/77] try abi3 --- .github/actions/setup-env/action.yml | 6 +++++- .github/workflows/main.yml | 13 ++++++++----- .github/workflows/release.yml | 4 ++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index e04bf29c..46ab2dc2 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -10,6 +10,10 @@ inputs: description: 'Target architecture for maturin' required: true default: 'x86_64' + python-target: + description: 'Target architecture for python installation' + required: true + default: 'x64' runs: using: 'composite' @@ -18,7 +22,7 @@ runs: uses: actions/setup-python@v5 with: python-version: ${{ inputs.python-version }} - architecture: ${{ matrix.target }} + architecture: ${{ matrix.python-target }} - name: Setup Rust toolchain uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ec9805f4..8c14c10c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,10 +1,10 @@ name: CI -on: workflow_dispatch - # pull_request: - # types: [opened, synchronize, reopened] - # push: - # branches: [main] +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: [main] jobs: @@ -43,6 +43,7 @@ jobs: with: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} + python-target: ${{ matrix.target == 'aarch64' && 'amd64' || 'x64' }} - name: Check typing run: pdm run mypy @@ -69,6 +70,7 @@ jobs: with: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} + python-target: ${{ matrix.target }} - name: Run tests run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml @@ -88,6 +90,7 @@ jobs: with: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} + python-target: ${{ matrix.target == 'aarch64' && 'amd64' || 'x64' }} - name: Run tests run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5d5ed947..a102cbd9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,7 +44,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.11' - architecture: ${{ matrix.target }} + architecture: ${{ matrix.target == 'aarch64' && 'amd64' || 'x64' }} - name: Build wheels uses: PyO3/maturin-action@v1 @@ -113,7 +113,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.11' - architecture: ${{ matrix.target }} + architecture: ${{ matrix.target == 'aarch64' && 'amd64' || 'x64' }} - name: Build wheels uses: PyO3/maturin-action@v1 From 87a1a2c69a2236f4bda8c827e4bc24609cf280f8 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 06:24:49 +0100 Subject: [PATCH 57/77] try abi3 --- .github/workflows/main.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8c14c10c..e3b15282 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,7 +43,7 @@ jobs: with: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} - python-target: ${{ matrix.target == 'aarch64' && 'amd64' || 'x64' }} + python-target: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} - name: Check typing run: pdm run mypy @@ -90,7 +90,7 @@ jobs: with: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} - python-target: ${{ matrix.target == 'aarch64' && 'amd64' || 'x64' }} + python-target: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} - name: Run tests run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a102cbd9..dedfc4b8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,7 +44,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.11' - architecture: ${{ matrix.target == 'aarch64' && 'amd64' || 'x64' }} + architecture: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} - name: Build wheels uses: PyO3/maturin-action@v1 @@ -113,7 +113,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.11' - architecture: ${{ matrix.target == 'aarch64' && 'amd64' || 'x64' }} + architecture: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} - name: Build wheels uses: PyO3/maturin-action@v1 From 68cb9aa867bc0788fa7fc6ad5b19a39ad5fbe338 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 06:27:07 +0100 Subject: [PATCH 58/77] try abi3 --- .github/workflows/main.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e3b15282..93ee2d58 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,7 +43,7 @@ jobs: with: python-version: ${{ matrix.python-version }} target: ${{ matrix.target }} - python-target: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} + python-target: 'x64' - name: Check typing run: pdm run mypy diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dedfc4b8..bdfd4a16 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,7 +44,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.11' - architecture: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} + architecture: 'x64' - name: Build wheels uses: PyO3/maturin-action@v1 From ef5ab9e071aa2b7fa1b17a1e4ceb45e3e14e6d2b Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 06:33:07 +0100 Subject: [PATCH 59/77] fix code quality --- .github/workflows/main.yml | 164 +++++++++++++++++++------------------ 1 file changed, 83 insertions(+), 81 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 93ee2d58..f295a3df 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,93 +19,95 @@ jobs: with: python-version: '3.11' target: 'x86_64' + python-target: 'x64' - name: Run pre-commit run: | + rustup component add rustfmt pdm run pre-commit run -a --show-diff-on-failure - name: Inspect dependencies with deptry run: | pdm run deptry . - linux: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - target: [x86_64, x86, aarch64] - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up the environment - uses: ./.github/actions/setup-env - with: - python-version: ${{ matrix.python-version }} - target: ${{ matrix.target }} - python-target: 'x64' - - - name: Check typing - run: pdm run mypy - - - name: Run tests - run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - - - name: Upload coverage reports to Codecov with GitHub Action on Python 3.11 and x86_64 - uses: codecov/codecov-action@v3 - if: ${{ matrix.python-version == '3.11' && matrix.target == 'x86_64' }} - - windows: - runs-on: windows-latest - strategy: - matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - target: [x64, x86] - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up the environment - uses: ./.github/actions/setup-env - with: - python-version: ${{ matrix.python-version }} - target: ${{ matrix.target }} - python-target: ${{ matrix.target }} - - - name: Run tests - run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - - macos: - runs-on: macos-latest - strategy: - matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - target: [x86_64, aarch64] - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up the environment - uses: ./.github/actions/setup-env - with: - python-version: ${{ matrix.python-version }} - target: ${{ matrix.target }} - python-target: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} - - - name: Run tests - run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - - check-docs: - runs-on: ubuntu-latest - steps: - - name: Check out - uses: actions/checkout@v4 - - - name: Set up the environment - uses: ./.github/actions/setup-env - with: - python-version: '3.11' - target: 'x86_64' - - - name: Check if documentation can be built - run: pdm run mkdocs build -s + # linux: + # runs-on: ubuntu-latest + # strategy: + # matrix: + # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + # target: [x86_64, x86, aarch64] + # steps: + # - name: Check out + # uses: actions/checkout@v4 + + # - name: Set up the environment + # uses: ./.github/actions/setup-env + # with: + # python-version: ${{ matrix.python-version }} + # target: ${{ matrix.target }} + # python-target: 'x64' + + # - name: Check typing + # run: pdm run mypy + + # - name: Run tests + # run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + # - name: Upload coverage reports to Codecov with GitHub Action on Python 3.11 and x86_64 + # uses: codecov/codecov-action@v3 + # if: ${{ matrix.python-version == '3.11' && matrix.target == 'x86_64' }} + + # windows: + # runs-on: windows-latest + # strategy: + # matrix: + # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + # target: [x64, x86] + # steps: + # - name: Check out + # uses: actions/checkout@v4 + + # - name: Set up the environment + # uses: ./.github/actions/setup-env + # with: + # python-version: ${{ matrix.python-version }} + # target: ${{ matrix.target }} + # python-target: ${{ matrix.target }} + + # - name: Run tests + # run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + # macos: + # runs-on: macos-latest + # strategy: + # matrix: + # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + # target: [x86_64, aarch64] + # steps: + # - name: Check out + # uses: actions/checkout@v4 + + # - name: Set up the environment + # uses: ./.github/actions/setup-env + # with: + # python-version: ${{ matrix.python-version }} + # target: ${{ matrix.target }} + # python-target: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} + + # - name: Run tests + # run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + # check-docs: + # runs-on: ubuntu-latest + # steps: + # - name: Check out + # uses: actions/checkout@v4 + + # - name: Set up the environment + # uses: ./.github/actions/setup-env + # with: + # python-version: '3.11' + # target: 'x86_64' + + # - name: Check if documentation can be built + # run: pdm run mkdocs build -s From 4585129d344d75b283c641a2cb03a67bf64268c7 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 06:39:01 +0100 Subject: [PATCH 60/77] fix the workflows --- .github/workflows/main.yml | 162 +++++++++++++++++----------------- .github/workflows/release.yml | 38 +++++--- 2 files changed, 108 insertions(+), 92 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f295a3df..83d96dec 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,84 +30,84 @@ jobs: run: | pdm run deptry . - # linux: - # runs-on: ubuntu-latest - # strategy: - # matrix: - # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - # target: [x86_64, x86, aarch64] - # steps: - # - name: Check out - # uses: actions/checkout@v4 - - # - name: Set up the environment - # uses: ./.github/actions/setup-env - # with: - # python-version: ${{ matrix.python-version }} - # target: ${{ matrix.target }} - # python-target: 'x64' - - # - name: Check typing - # run: pdm run mypy - - # - name: Run tests - # run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - - # - name: Upload coverage reports to Codecov with GitHub Action on Python 3.11 and x86_64 - # uses: codecov/codecov-action@v3 - # if: ${{ matrix.python-version == '3.11' && matrix.target == 'x86_64' }} - - # windows: - # runs-on: windows-latest - # strategy: - # matrix: - # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - # target: [x64, x86] - # steps: - # - name: Check out - # uses: actions/checkout@v4 - - # - name: Set up the environment - # uses: ./.github/actions/setup-env - # with: - # python-version: ${{ matrix.python-version }} - # target: ${{ matrix.target }} - # python-target: ${{ matrix.target }} - - # - name: Run tests - # run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - - # macos: - # runs-on: macos-latest - # strategy: - # matrix: - # python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - # target: [x86_64, aarch64] - # steps: - # - name: Check out - # uses: actions/checkout@v4 - - # - name: Set up the environment - # uses: ./.github/actions/setup-env - # with: - # python-version: ${{ matrix.python-version }} - # target: ${{ matrix.target }} - # python-target: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} - - # - name: Run tests - # run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml - - # check-docs: - # runs-on: ubuntu-latest - # steps: - # - name: Check out - # uses: actions/checkout@v4 - - # - name: Set up the environment - # uses: ./.github/actions/setup-env - # with: - # python-version: '3.11' - # target: 'x86_64' - - # - name: Check if documentation can be built - # run: pdm run mkdocs build -s + linux: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + target: [x86_64, x86, aarch64] + steps: + - name: Check out + uses: actions/checkout@v4 + + - name: Set up the environment + uses: ./.github/actions/setup-env + with: + python-version: ${{ matrix.python-version }} + target: ${{ matrix.target }} + python-target: 'x64' + + - name: Check typing + run: pdm run mypy + + - name: Run tests + run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + - name: Upload coverage reports to Codecov with GitHub Action on Python 3.11 and x86_64 + uses: codecov/codecov-action@v3 + if: ${{ matrix.python-version == '3.11' && matrix.target == 'x86_64' }} + + windows: + runs-on: windows-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + target: [x64, x86] + steps: + - name: Check out + uses: actions/checkout@v4 + + - name: Set up the environment + uses: ./.github/actions/setup-env + with: + python-version: ${{ matrix.python-version }} + target: ${{ matrix.target }} + python-target: ${{ matrix.target }} + + - name: Run tests + run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + macos: + runs-on: macos-latest + strategy: + matrix: + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + target: [x86_64, aarch64] + steps: + - name: Check out + uses: actions/checkout@v4 + + - name: Set up the environment + uses: ./.github/actions/setup-env + with: + python-version: ${{ matrix.python-version }} + target: ${{ matrix.target }} + python-target: ${{ matrix.target == 'aarch64' && 'arm64' || 'x64' }} + + - name: Run tests + run: pdm run pytest tests --cov --cov-config=pyproject.toml --cov-report=xml + + check-docs: + runs-on: ubuntu-latest + steps: + - name: Check out + uses: actions/checkout@v4 + + - name: Set up the environment + uses: ./.github/actions/setup-env + with: + python-version: '3.11' + target: 'x86_64' + + - name: Check if documentation can be built + run: pdm run mkdocs build -s diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bdfd4a16..df912dfe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,11 +1,8 @@ name: Release -# //TODO: Change to on 'tag' on: - pull_request: - types: [opened, synchronize, reopened] - push: - branches: [main] + release: + types: [published] jobs: @@ -14,11 +11,16 @@ jobs: steps: - uses: actions/checkout@v4 - # //TODO: Change to fetch version from tag. + - name: Export tag + id: vars + run: echo tag=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT + - name: Update project version run: | PROJECT_VERSION="0.0.13a5" - sed -i "s/^version = \".*\"/version = \"$PROJECT_VERSION\"/" pyproject.toml + sed -i "s/^version = \".*\"/version = \"$RELEASE_VERSION\"/" pyproject.toml + env: + RELEASE_VERSION: ${{ steps.vars.outputs.tag }} - name: Upload updated pyproject.toml uses: actions/upload-artifact@v4 @@ -153,18 +155,32 @@ jobs: name: wheels-sdist path: dist - # //TODO: Remove the MATURIN_REPOSITORY_URL, change TEST_PYPI_TOKEN to PYPI_TOKEN. release: name: Release runs-on: ubuntu-latest needs: [linux, windows, macos, sdist] steps: - uses: actions/download-artifact@v4 - - name: Publish to Test PyPI + - name: Publish to PyPI uses: PyO3/maturin-action@v1 env: - MATURIN_PYPI_TOKEN: ${{ secrets.TEST_PYPI_TOKEN }} - MATURIN_REPOSITORY_URL: https://test.pypi.org/legacy/ + MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} with: command: upload args: --non-interactive --skip-existing wheels-*/* + + +# release: +# name: Release +# runs-on: ubuntu-latest +# needs: [linux, windows, macos, sdist] +# steps: +# - uses: actions/download-artifact@v4 +# - name: Publish to Test PyPI +# uses: PyO3/maturin-action@v1 +# env: +# MATURIN_PYPI_TOKEN: ${{ secrets.TEST_PYPI_TOKEN }} +# MATURIN_REPOSITORY_URL: https://test.pypi.org/legacy/ +# with: +# command: upload +# args: --non-interactive --skip-existing wheels-*/* From 7a637f3ad9372895847800de04eda50023ebf897 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 06:42:10 +0100 Subject: [PATCH 61/77] remove obsolete version line --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index df912dfe..9b5e1d07 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,6 @@ jobs: - name: Update project version run: | - PROJECT_VERSION="0.0.13a5" sed -i "s/^version = \".*\"/version = \"$RELEASE_VERSION\"/" pyproject.toml env: RELEASE_VERSION: ${{ steps.vars.outputs.tag }} From 628cf9f10b49c3ae88f02be42417fafd8f308898 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 09:04:35 +0100 Subject: [PATCH 62/77] move the rust functionality to deptry.rust --- .github/workflows/main.yml | 2 +- Makefile | 2 +- deptry/__init__.py | 9 --------- pyproject.toml | 7 +++++-- python/deptry/__init__.py | 5 +++++ {deptry => python/deptry}/__main__.py | 0 {deptry => python/deptry}/cli.py | 0 {deptry => python/deptry}/config.py | 0 {deptry => python/deptry}/core.py | 0 {deptry => python/deptry}/dependency.py | 0 {deptry => python/deptry}/dependency_getter/__init__.py | 0 {deptry => python/deptry}/dependency_getter/base.py | 0 {deptry => python/deptry}/dependency_getter/pdm.py | 0 {deptry => python/deptry}/dependency_getter/pep_621.py | 0 {deptry => python/deptry}/dependency_getter/poetry.py | 0 .../deptry}/dependency_getter/requirements_txt.py | 0 .../deptry}/dependency_specification_detector.py | 0 {deptry => python/deptry}/deprecate/ignore_flags.py | 0 {deptry => python/deptry}/deprecate/skip_flags.py | 0 {deptry => python/deptry}/exceptions.py | 0 {deptry => python/deptry}/imports/__init__.py | 0 {deptry => python/deptry}/imports/extract.py | 4 ++-- {deptry => python/deptry}/imports/extractors/__init__.py | 0 {deptry => python/deptry}/imports/extractors/base.py | 0 .../imports/extractors/notebook_import_extractor.py | 0 {deptry => python/deptry}/imports/location.py | 2 +- {deptry => python/deptry}/module.py | 0 {deptry => python/deptry}/python_file_finder.py | 0 {deptry => python/deptry}/reporters/__init__.py | 0 {deptry => python/deptry}/reporters/base.py | 0 {deptry => python/deptry}/reporters/json.py | 0 {deptry => python/deptry}/reporters/text.py | 0 deptry/deptry.pyi => python/deptry/rust.pyi | 2 +- {deptry => python/deptry}/stdlibs.py | 0 {deptry => python/deptry}/utils.py | 0 {deptry => python/deptry}/violations/__init__.py | 0 {deptry => python/deptry}/violations/base.py | 0 .../deptry}/violations/dep001_missing/__init__.py | 0 .../deptry}/violations/dep001_missing/finder.py | 0 .../deptry}/violations/dep001_missing/violation.py | 0 .../deptry}/violations/dep002_unused/__init__.py | 0 .../deptry}/violations/dep002_unused/finder.py | 0 .../deptry}/violations/dep002_unused/violation.py | 0 .../deptry}/violations/dep003_transitive/__init__.py | 0 .../deptry}/violations/dep003_transitive/finder.py | 0 .../deptry}/violations/dep003_transitive/violation.py | 0 .../deptry}/violations/dep004_misplaced_dev/__init__.py | 0 .../deptry}/violations/dep004_misplaced_dev/finder.py | 0 .../deptry}/violations/dep004_misplaced_dev/violation.py | 0 src/lib.rs | 2 +- 50 files changed, 17 insertions(+), 18 deletions(-) delete mode 100644 deptry/__init__.py create mode 100644 python/deptry/__init__.py rename {deptry => python/deptry}/__main__.py (100%) rename {deptry => python/deptry}/cli.py (100%) rename {deptry => python/deptry}/config.py (100%) rename {deptry => python/deptry}/core.py (100%) rename {deptry => python/deptry}/dependency.py (100%) rename {deptry => python/deptry}/dependency_getter/__init__.py (100%) rename {deptry => python/deptry}/dependency_getter/base.py (100%) rename {deptry => python/deptry}/dependency_getter/pdm.py (100%) rename {deptry => python/deptry}/dependency_getter/pep_621.py (100%) rename {deptry => python/deptry}/dependency_getter/poetry.py (100%) rename {deptry => python/deptry}/dependency_getter/requirements_txt.py (100%) rename {deptry => python/deptry}/dependency_specification_detector.py (100%) rename {deptry => python/deptry}/deprecate/ignore_flags.py (100%) rename {deptry => python/deptry}/deprecate/skip_flags.py (100%) rename {deptry => python/deptry}/exceptions.py (100%) rename {deptry => python/deptry}/imports/__init__.py (100%) rename {deptry => python/deptry}/imports/extract.py (94%) rename {deptry => python/deptry}/imports/extractors/__init__.py (100%) rename {deptry => python/deptry}/imports/extractors/base.py (100%) rename {deptry => python/deptry}/imports/extractors/notebook_import_extractor.py (100%) rename {deptry => python/deptry}/imports/location.py (89%) rename {deptry => python/deptry}/module.py (100%) rename {deptry => python/deptry}/python_file_finder.py (100%) rename {deptry => python/deptry}/reporters/__init__.py (100%) rename {deptry => python/deptry}/reporters/base.py (100%) rename {deptry => python/deptry}/reporters/json.py (100%) rename {deptry => python/deptry}/reporters/text.py (100%) rename deptry/deptry.pyi => python/deptry/rust.pyi (87%) rename {deptry => python/deptry}/stdlibs.py (100%) rename {deptry => python/deptry}/utils.py (100%) rename {deptry => python/deptry}/violations/__init__.py (100%) rename {deptry => python/deptry}/violations/base.py (100%) rename {deptry => python/deptry}/violations/dep001_missing/__init__.py (100%) rename {deptry => python/deptry}/violations/dep001_missing/finder.py (100%) rename {deptry => python/deptry}/violations/dep001_missing/violation.py (100%) rename {deptry => python/deptry}/violations/dep002_unused/__init__.py (100%) rename {deptry => python/deptry}/violations/dep002_unused/finder.py (100%) rename {deptry => python/deptry}/violations/dep002_unused/violation.py (100%) rename {deptry => python/deptry}/violations/dep003_transitive/__init__.py (100%) rename {deptry => python/deptry}/violations/dep003_transitive/finder.py (100%) rename {deptry => python/deptry}/violations/dep003_transitive/violation.py (100%) rename {deptry => python/deptry}/violations/dep004_misplaced_dev/__init__.py (100%) rename {deptry => python/deptry}/violations/dep004_misplaced_dev/finder.py (100%) rename {deptry => python/deptry}/violations/dep004_misplaced_dev/violation.py (100%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 83d96dec..0b8dd49c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,7 +28,7 @@ jobs: - name: Inspect dependencies with deptry run: | - pdm run deptry . + pdm run deptry python linux: runs-on: ubuntu-latest diff --git a/Makefile b/Makefile index c0e19417..09bf7942 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ check: ## Run code quality tools. @echo "🚀 Static type checking: Running mypy" @pdm run mypy @echo "🚀 Checking for dependency issues: Running deptry" - @pdm run deptry . + @pdm run deptry python .PHONY: test test: ## Test the code with pytest. diff --git a/deptry/__init__.py b/deptry/__init__.py deleted file mode 100644 index f809d859..00000000 --- a/deptry/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import annotations - -import logging - -# //TODO: Remove this, and see if we can move the function to a submodule. -# Required to make `from deptry import get_imports_from_py_file` work. -from .deptry import * # noqa: F403 - -logging.getLogger("nbconvert").setLevel(logging.WARNING) diff --git a/pyproject.toml b/pyproject.toml index 2975db3e..bc6115de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,8 @@ build-backend = "maturin" [tool.maturin] features = ["pyo3/extension-module"] +python-source = "python" +module-name = "deptry.rust" [tool.coverage.report] skip_empty = true @@ -82,10 +84,11 @@ exclude_lines = [ [tool.coverage.run] branch = true -source = ["deptry"] +source = ["python/deptry"] [tool.mypy] -files = ["deptry", "scripts", "tests"] +mypy_path = "python" +files = ["python/deptry", "scripts", "tests"] explicit_package_bases = true exclude = ["tests/data"] disallow_any_unimported = true diff --git a/python/deptry/__init__.py b/python/deptry/__init__.py new file mode 100644 index 00000000..7182c449 --- /dev/null +++ b/python/deptry/__init__.py @@ -0,0 +1,5 @@ +from __future__ import annotations + +import logging + +logging.getLogger("nbconvert").setLevel(logging.WARNING) diff --git a/deptry/__main__.py b/python/deptry/__main__.py similarity index 100% rename from deptry/__main__.py rename to python/deptry/__main__.py diff --git a/deptry/cli.py b/python/deptry/cli.py similarity index 100% rename from deptry/cli.py rename to python/deptry/cli.py diff --git a/deptry/config.py b/python/deptry/config.py similarity index 100% rename from deptry/config.py rename to python/deptry/config.py diff --git a/deptry/core.py b/python/deptry/core.py similarity index 100% rename from deptry/core.py rename to python/deptry/core.py diff --git a/deptry/dependency.py b/python/deptry/dependency.py similarity index 100% rename from deptry/dependency.py rename to python/deptry/dependency.py diff --git a/deptry/dependency_getter/__init__.py b/python/deptry/dependency_getter/__init__.py similarity index 100% rename from deptry/dependency_getter/__init__.py rename to python/deptry/dependency_getter/__init__.py diff --git a/deptry/dependency_getter/base.py b/python/deptry/dependency_getter/base.py similarity index 100% rename from deptry/dependency_getter/base.py rename to python/deptry/dependency_getter/base.py diff --git a/deptry/dependency_getter/pdm.py b/python/deptry/dependency_getter/pdm.py similarity index 100% rename from deptry/dependency_getter/pdm.py rename to python/deptry/dependency_getter/pdm.py diff --git a/deptry/dependency_getter/pep_621.py b/python/deptry/dependency_getter/pep_621.py similarity index 100% rename from deptry/dependency_getter/pep_621.py rename to python/deptry/dependency_getter/pep_621.py diff --git a/deptry/dependency_getter/poetry.py b/python/deptry/dependency_getter/poetry.py similarity index 100% rename from deptry/dependency_getter/poetry.py rename to python/deptry/dependency_getter/poetry.py diff --git a/deptry/dependency_getter/requirements_txt.py b/python/deptry/dependency_getter/requirements_txt.py similarity index 100% rename from deptry/dependency_getter/requirements_txt.py rename to python/deptry/dependency_getter/requirements_txt.py diff --git a/deptry/dependency_specification_detector.py b/python/deptry/dependency_specification_detector.py similarity index 100% rename from deptry/dependency_specification_detector.py rename to python/deptry/dependency_specification_detector.py diff --git a/deptry/deprecate/ignore_flags.py b/python/deptry/deprecate/ignore_flags.py similarity index 100% rename from deptry/deprecate/ignore_flags.py rename to python/deptry/deprecate/ignore_flags.py diff --git a/deptry/deprecate/skip_flags.py b/python/deptry/deprecate/skip_flags.py similarity index 100% rename from deptry/deprecate/skip_flags.py rename to python/deptry/deprecate/skip_flags.py diff --git a/deptry/exceptions.py b/python/deptry/exceptions.py similarity index 100% rename from deptry/exceptions.py rename to python/deptry/exceptions.py diff --git a/deptry/imports/__init__.py b/python/deptry/imports/__init__.py similarity index 100% rename from deptry/imports/__init__.py rename to python/deptry/imports/__init__.py diff --git a/deptry/imports/extract.py b/python/deptry/imports/extract.py similarity index 94% rename from deptry/imports/extract.py rename to python/deptry/imports/extract.py index b366c91c..36701dbd 100644 --- a/deptry/imports/extract.py +++ b/python/deptry/imports/extract.py @@ -4,13 +4,13 @@ from collections import defaultdict from typing import TYPE_CHECKING -from deptry import get_imports_from_py_files from deptry.imports.extractors import NotebookImportExtractor +from deptry.rust import get_imports_from_py_files if TYPE_CHECKING: from pathlib import Path - from deptry import Location as RustLocation + from deptry.rust import Location as RustLocation from deptry.imports.location import Location diff --git a/deptry/imports/extractors/__init__.py b/python/deptry/imports/extractors/__init__.py similarity index 100% rename from deptry/imports/extractors/__init__.py rename to python/deptry/imports/extractors/__init__.py diff --git a/deptry/imports/extractors/base.py b/python/deptry/imports/extractors/base.py similarity index 100% rename from deptry/imports/extractors/base.py rename to python/deptry/imports/extractors/base.py diff --git a/deptry/imports/extractors/notebook_import_extractor.py b/python/deptry/imports/extractors/notebook_import_extractor.py similarity index 100% rename from deptry/imports/extractors/notebook_import_extractor.py rename to python/deptry/imports/extractors/notebook_import_extractor.py diff --git a/deptry/imports/location.py b/python/deptry/imports/location.py similarity index 89% rename from deptry/imports/location.py rename to python/deptry/imports/location.py index e1017443..0218110c 100644 --- a/deptry/imports/location.py +++ b/python/deptry/imports/location.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from deptry import Location as RustLocation + from deptry.rust import Location as RustLocation @dataclass(frozen=True) diff --git a/deptry/module.py b/python/deptry/module.py similarity index 100% rename from deptry/module.py rename to python/deptry/module.py diff --git a/deptry/python_file_finder.py b/python/deptry/python_file_finder.py similarity index 100% rename from deptry/python_file_finder.py rename to python/deptry/python_file_finder.py diff --git a/deptry/reporters/__init__.py b/python/deptry/reporters/__init__.py similarity index 100% rename from deptry/reporters/__init__.py rename to python/deptry/reporters/__init__.py diff --git a/deptry/reporters/base.py b/python/deptry/reporters/base.py similarity index 100% rename from deptry/reporters/base.py rename to python/deptry/reporters/base.py diff --git a/deptry/reporters/json.py b/python/deptry/reporters/json.py similarity index 100% rename from deptry/reporters/json.py rename to python/deptry/reporters/json.py diff --git a/deptry/reporters/text.py b/python/deptry/reporters/text.py similarity index 100% rename from deptry/reporters/text.py rename to python/deptry/reporters/text.py diff --git a/deptry/deptry.pyi b/python/deptry/rust.pyi similarity index 87% rename from deptry/deptry.pyi rename to python/deptry/rust.pyi index 9b49a83b..f4344df9 100644 --- a/deptry/deptry.pyi +++ b/python/deptry/rust.pyi @@ -1,4 +1,4 @@ -from deptry import Location as RustLocation +from .rust import Location as RustLocation def get_imports_from_py_files(file_paths: list[str]) -> dict[str, list[RustLocation]]: ... def get_imports_from_py_file(file_path: str) -> dict[str, list[RustLocation]]: ... diff --git a/deptry/stdlibs.py b/python/deptry/stdlibs.py similarity index 100% rename from deptry/stdlibs.py rename to python/deptry/stdlibs.py diff --git a/deptry/utils.py b/python/deptry/utils.py similarity index 100% rename from deptry/utils.py rename to python/deptry/utils.py diff --git a/deptry/violations/__init__.py b/python/deptry/violations/__init__.py similarity index 100% rename from deptry/violations/__init__.py rename to python/deptry/violations/__init__.py diff --git a/deptry/violations/base.py b/python/deptry/violations/base.py similarity index 100% rename from deptry/violations/base.py rename to python/deptry/violations/base.py diff --git a/deptry/violations/dep001_missing/__init__.py b/python/deptry/violations/dep001_missing/__init__.py similarity index 100% rename from deptry/violations/dep001_missing/__init__.py rename to python/deptry/violations/dep001_missing/__init__.py diff --git a/deptry/violations/dep001_missing/finder.py b/python/deptry/violations/dep001_missing/finder.py similarity index 100% rename from deptry/violations/dep001_missing/finder.py rename to python/deptry/violations/dep001_missing/finder.py diff --git a/deptry/violations/dep001_missing/violation.py b/python/deptry/violations/dep001_missing/violation.py similarity index 100% rename from deptry/violations/dep001_missing/violation.py rename to python/deptry/violations/dep001_missing/violation.py diff --git a/deptry/violations/dep002_unused/__init__.py b/python/deptry/violations/dep002_unused/__init__.py similarity index 100% rename from deptry/violations/dep002_unused/__init__.py rename to python/deptry/violations/dep002_unused/__init__.py diff --git a/deptry/violations/dep002_unused/finder.py b/python/deptry/violations/dep002_unused/finder.py similarity index 100% rename from deptry/violations/dep002_unused/finder.py rename to python/deptry/violations/dep002_unused/finder.py diff --git a/deptry/violations/dep002_unused/violation.py b/python/deptry/violations/dep002_unused/violation.py similarity index 100% rename from deptry/violations/dep002_unused/violation.py rename to python/deptry/violations/dep002_unused/violation.py diff --git a/deptry/violations/dep003_transitive/__init__.py b/python/deptry/violations/dep003_transitive/__init__.py similarity index 100% rename from deptry/violations/dep003_transitive/__init__.py rename to python/deptry/violations/dep003_transitive/__init__.py diff --git a/deptry/violations/dep003_transitive/finder.py b/python/deptry/violations/dep003_transitive/finder.py similarity index 100% rename from deptry/violations/dep003_transitive/finder.py rename to python/deptry/violations/dep003_transitive/finder.py diff --git a/deptry/violations/dep003_transitive/violation.py b/python/deptry/violations/dep003_transitive/violation.py similarity index 100% rename from deptry/violations/dep003_transitive/violation.py rename to python/deptry/violations/dep003_transitive/violation.py diff --git a/deptry/violations/dep004_misplaced_dev/__init__.py b/python/deptry/violations/dep004_misplaced_dev/__init__.py similarity index 100% rename from deptry/violations/dep004_misplaced_dev/__init__.py rename to python/deptry/violations/dep004_misplaced_dev/__init__.py diff --git a/deptry/violations/dep004_misplaced_dev/finder.py b/python/deptry/violations/dep004_misplaced_dev/finder.py similarity index 100% rename from deptry/violations/dep004_misplaced_dev/finder.py rename to python/deptry/violations/dep004_misplaced_dev/finder.py diff --git a/deptry/violations/dep004_misplaced_dev/violation.py b/python/deptry/violations/dep004_misplaced_dev/violation.py similarity index 100% rename from deptry/violations/dep004_misplaced_dev/violation.py rename to python/deptry/violations/dep004_misplaced_dev/violation.py diff --git a/src/lib.rs b/src/lib.rs index f6f23b3c..96dd52c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ use rustpython_ast::Visitor; use visitor::ImportVisitor; #[pymodule] -fn deptry(py: Python, m: &PyModule) -> PyResult<()> { +fn rust(py: Python, m: &PyModule) -> PyResult<()> { pyo3_log::init(); // Initialize logging to forward to Python's logger m.add_function(wrap_pyfunction!(get_imports_from_py_files, m)?)?; From 90731327ec122b010db84faf2a50607ff18d93d4 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 11:09:32 +0100 Subject: [PATCH 63/77] fix some ruff in tests --- .pre-commit-config.yaml | 2 +- docs/contributing.md | 2 +- tests/functional/cli/test_cli.py | 2 +- tests/functional/cli/test_cli_arg_types.py | 1 - tests/unit/dependency_getter/test_pdm.py | 1 + tests/unit/dependency_getter/test_pep_621.py | 1 + tests/unit/dependency_getter/test_poetry.py | 1 + tests/unit/dependency_getter/test_requirements_txt.py | 2 +- tests/unit/deprecate/test_ignore_flags.py | 1 - tests/unit/imports/test_extract.py | 2 +- tests/unit/reporters/test_json.py | 1 + tests/unit/reporters/test_text.py | 2 +- tests/unit/test_config.py | 2 +- tests/unit/test_core.py | 2 +- tests/unit/test_dependency_specification_detector.py | 2 +- tests/unit/test_python_file_finder.py | 2 +- 16 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1f7b899f..e945cd6b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - id: ruff-format - repo: https://github.com/doublify/pre-commit-rust - rev: master + rev: v1.0 hooks: - id: fmt - id: cargo-check diff --git a/docs/contributing.md b/docs/contributing.md index f34b4626..db66fbd4 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -40,7 +40,7 @@ If you are proposing a new feature: ## Get started! -Ready to contribute? Here's how to set up _deptry_ for local development. Please note this documentation assumes you already have [Poetry](https://python-poetry.org/) and [Git](https://git-scm.com/) installed and ready to go. +Ready to contribute? Here's how to set up _deptry_ for local development. Please note this documentation assumes you already have [PDM](https://python-poetry.org/) and [Git](https://git-scm.com/) installed and ready to go. 1. [Fork](https://github.com/fpgmaas/deptry/fork) the _deptry_ repository on GitHub. diff --git a/tests/functional/cli/test_cli.py b/tests/functional/cli/test_cli.py index d3d581ec..6908c681 100644 --- a/tests/functional/cli/test_cli.py +++ b/tests/functional/cli/test_cli.py @@ -5,8 +5,8 @@ from typing import TYPE_CHECKING from click.testing import CliRunner - from deptry.cli import deptry + from tests.utils import get_issues_report, stylize if TYPE_CHECKING: diff --git a/tests/functional/cli/test_cli_arg_types.py b/tests/functional/cli/test_cli_arg_types.py index abc1b320..4b5f03e8 100644 --- a/tests/functional/cli/test_cli_arg_types.py +++ b/tests/functional/cli/test_cli_arg_types.py @@ -6,7 +6,6 @@ import click import pytest - from deptry.cli import CommaSeparatedMappingParamType, CommaSeparatedTupleParamType if TYPE_CHECKING: diff --git a/tests/unit/dependency_getter/test_pdm.py b/tests/unit/dependency_getter/test_pdm.py index f25eebd4..8030b399 100644 --- a/tests/unit/dependency_getter/test_pdm.py +++ b/tests/unit/dependency_getter/test_pdm.py @@ -3,6 +3,7 @@ from pathlib import Path from deptry.dependency_getter.pdm import PDMDependencyGetter + from tests.utils import run_within_dir diff --git a/tests/unit/dependency_getter/test_pep_621.py b/tests/unit/dependency_getter/test_pep_621.py index 55c77708..fa784951 100644 --- a/tests/unit/dependency_getter/test_pep_621.py +++ b/tests/unit/dependency_getter/test_pep_621.py @@ -3,6 +3,7 @@ from pathlib import Path from deptry.dependency_getter.pep_621 import PEP621DependencyGetter + from tests.utils import run_within_dir diff --git a/tests/unit/dependency_getter/test_poetry.py b/tests/unit/dependency_getter/test_poetry.py index c0cdad8f..d5241031 100644 --- a/tests/unit/dependency_getter/test_poetry.py +++ b/tests/unit/dependency_getter/test_poetry.py @@ -3,6 +3,7 @@ from pathlib import Path from deptry.dependency_getter.poetry import PoetryDependencyGetter + from tests.utils import run_within_dir diff --git a/tests/unit/dependency_getter/test_requirements_txt.py b/tests/unit/dependency_getter/test_requirements_txt.py index 563abdf9..02702b93 100644 --- a/tests/unit/dependency_getter/test_requirements_txt.py +++ b/tests/unit/dependency_getter/test_requirements_txt.py @@ -3,8 +3,8 @@ from pathlib import Path import pytest - from deptry.dependency_getter.requirements_txt import RequirementsTxtDependencyGetter + from tests.utils import run_within_dir diff --git a/tests/unit/deprecate/test_ignore_flags.py b/tests/unit/deprecate/test_ignore_flags.py index 312706d1..4d3fca6a 100644 --- a/tests/unit/deprecate/test_ignore_flags.py +++ b/tests/unit/deprecate/test_ignore_flags.py @@ -3,7 +3,6 @@ from typing import TYPE_CHECKING import pytest - from deptry.deprecate.ignore_flags import generate_deprecation_warning, get_value_for_per_rule_ignores_argument if TYPE_CHECKING: diff --git a/tests/unit/imports/test_extract.py b/tests/unit/imports/test_extract.py index 4991ad2f..2b24a63d 100644 --- a/tests/unit/imports/test_extract.py +++ b/tests/unit/imports/test_extract.py @@ -8,9 +8,9 @@ from typing import TYPE_CHECKING import pytest - from deptry.imports.extract import get_imported_modules_from_ipynb_file, get_imported_modules_from_list_of_files from deptry.imports.location import Location + from tests.utils import run_within_dir if TYPE_CHECKING: diff --git a/tests/unit/reporters/test_json.py b/tests/unit/reporters/test_json.py index ed2dab72..389eba52 100644 --- a/tests/unit/reporters/test_json.py +++ b/tests/unit/reporters/test_json.py @@ -13,6 +13,7 @@ DEP003TransitiveDependencyViolation, DEP004MisplacedDevDependencyViolation, ) + from tests.utils import run_within_dir diff --git a/tests/unit/reporters/test_text.py b/tests/unit/reporters/test_text.py index 8fbc578d..1908ea75 100644 --- a/tests/unit/reporters/test_text.py +++ b/tests/unit/reporters/test_text.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING import pytest - from deptry.dependency import Dependency from deptry.imports.location import Location from deptry.module import Module @@ -17,6 +16,7 @@ DEP003TransitiveDependencyViolation, DEP004MisplacedDevDependencyViolation, ) + from tests.utils import stylize if TYPE_CHECKING: diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 2e42387d..03a61d1e 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -7,9 +7,9 @@ import click import pytest from click import Argument - from deptry.config import read_configuration_from_pyproject_toml from deptry.exceptions import InvalidPyprojectTOMLOptionsError + from tests.utils import run_within_dir if TYPE_CHECKING: diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py index 4a91aa27..b7db407e 100644 --- a/tests/unit/test_core.py +++ b/tests/unit/test_core.py @@ -6,7 +6,6 @@ from unittest import mock import pytest - from deptry.core import Core from deptry.dependency import Dependency from deptry.exceptions import UnsupportedPythonVersionError @@ -19,6 +18,7 @@ DEP003TransitiveDependencyViolation, DEP004MisplacedDevDependencyViolation, ) + from tests.utils import create_files, run_within_dir diff --git a/tests/unit/test_dependency_specification_detector.py b/tests/unit/test_dependency_specification_detector.py index ae129c92..033238be 100644 --- a/tests/unit/test_dependency_specification_detector.py +++ b/tests/unit/test_dependency_specification_detector.py @@ -4,9 +4,9 @@ from pathlib import Path import pytest - from deptry.dependency_specification_detector import DependencyManagementFormat, DependencySpecificationDetector from deptry.exceptions import DependencySpecificationNotFoundError + from tests.utils import run_within_dir diff --git a/tests/unit/test_python_file_finder.py b/tests/unit/test_python_file_finder.py index bb8a0a5d..5409547e 100644 --- a/tests/unit/test_python_file_finder.py +++ b/tests/unit/test_python_file_finder.py @@ -3,10 +3,10 @@ from pathlib import Path import pytest +from deptry.python_file_finder import PythonFileFinder from pathspec import PathSpec from pathspec.patterns.gitwildmatch import GitWildMatchPattern -from deptry.python_file_finder import PythonFileFinder from tests.utils import create_files, run_within_dir From f0cc9e04abfbd831520e8db208f29f70d384d139 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 14:41:08 +0100 Subject: [PATCH 64/77] remove warning --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 96dd52c5..c75b9faf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ use rustpython_ast::Visitor; use visitor::ImportVisitor; #[pymodule] -fn rust(py: Python, m: &PyModule) -> PyResult<()> { +fn rust(_py: Python, m: &PyModule) -> PyResult<()> { pyo3_log::init(); // Initialize logging to forward to Python's logger m.add_function(wrap_pyfunction!(get_imports_from_py_files, m)?)?; From d208b3d6d2e44d1db19118e543f158786f3f04a0 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 16:36:59 +0100 Subject: [PATCH 65/77] improve release pipeline --- .github/workflows/release.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b5e1d07..76400c4d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -154,8 +154,8 @@ jobs: name: wheels-sdist path: dist - release: - name: Release + publish: + name: Publish runs-on: ubuntu-latest needs: [linux, windows, macos, sdist] steps: @@ -168,18 +168,18 @@ jobs: command: upload args: --non-interactive --skip-existing wheels-*/* + check-docs: + runs-on: ubuntu-latest + needs: publish + steps: + - name: Check out + uses: actions/checkout@v4 + + - name: Set up the environment + uses: ./.github/actions/setup-env + with: + python-version: '3.11' + target: 'x86_64' -# release: -# name: Release -# runs-on: ubuntu-latest -# needs: [linux, windows, macos, sdist] -# steps: -# - uses: actions/download-artifact@v4 -# - name: Publish to Test PyPI -# uses: PyO3/maturin-action@v1 -# env: -# MATURIN_PYPI_TOKEN: ${{ secrets.TEST_PYPI_TOKEN }} -# MATURIN_REPOSITORY_URL: https://test.pypi.org/legacy/ -# with: -# command: upload -# args: --non-interactive --skip-existing wheels-*/* + - name: Deploy documentation + run: poetry run mkdocs gh-deploy --force From 4520f0ccccbc982a964b5fd2cf357c82f27f7602 Mon Sep 17 00:00:00 2001 From: Florian Maas Date: Tue, 12 Mar 2024 17:06:30 +0100 Subject: [PATCH 66/77] split import detection into its own module --- Makefile | 16 +-- src/imports.rs | 152 +++++++++++++++++++++++++++++ src/lib.rs | 151 +--------------------------- tests/unit/imports/test_extract.py | 4 +- 4 files changed, 159 insertions(+), 164 deletions(-) create mode 100644 src/imports.rs diff --git a/Makefile b/Makefile index 09bf7942..86a6b9a4 100644 --- a/Makefile +++ b/Makefile @@ -22,21 +22,7 @@ test: ## Test the code with pytest. .PHONY: build build: clean-build ## Build wheel and sdist files using PDM. @echo "🚀 Creating wheel and sdist files" - @pdm build - -.PHONY: clean-build -clean-build: ## clean build artifacts - @rm -rf dist - -.PHONY: publish -publish: ## Publish a release to PyPI. - @echo "🚀 Publishing: Dry run." - @PDM_PYPI_TOKEN=$(PYPI_TOKEN) pdm publish --dry-run - @echo "🚀 Publishing." - @PDM_PYPI_TOKEN=$(PYPI_TOKEN) pdm publish - -.PHONY: build-and-publish -build-and-publish: build publish ## Build and publish. + @maturin build .PHONY: docs-test docs-test: ## Test if documentation can be built without warnings or errors. diff --git a/src/imports.rs b/src/imports.rs new file mode 100644 index 00000000..c5d1dd3d --- /dev/null +++ b/src/imports.rs @@ -0,0 +1,152 @@ +use crate::file_utils; +use crate::location; +use crate::visitor; + +use file_utils::read_file; +use location::Location; +use pyo3::exceptions::PySyntaxError; +use pyo3::prelude::*; +use pyo3::types::{PyDict, PyList, PyString}; +use rayon::prelude::*; +use rustpython_ast::Mod; +use rustpython_ast::Visitor; +use rustpython_parser::source_code::LineIndex; +use rustpython_parser::text_size::TextRange; +use rustpython_parser::{parse, Mode}; +use std::collections::HashMap; +use visitor::ImportVisitor; + +/// Processes multiple Python files in parallel to extract import statements and their locations. +/// Accepts a list of file paths and returns a dictionary mapping module names to their import locations. +#[pyfunction] +pub fn get_imports_from_py_files(py: Python, file_paths: Vec<&PyString>) -> PyResult { + let rust_file_paths: Vec = file_paths + .iter() + .map(|py_str| py_str.to_str().unwrap().to_owned()) + .collect(); + + // Process each file in parallel and collect results + let results: PyResult> = rust_file_paths + .par_iter() + .map(|path_str| _get_imports_from_py_file(path_str)) + .collect(); + + let results = results?; + + // Merge results from each thread + let mut all_imports = HashMap::new(); + for file_result in results { + for (module, locations) in file_result { + all_imports + .entry(module) + .or_insert_with(Vec::new) + .extend(locations); + } + } + + convert_to_python_dict(py, all_imports) +} + +/// Processes a single Python file to extract import statements and their locations. +/// Accepts a single file path and returns a dictionary mapping module names to their import locations. +#[pyfunction] +pub fn get_imports_from_py_file(py: Python, file_path: &PyString) -> PyResult { + let path_str = file_path.to_str()?; + let result = _get_imports_from_py_file(path_str)?; + + convert_to_python_dict(py, result) +} + +/// Core helper function that extracts import statements and their locations from the content of a single Python file. +/// Used internally by both parallel and single file processing functions. +fn _get_imports_from_py_file(path_str: &str) -> PyResult>> { + let file_content = match read_file(path_str) { + Ok(content) => content, + Err(_) => { + log::warn!("Warning: File {} could not be read. Skipping...", path_str); + return Ok(HashMap::new()); + } + }; + + let ast = get_ast_from_file_content(&file_content, path_str) + .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", path_str, e)))?; + + let imported_modules = extract_imports_from_ast(ast); + Ok(convert_imports_with_textranges_to_location_objects( + imported_modules, + path_str, + &file_content, + )) +} + +/// Parses the content of a Python file into an abstract syntax tree (AST). +pub fn get_ast_from_file_content(file_content: &str, file_path: &str) -> PyResult { + parse(&file_content, Mode::Module, file_path) + .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e))) +} + +/// Iterates through an AST to identify and collect import statements, and returns them together with their +/// a TextRange for each occurence. +fn extract_imports_from_ast(ast: Mod) -> HashMap> { + let mut visitor = ImportVisitor::new(); + + match ast { + Mod::Module(module) => { + for stmt in module.body { + visitor.visit_stmt(stmt); + } + } + _ => {} + } + visitor.get_imports() +} + +/// Converts textual ranges of import statements into structured location objects. +/// Facilitates the mapping of imports to detailed, file-specific location data (file, line, column). +fn convert_imports_with_textranges_to_location_objects( + imports: HashMap>, + file_path: &str, + source_code: &str, +) -> HashMap> { + let line_index = LineIndex::from_source_text(source_code); + let mut imports_with_locations = HashMap::>::new(); + + for (module, ranges) in imports { + let locations: Vec = ranges + .iter() + .map(|range| { + let start_line = line_index.line_index(range.start()).get() as usize; + let start_col = line_index + .source_location(range.start(), source_code) + .column + .get() as usize; + Location { + file: file_path.to_string(), + line: Some(start_line), + column: Some(start_col), + } + }) + .collect(); + imports_with_locations.insert(module, locations); + } + imports_with_locations +} + +/// Transforms a Rust HashMap containing import data into a Python dictionary suitable for Python-side consumption. +fn convert_to_python_dict( + py: Python<'_>, + imports_with_locations: HashMap>, +) -> PyResult { + let imports_dict = PyDict::new(py); + + for (module, locations) in imports_with_locations { + let py_locations: Vec = locations + .into_iter() + .map(|location| location.into_py(py)) + .collect(); + let locations_list = PyList::new(py, &py_locations); + imports_dict.set_item(module, locations_list)?; + } + + Ok(imports_dict.into()) +} diff --git a/src/lib.rs b/src/lib.rs index c75b9faf..defb4cb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,165 +1,20 @@ // lib.rs -use pyo3::exceptions::PySyntaxError; use pyo3::prelude::*; -use pyo3::types::{PyDict, PyList, PyString}; -use rustpython_ast::Mod; -use rustpython_parser::source_code::LineIndex; -use rustpython_parser::text_size::TextRange; -use rustpython_parser::{parse, Mode}; -use std::collections::HashMap; mod file_utils; +mod imports; mod location; mod visitor; -use file_utils::read_file; use location::Location; -use rayon::prelude::*; -use rustpython_ast::Visitor; -use visitor::ImportVisitor; #[pymodule] fn rust(_py: Python, m: &PyModule) -> PyResult<()> { pyo3_log::init(); // Initialize logging to forward to Python's logger - m.add_function(wrap_pyfunction!(get_imports_from_py_files, m)?)?; - m.add_function(wrap_pyfunction!(get_imports_from_py_file, m)?)?; + m.add_function(wrap_pyfunction!(imports::get_imports_from_py_files, m)?)?; + m.add_function(wrap_pyfunction!(imports::get_imports_from_py_file, m)?)?; m.add_class::()?; Ok(()) } - -/// Processes multiple Python files in parallel to extract import statements and their locations. -/// Accepts a list of file paths and returns a dictionary mapping module names to their import locations. -#[pyfunction] -fn get_imports_from_py_files(py: Python, file_paths: Vec<&PyString>) -> PyResult { - let rust_file_paths: Vec = file_paths - .iter() - .map(|py_str| py_str.to_str().unwrap().to_owned()) - .collect(); - - // Process each file in parallel and collect results - let results: PyResult> = rust_file_paths - .par_iter() - .map(|path_str| _get_imports_from_py_file(path_str)) - .collect(); - - let results = results?; - - // Merge results from each thread - let mut all_imports = HashMap::new(); - for file_result in results { - for (module, locations) in file_result { - all_imports - .entry(module) - .or_insert_with(Vec::new) - .extend(locations); - } - } - - convert_to_python_dict(py, all_imports) -} - -/// Processes a single Python file to extract import statements and their locations. -/// Accepts a single file path and returns a dictionary mapping module names to their import locations. -#[pyfunction] -fn get_imports_from_py_file(py: Python, file_path: &PyString) -> PyResult { - let path_str = file_path.to_str()?; - let result = _get_imports_from_py_file(path_str)?; - - convert_to_python_dict(py, result) -} - -/// Core helper function that extracts import statements and their locations from the content of a single Python file. -/// Used internally by both parallel and single file processing functions. -fn _get_imports_from_py_file(path_str: &str) -> PyResult>> { - let file_content = match read_file(path_str) { - Ok(content) => content, - Err(_) => { - log::warn!("Warning: File {} could not be read. Skipping...", path_str); - return Ok(HashMap::new()); - } - }; - - let ast = get_ast_from_file_content(&file_content, path_str) - .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", path_str, e)))?; - - let imported_modules = extract_imports_from_ast(ast); - Ok(convert_imports_with_textranges_to_location_objects( - imported_modules, - path_str, - &file_content, - )) -} - -/// Parses the content of a Python file into an abstract syntax tree (AST). -pub fn get_ast_from_file_content(file_content: &str, file_path: &str) -> PyResult { - parse(&file_content, Mode::Module, file_path) - .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e))) -} - -/// Iterates through an AST to identify and collect import statements, and returns them together with their -/// a TextRange for each occurence. -fn extract_imports_from_ast(ast: Mod) -> HashMap> { - let mut visitor = ImportVisitor::new(); - - match ast { - Mod::Module(module) => { - for stmt in module.body { - visitor.visit_stmt(stmt); - } - } - _ => {} - } - visitor.get_imports() -} - -/// Converts textual ranges of import statements into structured location objects. -/// Facilitates the mapping of imports to detailed, file-specific location data (file, line, column). -fn convert_imports_with_textranges_to_location_objects( - imports: HashMap>, - file_path: &str, - source_code: &str, -) -> HashMap> { - let line_index = LineIndex::from_source_text(source_code); - let mut imports_with_locations = HashMap::>::new(); - - for (module, ranges) in imports { - let locations: Vec = ranges - .iter() - .map(|range| { - let start_line = line_index.line_index(range.start()).get() as usize; - let start_col = line_index - .source_location(range.start(), source_code) - .column - .get() as usize; - Location { - file: file_path.to_string(), - line: Some(start_line), - column: Some(start_col), - } - }) - .collect(); - imports_with_locations.insert(module, locations); - } - imports_with_locations -} - -/// Transforms a Rust HashMap containing import data into a Python dictionary suitable for Python-side consumption. -fn convert_to_python_dict( - py: Python<'_>, - imports_with_locations: HashMap>, -) -> PyResult { - let imports_dict = PyDict::new(py); - - for (module, locations) in imports_with_locations { - let py_locations: Vec = locations - .into_iter() - .map(|location| location.into_py(py)) - .collect(); - let locations_list = PyList::new(py, &py_locations); - imports_dict.set_item(module, locations_list)?; - } - - Ok(imports_dict.into()) -} diff --git a/tests/unit/imports/test_extract.py b/tests/unit/imports/test_extract.py index 2b24a63d..e0ada3e1 100644 --- a/tests/unit/imports/test_extract.py +++ b/tests/unit/imports/test_extract.py @@ -134,5 +134,7 @@ def test_import_parser_file_encodings_warning(tmp_path: Path, caplog: LogCapture assert get_imported_modules_from_list_of_files([file_path]) == {} # //TODO logging from Rust still includes it's own warning and file + line number. Can we get rid of that? - pattern = re.compile(r"WARNING deptry:lib.rs:\d+ Warning: File file1.py could not be read. Skipping...\n") + pattern = re.compile( + r"WARNING deptry.imports:imports.rs:\d+ Warning: File file1.py could not be read. Skipping...\n" + ) assert pattern.search(caplog.text) is not None From d77c4c01860928815e9e22fc5e4c5505e639e9c3 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 21:38:51 +0100 Subject: [PATCH 67/77] chore: misc tweaks --- pdm.lock | 95 +++++++++++++++++++------------------------------- pyproject.toml | 28 +++++++-------- 2 files changed, 49 insertions(+), 74 deletions(-) diff --git a/pdm.lock b/pdm.lock index a3261d69..bdaf258c 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev", "docs", "typing"] strategy = ["cross_platform", "inherit_metadata"] lock_version = "4.4.1" -content_hash = "sha256:5f1735071095c166db7483350395fa16219910cfb61ad973163ee21df5bb1648" +content_hash = "sha256:0d224338d6c21c2dc206b6950ff3c9d62c2f8f691cb75189a7fd14e2362a9a85" [[package]] name = "babel" @@ -474,31 +474,6 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] -[[package]] -name = "maturin" -version = "1.5.0" -requires_python = ">=3.7" -summary = "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages" -groups = ["dev"] -dependencies = [ - "tomli>=1.1.0; python_version < \"3.11\"", -] -files = [ - {file = "maturin-1.5.0-py3-none-linux_armv6l.whl", hash = "sha256:0b976116b7cfaafbc8c3f0acfaec6702520c49e86e48ea80e2c282b7f8118c1a"}, - {file = "maturin-1.5.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d277adf9b27143627ba7be7ea254513d3e85008fb16a94638b56884a41b4e5a2"}, - {file = "maturin-1.5.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d6a314472e07b6bdfa4cdf97d24cda1defe008d36d4b75de2efd3383e7a2d7bf"}, - {file = "maturin-1.5.0-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:a5c038ded82c7595d99e94a208aa8af2b5c94eef4c8fcf5ef6e841957e506201"}, - {file = "maturin-1.5.0-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:faa0d099a8045afc9977284cb3a1c26e5ebc9a7f0fe4d53b7ee17f62fd279f4a"}, - {file = "maturin-1.5.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:9cba3737cb92ce5c1bd82cbb9b1fde412b2aac8882ac38b8340980f5eb858d8c"}, - {file = "maturin-1.5.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:1b29bf8771f27d2e6b2685c82de952b5732ee79e5c0030ffd5dab5ccb99137a1"}, - {file = "maturin-1.5.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:f271f315fb78d2ff5fdf60f8d3ada2a04a66ac6fbd3cbb318c4eb4e9766449bc"}, - {file = "maturin-1.5.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76e3270ff87b5484976d23e3d88475cd64acf41b54f561263f253d8fca0baab3"}, - {file = "maturin-1.5.0-py3-none-win32.whl", hash = "sha256:eb35dfe5994ad2c34d2874a73720847ecc2adb28f934e9a7cbcdb8826b240e60"}, - {file = "maturin-1.5.0-py3-none-win_amd64.whl", hash = "sha256:b3a499ff5960e46115488e68011809ce99857864ce3a91cf5d0fff3adbd89e8c"}, - {file = "maturin-1.5.0-py3-none-win_arm64.whl", hash = "sha256:2e4c01370a5c10b6c4887bee66d3582bdb38c3805168c1393f072bd266da08d4"}, - {file = "maturin-1.5.0.tar.gz", hash = "sha256:e046ea2aed687991d58c42f6276dfcc0c037092934654f538b5877fd57dd3a9c"}, -] - [[package]] name = "mergedeep" version = "1.3.4" @@ -539,7 +514,7 @@ files = [ [[package]] name = "mkdocs-material" -version = "9.5.10" +version = "9.5.13" requires_python = ">=3.8" summary = "Documentation that simply works" groups = ["docs"] @@ -557,8 +532,8 @@ dependencies = [ "requests~=2.26", ] files = [ - {file = "mkdocs_material-9.5.10-py3-none-any.whl", hash = "sha256:3c6c46b57d2ee3c8890e6e0406e68b6863cf65768f0f436990a742702d198442"}, - {file = "mkdocs_material-9.5.10.tar.gz", hash = "sha256:6ad626dbb31070ebbaedff813323a16a406629620e04b96458f16e6e9c7008fe"}, + {file = "mkdocs_material-9.5.13-py3-none-any.whl", hash = "sha256:5cbe17fee4e3b4980c8420a04cc762d8dc052ef1e10532abd4fce88e5ea9ce6a"}, + {file = "mkdocs_material-9.5.13.tar.gz", hash = "sha256:d8e4caae576312a88fd2609b81cf43d233cdbe36860d67a68702b018b425bd87"}, ] [[package]] @@ -574,7 +549,7 @@ files = [ [[package]] name = "mypy" -version = "1.8.0" +version = "1.9.0" requires_python = ">=3.8" summary = "Optional static typing for Python" groups = ["typing"] @@ -584,33 +559,33 @@ dependencies = [ "typing-extensions>=4.1.0", ] files = [ - {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, - {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, - {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, - {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, - {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, - {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, - {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, - {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, - {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, - {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, - {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, - {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, - {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, - {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, - {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, - {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, - {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, - {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, - {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"}, + {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"}, + {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"}, + {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"}, + {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"}, + {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"}, + {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"}, + {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"}, + {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"}, + {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"}, + {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"}, + {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"}, + {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"}, + {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"}, + {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"}, + {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"}, + {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"}, + {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"}, ] [[package]] @@ -737,7 +712,7 @@ files = [ [[package]] name = "pytest" -version = "8.0.1" +version = "8.0.2" requires_python = ">=3.8" summary = "pytest: simple powerful testing with Python" groups = ["dev"] @@ -750,8 +725,8 @@ dependencies = [ "tomli>=1.0.0; python_version < \"3.11\"", ] files = [ - {file = "pytest-8.0.1-py3-none-any.whl", hash = "sha256:3e4f16fe1c0a9dc9d9389161c127c3edc5d810c38d6793042fb81d9f48a59fca"}, - {file = "pytest-8.0.1.tar.gz", hash = "sha256:267f6563751877d772019b13aacbe4e860d73fe8f651f28112e9ac37de7513ae"}, + {file = "pytest-8.0.2-py3-none-any.whl", hash = "sha256:edfaaef32ce5172d5466b5127b42e0d6d35ebbe4453f0e3505d96afd93f6b096"}, + {file = "pytest-8.0.2.tar.gz", hash = "sha256:d4051d623a2e0b7e51960ba963193b09ce6daeb9759a451844a21e4ddedfc1bd"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index bc6115de..5cb5ead3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,10 +2,10 @@ name = "deptry" version = "0.0.1" description = "A command line utility to check for unused, missing and transitive dependencies in a Python project." -authors = [ {name = "Florian Maas", email = "fpgmaas@gmail.com"} ] -maintainers = [ {name = "Mathieu Kniewallner", email = "mathieu.kniewallner@gmail.com"} ] +authors = [{ name = "Florian Maas", email = "fpgmaas@gmail.com" }] +maintainers = [{ name = "Mathieu Kniewallner", email = "mathieu.kniewallner@gmail.com" }] requires-python = ">=3.8,<4.0" -license = {file = "LICENSE"} +license = { file = "LICENSE" } classifiers = [ "Development Status :: 3 - Alpha", "Environment :: Console", @@ -27,25 +27,25 @@ dependencies = [ [tool.pdm.dev-dependencies] dev = [ - "pre-commit == 3.5.0", - "pytest == 8.0.1", - "pytest-cov == 4.1.0", - "maturin == 1.5.0", -] -typing = [ - "mypy == 1.8.0", - "types-chardet == 5.0.4.6", - "types-colorama == 0.4.15.20240205; sys_platform == 'win32'", + "pre-commit==3.5.0", + "pytest==8.0.2", + "pytest-cov==4.1.0", ] docs = [ - "mkdocs == 1.5.3", - "mkdocs-material == 9.5.10", + "mkdocs==1.5.3", + "mkdocs-material==9.5.13", +] +typing = [ + "mypy==1.9.0", + "types-chardet==5.0.4.6", + "types-colorama==0.4.15.20240205; sys_platform == 'win32'", ] [project.urls] homepage = "https://fpgmaas.github.io/deptry" repository = "https://github.com/fpgmaas/deptry" documentation = "https://fpgmaas.github.io/deptry" +changelog = "https://github.com/fpgmaas/deptry/blob/main/CHANGELOG.md" [project.scripts] deptry = "deptry.cli:deptry" From 06b2adbea0224ebe085afc44b4484ba07901631a Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 21:40:49 +0100 Subject: [PATCH 68/77] chore(pre-commit): run `fmt`/`clippy` locally --- .pre-commit-config.yaml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e945cd6b..f3e1138c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,8 +16,21 @@ repos: args: [--exit-non-zero-on-fix] - id: ruff-format - - repo: https://github.com/doublify/pre-commit-rust - rev: v1.0 + - repo: local hooks: - - id: fmt - - id: cargo-check + - id: cargo-fmt + name: cargo fmt + entry: cargo fmt -- + language: system + types: [rust] + pass_filenames: false + + - repo: local + hooks: + - id: cargo-clippy + name: cargo clippy + entry: cargo clippy + args: ["--all-targets", "--all-features", "--", "-D", "warnings"] + language: system + types: [rust] + pass_filenames: false From 9bfb7c7d59138947860f2bbb4e0dbdebd3d1c1ef Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 23:05:47 +0100 Subject: [PATCH 69/77] refactor: misc Rust tweaks --- Cargo.lock | 10 ---------- Cargo.toml | 3 +-- src/file_utils.rs | 31 ++++++++++++++++++------------- src/imports.rs | 15 +++++++-------- src/visitor.rs | 20 +++++++++----------- 5 files changed, 35 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e7f2bbe..3cd13ea0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,7 +132,6 @@ version = "0.1.0" dependencies = [ "chardetng", "encoding_rs", - "encoding_rs_io", "log", "pyo3", "pyo3-log", @@ -191,15 +190,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "encoding_rs_io" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83" -dependencies = [ - "encoding_rs", -] - [[package]] name = "generic-array" version = "0.14.7" diff --git a/Cargo.toml b/Cargo.toml index 381201d8..07afc45f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,8 @@ crate-type = ["cdylib"] [dependencies] chardetng = "0.1.17" encoding_rs = "0.8.33" -encoding_rs_io = "0.1.7" log = "0.4.21" -pyo3 = { version = "0.20.0", features = ["abi3-py38"] } +pyo3 = { version = "0.20.3", features = ["abi3-py38"] } pyo3-log = "0.9.0" rayon = "1.9.0" regex = "1.10.3" diff --git a/src/file_utils.rs b/src/file_utils.rs index b4cc8a00..eb96bf53 100644 --- a/src/file_utils.rs +++ b/src/file_utils.rs @@ -5,8 +5,9 @@ use encoding_rs::Encoding; use pyo3::exceptions::{PyFileNotFoundError, PyIOError}; use pyo3::prelude::*; use regex::Regex; +use std::fs; use std::fs::File; -use std::io::{self, BufReader, Read}; +use std::io::{BufReader, ErrorKind, Read}; use std::path::Path; /// Reads a Python file's content as a `String`. It first attempts to read the file as UTF-8. @@ -15,20 +16,24 @@ use std::path::Path; pub fn read_file(file_path: &str) -> PyResult { let path = Path::new(file_path); - match std::fs::read_to_string(&path) { + match fs::read_to_string(path) { Ok(content) => Ok(content), - Err(e) if e.kind() == io::ErrorKind::InvalidData => { - let file = File::open(&path).map_err(|_| { - PyFileNotFoundError::new_err(format!("File not found: '{}'", file_path)) - })?; - let mut buffer = Vec::new(); - BufReader::new(file).read_to_end(&mut buffer)?; + Err(e) => match e.kind() { + ErrorKind::NotFound => Err(PyFileNotFoundError::new_err(format!( + "File not found: '{}'", + file_path + ))), + ErrorKind::InvalidData => { + let file = File::open(path).unwrap(); + let mut buffer = Vec::new(); + BufReader::new(file).read_to_end(&mut buffer)?; - let encoding = detect_python_file_encoding_from_regex(&buffer) - .unwrap_or_else(|| guess_encoding(&buffer)); - read_with_encoding(&buffer, encoding) - } - Err(e) => Err(PyIOError::new_err(format!("An error occurred: '{}'", e))), + let encoding = detect_python_file_encoding_from_regex(&buffer) + .unwrap_or_else(|| guess_encoding(&buffer)); + read_with_encoding(&buffer, encoding) + } + _ => Err(PyIOError::new_err(format!("An error occurred: '{}'", e))), + }, } } diff --git a/src/imports.rs b/src/imports.rs index c5d1dd3d..25db77c7 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -72,6 +72,7 @@ fn _get_imports_from_py_file(path_str: &str) -> PyResult PyResult PyResult { - parse(&file_content, Mode::Module, file_path) + parse(file_content, Mode::Module, file_path) .map_err(|e| PySyntaxError::new_err(format!("Error parsing file {}: {}", file_path, e))) } /// Iterates through an AST to identify and collect import statements, and returns them together with their -/// a TextRange for each occurence. +/// respective TextRange for each occurrence. fn extract_imports_from_ast(ast: Mod) -> HashMap> { let mut visitor = ImportVisitor::new(); - match ast { - Mod::Module(module) => { - for stmt in module.body { - visitor.visit_stmt(stmt); - } + if let Mod::Module(module) = ast { + for stmt in module.body { + visitor.visit_stmt(stmt); } - _ => {} } + visitor.get_imports() } diff --git a/src/visitor.rs b/src/visitor.rs index 9730540c..b478acdc 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -22,7 +22,7 @@ impl ImportVisitor { impl Visitor for ImportVisitor { fn visit_stmt_import(&mut self, node: StmtImport) { for alias in &node.names { - let top_level_module = get_top_level_module_name(&alias.name.to_string()); + let top_level_module = get_top_level_module_name(&alias.name); self.imports .entry(top_level_module) .or_default() @@ -31,17 +31,15 @@ impl Visitor for ImportVisitor { } fn visit_stmt_import_from(&mut self, node: StmtImportFrom) { - if let Some(module) = &node.module { - let module_name = module.to_string(); - let top_level_module = get_top_level_module_name(&module_name); - let module_range = node.range; - if node.level == Some(Int::new(0)) { - self.imports - .entry(top_level_module) - .or_default() - .push(module_range); - } + let Some(module) = &node.module else { return }; + if node.level != Some(Int::new(0)) { + return; } + + self.imports + .entry(get_top_level_module_name(module.as_str())) + .or_default() + .push(node.range); } } From 18961d7950da99365f36042bf06d08b45e636d7b Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 23:08:22 +0100 Subject: [PATCH 70/77] refactor: remove some Poetry references --- .gitignore | 25 ------------------------- docs/contributing.md | 4 ++-- poetry.toml | 2 -- 3 files changed, 2 insertions(+), 29 deletions(-) delete mode 100644 poetry.toml diff --git a/.gitignore b/.gitignore index bd6469a6..9345bd42 100644 --- a/.gitignore +++ b/.gitignore @@ -92,31 +92,6 @@ target/ profile_default/ ipython_config.py -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide .pdm.toml # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm diff --git a/docs/contributing.md b/docs/contributing.md index db66fbd4..ccaee6fc 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -40,7 +40,7 @@ If you are proposing a new feature: ## Get started! -Ready to contribute? Here's how to set up _deptry_ for local development. Please note this documentation assumes you already have [PDM](https://python-poetry.org/) and [Git](https://git-scm.com/) installed and ready to go. +Ready to contribute? Here's how to set up _deptry_ for local development. Please note this documentation assumes you already have [PDM](https://pdm-project.org/latest/) and [Git](https://git-scm.com/) installed and ready to go. 1. [Fork](https://github.com/fpgmaas/deptry/fork) the _deptry_ repository on GitHub. @@ -62,7 +62,7 @@ Ready to contribute? Here's how to set up _deptry_ for local development. Please Then, install the virtual environment with: ```bash - poetry install + pdm install ``` 4. Install [pre-commit](https://pre-commit.com/) to run linters/formatters at commit time: diff --git a/poetry.toml b/poetry.toml deleted file mode 100644 index ab1033bd..00000000 --- a/poetry.toml +++ /dev/null @@ -1,2 +0,0 @@ -[virtualenvs] -in-project = true From 437c34220f3235ebc08e1f9b1755a7f7886b7998 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 23:14:33 +0100 Subject: [PATCH 71/77] ci: no need to build for 32-bits --- .github/workflows/main.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0b8dd49c..95127c65 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,7 +35,7 @@ jobs: strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - target: [x86_64, x86, aarch64] + target: [x86_64, aarch64] steps: - name: Check out uses: actions/checkout@v4 @@ -62,7 +62,7 @@ jobs: strategy: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] - target: [x64, x86] + target: [x64] steps: - name: Check out uses: actions/checkout@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 76400c4d..af829069 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: needs: [set-version] strategy: matrix: - target: [x86_64, x86, aarch64] + target: [x86_64, aarch64] steps: - name: Check out uses: actions/checkout@v4 @@ -67,7 +67,7 @@ jobs: needs: [set-version] strategy: matrix: - target: [x64, x86] + target: [x64] steps: - name: Check out uses: actions/checkout@v4 From a1b72a9ea4dc92c900df5374a54c502b3b824854 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 23:23:48 +0100 Subject: [PATCH 72/77] chore(ruff): add `deptry` as `known-first-party` --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 5cb5ead3..7b19ee6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -184,6 +184,7 @@ ignore = [ strict = true [tool.ruff.lint.isort] +known-first-party = ["deptry"] required-imports = ["from __future__ import annotations"] [tool.ruff.lint.per-file-ignores] From 21ff9a688705dbcc6136a66f1425ed8d6ef50e45 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 21:41:07 +0100 Subject: [PATCH 73/77] test: fix isort spacing --- tests/functional/cli/test_cli.py | 2 +- tests/functional/cli/test_cli_arg_types.py | 1 + tests/unit/dependency_getter/test_pdm.py | 1 - tests/unit/dependency_getter/test_pep_621.py | 1 - tests/unit/dependency_getter/test_poetry.py | 1 - tests/unit/dependency_getter/test_requirements_txt.py | 2 +- tests/unit/deprecate/test_ignore_flags.py | 1 + tests/unit/imports/test_extract.py | 2 +- tests/unit/reporters/test_json.py | 1 - tests/unit/reporters/test_text.py | 2 +- tests/unit/test_config.py | 2 +- tests/unit/test_core.py | 2 +- tests/unit/test_dependency_specification_detector.py | 2 +- tests/unit/test_python_file_finder.py | 2 +- 14 files changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/functional/cli/test_cli.py b/tests/functional/cli/test_cli.py index 6908c681..d3d581ec 100644 --- a/tests/functional/cli/test_cli.py +++ b/tests/functional/cli/test_cli.py @@ -5,8 +5,8 @@ from typing import TYPE_CHECKING from click.testing import CliRunner -from deptry.cli import deptry +from deptry.cli import deptry from tests.utils import get_issues_report, stylize if TYPE_CHECKING: diff --git a/tests/functional/cli/test_cli_arg_types.py b/tests/functional/cli/test_cli_arg_types.py index 4b5f03e8..abc1b320 100644 --- a/tests/functional/cli/test_cli_arg_types.py +++ b/tests/functional/cli/test_cli_arg_types.py @@ -6,6 +6,7 @@ import click import pytest + from deptry.cli import CommaSeparatedMappingParamType, CommaSeparatedTupleParamType if TYPE_CHECKING: diff --git a/tests/unit/dependency_getter/test_pdm.py b/tests/unit/dependency_getter/test_pdm.py index 8030b399..f25eebd4 100644 --- a/tests/unit/dependency_getter/test_pdm.py +++ b/tests/unit/dependency_getter/test_pdm.py @@ -3,7 +3,6 @@ from pathlib import Path from deptry.dependency_getter.pdm import PDMDependencyGetter - from tests.utils import run_within_dir diff --git a/tests/unit/dependency_getter/test_pep_621.py b/tests/unit/dependency_getter/test_pep_621.py index fa784951..55c77708 100644 --- a/tests/unit/dependency_getter/test_pep_621.py +++ b/tests/unit/dependency_getter/test_pep_621.py @@ -3,7 +3,6 @@ from pathlib import Path from deptry.dependency_getter.pep_621 import PEP621DependencyGetter - from tests.utils import run_within_dir diff --git a/tests/unit/dependency_getter/test_poetry.py b/tests/unit/dependency_getter/test_poetry.py index d5241031..c0cdad8f 100644 --- a/tests/unit/dependency_getter/test_poetry.py +++ b/tests/unit/dependency_getter/test_poetry.py @@ -3,7 +3,6 @@ from pathlib import Path from deptry.dependency_getter.poetry import PoetryDependencyGetter - from tests.utils import run_within_dir diff --git a/tests/unit/dependency_getter/test_requirements_txt.py b/tests/unit/dependency_getter/test_requirements_txt.py index 02702b93..563abdf9 100644 --- a/tests/unit/dependency_getter/test_requirements_txt.py +++ b/tests/unit/dependency_getter/test_requirements_txt.py @@ -3,8 +3,8 @@ from pathlib import Path import pytest -from deptry.dependency_getter.requirements_txt import RequirementsTxtDependencyGetter +from deptry.dependency_getter.requirements_txt import RequirementsTxtDependencyGetter from tests.utils import run_within_dir diff --git a/tests/unit/deprecate/test_ignore_flags.py b/tests/unit/deprecate/test_ignore_flags.py index 4d3fca6a..312706d1 100644 --- a/tests/unit/deprecate/test_ignore_flags.py +++ b/tests/unit/deprecate/test_ignore_flags.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING import pytest + from deptry.deprecate.ignore_flags import generate_deprecation_warning, get_value_for_per_rule_ignores_argument if TYPE_CHECKING: diff --git a/tests/unit/imports/test_extract.py b/tests/unit/imports/test_extract.py index e0ada3e1..05dd79a5 100644 --- a/tests/unit/imports/test_extract.py +++ b/tests/unit/imports/test_extract.py @@ -8,9 +8,9 @@ from typing import TYPE_CHECKING import pytest + from deptry.imports.extract import get_imported_modules_from_ipynb_file, get_imported_modules_from_list_of_files from deptry.imports.location import Location - from tests.utils import run_within_dir if TYPE_CHECKING: diff --git a/tests/unit/reporters/test_json.py b/tests/unit/reporters/test_json.py index 389eba52..ed2dab72 100644 --- a/tests/unit/reporters/test_json.py +++ b/tests/unit/reporters/test_json.py @@ -13,7 +13,6 @@ DEP003TransitiveDependencyViolation, DEP004MisplacedDevDependencyViolation, ) - from tests.utils import run_within_dir diff --git a/tests/unit/reporters/test_text.py b/tests/unit/reporters/test_text.py index 1908ea75..8fbc578d 100644 --- a/tests/unit/reporters/test_text.py +++ b/tests/unit/reporters/test_text.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING import pytest + from deptry.dependency import Dependency from deptry.imports.location import Location from deptry.module import Module @@ -16,7 +17,6 @@ DEP003TransitiveDependencyViolation, DEP004MisplacedDevDependencyViolation, ) - from tests.utils import stylize if TYPE_CHECKING: diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 03a61d1e..2e42387d 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -7,9 +7,9 @@ import click import pytest from click import Argument + from deptry.config import read_configuration_from_pyproject_toml from deptry.exceptions import InvalidPyprojectTOMLOptionsError - from tests.utils import run_within_dir if TYPE_CHECKING: diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py index b7db407e..4a91aa27 100644 --- a/tests/unit/test_core.py +++ b/tests/unit/test_core.py @@ -6,6 +6,7 @@ from unittest import mock import pytest + from deptry.core import Core from deptry.dependency import Dependency from deptry.exceptions import UnsupportedPythonVersionError @@ -18,7 +19,6 @@ DEP003TransitiveDependencyViolation, DEP004MisplacedDevDependencyViolation, ) - from tests.utils import create_files, run_within_dir diff --git a/tests/unit/test_dependency_specification_detector.py b/tests/unit/test_dependency_specification_detector.py index 033238be..ae129c92 100644 --- a/tests/unit/test_dependency_specification_detector.py +++ b/tests/unit/test_dependency_specification_detector.py @@ -4,9 +4,9 @@ from pathlib import Path import pytest + from deptry.dependency_specification_detector import DependencyManagementFormat, DependencySpecificationDetector from deptry.exceptions import DependencySpecificationNotFoundError - from tests.utils import run_within_dir diff --git a/tests/unit/test_python_file_finder.py b/tests/unit/test_python_file_finder.py index 5409547e..bb8a0a5d 100644 --- a/tests/unit/test_python_file_finder.py +++ b/tests/unit/test_python_file_finder.py @@ -3,10 +3,10 @@ from pathlib import Path import pytest -from deptry.python_file_finder import PythonFileFinder from pathspec import PathSpec from pathspec.patterns.gitwildmatch import GitWildMatchPattern +from deptry.python_file_finder import PythonFileFinder from tests.utils import create_files, run_within_dir From d71e8717bd90d3a09dd3dd9168bbab8986adc578 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 23:20:43 +0100 Subject: [PATCH 74/77] ci: add concurrency --- .github/workflows/main.yml | 5 +- .github/workflows/release.yml | 98 +++++++++++++++++------------------ 2 files changed, 53 insertions(+), 50 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 95127c65..c7fbfb1b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,8 +6,11 @@ on: push: branches: [main] -jobs: +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} +jobs: quality: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index af829069..42550a90 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,11 +1,10 @@ name: Release on: - release: - types: [published] + release: + types: [published] jobs: - set-version: runs-on: ubuntu-latest steps: @@ -17,15 +16,15 @@ jobs: - name: Update project version run: | - sed -i "s/^version = \".*\"/version = \"$RELEASE_VERSION\"/" pyproject.toml + sed -i "s/^version = \".*\"/version = \"$RELEASE_VERSION\"/" pyproject.toml env: - RELEASE_VERSION: ${{ steps.vars.outputs.tag }} + RELEASE_VERSION: ${{ steps.vars.outputs.tag }} - name: Upload updated pyproject.toml uses: actions/upload-artifact@v4 with: - name: pyproject-toml - path: pyproject.toml + name: pyproject-toml + path: pyproject.toml linux: runs-on: ubuntu-latest @@ -50,11 +49,11 @@ jobs: - name: Build wheels uses: PyO3/maturin-action@v1 with: - target: ${{ matrix.target }} - args: --release --out dist --find-interpreter - sccache: 'true' - manylinux: auto - rust-toolchain: 1.75.0 + target: ${{ matrix.target }} + args: --release --out dist --find-interpreter + sccache: 'true' + manylinux: auto + rust-toolchain: 1.75.0 - name: Upload wheels uses: actions/upload-artifact@v4 @@ -75,7 +74,7 @@ jobs: - name: Download updated pyproject.toml uses: actions/download-artifact@v4 with: - name: pyproject-toml + name: pyproject-toml - uses: actions/setup-python@v5 with: @@ -134,52 +133,53 @@ jobs: runs-on: ubuntu-latest needs: [set-version] steps: - - uses: actions/checkout@v4 - - - name: Download updated pyproject.toml - uses: actions/download-artifact@v4 - with: - name: pyproject-toml - - - name: Build sdist - uses: PyO3/maturin-action@v1 - with: - command: sdist - args: --out dist - rust-toolchain: 1.75.0 - - - name: Upload sdist - uses: actions/upload-artifact@v4 - with: - name: wheels-sdist - path: dist + - uses: actions/checkout@v4 + + - name: Download updated pyproject.toml + uses: actions/download-artifact@v4 + with: + name: pyproject-toml + + - name: Build sdist + uses: PyO3/maturin-action@v1 + with: + command: sdist + args: --out dist + rust-toolchain: 1.75.0 + + - name: Upload sdist + uses: actions/upload-artifact@v4 + with: + name: wheels-sdist + path: dist publish: name: Publish runs-on: ubuntu-latest needs: [linux, windows, macos, sdist] steps: - - uses: actions/download-artifact@v4 - - name: Publish to PyPI - uses: PyO3/maturin-action@v1 - env: - MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - with: - command: upload - args: --non-interactive --skip-existing wheels-*/* + - uses: actions/download-artifact@v4 + + - name: Publish to PyPI + uses: PyO3/maturin-action@v1 + env: + MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + with: + command: upload + args: --non-interactive --skip-existing wheels-*/* check-docs: runs-on: ubuntu-latest needs: publish steps: - - name: Check out - uses: actions/checkout@v4 + - name: Check out + uses: actions/checkout@v4 - - name: Set up the environment - uses: ./.github/actions/setup-env - with: - python-version: '3.11' - target: 'x86_64' + - name: Set up the environment + uses: ./.github/actions/setup-env + with: + python-version: '3.11' + target: 'x86_64' - - name: Deploy documentation - run: poetry run mkdocs gh-deploy --force + - name: Deploy documentation + run: poetry run mkdocs gh-deploy --force From de371b1a2596d662b010e6917fe468fad545d978 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 23:21:00 +0100 Subject: [PATCH 75/77] ci: remove another Poetry reference --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 42550a90..bc99cb51 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -182,4 +182,4 @@ jobs: target: 'x86_64' - name: Deploy documentation - run: poetry run mkdocs gh-deploy --force + run: pdm run mkdocs gh-deploy --force From 86bdcaa7a3420c6127268b96b1c20694e0bb6d63 Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 23:26:40 +0100 Subject: [PATCH 76/77] chore: add rust toolchain --- rust-toolchain.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..6d833ff5 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.75" From 7160a4b6f63f594509be3da57102de57c812287a Mon Sep 17 00:00:00 2001 From: Mathieu Kniewallner Date: Tue, 12 Mar 2024 23:29:58 +0100 Subject: [PATCH 77/77] ci: use `rustup` and add cache --- .github/actions/setup-env/action.yml | 7 ++++--- .github/workflows/release.yml | 4 ---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/actions/setup-env/action.yml b/.github/actions/setup-env/action.yml index 46ab2dc2..4ebcff69 100644 --- a/.github/actions/setup-env/action.yml +++ b/.github/actions/setup-env/action.yml @@ -25,9 +25,10 @@ runs: architecture: ${{ matrix.python-target }} - name: Setup Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: 1.75.0 + run: rustup component add clippy rustfmt + shell: bash + + - uses: Swatinem/rust-cache@v2 - name: Install PDM and dependencies run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bc99cb51..930cf08c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -53,7 +53,6 @@ jobs: args: --release --out dist --find-interpreter sccache: 'true' manylinux: auto - rust-toolchain: 1.75.0 - name: Upload wheels uses: actions/upload-artifact@v4 @@ -87,7 +86,6 @@ jobs: target: ${{ matrix.target }} args: --release --out dist --find-interpreter sccache: 'true' - rust-toolchain: 1.75.0 - name: Upload wheels uses: actions/upload-artifact@v4 @@ -121,7 +119,6 @@ jobs: target: ${{ matrix.target }} args: --release --out dist --find-interpreter sccache: 'true' - rust-toolchain: 1.75.0 - name: Upload wheels uses: actions/upload-artifact@v4 @@ -145,7 +142,6 @@ jobs: with: command: sdist args: --out dist - rust-toolchain: 1.75.0 - name: Upload sdist uses: actions/upload-artifact@v4