diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index da12ed2..0f56faf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,32 +1,19 @@ name: CI -on: [pull_request, workflow_dispatch] +on: [pull_request, workflow_dispatch, workflow_call] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - get-python-versions: - name: Get Python versions - runs-on: ubuntu-latest - outputs: - python-matrix: ${{ steps.get-python-versions-action.outputs.latest-python-versions }} - steps: - - name: Get Python version matrix - uses: snok/latest-python-versions@v1 - id: get-python-versions-action - with: - min-version: 3.8 - ci: name: CI - needs: [get-python-versions] runs-on: ubuntu-latest strategy: fail-fast: false matrix: - python-version: ${{ fromJson(needs.get-python-versions.outputs.python-matrix) }} + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - name: Checkout ${{ github.repository }} @@ -53,12 +40,13 @@ jobs: - name: Install dependencies id: poetry-install - run: poetry install --no-interaction --no-root + run: poetry install --no-interaction - name: Run pre-commit run: poetry run pre-commit run --all-files - name: Run Tests + shell: bash run: | poetry run pytest \ --junitxml=pytest.xml \ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index db8f572..e04e6f4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.6.0 hooks: - id: check-yaml args: [--unsafe] @@ -8,14 +8,9 @@ repos: - id: mixed-line-ending ## Python - - repo: https://github.com/pycqa/isort - rev: 5.12.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.4 hooks: - - id: isort - types: [python] - - - repo: https://github.com/psf/black - rev: 23.9.1 - hooks: - - id: black - types: [python] + - id: ruff + args: [--fix] + - id: ruff-format diff --git a/docs/conf.py b/docs/conf.py index 07e9558..ef54d87 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -8,7 +8,7 @@ import welkin project = welkin.__name__ -copyright = welkin.__copyright__ +copyright = welkin.__copyright__ # noqa: A001 author = welkin.__author__ release = welkin.__version__ diff --git a/poetry.lock b/poetry.lock index f7ac1f9..4ee0040 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "alabaster" @@ -24,13 +24,13 @@ files = [ [[package]] name = "astroid" -version = "3.1.0" +version = "3.2.0" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.8.0" files = [ - {file = "astroid-3.1.0-py3-none-any.whl", hash = "sha256:951798f922990137ac090c53af473db7ab4e70c770e6d7fae0cec59f74411819"}, - {file = "astroid-3.1.0.tar.gz", hash = "sha256:ac248253bfa4bd924a0de213707e7ebeeb3138abeb48d798784ead1e56d419d4"}, + {file = "astroid-3.2.0-py3-none-any.whl", hash = "sha256:16ee8ca5c75ac828783028cc1f967777f0e507c6886a295ad143e0f405b975a2"}, + {file = "astroid-3.2.0.tar.gz", hash = "sha256:f7f829f8506ade59f1b3c6c93d8fac5b1ebc721685fa9af23e9794daf1d450a3"}, ] [package.dependencies] @@ -38,13 +38,13 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} [[package]] name = "babel" -version = "2.14.0" +version = "2.15.0" description = "Internationalization utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, - {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] [package.dependencies] @@ -53,52 +53,6 @@ pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] -[[package]] -name = "black" -version = "24.3.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, - {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, - {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, - {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, - {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, - {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, - {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, - {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, - {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, - {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, - {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, - {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, - {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, - {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, - {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, - {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, - {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, - {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, - {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, - {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, - {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, - {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "certifi" version = "2024.2.2" @@ -220,20 +174,6 @@ files = [ {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -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" @@ -247,63 +187,63 @@ files = [ [[package]] name = "coverage" -version = "7.4.3" +version = "7.5.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" 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"}, + {file = "coverage-7.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0884920835a033b78d1c73b6d3bbcda8161a900f38a488829a83982925f6c2e"}, + {file = "coverage-7.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:39afcd3d4339329c5f58de48a52f6e4e50f6578dd6099961cf22228feb25f38f"}, + {file = "coverage-7.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b0ceee8147444347da6a66be737c9d78f3353b0681715b668b72e79203e4a"}, + {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a9ca3f2fae0088c3c71d743d85404cec8df9be818a005ea065495bedc33da35"}, + {file = "coverage-7.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd215c0c7d7aab005221608a3c2b46f58c0285a819565887ee0b718c052aa4e"}, + {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4bf0655ab60d754491004a5efd7f9cccefcc1081a74c9ef2da4735d6ee4a6223"}, + {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:61c4bf1ba021817de12b813338c9be9f0ad5b1e781b9b340a6d29fc13e7c1b5e"}, + {file = "coverage-7.5.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db66fc317a046556a96b453a58eced5024af4582a8dbdc0c23ca4dbc0d5b3146"}, + {file = "coverage-7.5.1-cp310-cp310-win32.whl", hash = "sha256:b016ea6b959d3b9556cb401c55a37547135a587db0115635a443b2ce8f1c7228"}, + {file = "coverage-7.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:df4e745a81c110e7446b1cc8131bf986157770fa405fe90e15e850aaf7619bc8"}, + {file = "coverage-7.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:796a79f63eca8814ca3317a1ea443645c9ff0d18b188de470ed7ccd45ae79428"}, + {file = "coverage-7.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fc84a37bfd98db31beae3c2748811a3fa72bf2007ff7902f68746d9757f3746"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6175d1a0559986c6ee3f7fccfc4a90ecd12ba0a383dcc2da30c2b9918d67d8a3"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fc81d5878cd6274ce971e0a3a18a8803c3fe25457165314271cf78e3aae3aa2"}, + {file = "coverage-7.5.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:556cf1a7cbc8028cb60e1ff0be806be2eded2daf8129b8811c63e2b9a6c43bca"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9981706d300c18d8b220995ad22627647be11a4276721c10911e0e9fa44c83e8"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d7fed867ee50edf1a0b4a11e8e5d0895150e572af1cd6d315d557758bfa9c057"}, + {file = "coverage-7.5.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef48e2707fb320c8f139424a596f5b69955a85b178f15af261bab871873bb987"}, + {file = "coverage-7.5.1-cp311-cp311-win32.whl", hash = "sha256:9314d5678dcc665330df5b69c1e726a0e49b27df0461c08ca12674bcc19ef136"}, + {file = "coverage-7.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fa567e99765fe98f4e7d7394ce623e794d7cabb170f2ca2ac5a4174437e90dd"}, + {file = "coverage-7.5.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6cf3764c030e5338e7f61f95bd21147963cf6aa16e09d2f74f1fa52013c1206"}, + {file = "coverage-7.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ec92012fefebee89a6b9c79bc39051a6cb3891d562b9270ab10ecfdadbc0c34"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16db7f26000a07efcf6aea00316f6ac57e7d9a96501e990a36f40c965ec7a95d"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beccf7b8a10b09c4ae543582c1319c6df47d78fd732f854ac68d518ee1fb97fa"}, + {file = "coverage-7.5.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8748731ad392d736cc9ccac03c9845b13bb07d020a33423fa5b3a36521ac6e4e"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7352b9161b33fd0b643ccd1f21f3a3908daaddf414f1c6cb9d3a2fd618bf2572"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a588d39e0925f6a2bff87154752481273cdb1736270642aeb3635cb9b4cad07"}, + {file = "coverage-7.5.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:68f962d9b72ce69ea8621f57551b2fa9c70509af757ee3b8105d4f51b92b41a7"}, + {file = "coverage-7.5.1-cp312-cp312-win32.whl", hash = "sha256:f152cbf5b88aaeb836127d920dd0f5e7edff5a66f10c079157306c4343d86c19"}, + {file = "coverage-7.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:5a5740d1fb60ddf268a3811bcd353de34eb56dc24e8f52a7f05ee513b2d4f596"}, + {file = "coverage-7.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2213def81a50519d7cc56ed643c9e93e0247f5bbe0d1247d15fa520814a7cd7"}, + {file = "coverage-7.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5037f8fcc2a95b1f0e80585bd9d1ec31068a9bcb157d9750a172836e98bc7a90"}, + {file = "coverage-7.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3721c2c9e4c4953a41a26c14f4cef64330392a6d2d675c8b1db3b645e31f0e"}, + {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca498687ca46a62ae590253fba634a1fe9836bc56f626852fb2720f334c9e4e5"}, + {file = "coverage-7.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cdcbc320b14c3e5877ee79e649677cb7d89ef588852e9583e6b24c2e5072661"}, + {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:57e0204b5b745594e5bc14b9b50006da722827f0b8c776949f1135677e88d0b8"}, + {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fe7502616b67b234482c3ce276ff26f39ffe88adca2acf0261df4b8454668b4"}, + {file = "coverage-7.5.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9e78295f4144f9dacfed4f92935fbe1780021247c2fabf73a819b17f0ccfff8d"}, + {file = "coverage-7.5.1-cp38-cp38-win32.whl", hash = "sha256:1434e088b41594baa71188a17533083eabf5609e8e72f16ce8c186001e6b8c41"}, + {file = "coverage-7.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:0646599e9b139988b63704d704af8e8df7fa4cbc4a1f33df69d97f36cb0a38de"}, + {file = "coverage-7.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4cc37def103a2725bc672f84bd939a6fe4522310503207aae4d56351644682f1"}, + {file = "coverage-7.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc0b4d8bfeabd25ea75e94632f5b6e047eef8adaed0c2161ada1e922e7f7cece"}, + {file = "coverage-7.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d0a0f5e06881ecedfe6f3dd2f56dcb057b6dbeb3327fd32d4b12854df36bf26"}, + {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9735317685ba6ec7e3754798c8871c2f49aa5e687cc794a0b1d284b2389d1bd5"}, + {file = "coverage-7.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d21918e9ef11edf36764b93101e2ae8cc82aa5efdc7c5a4e9c6c35a48496d601"}, + {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3e757949f268364b96ca894b4c342b41dc6f8f8b66c37878aacef5930db61be"}, + {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:79afb6197e2f7f60c4824dd4b2d4c2ec5801ceb6ba9ce5d2c3080e5660d51a4f"}, + {file = "coverage-7.5.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1d0d98d95dd18fe29dc66808e1accf59f037d5716f86a501fc0256455219668"}, + {file = "coverage-7.5.1-cp39-cp39-win32.whl", hash = "sha256:1cc0fe9b0b3a8364093c53b0b4c0c2dd4bb23acbec4c9240b5f284095ccf7981"}, + {file = "coverage-7.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:dde0070c40ea8bb3641e811c1cfbf18e265d024deff6de52c5950677a8fb1e0f"}, + {file = "coverage-7.5.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:6537e7c10cc47c595828b8a8be04c72144725c383c4702703ff4e42e44577312"}, + {file = "coverage-7.5.1.tar.gz", hash = "sha256:54de9ef3a9da981f7af93eafde4ede199e0846cd819eb27c88e2b712aae9708c"}, ] [package.dependencies] @@ -336,13 +276,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.2.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, ] [package.extras] @@ -350,13 +290,13 @@ test = ["pytest (>=6)"] [[package]] name = "execnet" -version = "2.0.2" +version = "2.1.1" description = "execnet: rapid multi-Python deployment" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41"}, - {file = "execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af"}, + {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, + {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, ] [package.extras] @@ -364,29 +304,29 @@ testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "filelock" -version = "3.13.1" +version = "3.14.0" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, + {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, ] [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)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] [[package]] name = "identify" -version = "2.5.35" +version = "2.5.36" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.35-py2.py3-none-any.whl", hash = "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e"}, - {file = "identify-2.5.35.tar.gz", hash = "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791"}, + {file = "identify-2.5.36-py2.py3-none-any.whl", hash = "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa"}, + {file = "identify-2.5.36.tar.gz", hash = "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d"}, ] [package.extras] @@ -416,22 +356,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.1" +version = "7.1.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" 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.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, + {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, ] [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"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "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"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "inflection" @@ -455,20 +395,6 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[[package]] -name = "isort" -version = "5.13.2" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, -] - -[package.extras] -colors = ["colorama (>=0.4.6)"] - [[package]] name = "jinja2" version = "3.1.4" @@ -708,17 +634,6 @@ files = [ {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, ] -[[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" -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"}, -] - [[package]] name = "myst-parser" version = "2.0.0" @@ -761,50 +676,40 @@ setuptools = "*" [[package]] name = "packaging" -version = "23.2" +version = "24.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] name = "platformdirs" -version = "4.2.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.2.1" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, - {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, + {file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"}, + {file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"}, ] [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)"] +type = ["mypy (>=1.8)"] [[package]] name = "pluggy" -version = "1.4.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -850,28 +755,27 @@ virtualenv = ">=20.10.0" [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" -version = "8.0.2" +version = "8.2.0" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.0.2-py3-none-any.whl", hash = "sha256:edfaaef32ce5172d5466b5127b42e0d6d35ebbe4453f0e3505d96afd93f6b096"}, - {file = "pytest-8.0.2.tar.gz", hash = "sha256:d4051d623a2e0b7e51960ba963193b09ce6daeb9759a451844a21e4ddedfc1bd"}, + {file = "pytest-8.2.0-py3-none-any.whl", hash = "sha256:1733f0620f6cda4095bbf0d9ff8022486e91892245bb9e7d5542c018f612f233"}, + {file = "pytest-8.2.0.tar.gz", hash = "sha256:d507d4482197eac0ba2bae2e9babf0672eb333017bcedaa5fb1a3d42c1174b3f"}, ] [package.dependencies] @@ -879,11 +783,11 @@ 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\""} +pluggy = ">=1.5,<2.0" +tomli = {version = ">=1", 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"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" @@ -935,18 +839,18 @@ vcrpy = "*" [[package]] name = "pytest-xdist" -version = "3.5.0" +version = "3.6.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-xdist-3.5.0.tar.gz", hash = "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a"}, - {file = "pytest_xdist-3.5.0-py3-none-any.whl", hash = "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24"}, + {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, + {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, ] [package.dependencies] -execnet = ">=1.1" -pytest = ">=6.2.0" +execnet = ">=2.1" +pytest = ">=7.0.0" [package.extras] psutil = ["psutil (>=3.0)"] @@ -1013,7 +917,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1021,16 +924,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {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"}, @@ -1047,7 +942,6 @@ files = [ {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"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1055,7 +949,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1082,20 +975,46 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "ruff" +version = "0.3.7" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e8377cccb2f07abd25e84fc5b2cbe48eeb0fea9f1719cad7caedb061d70e5ce"}, + {file = "ruff-0.3.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:15a4d1cc1e64e556fa0d67bfd388fed416b7f3b26d5d1c3e7d192c897e39ba4b"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28bdf3d7dc71dd46929fafeec98ba89b7c3550c3f0978e36389b5631b793663"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:379b67d4f49774ba679593b232dcd90d9e10f04d96e3c8ce4a28037ae473f7bb"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c060aea8ad5ef21cdfbbe05475ab5104ce7827b639a78dd55383a6e9895b7c51"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ebf8f615dde968272d70502c083ebf963b6781aacd3079081e03b32adfe4d58a"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48098bd8f5c38897b03604f5428901b65e3c97d40b3952e38637b5404b739a2"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da8a4fda219bf9024692b1bc68c9cff4b80507879ada8769dc7e985755d662ea"}, + {file = "ruff-0.3.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c44e0149f1d8b48c4d5c33d88c677a4aa22fd09b1683d6a7ff55b816b5d074f"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3050ec0af72b709a62ecc2aca941b9cd479a7bf2b36cc4562f0033d688e44fa1"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a29cc38e4c1ab00da18a3f6777f8b50099d73326981bb7d182e54a9a21bb4ff7"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b15cc59c19edca917f51b1956637db47e200b0fc5e6e1878233d3a938384b0b"}, + {file = "ruff-0.3.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e491045781b1e38b72c91247cf4634f040f8d0cb3e6d3d64d38dcf43616650b4"}, + {file = "ruff-0.3.7-py3-none-win32.whl", hash = "sha256:bc931de87593d64fad3a22e201e55ad76271f1d5bfc44e1a1887edd0903c7d9f"}, + {file = "ruff-0.3.7-py3-none-win_amd64.whl", hash = "sha256:5ef0e501e1e39f35e03c2acb1d1238c595b8bb36cf7a170e7c1df1b73da00e74"}, + {file = "ruff-0.3.7-py3-none-win_arm64.whl", hash = "sha256:789e144f6dc7019d1f92a812891c645274ed08af6037d11fc65fcbc183b7d59f"}, + {file = "ruff-0.3.7.tar.gz", hash = "sha256:d5c1aebee5162c2226784800ae031f660c350e7a3402c4d1f8ea4e97e232e3ba"}, +] + [[package]] name = "setuptools" -version = "69.1.1" +version = "69.5.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, - {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, + {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"}, + {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"}, ] [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"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "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)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "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]] @@ -1303,13 +1222,13 @@ files = [ [[package]] name = "typing-extensions" -version = "4.10.0" +version = "4.11.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, - {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] [[package]] @@ -1366,13 +1285,13 @@ tests = ["Werkzeug (==2.0.3)", "aiohttp", "boto3", "httplib2", "httpx", "pytest" [[package]] name = "virtualenv" -version = "20.25.1" +version = "20.26.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, - {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, + {file = "virtualenv-20.26.1-py3-none-any.whl", hash = "sha256:7aa9982a728ae5892558bff6a2839c00b9ed145523ece2274fad6f414690ae75"}, + {file = "virtualenv-20.26.1.tar.gz", hash = "sha256:604bfdceaeece392802e6ae48e69cec49168b9c5f4a44e483963f9242eb0e78b"}, ] [package.dependencies] @@ -1381,7 +1300,7 @@ 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)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "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]] @@ -1568,20 +1487,20 @@ multidict = ">=4.0" [[package]] name = "zipp" -version = "3.17.0" +version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [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"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "818bed90bdcf471c5bd20d3792411c76a119f07a40ad899b0ad91a7125030de4" +content-hash = "4733215c87b487b90c900694fbd2b99ad031934515d9e0cda40ac0eaef2768f1" diff --git a/pyproject.toml b/pyproject.toml index c1b8ded..968c38b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "welkin" -version = "0.1.2" +version = "0.1.3" description = "Python Welkin Health API Wrapper." authors = ["Sam Morgan "] license = "GPL-3.0-or-later" @@ -23,9 +23,8 @@ portalocker = "^2.8.2" inflection = "^0.5.1" [tool.poetry.group.dev.dependencies] -black = ">=22.10,<25.0" -isort = "^5.10.1" pre-commit = "^3.5.0" +ruff = "^0.3.6" [tool.poetry.group.test.dependencies] pytest = "^8.0.2" @@ -44,8 +43,9 @@ myst-parser = "^2.0.0" requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" -[tool.isort] -profile = "black" +[tool.coverage.report] +# Regexes for lines to exclude from consideration +exclude_also = ["if TYPE_CHECKING:"] [tool.coverage.run] omit = ["test/*"] @@ -53,3 +53,61 @@ omit = ["test/*"] [tool.pytest.ini_options] addopts = ["-n=auto"] env_files = [".env", ".env.example"] + +[tool.ruff] +cache-dir = "~/.cache/ruff" +extend-exclude = ["*migrations/*"] +line-length = 92 +target-version = "py38" +show-fixes = true + +[tool.ruff.lint] +ignore = [ + "D1", # Missing docstrings + "D205", # 1 blank line required between summary line and description (does not allow wrapping of summary lines) + "D407", # Dashed underline after doc section (not compatible with google style) +] +select = [ # https://docs.astral.sh/ruff/rules + "F", # pyflakes + "E", # pycodestyle + "W", # pycodestyle + "C90", # mccabe + "I", # isort + "N", # pep8-naming + "D", # pydocstyle + "UP", # pyupgrade + "B", # flake8-bugbear + "S", # flake8-bandit + "A", # flake8-builtins + "C4", # flake8-comprehensions + "DTZ", # flake8-datetimez + "ISC", # flake8-implicit-str-concat + "EXE", # flake8-executable + "PT", # flake8-pytest-style + "Q", # flake8-quotes + "RET", # flake8-return + "TCH", # flake8-type-checking + "SIM", # flake8-simplify + "T20", # flake8-print + "TID", # flake8-tidy-imports + "ERA", # eradicate + "PL", # pylint + "RUF", # ruff +] +unfixable = ["D407"] + +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false + +[tool.ruff.lint.isort] +combine-as-imports = true + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["E402"] +"**/{tests,docs}/*" = ["S", "PLR2004", "PLR0913"] +"**/conftest.py" = ["S", "PLR2004", "PLR0913"] +"**/test*.py" = ["S", "PLR2004", "PLR0913"] + +[tool.ruff.lint.pydocstyle] +convention = "google" diff --git a/test/conftest.py b/test/conftest.py index 654ddf2..cacb3e8 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import inspect import json import os @@ -5,7 +7,6 @@ from datetime import date, datetime, time, timedelta, timezone from http import HTTPStatus from pathlib import Path -from uuid import uuid4 import pytest @@ -15,7 +16,7 @@ def pytest_collection_modifyitems(items): # Ensure auth tests execute first, otherwise all other tests will fail. - items.sort(key=lambda x: True if "authentication" not in x.nodeid else False) + items.sort(key=lambda x: "authentication" not in x.nodeid) def redact(field_name, extra=""): @@ -34,12 +35,12 @@ def redact(field_name, extra=""): "updatedBy", "updatedByName", ] -CLIENT_INIT = dict( - tenant=os.environ["WELKIN_TENANT"], - instance=os.environ["WELKIN_INSTANCE"], - api_client=os.environ["WELKIN_API_CLIENT"], - secret_key=os.environ["WELKIN_SECRET"], -) +CLIENT_INIT = { + "tenant": os.environ["WELKIN_TENANT"], + "instance": os.environ["WELKIN_INSTANCE"], + "api_client": os.environ["WELKIN_API_CLIENT"], + "secret_key": os.environ["WELKIN_SECRET"], +} @pytest.fixture(scope="module") @@ -61,7 +62,6 @@ def vcr(vcr): def scrub_request(blacklist, replacement="REDACTED"): def before_record_request(request): - # request.body = filter_body(request.body, blacklist, replacement) if "api_clients" in request.path: return None uri_comps = request.uri.split("/") @@ -188,5 +188,5 @@ def est_datetime_str(): @pytest.fixture -def _uuid(): - return uuid4() +def uuid4(): + return uuid.uuid4() diff --git a/test/test_assessments.py b/test/test_assessments.py index 034b8f0..8924e29 100644 --- a/test/test_assessments.py +++ b/test/test_assessments.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from welkin.exceptions import WelkinHTTPError @@ -8,14 +10,10 @@ def test_assessment_record_answers_update(client, vcr_cassette): patient = client.Patient(id="371dd15c-cedc-4425-a394-d666c8d3fc01") - assmt_record = patient.AssessmentRecord( - id="c8764b19-ffa3-406a-b446-c971036a7a1d" - ).get() + assmt_record = patient.AssessmentRecord(id="c8764b19-ffa3-406a-b446-c971036a7a1d").get() hi_answer = assmt_record.answers["cdt-hello__cdtf-hi"] assmt_record.AssessmentRecordAnswers(**{"cdt-hello__cdtf-hi": "abc123def"}).update() - assmt_record = patient.AssessmentRecord( - id="c8764b19-ffa3-406a-b446-c971036a7a1d" - ).get() + assmt_record = patient.AssessmentRecord(id="c8764b19-ffa3-406a-b446-c971036a7a1d").get() assert assmt_record.answers["cdt-hello__cdtf-hi"] == "abc123def" assert hi_answer != assmt_record.answers["cdt-hello__cdtf-hi"] @@ -26,9 +24,7 @@ def test_assessment_record_answers_update(client, vcr_cassette): def test_assessment_record_get(client, vcr_cassette): patient = client.Patient(id="371dd15c-cedc-4425-a394-d666c8d3fc01") - assmt_record = patient.AssessmentRecord( - id="c8764b19-ffa3-406a-b446-c971036a7a1d" - ).get() + assmt_record = patient.AssessmentRecord(id="c8764b19-ffa3-406a-b446-c971036a7a1d").get() assert isinstance(assmt_record, AssessmentRecord) assert assmt_record.id == "c8764b19-ffa3-406a-b446-c971036a7a1d" @@ -37,9 +33,9 @@ def test_assessment_record_get(client, vcr_cassette): @pytest.mark.vcr def test_assessment_record_get_w_patient_id(client, vcr_cassette): - assmt_record = client.AssessmentRecord( - id="c8764b19-ffa3-406a-b446-c971036a7a1d" - ).get(patient_id="371dd15c-cedc-4425-a394-d666c8d3fc01") + assmt_record = client.AssessmentRecord(id="c8764b19-ffa3-406a-b446-c971036a7a1d").get( + patient_id="371dd15c-cedc-4425-a394-d666c8d3fc01" + ) assert isinstance(assmt_record, AssessmentRecord) assert assmt_record.id == "c8764b19-ffa3-406a-b446-c971036a7a1d" @@ -50,9 +46,7 @@ def test_assessment_record_get_w_patient_id(client, vcr_cassette): def test_assessment_record_update(client, vcr_cassette): patient = client.Patient(id="371dd15c-cedc-4425-a394-d666c8d3fc01") - assmt_record = patient.AssessmentRecord( - id="e18a2759-5089-44e7-9d31-cf942476ffab" - ).get() + assmt_record = patient.AssessmentRecord(id="e18a2759-5089-44e7-9d31-cf942476ffab").get() status = assmt_record.status assmt_record.status = "COMPLETED" @@ -84,8 +78,7 @@ def test_assessment_record_delete(client, vcr_cassette): with pytest.raises(WelkinHTTPError) as excinfo: assmt_record.get() - assert excinfo.value.response.status_code == 404 - + assert excinfo.value.response.status_code == 404 assert len(vcr_cassette) == 2 diff --git a/test/test_authentication.py b/test/test_authentication.py index 9d731ac..4113bce 100644 --- a/test/test_authentication.py +++ b/test/test_authentication.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import dbm from pathlib import Path @@ -13,7 +15,7 @@ def auth_class(client): auth.token_method = lambda: {"token": "API_TOKEN"} try: - auth.token + auth.token # noqa: B018 except dbm.error: Path(DB_PATH).unlink() return auth_class(client) diff --git a/test/test_base.py b/test/test_base.py index 9531f54..127eb0d 100644 --- a/test/test_base.py +++ b/test/test_base.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import inspect import pytest @@ -31,7 +33,8 @@ def test_method_args(client, class_name: str): continue # skip dunder methods if hasattr(method, "__wrapped__"): - method = method.__wrapped__ # unwrap decorated functions + # unwrap decorated functions + method = method.__wrapped__ # noqa: PLW2901 if method.__qualname__ != f"{class_name}.{method_name}": continue # skip methods from parent classes diff --git a/test/test_calendar.py b/test/test_calendar.py index 6af58f9..4532765 100644 --- a/test/test_calendar.py +++ b/test/test_calendar.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from datetime import datetime, timedelta, timezone import pytest @@ -8,7 +10,6 @@ CalendarEvents, Schedule, Schedules, - WorkHours, ) UTC = timezone.utc diff --git a/test/test_care_plan.py b/test/test_care_plan.py index 8e7e088..3adb51a 100644 --- a/test/test_care_plan.py +++ b/test/test_care_plan.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from welkin.models import CarePlan diff --git a/test/test_cdts.py b/test/test_cdts.py index 1d07893..e3cee98 100644 --- a/test/test_cdts.py +++ b/test/test_cdts.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from welkin.exceptions import WelkinHTTPError @@ -100,6 +102,5 @@ def test_cdt_delete(client, vcr_cassette): with pytest.raises(WelkinHTTPError) as excinfo: cdt.get() - assert excinfo.value.response.status_code == 404 - + assert excinfo.value.response.status_code == 404 assert len(vcr_cassette) == 3 diff --git a/test/test_chat.py b/test/test_chat.py index a9cdda4..74532e9 100644 --- a/test/test_chat.py +++ b/test/test_chat.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from welkin.models.chat import Chat, Chats, ChatSearchResult, SearchChats diff --git a/test/test_client.py b/test/test_client.py index c022cb8..b303542 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import inspect import pytest diff --git a/test/test_document.py b/test/test_document.py index b52253b..5405ee9 100644 --- a/test/test_document.py +++ b/test/test_document.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from io import BytesIO import pytest @@ -25,9 +27,7 @@ def test_document_summaries_get_patient_id(client, vcr_cassette): @pytest.mark.vcr def test_document_summaries_subresource(client, vcr_cassette): documents = ( - client.Patient(id="283f50d3-0840-426f-b07b-bd8e4ab76401") - .DocumentSummaries() - .get() + client.Patient(id="283f50d3-0840-426f-b07b-bd8e4ab76401").DocumentSummaries().get() ) assert isinstance(documents, DocumentSummaries) @@ -50,17 +50,16 @@ def test_document_summary_get(client, vcr_cassette): @pytest.mark.vcr def test_document_summary_delete(client, vcr_cassette): - document = client.Patient( - id="283f50d3-0840-426f-b07b-bd8e4ab76401" - ).DocumentSummary(id="5106ec9d-da83-4ce6-89d0-6a9b7fde0138") + document = client.Patient(id="283f50d3-0840-426f-b07b-bd8e4ab76401").DocumentSummary( + id="5106ec9d-da83-4ce6-89d0-6a9b7fde0138" + ) document.delete() with pytest.raises(WelkinHTTPError) as excinfo: document.get() - assert excinfo.value.response.status_code == 404 - + assert excinfo.value.response.status_code == 404 assert len(vcr_cassette) == 2 @@ -79,7 +78,11 @@ def test_document_summary_create(client, vcr_cassette): @pytest.mark.vcr @pytest.mark.skip( - reason="the bytes upload hits this issue in vcr: https://github.com/kevin1024/vcrpy/issues/660 but this test shows the correct implementation" + reason=( + "the bytes upload hits this issue in vcr: " + "https://github.com/kevin1024/vcrpy/issues/660 " + "but this test shows the correct implementation" + ) ) def test_document_summary_files_create(client, vcr_cassette): with open("test/walrus_uJGKbRm.jpeg", "rb") as f: diff --git a/test/test_email.py b/test/test_email.py index e8a42bd..ab340b0 100644 --- a/test/test_email.py +++ b/test/test_email.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from welkin.exceptions import WelkinHTTPError diff --git a/test/test_encounters.py b/test/test_encounters.py index 1e5d159..a6ff19c 100644 --- a/test/test_encounters.py +++ b/test/test_encounters.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from datetime import datetime, timedelta, timezone import pytest @@ -121,8 +123,7 @@ def test_encounter_delete(client, vcr_cassette): with pytest.raises(WelkinHTTPError) as excinfo: encounter.get() - assert excinfo.value.response.status_code == 404 - + assert excinfo.value.response.status_code == 404 assert len(vcr_cassette) == 3 @@ -242,8 +243,7 @@ def test_encounter_assessment_delete(client, vcr_cassette): with pytest.raises(WelkinHTTPError) as excinfo: assessment.get() - assert excinfo.value.response.status_code == 404 - + assert excinfo.value.response.status_code == 404 assert len(vcr_cassette) == 2 diff --git a/test/test_exception.py b/test/test_exception.py index 833d56a..d0cb8ab 100644 --- a/test/test_exception.py +++ b/test/test_exception.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import json import pytest diff --git a/test/test_formation.py b/test/test_formation.py index 953c443..8b88ad1 100644 --- a/test/test_formation.py +++ b/test/test_formation.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from welkin.models.formation import ( @@ -88,9 +90,7 @@ def test_encounters_read(self, formation, vcr_cassette): @pytest.mark.vcr def test_encounter_read(self, formation, vcr_cassette): - encounter_template = formation.Encounter( - name="etmp-coaching-introduction" - ).get() + encounter_template = formation.Encounter(name="etmp-coaching-introduction").get() assert isinstance(encounter_template, Encounter) assert encounter_template.name == "etmp-coaching-introduction" diff --git a/test/test_patients.py b/test/test_patients.py index c768851..716365c 100644 --- a/test/test_patients.py +++ b/test/test_patients.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from datetime import date import pytest @@ -18,7 +20,9 @@ def test_patient_create(client, vcr_cassette): @pytest.mark.vcr def test_patient_create_birthdate(client, vcr_cassette): patient = client.Patient( - firstName="happy", lastName="borf", birthDate=date.today() + firstName="happy", + lastName="borf", + birthDate=date.today(), # noqa: DTZ011 ).create() assert isinstance(patient, Patient) diff --git a/test/test_program.py b/test/test_program.py index 55a7c8f..c6895ab 100644 --- a/test/test_program.py +++ b/test/test_program.py @@ -1,8 +1,10 @@ +from __future__ import annotations + from http import HTTPStatus +from typing import TYPE_CHECKING import pytest -from welkin import Client from welkin.exceptions import WelkinHTTPError from welkin.models import ( Patient, @@ -11,7 +13,10 @@ ProgramPhase, ProgramPhases, ) -from welkin.models.formation import Program + +if TYPE_CHECKING: + from welkin import Client + from welkin.models.formation import Program @pytest.mark.vcr @@ -60,9 +65,7 @@ def patient_program( "programName", ], ) - def test_read( - self, patient: Patient, patient_program: PatientProgram, identifier: str - ): + def test_read(self, patient: Patient, patient_program: PatientProgram, identifier: str): prog = patient.PatientProgram( **{identifier: getattr(patient_program, identifier)} ).get() @@ -74,7 +77,7 @@ def test_read( assert prog.id == patient_program.id def test_read_no_id(self, client): - with pytest.raises(ValueError): + with pytest.raises(ValueError, match="Program must have"): client.Patient(id="notarealid").PatientProgram().get() def test_update( diff --git a/test/test_sms.py b/test/test_sms.py index c596232..62679f8 100644 --- a/test/test_sms.py +++ b/test/test_sms.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from welkin.exceptions import WelkinHTTPError diff --git a/test/test_users.py b/test/test_users.py index 54044a7..27d4c4f 100644 --- a/test/test_users.py +++ b/test/test_users.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pytest from welkin.exceptions import WelkinHTTPError diff --git a/test/test_util.py b/test/test_util.py index 4f58f19..adebb3c 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import copy import sys @@ -17,7 +19,7 @@ class TestCleanRequestPayload: @pytest.fixture - def payload(self, _uuid, base_date, utc_datetime, pst_datetime): + def payload(self, uuid4, base_date, utc_datetime, pst_datetime): return { "datetime": pst_datetime, "date": base_date, @@ -30,12 +32,12 @@ def payload(self, _uuid, base_date, utc_datetime, pst_datetime): "int": [-sys.maxsize, 0, sys.maxsize], "float": [sys.float_info.min, 1, sys.float_info.max], "bool": [True, False], - "_uuid4": _uuid, + "uuid4": uuid4, "none": None, } def test_clean_request_payload( - self, payload, _uuid, pst_datetime_str, base_date_str, utc_datetime_str + self, payload, uuid4, pst_datetime_str, base_date_str, utc_datetime_str ): payload_copy = copy.deepcopy(payload) cleaned = clean_request_payload(payload) @@ -45,7 +47,7 @@ def test_clean_request_payload( assert cleaned["date"] == base_date_str assert cleaned["dict"]["nested"]["date"] == base_date_str assert cleaned["list"][0] == utc_datetime_str - assert cleaned["_uuid4"] == str(_uuid) + assert cleaned["uuid4"] == str(uuid4) class TestCleanJsonList: @@ -98,20 +100,11 @@ def test_clean_date(base_date, base_date_str): @pytest.mark.parametrize( - "dt,expected", + ("dt", "expected"), [ - ( - "utc_datetime", - "utc_datetime_str", - ), - ( - "pst_datetime", - "pst_datetime_str", - ), - ( - "est_datetime", - "est_datetime_str", - ), + ("utc_datetime", "utc_datetime_str"), + ("pst_datetime", "pst_datetime_str"), + ("est_datetime", "est_datetime_str"), ], ) def test_clean_datetime(dt, expected, request): @@ -120,7 +113,7 @@ def test_clean_datetime(dt, expected, request): @pytest.mark.parametrize( - "input", + "string", [ "foo_bar", "fooBar", @@ -130,9 +123,9 @@ def test_clean_datetime(dt, expected, request): "FOOBar", ], ) -def test_case_converters(input): - assert to_camel_case(input) == "fooBar" - assert to_snake_case(input) == "foo_bar" +def test_case_converters(string): + assert to_camel_case(string) == "fooBar" + assert to_snake_case(string) == "foo_bar" def test_find_model_id(client): diff --git a/welkin/__init__.py b/welkin/__init__.py index 976679b..c57cc8d 100644 --- a/welkin/__init__.py +++ b/welkin/__init__.py @@ -1,4 +1,4 @@ -"""Welkin Health API wrapper +"""Welkin Health API wrapper. https://developers.welkinhealth.com/ @@ -45,6 +45,9 @@ For this example we will assume Client Name is VBOPNRYRWJIP and Secret Key is +}B{KGTG6#zG%P;tQm0C """ + +# ruff: noqa: F401 + from welkin.__version__ import ( __author__, __author_email__, diff --git a/welkin/__version__.py b/welkin/__version__.py index 48905ff..3a46c21 100644 --- a/welkin/__version__.py +++ b/welkin/__version__.py @@ -1,14 +1,21 @@ """Package version information.""" -from datetime import date + +from __future__ import annotations + +from datetime import datetime, timezone from importlib.metadata import distribution +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from importlib.metadata._adapters import Message -_dist_metadata: dict = distribution("welkin").metadata.json +_metadata: Message = distribution("welkin").metadata -__title__ = _dist_metadata["name"] -__description__ = _dist_metadata["summary"] -__url__ = _dist_metadata["home_page"] -__version__ = _dist_metadata["version"] -__author__ = _dist_metadata["author"] -__author_email__ = _dist_metadata["author_email"] -__license__ = _dist_metadata["license"] -__copyright__ = f"{date.today().year} Lightmatter" +__title__ = _metadata.get("Name") +__description__ = _metadata.get("Summary") +__url__ = _metadata.get("Home-page") +__version__ = _metadata.get("Version") +__author__ = _metadata.get("Author") +__author_email__ = _metadata.get("Author-email") +__license__ = _metadata.get("License") +__copyright__ = f"{datetime.now(tz=timezone.utc):%Y} Lightmatter" diff --git a/welkin/authentication.py b/welkin/authentication.py index f722538..e62d573 100644 --- a/welkin/authentication.py +++ b/welkin/authentication.py @@ -1,13 +1,18 @@ +from __future__ import annotations + import logging import shelve import tempfile from pathlib import Path -from typing import Callable +from typing import TYPE_CHECKING, Callable from portalocker import Lock -from requests import PreparedRequest from requests.auth import AuthBase +if TYPE_CHECKING: + from requests import PreparedRequest + + logger = logging.getLogger(__name__) @@ -50,12 +55,11 @@ def __call__(self, r: PreparedRequest) -> PreparedRequest: @property def token(self) -> str: - with Lock(DB_LOCK): - with shelve.open(DB_PATH) as db: - try: - return db[self.tenant]["token"] - except KeyError: - pass + with Lock(DB_LOCK), shelve.open(DB_PATH) as db: # noqa: S301 + try: + return db[self.tenant]["token"] + except KeyError: + pass self.refresh_token() @@ -63,9 +67,8 @@ def token(self) -> str: @token.setter def token(self, value: dict) -> None: - with Lock(DB_LOCK): - with shelve.open(DB_PATH) as db: - db[self.tenant] = value + with Lock(DB_LOCK), shelve.open(DB_PATH) as db: # noqa: S301 + db[self.tenant] = value def refresh_token(self) -> None: self.token = self.token_method() diff --git a/welkin/client.py b/welkin/client.py index 79b56ef..1be0936 100644 --- a/welkin/client.py +++ b/welkin/client.py @@ -1,7 +1,10 @@ -"""Client +"""Client. This module provides a Client object to interface with the Welkin Health API. """ + +from __future__ import annotations + import logging from http import HTTPStatus from json import JSONDecodeError @@ -62,7 +65,7 @@ class Client(Session): user = welkin.User(id="301b2895-cbf0-4cac-b4cf-1d082faee95c").get() # Read users = welkin.Users().get() # Read all/list uasers = welkin.Users().get( - search="lightmatter", region="east-coast", seat_assigned=True, user_state="ACTIVE" + search="foo", region="east-coast", seat_assigned=True, user_state="ACTIVE" ) # Filtered read all/list user.update(firstName="Baz") # Update @@ -106,7 +109,7 @@ class Client(Session): Users = models.Users WorkHours = models.WorkHours - def __init__( + def __init__( # noqa: PLR0913 self, tenant, instance, @@ -171,12 +174,12 @@ def prepare_request(self, request): return super().prepare_request(request) - def request( + def request( # noqa: C901, PLR0912 self, method: str, path: str, - meta_key: str = None, - meta_dict: dict = {}, + meta_key: str | None = None, + meta_dict: dict | None = None, *args, **kwargs, ): @@ -185,17 +188,23 @@ def request( Args: method (str): Method for the new Request object. path (str): Path from host for the new Request object. + meta_key (str | None, optional): Key for metadata in the response JSON. + Defaults to None. + meta_dict (dict | None, optional): Metadata dictionary for the response JSON. + Defaults to None. + *args: Arguments to pass to `Session.request`. + **kwargs: Keyword arguments to pass to `Session.request`. Returns: dict: Response JSON """ if not isinstance(path, str): - path = "/".join((str(s) for s in path if s)) + path = "/".join(str(s) for s in path if s) path = path.rstrip("/") for _ in range(2): response = super().request( - method=method, url=urljoin(self.host, path), *args, **kwargs + *args, method=method, url=urljoin(self.host, path), **kwargs ) try: @@ -268,10 +277,10 @@ def request( return resource or json def get_token(self) -> dict: - data = {"secret": self.auth.secret_key} - response = self.post(f"admin/api_clients/{self.auth.api_client}", json=data) - - return response + return self.post( + f"admin/api_clients/{self.auth.api_client}", + json={"secret": self.auth.secret_key}, + ) class TimeoutHTTPAdapter(HTTPAdapter): @@ -281,6 +290,8 @@ def __init__(self, timeout, *args, **kwargs): Args: timeout (int): How many seconds to wait for the server to send data before giving up. + *args: Arguments to pass to `HTTPAdapter`. + **kwargs: Keyword arguments to pass to `HTTPAdapter`. """ self.timeout = timeout super().__init__(*args, **kwargs) diff --git a/welkin/exceptions.py b/welkin/exceptions.py index 39392cd..af34fff 100644 --- a/welkin/exceptions.py +++ b/welkin/exceptions.py @@ -1,3 +1,6 @@ +from __future__ import annotations + +import contextlib import json from requests import HTTPError @@ -22,9 +25,7 @@ def __init__(self, exc): response = exc.response msg = exc.args[0] - try: + with contextlib.suppress(json.JSONDecodeError): msg = f"{msg}\n{json.dumps(response.json(), indent=2)}" - except json.JSONDecodeError: - pass super(HTTPError, self).__init__(msg, request=request, response=response) diff --git a/welkin/models/assessment.py b/welkin/models/assessment.py index 457c490..dda1f08 100644 --- a/welkin/models/assessment.py +++ b/welkin/models/assessment.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from welkin.models.base import Collection, Resource from welkin.pagination import PageableIterator from welkin.util import model_id @@ -58,7 +60,7 @@ def update(self, patient_id: str, assessment_record_id: str): class AssessmentRecord(Resource): - subresources = [AssessmentRecordAnswers] + subresources = (AssessmentRecordAnswers,) @model_id("Patient") def create(self, patient_id: str): diff --git a/welkin/models/base.py b/welkin/models/base.py index a438c8c..489842f 100644 --- a/welkin/models/base.py +++ b/welkin/models/base.py @@ -1,4 +1,7 @@ +from __future__ import annotations + import sys +from types import MappingProxyType from welkin.pagination import PageIterator @@ -6,7 +9,7 @@ class SchemaBase: _client = None _parent = None - subresources = [] + subresources = () def __getattr__(self, name): try: @@ -25,7 +28,7 @@ def __getattr__(self, name): class Resource(dict, SchemaBase): - nested_objects = {} + nested_objects = MappingProxyType({}) def __getattr__(self, name): try: @@ -49,7 +52,7 @@ def __delattr__(self, name): super().__delitem__(name) def __str__(self): - id = getattr(self, "id", "") + id = getattr(self, "id", "") # noqa: A001 return f"{self.__class__.__name__} #{id}" if id else self.__class__.__name__ @@ -65,8 +68,8 @@ def get(self, resource, subresource=None, *args, **kwargs): def patch(self, resource, data, *args, **kwargs): response = self._client.patch( resource, - json=data, *args, + json=data, **kwargs, ) @@ -77,8 +80,8 @@ def patch(self, resource, data, *args, **kwargs): def post(self, resource, *args, **kwargs): response = self._client.post( resource, - json=self, *args, + json=self, **kwargs, ) super().update(response) @@ -88,8 +91,8 @@ def post(self, resource, *args, **kwargs): def put(self, resource, *args, **kwargs): response = self._client.put( resource, - json=self, *args, + json=self, **kwargs, ) diff --git a/welkin/models/calendar.py b/welkin/models/calendar.py index 90b1cff..dfb49b1 100644 --- a/welkin/models/calendar.py +++ b/welkin/models/calendar.py @@ -1,9 +1,14 @@ -from datetime import datetime, timezone +from __future__ import annotations + from enum import Enum +from typing import TYPE_CHECKING from welkin.models.base import Collection, Resource from welkin.pagination import PageableIterator +if TYPE_CHECKING: + from datetime import datetime + class EventType(Enum): GROUP_THERAPY = "GROUP_THERAPY" @@ -34,9 +39,7 @@ def get(self): return super().get(f"{self._client.instance}/calendar/events/{self.id}") def update(self, **kwargs): - return super().patch( - f"{self._client.instance}/calendar/events/{self.id}", kwargs - ) + return super().patch(f"{self._client.instance}/calendar/events/{self.id}", kwargs) def delete(self): return super().delete(f"{self._client.instance}/calendar/events/{self.id}") @@ -46,17 +49,17 @@ class CalendarEvents(Collection): resource = CalendarEvent iterator = PageableIterator - def get( + def get( # noqa: PLR0913 self, from_date: datetime, to_date: datetime, - participant_ids: list = None, - event_type: str = None, - sort: str = None, - include_cancelled: bool = None, - include_encounter_info: bool = None, - exclude_assigned_to_encounter_events: bool = None, - viewer_timezone: str = None, + participant_ids: list | None = None, + event_type: str | None = None, + sort: str | None = None, + include_cancelled: bool | None = None, + include_encounter_info: bool | None = None, + exclude_assigned_to_encounter_events: bool | None = None, + viewer_timezone: str | None = None, *args, **kwargs, ): @@ -78,7 +81,7 @@ def get( } return super().get( - f"{self._client.instance}/calendar/events", params=params, *args, **kwargs + f"{self._client.instance}/calendar/events", *args, params=params, **kwargs ) @@ -90,12 +93,12 @@ class Schedules(Collection): resource = Schedule iterator = PageableIterator - def get( + def get( # noqa: PLR0913 self, ids: list, from_date: datetime, to_date: datetime, - include_cancelled: bool = None, + include_cancelled: bool | None = None, available: bool = False, full: bool = False, *args, @@ -115,7 +118,7 @@ def get( } return super().get( - f"{self._client.instance}/calendar/{route}", params=params, *args, **kwargs + f"{self._client.instance}/calendar/{route}", *args, params=params, **kwargs ) @@ -126,8 +129,8 @@ def get( self, from_date: datetime, to_date: datetime, - psm_ids: list = None, - timezone: str = None, + psm_ids: list | None = None, + timezone: str | None = None, *args, **kwargs, ): @@ -146,7 +149,7 @@ def get( ) # When no work hours are found Welkin returns an {None: []} dictionary - if isinstance(response, dict) and None in response.keys(): + if isinstance(response, dict) and None in response: return WorkHours([]) return response diff --git a/welkin/models/care_plan.py b/welkin/models/care_plan.py index 1423b36..0b81112 100644 --- a/welkin/models/care_plan.py +++ b/welkin/models/care_plan.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from welkin.models.base import Resource from welkin.util import model_id @@ -11,7 +13,7 @@ def update(self, patient_id: str): class CarePlan(Resource): - subresources = [CarePlanOverview] + subresources = (CarePlanOverview,) @model_id("Patient") def create(self, patient_id: str): diff --git a/welkin/models/cdt.py b/welkin/models/cdt.py index 7d45588..65e682c 100644 --- a/welkin/models/cdt.py +++ b/welkin/models/cdt.py @@ -1,9 +1,14 @@ -from datetime import datetime +from __future__ import annotations + +from typing import TYPE_CHECKING from welkin.models.base import Collection, Resource from welkin.pagination import PageNumberIterator from welkin.util import model_id +if TYPE_CHECKING: + from datetime import datetime + class CDT(Resource): @model_id("Patient") @@ -37,15 +42,15 @@ class CDTs(Collection): iterator = PageNumberIterator @model_id("Patient") - def get( + def get( # noqa: PLR0913 self, patient_id: str, cdt_name: str, - fields: list = None, - filters: dict = None, - date_start: datetime = None, - date_end: datetime = None, - sort: str = None, + fields: list | None = None, + filters: dict | None = None, + date_start: datetime | None = None, + date_end: datetime | None = None, + sort: str | None = None, *args, **kwargs, ): @@ -59,13 +64,13 @@ def get( return super().get( f"{self._client.instance}/patients/{patient_id}/cdts/{cdt_name}", - params=params, *args, + params=params, **kwargs, ) @model_id("Patient") - def update(self, patient_id: str, cdt_name: str, body: dict = None, **kwargs): + def update(self, patient_id: str, cdt_name: str, body: dict | None = None, **kwargs): return super().patch( f"{self._client.instance}/patients/{patient_id}/cdts/{cdt_name}", json=body, diff --git a/welkin/models/chat.py b/welkin/models/chat.py index 64d8c3e..45c7434 100644 --- a/welkin/models/chat.py +++ b/welkin/models/chat.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from welkin.models.base import Collection, Resource from welkin.pagination import MetaIterator from welkin.util import model_id @@ -6,9 +8,7 @@ class Chat(Resource): @model_id("Patient") def create(self, patient_id: str): - return super().post( - f"{self._client.instance}/patients/{patient_id}/chat/inbound" - ) + return super().post(f"{self._client.instance}/patients/{patient_id}/chat/inbound") def __str__(self): return f"{self.sender['clientType']} {self.message}" @@ -26,8 +26,8 @@ def get(self, patient_id: str, include_archived: bool = False, *args, **kwargs): return super().get( f"{self._client.instance}/patients/{patient_id}/chat", - params=params, *args, + params=params, **kwargs, ) @@ -58,7 +58,7 @@ def get( return super().get( f"{self._client.instance}/patients/{patient_id}/chat/search", - params=params, *args, + params=params, **kwargs, ) diff --git a/welkin/models/document.py b/welkin/models/document.py index 5286338..27cbdb3 100644 --- a/welkin/models/document.py +++ b/welkin/models/document.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from io import BytesIO from welkin.models.base import Collection, Resource @@ -25,21 +27,21 @@ def create( self, patient_id: str, document_summary_id: str, - files: list = None, + files: list | None = None, *args, **kwargs, ): return super().post( f"{self._client.instance}/patients/{patient_id}/document-summary/" f"{document_summary_id}/files", - files=files, *args, + files=files, **kwargs, ) class DocumentSummary(Resource): - subresources = [DocumentSummaryFile, DocumentSummaryFiles] + subresources = (DocumentSummaryFile, DocumentSummaryFiles) @model_id("Patient") def get(self, patient_id: str): diff --git a/welkin/models/email.py b/welkin/models/email.py index 4890adc..4157ab8 100644 --- a/welkin/models/email.py +++ b/welkin/models/email.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from welkin.models.base import Collection, Resource from welkin.pagination import PageableIterator from welkin.util import model_id @@ -18,14 +20,14 @@ class Emails(Collection): iterator = PageableIterator @model_id("Patient") - def get(self, patient_id: str, sort: str = None, *args, **kwargs): + def get(self, patient_id: str, sort: str | None = None, *args, **kwargs): params = { "sort": sort, } return super().get( f"{self._client.instance}/patients/{patient_id}/emails", - params=params, *args, + params=params, **kwargs, ) diff --git a/welkin/models/encounter.py b/welkin/models/encounter.py index 49255e9..d9f29cd 100644 --- a/welkin/models/encounter.py +++ b/welkin/models/encounter.py @@ -1,4 +1,7 @@ +from __future__ import annotations + from enum import Enum +from types import MappingProxyType from welkin.models.assessment import Assessment, Assessments from welkin.models.base import Collection, Resource @@ -29,12 +32,14 @@ class EncounterStatus(Enum): class Encounter(Resource): - subresources = [Assessment, Assessments, EncounterDisposition] - nested_objects = { - "assessmentLinks": "Assessments", - "userRelatedToCalendarEvent": "User", - "disposition": "EncounterDisposition", - } + subresources = (Assessment, Assessments, EncounterDisposition) + nested_objects = MappingProxyType( + { + "assessmentLinks": "Assessments", + "userRelatedToCalendarEvent": "User", + "disposition": "EncounterDisposition", + } + ) @model_id("Patient") def create(self, patient_id: str): @@ -68,15 +73,15 @@ class Encounters(Collection): resource = Encounter iterator = MetaInfoIterator - def get( + def get( # noqa: PLR0913 self, - patient_id: str = None, - user_id: str = None, - related_data: bool = None, - with_care_team: bool = None, - only_with_calendar_event: bool = None, - statuses: list = None, - sort: str = None, + patient_id: str | None = None, + user_id: str | None = None, + related_data: bool | None = None, + with_care_team: bool | None = None, + only_with_calendar_event: bool | None = None, + statuses: list | None = None, + sort: str | None = None, *args, **kwargs, ): @@ -99,4 +104,4 @@ def get( "onlyWithCalendarEvent": only_with_calendar_event, } - return super().get(path, params=params, *args, **kwargs) + return super().get(path, *args, params=params, **kwargs) diff --git a/welkin/models/formation.py b/welkin/models/formation.py index 699dc49..f6e1660 100644 --- a/welkin/models/formation.py +++ b/welkin/models/formation.py @@ -1,4 +1,4 @@ -from typing import Union +from __future__ import annotations from welkin.models.base import Collection, Resource from welkin.pagination import FormationIterator @@ -10,9 +10,7 @@ class FormationBase: def __new__(cls, *args, **kwargs): if not cls.endpoint: - raise AttributeError( - f"The `endpoint` attribute must be set on {cls.__name__}" - ) + raise AttributeError(f"The `endpoint` attribute must be set on {cls.__name__}") return super().__new__(cls) @@ -116,7 +114,7 @@ class Formation(Target): Program = Program Programs = Programs - def __init__(self, version: Union[int, str] = "current"): + def __init__(self, version: int | str = "current"): super().__init__() self._base_path = f"{self._client.instance}/formations/{version}" diff --git a/welkin/models/patient.py b/welkin/models/patient.py index a565e91..3eea760 100644 --- a/welkin/models/patient.py +++ b/welkin/models/patient.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from welkin.models.assessment import AssessmentRecord, AssessmentRecords from welkin.models.base import Collection, Resource from welkin.models.care_plan import CarePlan @@ -16,7 +18,7 @@ class Patient(Resource): - subresources = [ + subresources = ( AssessmentRecord, AssessmentRecords, CarePlan, @@ -36,30 +38,30 @@ class Patient(Resource): SearchChats, SMS, SMSes, - ] + ) def create(self): return super().post(f"{self._client.instance}/patients") - def get(self, expand: bool = None): + def get(self, expand: bool | None = None): _id = None if hasattr(self, "id"): - type = None + _type = None _id = self.id elif hasattr(self, "externalId"): - type = "EID" + _type = "EID" _id = self.externalId elif hasattr(self, "externalGuid"): - type = "EGUID" + _type = "EGUID" _id = self.externalGuid elif hasattr(self, "mrn"): - type = "MRN" + _type = "MRN" _id = self.mrn return super().get( f"{self._client.instance}/patients/{_id}", params={ - "type": type, + "type": _type, expand: expand, }, ) @@ -78,8 +80,8 @@ class Patients(Collection): resource = Patient iterator = PageableIterator - def get(self, filter={}, *args, **kwargs): + def get(self, filter: dict | None = None, *args, **kwargs): # noqa: A002 # TODO: Add sort and query arguments. return super().post( - f"{self._client.instance}/by-filter/patients", json=filter, *args, **kwargs + f"{self._client.instance}/by-filter/patients", *args, json=filter, **kwargs ) diff --git a/welkin/models/program.py b/welkin/models/program.py index d451d56..637b7cb 100644 --- a/welkin/models/program.py +++ b/welkin/models/program.py @@ -1,3 +1,7 @@ +from __future__ import annotations + +from types import MappingProxyType + from welkin.models.base import Collection, Resource from welkin.pagination import MetaInfoIterator from welkin.util import model_id @@ -12,19 +16,21 @@ class ProgramPhases(Collection): class PatientProgram(Resource): - subresources = [ProgramPhase] - nested_objects = { - "phases": "ProgramPhase", - "currentPhase": "ProgramPhase", - "pathHistory": "ProgramPhases", - } + subresources = (ProgramPhase,) + nested_objects = MappingProxyType( + { + "phases": "ProgramPhase", + "currentPhase": "ProgramPhase", + "pathHistory": "ProgramPhases", + } + ) @model_id("Patient") def get( self, patient_id: str, - assigned_programs: bool = None, - sort: str = None, + assigned_programs: bool | None = None, + sort: str | None = None, *args, **kwargs, ): @@ -38,11 +44,11 @@ def get( return super().get( path, + *args, params={ "assignedPrograms": assigned_programs, "sort": sort, }, - *args, **kwargs, ) @@ -69,17 +75,17 @@ class PatientPrograms(Collection): def get( self, patient_id: str, - assigned_programs: bool = None, - sort: str = None, + assigned_programs: bool | None = None, + sort: str | None = None, *args, **kwargs, ): return super().get( f"{self._client.instance}/patients/{patient_id}/programs", + *args, params={ "assignedPrograms": assigned_programs, "sort": sort, }, - *args, **kwargs, ) diff --git a/welkin/models/sms.py b/welkin/models/sms.py index 6a23546..580ec1c 100644 --- a/welkin/models/sms.py +++ b/welkin/models/sms.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from welkin.models.base import Collection, Resource from welkin.pagination import PageableIterator from welkin.util import model_id @@ -18,14 +20,14 @@ class SMSes(Collection): iterator = PageableIterator @model_id("Patient") - def get(self, patient_id: str, sort: str = None, *args, **kwargs): + def get(self, patient_id: str, sort: str | None = None, *args, **kwargs): params = { "sort": sort, } return super().get( f"{self._client.instance}/patients/{patient_id}/sms", - params=params, *args, + params=params, **kwargs, ) diff --git a/welkin/models/user.py b/welkin/models/user.py index 11a7190..4f6b745 100644 --- a/welkin/models/user.py +++ b/welkin/models/user.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from enum import Enum from welkin.models.base import Collection, Resource @@ -6,7 +8,7 @@ class User(Resource): - subresources = [Encounters] + subresources = (Encounters,) def __str__(self): try: @@ -18,13 +20,13 @@ def create(self): return super().post("admin/users") def get(self): - return super().get(f"admin/users/{self.id}", params=dict(type="ID")) + return super().get(f"admin/users/{self.id}", params={"type": "ID"}) def update(self, **kwargs): return super().patch(f"admin/users/{self.username}", kwargs) def delete(self): - return super().delete(f"admin/users/{self.id}", params=dict(type="ID")) + return super().delete(f"admin/users/{self.id}", params={"type": "ID"}) class UserState(Enum): @@ -39,19 +41,15 @@ class Users(Collection): def get( self, - search: str = None, - region: str = None, - seat_assigned: bool = None, - user_state: str = None, + search: str | None = None, + region: str | None = None, + seat_assigned: bool | None = None, + user_state: str | None = None, *args, **kwargs, ): # TODO: Figure out sort arguments - params = dict( - search=search, - seatAssigned=seat_assigned, - userState=user_state, - ) + params = {"search": search, "seatAssigned": seat_assigned, "userState": user_state} # User state validation if user_state: @@ -62,4 +60,4 @@ def get( path = f"{self._client.instance}/users" params["region"] = region - return super().get(path, params=params, *args, **kwargs) + return super().get(path, *args, params=params, **kwargs) diff --git a/welkin/pagination.py b/welkin/pagination.py index 23a7e4e..137d955 100644 --- a/welkin/pagination.py +++ b/welkin/pagination.py @@ -1,5 +1,12 @@ +from __future__ import annotations + +DEFAULT_PAGE_SIZE = 20 + + class PageIterator: - def __init__(self, collection, resource, method, size=20, *args, **kwargs): + def __init__( + self, collection, resource, method, size=DEFAULT_PAGE_SIZE, *args, **kwargs + ): self.collection = collection self.resource = resource self.method = method @@ -7,7 +14,7 @@ def __init__(self, collection, resource, method, size=20, *args, **kwargs): self.meta_key = None self.meta_dict = {"totalPages": 1, "number": 0, "last": True} - if size != 20: + if size != DEFAULT_PAGE_SIZE: kwargs.setdefault("params", {}).update(size=size) self.args = args @@ -28,9 +35,9 @@ def __next__(self): self.resources, meta = self.method( self.resource, + *self.args, meta_key=self.meta_key, meta_dict=self.meta_dict, - *self.args, **self.kwargs, ) @@ -41,15 +48,11 @@ def __next__(self): raise StopIteration def _pre_request(self): - """ - Function to execute before making the next request, e.g. update paging params - """ + """Function to execute before making the next request, e.g. update paging params.""" self.kwargs.setdefault("params", {}) def _post_request(self, meta): - """ - Function to execute after making the next request, e.g. updating page tracking - """ + """Function to execute after making the next request, e.g. update page tracking.""" self.last = True @property @@ -63,9 +66,7 @@ def resources(self, value): class PageableIterator(PageIterator): - """ - Most common paging class - """ + """Most common paging class.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -84,10 +85,10 @@ def _post_request(self, meta): class FormationIterator(PageIterator): - """ - Specifically for paginating formations responses - Similar to PageableIterator but includes special behavior for - single item formations, e.g. encounter disposition + """Specifically for paginating formations responses. + + Similar to PageableIterator but includes special behavior for single item formations, + e.g. encounter disposition """ def __init__(self, *args, **kwargs): @@ -107,9 +108,9 @@ def __next__(self): data = self.method( self.resource, + *self.args, meta_key=self.meta_key, meta_dict=self.meta_dict, - *self.args, **self.kwargs, ) if isinstance(data, dict): @@ -132,9 +133,7 @@ def _post_request(self, meta): class PageNumberIterator(PageableIterator): - """ - PageableIterator with a different key used for the page count - """ + """PageableIterator with a different key used for the page count.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -147,9 +146,7 @@ def _post_request(self, meta): class MetaInfoIterator(PageIterator): - """ - Functionally identical to PageableIterator with various renamed keys - """ + """Functionally identical to PageableIterator with various renamed keys.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -170,9 +167,7 @@ def _post_request(self, meta): class MetaIterator(PageIterator): - """ - Paging class for token based paging - """ + """Paging class for token based paging.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/welkin/util.py b/welkin/util.py index 05ae8b7..323e11a 100644 --- a/welkin/util.py +++ b/welkin/util.py @@ -1,6 +1,8 @@ +from __future__ import annotations + from datetime import date, datetime, timezone from functools import lru_cache, wraps -from typing import Any, Callable, Tuple, Union +from typing import Any, Callable from uuid import UUID import inflection @@ -20,7 +22,9 @@ def __init__(self): _build_resources(self, "_client", self._client) -def _build_resources(instance: type, attribute_name: str, value: type = None) -> None: +def _build_resources( + instance: type, attribute_name: str, value: type | None = None +) -> None: """Add an attribute pointing to an instance for each resource. Args: @@ -54,13 +58,13 @@ def clean_data(value: Any) -> Any: """ if isinstance(value, datetime): return clean_datetime(value) - elif isinstance(value, date): + if isinstance(value, date): return clean_date(value) - elif isinstance(value, dict): + if isinstance(value, dict): return clean_request_payload(value) - elif isinstance(value, list): + if isinstance(value, list): return clean_json_list(value) - elif isinstance(value, UUID): + if isinstance(value, UUID): return str(value) # No cleaning needed @@ -112,7 +116,7 @@ def clean_datetime(dt: datetime) -> str: ) -def find_model_id(instance: Union[Collection, Resource], model_name: str) -> str: +def find_model_id(instance: Collection | Resource, model_name: str) -> str: """Recursively traverse the `_parent` chain searching for a model id. Args: @@ -129,9 +133,9 @@ def find_model_id(instance: Union[Collection, Resource], model_name: str) -> str if instance.__class__.__name__ == model_name: return instance.id - elif hasattr(instance, body_id_key): + if hasattr(instance, body_id_key): return getattr(instance, body_id_key) - elif instance._parent is not None: + if instance._parent is not None: return find_model_id(instance._parent, model_name) raise AttributeError( @@ -139,11 +143,11 @@ def find_model_id(instance: Union[Collection, Resource], model_name: str) -> str ) -def model_id(*models: Tuple[str]) -> Callable: +def model_id(*models: tuple[str]) -> Callable: """Insert values for `model_id` arguments if not provided. Args: - *models (Tuple[str]): The model names to search for. + *models (tuple[str]): The model names to search for. Raises: TypeError: If no ID is found and no arguments are provided.