From 3651581381a17cb1336aba58855d6f6bcdfa3732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Brunner?= Date: Thu, 17 Oct 2024 12:14:41 +0200 Subject: [PATCH] Remove dependency to setoptconf --- poetry.lock | 155 +++++++- prospector/config/__init__.py | 26 +- prospector/config/configuration.py | 584 ++++++++++++++-------------- prospector/config/datatype.py | 19 - prospector/formatters/__init__.py | 7 +- prospector/profiles/profile.py | 18 +- prospector/run.py | 4 +- prospector/tools/__init__.py | 2 + prospector/tools/pylint/__init__.py | 7 +- pyproject.toml | 2 +- 10 files changed, 457 insertions(+), 367 deletions(-) delete mode 100644 prospector/config/datatype.py diff --git a/poetry.lock b/poetry.lock index 47a2064a..8eff63e3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,15 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] [[package]] name = "astroid" @@ -1059,6 +1070,130 @@ files = [ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] +[[package]] +name = "pydantic" +version = "2.9.2" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, + {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.23.4" +typing-extensions = [ + {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, + {version = ">=4.6.1", markers = "python_version < \"3.13\""}, +] + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] + +[[package]] +name = "pydantic-core" +version = "2.23.4" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, + {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, + {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, + {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, + {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, + {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, + {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, + {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, + {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, + {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, + {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, + {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, + {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, + {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + [[package]] name = "pydocstyle" version = "6.3.0" @@ -1116,8 +1251,8 @@ files = [ astroid = ">=3.3.4,<=3.4.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ - {version = ">=0.2", markers = "python_version < \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.2", markers = "python_version < \"3.11\""}, {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, ] isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" @@ -1522,20 +1657,6 @@ files = [ {file = "semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc"}, ] -[[package]] -name = "setoptconf-tmp" -version = "0.3.1" -description = "A module for retrieving program settings from various sources in a consistant method." -optional = false -python-versions = "*" -files = [ - {file = "setoptconf-tmp-0.3.1.tar.gz", hash = "sha256:e0480addd11347ba52f762f3c4d8afa3e10ad0affbc53e3ffddc0ca5f27d5778"}, - {file = "setoptconf_tmp-0.3.1-py3-none-any.whl", hash = "sha256:76035d5cd1593d38b9056ae12d460eca3aaa34ad05c315b69145e138ba80a745"}, -] - -[package.extras] -yaml = ["pyyaml"] - [[package]] name = "setuptools" version = "75.1.0" @@ -1826,4 +1947,4 @@ with-vulture = ["vulture"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "c307a3a29e1e8760841d5af9bbb07bdb1cde719ca0601c46b36a8caff90d2c25" +content-hash = "8d0fd7880428290605a8e25c1994cf7ad932259c1645d297dbb391d67f7f5c30" diff --git a/prospector/config/__init__.py b/prospector/config/__init__.py index 52478bba..b9dbc1d0 100644 --- a/prospector/config/__init__.py +++ b/prospector/config/__init__.py @@ -2,7 +2,7 @@ import re import sys from pathlib import Path -from typing import Dict, List, Union +from typing import Dict, List, Tuple, Union try: # Python >= 3.11 import re._constants as sre_constants @@ -27,8 +27,8 @@ class ProspectorConfig: # is a config object and its sole purpose is to hold many properties! def __init__(self, workdir: Path = None): - self.config, self.arguments = self._configure_prospector() - self.paths = self._get_work_path(self.config, self.arguments) + self.config = self._configure_prospector() + self.paths = self._get_work_path(self.config) self.explicit_file_mode = all(p.is_file for p in self.paths) self.workdir = workdir or Path.cwd() @@ -106,23 +106,19 @@ def get_output_report(self): return output_report - def _configure_prospector(self): - # first we will configure prospector as a whole - mgr = cfg.build_manager() - config = mgr.retrieve(*cfg.build_default_sources()) - return config, mgr.arguments + def _configure_prospector(self) -> cfg.Config: + # First we will configure prospector as a whole + return cfg.get_config() - def _get_work_path(self, config, arguments) -> List[Path]: + def _get_work_path(self, config) -> List[Path]: # Figure out what paths we're prospecting - if config["path"]: - paths = [Path(self.config["path"])] - elif arguments["checkpath"]: - paths = [Path(p) for p in arguments["checkpath"]] + if config.path: + paths = [Path(self.config.path)] else: paths = [Path.cwd()] return [p.resolve() for p in paths] - def _get_profile(self, workdir: Path, config): + def _get_profile(self, workdir: Path, config: cfg.Config) -> Tuple[ProspectorProfile, str]: # Use the specified profiles profile_provided = False if len(config.profiles) > 0: @@ -168,7 +164,7 @@ def _get_profile(self, workdir: Path, config): # Use the strictness profile only if no profile has been given if config.strictness is not None and config.strictness: - cmdline_implicit.append("strictness_%s" % config.strictness) + cmdline_implicit.append("strictness_%s" % config.strictness.value) strictness = config.strictness # the profile path is diff --git a/prospector/config/configuration.py b/prospector/config/configuration.py index c4fe2b0f..d05ca6d8 100644 --- a/prospector/config/configuration.py +++ b/prospector/config/configuration.py @@ -1,325 +1,315 @@ # flake8: noqa -import importlib.metadata +import argparse +import os +from enum import Enum +from typing import List, Optional, Union, get_args, get_origin -import setoptconf as soc +import toml +from pydantic import BaseModel +from pydantic.fields import FieldInfo -from prospector.config.datatype import OutputChoice -from prospector.formatters import FORMATTERS -from prospector.tools import DEFAULT_TOOLS, TOOLS +from prospector.formatters import FORMATTERS, Formatters +from prospector.tools import DEFAULT_TOOLS, TOOLS, Tools -__all__ = ("build_manager",) -_VERSION = importlib.metadata.version("prospector") +class Strictness(Enum): + veryhigh = "veryhigh" + high = "high" + medium = "medium" + low = "low" + verylow = "verylow" -def build_manager(): - manager = soc.ConfigurationManager("prospector") +class Config(BaseModel): + zero_exit: bool = False + autodetect: bool = True + uses: List[str] = [] + blending: bool = True + doc_warnings: Optional[bool] = None + test_warnings: Optional[bool] = None + no_style_warnings: Optional[bool] = None + member_warnings: Optional[bool] = None + full_pep8: Optional[bool] = None + max_line_length: Optional[int] = None + messages_only: bool = False + summary_only: bool = False + quiet: bool = False + output_format: Optional[List[Formatters]] = None + absolute_paths: bool = False + tools: Optional[List[Tools]] = None + with_tools: List[str] = [] + without_tools: List[str] = [] + profiles: List[str] = [] + profile_path: List[str] = [] + strictness: Optional[Strictness] = None + show_profile: bool = False + no_external_config: bool = False + legacy_tool_names: bool = False + pylint_config_file: Optional[str] = None + path: Optional[str] = None + ignore_patterns: List[str] = [] + ignore_paths: List[str] = [] + die_on_tool_error: bool = False + include_tool_stdout: bool = False + direct_tool_stdout: bool = False - manager.add(soc.BooleanSetting("zero_exit", default=False)) - manager.add(soc.BooleanSetting("autodetect", default=True)) - manager.add(soc.ListSetting("uses", soc.String, default=[])) +def _parse_value( + name: str, value_str: str, conf: FieldInfo +) -> None | bool | int | float | str | List[bool] | List[int] | List[float] | List[str]: - manager.add(soc.BooleanSetting("blending", default=True)) + value = None - manager.add(soc.BooleanSetting("doc_warnings", default=None)) - manager.add(soc.BooleanSetting("test_warnings", default=None)) - manager.add(soc.BooleanSetting("no_style_warnings", default=None)) - manager.add(soc.BooleanSetting("member_warnings", default=None)) - manager.add(soc.BooleanSetting("full_pep8", default=None)) - manager.add(soc.IntegerSetting("max_line_length", default=None)) + type_ = conf.annotation + origin = get_origin(type_) + if origin is Union: + args = get_args(type_) + if args[1] is type(None): + type_ = args[0] + origin = get_origin(type_) - manager.add(soc.BooleanSetting("messages_only", default=False)) - manager.add(soc.BooleanSetting("summary_only", default=False)) - manager.add(soc.BooleanSetting("quiet", default=False)) - manager.add( - soc.ListSetting( - "output_format", - OutputChoice(sorted(FORMATTERS.keys())), - default=None, - ) - ) - manager.add(soc.BooleanSetting("absolute_paths", default=False)) + if origin is None: + if type_ is bool: + value = value_str.lower() in ("1", "true", "yes") + elif type_ is int: + value = int(value_str) + elif type_ is float: + value = float(value_str) + elif type_ is str: + value = value_str + else: + if origin == list or origin == List: + sub_type = get_args(type_)[0] + if sub_type is str: + value = value_str.split(",") + elif sub_type is bool: + value = [x.lower() in ("1", "true", "yes") for x in value_str.split(",")] + elif sub_type is int: + value = [int(x) for x in value_str.split(",")] + elif sub_type is float: + value = [float(x) for x in value_str.split(",")] - manager.add( - soc.ListSetting( - "tools", - soc.Choice(sorted(TOOLS.keys())), - default=None, - ) - ) - manager.add(soc.ListSetting("with_tools", soc.String, default=[])) - manager.add(soc.ListSetting("without_tools", soc.String, default=[])) - manager.add(soc.ListSetting("profiles", soc.String, default=[])) - manager.add(soc.ListSetting("profile_path", soc.String, default=[])) - manager.add( - soc.ChoiceSetting( - "strictness", - ["veryhigh", "high", "medium", "low", "verylow"], - default=None, + if value is None: + print(f"Could not parse {name}={value_str}") + return value + + +def get_config() -> Config: + args = build_command_line_parser().parse_args() + + config = {} + config_directory = os.getenv("XDG_CONFIG_HOME") or os.path.expanduser( + os.path.join( + "~", + ".config", ) ) - manager.add(soc.BooleanSetting("show_profile", default=False)) - manager.add(soc.BooleanSetting("no_external_config", default=False)) - manager.add(soc.BooleanSetting("legacy_tool_names", default=False)) - manager.add(soc.StringSetting("pylint_config_file", default=None)) + for keys, config_filename in ( + (["prospector"], os.path.expanduser(os.path.join("~", ".prospectorrc"))), + (["prospector"], os.path.join(config_directory, ".prospectorrc")), + (["prospector"], ".prospectorrc"), + (["tool", "prospector"], "pyproject.toml"), + ): + if os.path.exists(config_filename): + with open(config_filename) as f: + new_config = toml.load(f) + for key in keys: + new_config = new_config.get(key, {}) + config.update(new_config) - manager.add(soc.StringSetting("path", default=None)) + for name, conf in Config.model_fields.items(): + env_name = f"PROSPECTOR_{name.upper()}" + if env_name in os.environ: + value_str = os.environ[env_name] + value = _parse_value(name, value_str, conf) + if value is not None: + config[name] = value - manager.add(soc.ListSetting("ignore_patterns", soc.String, default=[])) - manager.add(soc.ListSetting("ignore_paths", soc.String, default=[])) + for name, conf in Config.model_fields.items(): + if hasattr(args, name): + value = getattr(args, name) + if isinstance(value, str): + value = _parse_value(name, value, conf) + if value is not None: + config[name] = value - manager.add(soc.BooleanSetting("die_on_tool_error", default=False)) - manager.add(soc.BooleanSetting("include_tool_stdout", default=False)) - manager.add(soc.BooleanSetting("direct_tool_stdout", default=False)) + return Config(**config) - return manager +def build_command_line_parser( + prog=None, description="Performs static analysis of Python code" +) -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(prog=prog, description=description) -def build_default_sources(): - sources = [ - build_command_line_source(), - soc.EnvironmentVariableSource(), - soc.ConfigFileSource( - ( - ".prospectorrc", - "setup.cfg", - "tox.ini", - ) + parser.add_argument( + "-0", + "--zero-exit", + action="store_true", + help="Prospector will exit with a code of 1 (one) if any messages are found. This makes automation easier; if there are any problems at all, the exit code is non-zero. However this behaviour is not always desirable, so if this flag is set, prospector will exit with a code of 0 if it ran successfully, and non-zero if it failed to run.", + ) + parser.add_argument( + "-A", + "--no-autodetect", + action="store_true", + help="Turn off auto-detection of frameworks and libraries used. By default, autodetection will be used. To specify manually, see the --uses option.", + ) + parser.add_argument( + "-u", + "--uses", + help="A list of one or more libraries or frameworks that the project uses. Possible values are: django, celery, flask. This will be autodetected by default, but if autodetection doesn't work, manually specify them using this flag.", + ) + parser.add_argument( + "-B", + "--no-blending", + action="store_true", + help="Turn off blending of messages. Prospector will merge together messages from different tools if they represent the same error. Use this option to see all unmerged messages.", + ) + parser.add_argument("-D", "--doc-warnings", action="store_true", help="Include warnings about documentation.") + parser.add_argument("-T", "--test-warnings", action="store_true", help="Also check test modules and packages.") + parser.add_argument( + "--legacy-tool-names", + action="store_true", + help="Output deprecated names for tools (pep8, pep257) instead of updated names (pycodestyle, pydocstyle)", + ) + parser.add_argument( + "-8", + "--no-style-warnings", + action="store_true", + help="Don't create any warnings about style. This disables the PEP8 tool and similar checks for formatting.", + ) + parser.add_argument( + "-m", + "--member-warnings", + action="store_true", + help="Attempt to warn when code tries to access an attribute of a class or member of a module which does not exist. This is disabled by default as it tends to be quite inaccurate.", + ) + parser.add_argument( + "-q", + "--quiet", + action="store_true", + help="Run but do not output anything to stdout. Useful to suppress output in scripts without sending to a file (via -o)", + ) + parser.add_argument( + "-F", + "--full-pep8", + action="store_true", + help="Enables every PEP8 warning, so that all PEP8 style violation will be reported.", + ) + parser.add_argument( + "--max-line-length", + help="The maximum line length allowed. This will be set by the strictness if no value is explicitly specified", + ) + parser.add_argument( + "-M", + "--messages-only", + action="store_true", + help="Only output message information (don't output summary information about the checks)", + ) + parser.add_argument( + "-S", + "--summary-only", + action="store_true", + help="Only output summary information about the checks (don't output message information)", + ) + parser.add_argument( + "-o", + "--output-format", + help="The output format. Valid values are: {}. This will output to stdout by default, however a target file can be used instead by adding :path-to-output-file, eg, -o json:output.json".format( + ", ".join(sorted(FORMATTERS.keys())) + ), + ) + parser.add_argument( + "--absolute-paths", + help="Whether to output absolute paths when referencing files in messages. By default, paths will be relative to the project path", + ) + parser.add_argument( + "-t", + "--tool", + help="A list of tools to run. This lets you set exactly which tools to run. To add extra tools to the defaults, see --with-tool. Possible values are: {}. By default, the following tools will be run: {}".format( + ", ".join(sorted(TOOLS.keys())), ", ".join(sorted(DEFAULT_TOOLS)) ), - soc.ConfigFileSource( - ( - soc.ConfigDirectory(".prospectorrc"), - soc.HomeDirectory(".prospectorrc"), - ) + ) + parser.add_argument( + "-w", + "--with-tool", + help="A list of tools to run in addition to the default tools. To specify all tools explicitly, use the --tool argument. Possible values are {}.".format( + ", ".join(sorted(TOOLS.keys())) ), - ] - - return sources - - -def build_command_line_source(prog=None, description="Performs static analysis of Python code"): - parser_options = {} - if prog is not None: - parser_options["prog"] = prog - if description is not None: - parser_options["description"] = description - - options = { - "zero_exit": { - "flags": ["-0", "--zero-exit"], - "help": "Prospector will exit with a code of 1 (one) if any messages" - " are found. This makes automation easier; if there are any" - " problems at all, the exit code is non-zero. However this behaviour" - " is not always desirable, so if this flag is set, prospector will" - " exit with a code of 0 if it ran successfully, and non-zero if" - " it failed to run.", - }, - "autodetect": { - "flags": ["-A", "--no-autodetect"], - "help": "Turn off auto-detection of frameworks and libraries used." - " By default, autodetection will be used. To specify" - " manually, see the --uses option.", - }, - "uses": { - "flags": ["-u", "--uses"], - "help": "A list of one or more libraries or frameworks that the" - " project uses. Possible values are: django, celery, flask. This will be" - " autodetected by default, but if autodetection doesn't" - " work, manually specify them using this flag.", - }, - "blending": { - "flags": ["-B", "--no-blending"], - "help": "Turn off blending of messages. Prospector will merge" - " together messages from different tools if they represent" - " the same error. Use this option to see all unmerged" - " messages.", - }, - "doc_warnings": { - "flags": ["-D", "--doc-warnings"], - "help": "Include warnings about documentation.", - }, - "test_warnings": { - "flags": ["-T", "--test-warnings"], - "help": "Also check test modules and packages.", - }, - "legacy_tool_names": { - "flags": ["--legacy-tool-names"], - "help": "Output deprecated names for tools (pep8, pep257) " - "instead of updated names (pycodestyle, pydocstyle)", - }, - "no_style_warnings": { - "flags": ["-8", "--no-style-warnings"], - "help": "Don't create any warnings about style. This disables the" - " PEP8 tool and similar checks for formatting.", - }, - "member_warnings": { - "flags": ["-m", "--member-warnings"], - "help": "Attempt to warn when code tries to access an attribute of a " - "class or member of a module which does not exist. This is disabled " - "by default as it tends to be quite inaccurate.", - }, - "quiet": { - "flags": ["-q", "--quiet"], - "help": "Run but do not output anything to stdout. Useful to suppress " - "output in scripts without sending to a file (via -o)", - }, - "full_pep8": { - "flags": ["-F", "--full-pep8"], - "help": "Enables every PEP8 warning, so that all PEP8 style violation will be reported.", - }, - "max_line_length": { - "flags": ["--max-line-length"], - "help": "The maximum line length allowed. This will be set by the strictness if no" - " value is explicitly specified", - }, - "messages_only": { - "flags": ["-M", "--messages-only"], - "help": "Only output message information (don't output summary" " information about the checks)", - }, - "summary_only": { - "flags": ["-S", "--summary-only"], - "help": "Only output summary information about the checks (don't" "output message information)", - }, - "output_format": { - "flags": ["-o", "--output-format"], - "help": "The output format. Valid values are: %s. This will output to stdout by default, " - "however a target file can be used instead by adding :path-to-output-file, eg, -o json:output.json" - % (", ".join(sorted(FORMATTERS.keys())),), - }, - "absolute_paths": { - "help": "Whether to output absolute paths when referencing files " - "in messages. By default, paths will be relative to the " - "project path", - }, - "tools": { - "flags": ["-t", "--tool"], - "help": "A list of tools to run. This lets you set exactly which " - "tools to run. To add extra tools to the defaults, see " - "--with-tool. Possible values are: %s. By " - "default, the following tools will be run: %s" - % ( - ", ".join(sorted(TOOLS.keys())), - ", ".join(sorted(DEFAULT_TOOLS)), - ), - }, - "with_tools": { - "flags": ["-w", "--with-tool"], - "help": "A list of tools to run in addition to the default tools. " - "To specify all tools explicitly, use the --tool argument. " - "Possible values are %s." % (", ".join(sorted(TOOLS.keys()))), - }, - "without_tools": { - "flags": ["-W", "--without-tool"], - "help": "A list of tools that should not be run. Useful to turn off " - "only a single tool from the defaults. " - "To specify all tools explicitly, use the --tool argument. " - "Possible values are %s." % (", ".join(sorted(TOOLS.keys()))), - }, - "profiles": { - "flags": ["-P", "--profile"], - "help": "The list of profiles to load. A profile is a certain" - " 'type' of behaviour for prospector, and is represented" - " by a YAML configuration file. Either a full path to the YAML" - " file describing the profile must be provided, or it must be" - " on the profile path (see --profile-path)", - }, - "profile_path": { - "flags": ["--profile-path"], - "help": "Additional paths to search for profile files. By default this" - " is the path that prospector will check, and a directory " - ' called ".prospector" in the path that prospector will check.', - }, - "show_profile": { - "flags": ["--show-profile"], - "help": "Include the computed profile in the summary. This will show what" - " prospector has decided the overall profile is once all profiles" - " have been combined and inherited from. This will produce a large" - " output in most cases so is only useful when trying to debug why" - " prospector is not behaving like you expect.", - }, - "strictness": { - "flags": ["-s", "--strictness"], - "help": "How strict the checker should be. This affects how" - " harshly the checker will enforce coding guidelines. The" - ' default value is "medium", possible values are' - ' "veryhigh", "high", "medium", "low" and "verylow".', - }, - "no_external_config": { - "flags": ["-E", "--no-external-config"], - "help": "Determines how prospector should behave when" - " configuration already exists for a tool. By default," - " prospector will use existing configuration. This flag" - " will cause prospector to ignore existing configuration" - " and use its own settings for every tool. Note that" - " prospector will always use its own config for tools which" - " do not have custom configuration.", - }, - "pylint_config_file": { - "flags": ["--pylint-config-file"], - "help": "The path to a pylintrc file to use to configure pylint. Prospector will find" - " .pylintrc files in the root of the project, but you can use this option to " - "specify manually where it is.", - }, - "ignore_patterns": { - "flags": ["-I", "--ignore-patterns"], - "help": "A list of paths to ignore, as a list of regular" - " expressions. Files and folders will be ignored if their" - " full path contains any of these patterns.", - }, - "ignore_paths": { - "flags": ["-i", "--ignore-paths"], - "help": "A list of file or directory names to ignore. If the" - " complete name matches any of the items in this list, the" - " file or directory (and all subdirectories) will be" - " ignored.", - }, - "die_on_tool_error": { - "flags": ["-X", "--die-on-tool-error"], - "help": "If a tool fails to run, prospector will try to carry on." - " Use this flag to cause prospector to die and raise the" - " exception the tool generated. Mostly useful for" - " development on prospector.", - }, - "include-tool-stdout": { - "flags": ["--include-tool-stdout"], - "help": "There are various places where tools will output warnings to " - "stdout/stderr, which breaks parsing of JSON output. Therefore while tols " - "is running, this is suppressed. For developing, it is sometimes useful to " - "see this. This flag will cause stdout/stderr from a tool to be shown as " - "a normal message amongst other warnings. See also --direct-tool-stdout", - }, - "direct-tool-stdout": { - "flags": ["--direct-tool-stdout"], - "help": "Same as --include-tool-stdout, except the output will be printed " - "directly rather than shown as a message.", - }, - "path": { - "flags": ["-p", "--path"], - "help": "The path to a Python project to inspect. Defaults to PWD" - " if not specified. Note: This command line argument is" - " deprecated and will be removed in a future update. Please" - " use the positional PATH argument instead.", - }, - } - - positional = ( - ( - "checkpath", - { - "help": "The path to a Python project to inspect. Defaults to PWD" - " if not specified. If multiple paths are specified," - " they must all be files (no directories).", - "metavar": "PATH", - "nargs": "*", - }, + ) + parser.add_argument( + "-W", + "--without-tool", + help="A list of tools that should not be run. Useful to turn off only a single tool from the defaults. To specify all tools explicitly, use the --tool argument. Possible values are {}.".format( + ", ".join(sorted(TOOLS.keys())) ), ) + parser.add_argument( + "-P", + "--profile", + help="The list of profiles to load. A profile is a certain 'type' of behaviour for prospector, and is represented by a YAML configuration file. Either a full path to the YAML file describing the profile must be provided, or it must be on the profile path (see --profile-path)", + ) + parser.add_argument( + "--profile-path", + help="Additional paths to search for profile files. By default this is the path that prospector will check, and a directory called '.prospector' in the path that prospector will check.", + ) + parser.add_argument( + "--show-profile", + action="store_true", + help="Include the computed profile in the summary. This will show what prospector has decided the overall profile is once all profiles have been combined and inherited from. This will produce a large output in most cases so is only useful when trying to debug why prospector is not behaving like you expect.", + ) + parser.add_argument( + "-s", + "--strictness", + help='How strict the checker should be. This affects how harshly the checker will enforce coding guidelines. The default value is "medium", possible values are "veryhigh", "high", "medium", "low" and "verylow".', + ) + parser.add_argument( + "-E", + "--no-external-config", + action="store_true", + help="Determines how prospector should behave when configuration already exists for a tool. By default, prospector will use existing configuration. This flag will cause prospector to ignore existing configuration and use its own settings for every tool. Note that prospector will always use its own config for tools which do not have custom configuration.", + ) + parser.add_argument( + "--pylint-config-file", + help="The path to a pylintrc file to use to configure pylint. Prospector will find .pylintrc files in the root of the project, but you can use this option to specify manually where it is.", + ) + parser.add_argument( + "-I", + "--ignore-patterns", + help="A list of paths to ignore, as a list of regular expressions. Files and folders will be ignored if their full path contains any of these patterns.", + ) + parser.add_argument( + "-i", + "--ignore-paths", + help="A list of file or directory names to ignore. If the complete name matches any of the items in this list, the file or directory (and all subdirectories) will be ignored.", + ) + parser.add_argument( + "-X", + "--die-on-tool-error", + action="store_true", + help="If a tool fails to run, prospector will try to carry on. Use this flag to cause prospector to die and raise the exception the tool generated. Mostly useful for development on prospector.", + ) + parser.add_argument( + "--include-tool-stdout", + action="store_true", + help="There are various places where tools will output warnings to stdout/stderr, which breaks parsing of JSON output. Therefore while tols is running, this is suppressed. For developing, it is sometimes useful to see this. This flag will cause stdout/stderr from a tool to be shown as a normal message amongst other warnings. See also --direct-tool-stdout", + ) + parser.add_argument( + "--direct-tool-stdout", + action="store_true", + help="Same as --include-tool-stdout, except the output will be printed directly rather than shown as a message.", + ) + parser.add_argument( + "-p", + "--path", + help="The path to a Python project to inspect. Defaults to PWD if not specified. Note: This command line argument is deprecated and will be removed in a future update. Please use the positional PATH argument instead.", + ) - return soc.CommandLineSource( - options=options, - version=_VERSION, - parser_options=parser_options, - positional=positional, + parser.add_argument( + "path", + help="The path to a Python project to inspect. Defaults to PWD if not specified. If multiple paths are specified, they must all be files (no directories).", + metavar="PATH", + nargs="?", ) + + return parser diff --git a/prospector/config/datatype.py b/prospector/config/datatype.py deleted file mode 100644 index d3482e04..00000000 --- a/prospector/config/datatype.py +++ /dev/null @@ -1,19 +0,0 @@ -import os -import re -import sys - -from setoptconf.datatype import Choice - - -class OutputChoice(Choice): - def sanitize(self, value): - parsed = re.split(r"[;:]", value) - output_format, output_targets = parsed[0], parsed[1:] - checked_targets = [] - for target in output_targets: - if sys.platform.startswith("win") and target.startswith((os.path.sep, os.path.altsep)): - checked_targets[-1] += ":" + target - else: - checked_targets.append(target) - validated_format = super().sanitize(output_format) - return validated_format, checked_targets diff --git a/prospector/formatters/__init__.py b/prospector/formatters/__init__.py index 2328bbc2..dae23dce 100644 --- a/prospector/formatters/__init__.py +++ b/prospector/formatters/__init__.py @@ -1,8 +1,6 @@ -from . import emacs, grouped, json, pylint, text, vscode, xunit, yaml -from .base import Formatter - -__all__ = ("FORMATTERS", "Formatter") +from enum import Enum +from . import emacs, grouped, json, pylint, text, vscode, xunit, yaml FORMATTERS = { "json": json.JsonFormatter, @@ -14,3 +12,4 @@ "xunit": xunit.XunitFormatter, "vscode": vscode.VSCodeFormatter, } +Formatters = Enum("Formatters", FORMATTERS) diff --git a/prospector/profiles/profile.py b/prospector/profiles/profile.py index 1cda9033..7186837e 100644 --- a/prospector/profiles/profile.py +++ b/prospector/profiles/profile.py @@ -99,7 +99,7 @@ def load( profile_path: List[Path], allow_shorthand: bool = True, forced_inherits: Optional[List[str]] = None, - ): + ) -> "ProspectorProfile": # First simply load all of the profiles and those that it explicitly inherits from data, inherits = _load_and_merge( name_or_path, @@ -110,12 +110,12 @@ def load( return ProspectorProfile(str(name_or_path), data, inherits) -def _is_valid_extension(filename): +def _is_valid_extension(filename: str) -> bool: ext = os.path.splitext(filename)[1] return ext in (".yml", ".yaml") -def _load_content_package(name): +def _load_content_package(name: str) -> Optional[Dict[str, Any]]: name_split = name.split(":", 1) module_name = f"prospector_profile_{name_split[0]}" file_names = ( @@ -419,12 +419,12 @@ def _transform_legacy(profile_dict): def _load_profile( - name_or_path, - profile_path, - shorthands_found=None, - already_loaded=None, - allow_shorthand=True, - forced_inherits=None, + name_or_path: Union[str, Path], + profile_path: list[Path], + shorthands_found: Optional[set[str]] = None, + already_loaded: Optional[list[str]] = None, + allow_shorthand: bool = True, + forced_inherits: Optional[list[str]] = None, ): # recursively get the contents of the basic profile and those it inherits from base_contents = _load_content(name_or_path, profile_path) diff --git a/prospector/run.py b/prospector/run.py index 75d8395d..33e677e7 100644 --- a/prospector/run.py +++ b/prospector/run.py @@ -178,9 +178,7 @@ def get_parser(): This is a helper method to return an argparse parser, to be used with the Sphinx argparse plugin for documentation. """ - manager = cfg.build_manager() - source = cfg.build_command_line_source(prog="prospector", description=None) - return source.build_parser(manager.settings, None) + return cfg.build_command_line_parser() def main(): diff --git a/prospector/tools/__init__.py b/prospector/tools/__init__.py index f04f7a44..e6b4f523 100644 --- a/prospector/tools/__init__.py +++ b/prospector/tools/__init__.py @@ -1,4 +1,5 @@ import importlib +from enum import Enum from prospector.exceptions import FatalProspectorException from prospector.tools.base import ToolBase @@ -66,6 +67,7 @@ def _profile_validator_tool(*args, **kwargs): "bandit": _optional_tool("bandit"), } +Tools = Enum("Tools", TOOLS) DEFAULT_TOOLS = ( "dodgy", diff --git a/prospector/tools/pylint/__init__.py b/prospector/tools/pylint/__init__.py index 7cd04ac5..8ae3c1d6 100644 --- a/prospector/tools/pylint/__init__.py +++ b/prospector/tools/pylint/__init__.py @@ -3,7 +3,7 @@ import sys from collections import defaultdict from pathlib import Path -from typing import List +from typing import TYPE_CHECKING, List from pylint.config import find_default_config_files from pylint.exceptions import UnknownMessageError @@ -15,6 +15,9 @@ from prospector.tools.pylint.collector import Collector from prospector.tools.pylint.linter import ProspectorLinter +if TYPE_CHECKING: + from prospector.config.configuration import Config + _UNUSED_WILDCARD_IMPORT_RE = re.compile(r"^Unused import(\(s\))? (.*) from wildcard import") @@ -165,7 +168,7 @@ def _get_pylint_check_paths(self, found_files: FileFinder) -> List[Path]: return sorted(check_paths) def _get_pylint_configuration( - self, check_paths: List[Path], linter: ProspectorLinter, prospector_config, pylint_options + self, check_paths: List[Path], linter: ProspectorLinter, prospector_config: "Config", pylint_options ): self._args = check_paths linter.load_default_plugins() diff --git a/pyproject.toml b/pyproject.toml index 99ca82de..96971334 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,6 @@ pep8-naming = ">=0.3.3,<=0.10.0" pydocstyle = ">=2.0.0" dodgy = "^0.2.1" toml = "^0.10.2" -setoptconf-tmp = "^0.3.1" GitPython = "^3.1.27" packaging = "*" bandit = {version = ">=1.5.1", optional = true} @@ -60,6 +59,7 @@ vulture = {version = ">=1.5", optional = true} mypy = {version = ">=0.600", optional = true} pyright = {version = ">=1.1.3", optional = true} pyroma = {version = ">=2.4", optional = true} +pydantic = "^2.9.2" [tool.poetry.extras] with_bandit = ["bandit"]