From 295ed69fcf94832356edf44212817cf932981b91 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 28 May 2024 11:13:04 +0200 Subject: [PATCH 01/32] :green_heart: move git volume target attempt to resolve git branch using coveralls --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7b30daa..45f2937 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -68,7 +68,7 @@ services: # required by coveralls - type: bind source: ./.git/ - target: /var/uwsgi/.git/ + target: /var/uwsgi/smarter/.git/ read_only: true # Expose the default port From df10c0419f19d1cbf77b3f08242cc8a250304276 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 28 May 2024 11:15:28 +0200 Subject: [PATCH 02/32] :rewind: Revert ":green_heart: move git volume target" This reverts commit 295ed69fcf94832356edf44212817cf932981b91. --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 45f2937..7b30daa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -68,7 +68,7 @@ services: # required by coveralls - type: bind source: ./.git/ - target: /var/uwsgi/smarter/.git/ + target: /var/uwsgi/.git/ read_only: true # Expose the default port From 7bf7cee6b09d76641daf990961adf471630afa1a Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 28 May 2024 11:17:05 +0200 Subject: [PATCH 03/32] :green_heart: attempt to fix coveralls step --- .github/workflows/docker-compose-workflow.yml | 2 +- docker-compose.yml | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/docker-compose-workflow.yml b/.github/workflows/docker-compose-workflow.yml index 4868eb7..4c7640f 100644 --- a/.github/workflows/docker-compose-workflow.yml +++ b/.github/workflows/docker-compose-workflow.yml @@ -45,7 +45,7 @@ jobs: - name: Submitting coverage and code quality run: | - docker-compose run --rm uwsgi coveralls + docker-compose run --rm --volume ./.git/:/var/uwsgi/smarter/.git/ uwsgi coveralls - name: Stop containers if: always() diff --git a/docker-compose.yml b/docker-compose.yml index 7b30daa..48aae79 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -65,12 +65,6 @@ services: source: ./flask-data/ target: /var/uwsgi/ - # required by coveralls - - type: bind - source: ./.git/ - target: /var/uwsgi/.git/ - read_only: true - # Expose the default port # link container to database From 4b8fb8fc83c4a983886f3fabb031ec5a11fe76fd Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 28 May 2024 11:19:41 +0200 Subject: [PATCH 04/32] :rewind: Revert ":green_heart: attempt to fix coveralls step" This reverts commit 7bf7cee6b09d76641daf990961adf471630afa1a. --- .github/workflows/docker-compose-workflow.yml | 2 +- docker-compose.yml | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker-compose-workflow.yml b/.github/workflows/docker-compose-workflow.yml index 4c7640f..4868eb7 100644 --- a/.github/workflows/docker-compose-workflow.yml +++ b/.github/workflows/docker-compose-workflow.yml @@ -45,7 +45,7 @@ jobs: - name: Submitting coverage and code quality run: | - docker-compose run --rm --volume ./.git/:/var/uwsgi/smarter/.git/ uwsgi coveralls + docker-compose run --rm uwsgi coveralls - name: Stop containers if: always() diff --git a/docker-compose.yml b/docker-compose.yml index 48aae79..7b30daa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -65,6 +65,12 @@ services: source: ./flask-data/ target: /var/uwsgi/ + # required by coveralls + - type: bind + source: ./.git/ + target: /var/uwsgi/.git/ + read_only: true + # Expose the default port # link container to database From 8971a01a1b4d57c64c470610c0ab3568f6005fd1 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 28 May 2024 11:39:32 +0200 Subject: [PATCH 05/32] :green_heart: update container requirement add git dependency and configure safedir to solve CI issues with coveralls --- uwsgi/Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/uwsgi/Dockerfile b/uwsgi/Dockerfile index 703d58a..7882485 100644 --- a/uwsgi/Dockerfile +++ b/uwsgi/Dockerfile @@ -79,8 +79,12 @@ RUN dpkg-reconfigure -f noninteractive tzdata # install required packages RUN apt-get update && apt-get install -y \ libxml2 \ + git \ && rm -rf /var/lib/apt/lists/* +# set safe directory for uwsgi +RUN git config --global --add safe.directory /var/uwsgi + # Set some useful variables ENV \ PYTHONUNBUFFERED=1 \ From 5a16f75d706b536d001bb0eaef21026dcf745890 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 28 May 2024 11:45:30 +0200 Subject: [PATCH 06/32] :card_file_box: rename manifacturer into manufacturer --- flask-data/smarter/database/models.py | 2 +- flask-data/smarter/resources/chips.py | 6 +++--- flask-data/smarter/tests/fixtures/supportedChips.json | 8 ++++---- flask-data/smarter/tests/test_chips.py | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/flask-data/smarter/database/models.py b/flask-data/smarter/database/models.py index 5334ebb..94899c9 100644 --- a/flask-data/smarter/database/models.py +++ b/flask-data/smarter/database/models.py @@ -96,7 +96,7 @@ def __str__(self): class SupportedChip(db.Document): name = db.StringField(required=True, unique=True) species = db.StringField(required=True) - manifacturer = db.StringField() + manufacturer = db.StringField() n_of_snps = db.IntField(default=0) meta = { diff --git a/flask-data/smarter/resources/chips.py b/flask-data/smarter/resources/chips.py index 859dc21..d2cda21 100644 --- a/flask-data/smarter/resources/chips.py +++ b/flask-data/smarter/resources/chips.py @@ -49,7 +49,7 @@ class SupportedChipListApi(ListView): parser = reqparse.RequestParser() parser.add_argument('species', help="Species name") - parser.add_argument('manifacturer', help="Chip manifacturer") + parser.add_argument('manufacturer', help="Chip manufacturer") parser.add_argument('name', help="Chip name") def get_queryset(self): @@ -87,11 +87,11 @@ def get(self): in: query type: string description: Chip name - - name: manifacturer + - name: manufacturer in: query type: string enum: ['affymetrix', 'illumina'] - description: Chip manifacturer + description: Chip manufacturer responses: '200': description: Chips to be returned diff --git a/flask-data/smarter/tests/fixtures/supportedChips.json b/flask-data/smarter/tests/fixtures/supportedChips.json index 0b50553..5c18fab 100644 --- a/flask-data/smarter/tests/fixtures/supportedChips.json +++ b/flask-data/smarter/tests/fixtures/supportedChips.json @@ -5,7 +5,7 @@ }, "name": "IlluminaOvineSNP50", "species": "Sheep", - "manifacturer": "illumina", + "manufacturer": "illumina", "n_of_snps": 54241 }, { @@ -14,7 +14,7 @@ }, "name": "IlluminaOvineHDSNP", "species": "Sheep", - "manifacturer": "illumina", + "manufacturer": "illumina", "n_of_snps": 606006 }, { @@ -23,7 +23,7 @@ }, "name": "IlluminaGoatSNP50", "species": "Goat", - "manifacturer": "illumina", + "manufacturer": "illumina", "n_of_snps": 59727 }, { @@ -32,7 +32,7 @@ }, "name": "AffymetrixAxiomOviCan", "species": "Sheep", - "manifacturer": "affymetrix", + "manufacturer": "affymetrix", "n_of_snps": 56793 } ] diff --git a/flask-data/smarter/tests/test_chips.py b/flask-data/smarter/tests/test_chips.py index 67ef5d4..fbc99b2 100644 --- a/flask-data/smarter/tests/test_chips.py +++ b/flask-data/smarter/tests/test_chips.py @@ -129,11 +129,11 @@ def test_get_chips_by_species(self): self.assertListEqual(test['items'], [self.data[-2]]) self.assertEqual(response.status_code, 200) - def test_get_chips_by_manifacturer(self): + def test_get_chips_by_manufacturer(self): response = self.client.get( self.test_endpoint, headers=self.headers, - query_string={'manifacturer': 'affymetrix'} + query_string={'manufacturer': 'affymetrix'} ) test = response.json From bdcb3d88c1a4aba4d30780d18eacce9babc6821d Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 28 May 2024 11:55:14 +0200 Subject: [PATCH 07/32] :arrow_up: upgrade dependencies --- poetry.lock | 1133 +++++++++++++++++++++++++-------------------------- 1 file changed, 549 insertions(+), 584 deletions(-) diff --git a/poetry.lock b/poetry.lock index 88363e2..e1cfe73 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,14 +1,14 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "alabaster" -version = "0.7.13" -description = "A configurable sidebar-enabled Sphinx theme" +version = "0.7.16" +description = "A light, configurable Sphinx theme" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] [[package]] @@ -25,102 +25,91 @@ files = [ [package.extras] dev = ["black", "coverage", "isort", "pre-commit", "pyenchant", "pylint"] -[[package]] -name = "appnope" -version = "0.1.3" -description = "Disable App Nap on macOS >= 10.9" -optional = false -python-versions = "*" -files = [ - {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, - {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, -] - [[package]] name = "asttokens" -version = "2.4.0" +version = "2.4.1" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" files = [ - {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, - {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, ] [package.dependencies] six = ">=1.12.0" [package.extras] -test = ["astroid", "pytest"] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] [[package]] name = "attrs" -version = "23.1.0" +version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] +dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "babel" -version = "2.12.1" +version = "2.15.0" description = "Internationalization utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, - {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] -[[package]] -name = "backcall" -version = "0.2.0" -description = "Specifications for callback functions passed in to an API" -optional = false -python-versions = "*" -files = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "bcrypt" -version = "4.0.1" +version = "4.1.3" description = "Modern password hashing for your software and your servers" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "bcrypt-4.0.1-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3"}, - {file = "bcrypt-4.0.1-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2"}, - {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535"}, - {file = "bcrypt-4.0.1-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e"}, - {file = "bcrypt-4.0.1-cp36-abi3-win32.whl", hash = "sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab"}, - {file = "bcrypt-4.0.1-cp36-abi3-win_amd64.whl", hash = "sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9"}, - {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c"}, - {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b"}, - {file = "bcrypt-4.0.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d"}, - {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d"}, - {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215"}, - {file = "bcrypt-4.0.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c"}, - {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda"}, - {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665"}, - {file = "bcrypt-4.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71"}, - {file = "bcrypt-4.0.1.tar.gz", hash = "sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd"}, + {file = "bcrypt-4.1.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:48429c83292b57bf4af6ab75809f8f4daf52aa5d480632e53707805cc1ce9b74"}, + {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a8bea4c152b91fd8319fef4c6a790da5c07840421c2b785084989bf8bbb7455"}, + {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d3b317050a9a711a5c7214bf04e28333cf528e0ed0ec9a4e55ba628d0f07c1a"}, + {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:094fd31e08c2b102a14880ee5b3d09913ecf334cd604af27e1013c76831f7b05"}, + {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4fb253d65da30d9269e0a6f4b0de32bd657a0208a6f4e43d3e645774fb5457f3"}, + {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:193bb49eeeb9c1e2db9ba65d09dc6384edd5608d9d672b4125e9320af9153a15"}, + {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:8cbb119267068c2581ae38790e0d1fbae65d0725247a930fc9900c285d95725d"}, + {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6cac78a8d42f9d120b3987f82252bdbeb7e6e900a5e1ba37f6be6fe4e3848286"}, + {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:01746eb2c4299dd0ae1670234bf77704f581dd72cc180f444bfe74eb80495b64"}, + {file = "bcrypt-4.1.3-cp37-abi3-win32.whl", hash = "sha256:037c5bf7c196a63dcce75545c8874610c600809d5d82c305dd327cd4969995bf"}, + {file = "bcrypt-4.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:8a893d192dfb7c8e883c4576813bf18bb9d59e2cfd88b68b725990f033f1b978"}, + {file = "bcrypt-4.1.3-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d4cf6ef1525f79255ef048b3489602868c47aea61f375377f0d00514fe4a78c"}, + {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5698ce5292a4e4b9e5861f7e53b1d89242ad39d54c3da451a93cac17b61921a"}, + {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec3c2e1ca3e5c4b9edb94290b356d082b721f3f50758bce7cce11d8a7c89ce84"}, + {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3a5be252fef513363fe281bafc596c31b552cf81d04c5085bc5dac29670faa08"}, + {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5f7cd3399fbc4ec290378b541b0cf3d4398e4737a65d0f938c7c0f9d5e686611"}, + {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:c4c8d9b3e97209dd7111bf726e79f638ad9224b4691d1c7cfefa571a09b1b2d6"}, + {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:31adb9cbb8737a581a843e13df22ffb7c84638342de3708a98d5c986770f2834"}, + {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:551b320396e1d05e49cc18dd77d970accd52b322441628aca04801bbd1d52a73"}, + {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6717543d2c110a155e6821ce5670c1f512f602eabb77dba95717ca76af79867d"}, + {file = "bcrypt-4.1.3-cp39-abi3-win32.whl", hash = "sha256:6004f5229b50f8493c49232b8e75726b568535fd300e5039e255d919fc3a07f2"}, + {file = "bcrypt-4.1.3-cp39-abi3-win_amd64.whl", hash = "sha256:2505b54afb074627111b5a8dc9b6ae69d0f01fea65c2fcaea403448c503d3991"}, + {file = "bcrypt-4.1.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:cb9c707c10bddaf9e5ba7cdb769f3e889e60b7d4fea22834b261f51ca2b89fed"}, + {file = "bcrypt-4.1.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9f8ea645eb94fb6e7bea0cf4ba121c07a3a182ac52876493870033141aa687bc"}, + {file = "bcrypt-4.1.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f44a97780677e7ac0ca393bd7982b19dbbd8d7228c1afe10b128fd9550eef5f1"}, + {file = "bcrypt-4.1.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d84702adb8f2798d813b17d8187d27076cca3cd52fe3686bb07a9083930ce650"}, + {file = "bcrypt-4.1.3.tar.gz", hash = "sha256:2ee15dd749f5952fe3f0430d0ff6b74082e159c50332a1413d51b5689cf06623"}, ] [package.extras] @@ -129,97 +118,112 @@ typecheck = ["mypy"] [[package]] name = "certifi" -version = "2023.7.22" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, - {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] @@ -343,22 +347,23 @@ files = [ [[package]] name = "dnspython" -version = "2.4.2" +version = "2.6.1" description = "DNS toolkit" optional = false -python-versions = ">=3.8,<4.0" +python-versions = ">=3.8" files = [ - {file = "dnspython-2.4.2-py3-none-any.whl", hash = "sha256:57c6fbaaeaaf39c891292012060beb141791735dbb4004798328fc2c467402d8"}, - {file = "dnspython-2.4.2.tar.gz", hash = "sha256:8dcfae8c7460a2f84b4072e26f1c9f4101ca20c071649cb7c34e8b6a93d58984"}, + {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, + {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, ] [package.extras] -dnssec = ["cryptography (>=2.6,<42.0)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.24.1)"] -doq = ["aioquic (>=0.9.20)"] -idna = ["idna (>=2.1,<4.0)"] -trio = ["trio (>=0.14,<0.23)"] -wmi = ["wmi (>=1.5.1,<2.0.0)"] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=41)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] +doq = ["aioquic (>=0.9.25)"] +idna = ["idna (>=3.6)"] +trio = ["trio (>=0.23)"] +wmi = ["wmi (>=1.5.1)"] [[package]] name = "docopt" @@ -383,13 +388,13 @@ files = [ [[package]] name = "email-validator" -version = "2.0.0.post2" +version = "2.1.1" description = "A robust email address syntax and deliverability validation library." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "email_validator-2.0.0.post2-py3-none-any.whl", hash = "sha256:2466ba57cda361fb7309fd3d5a225723c788ca4bbad32a0ebd5373b99730285c"}, - {file = "email_validator-2.0.0.post2.tar.gz", hash = "sha256:1ff6e86044200c56ae23595695c54e9614f4a9551e0e393614f764860b3d7900"}, + {file = "email_validator-2.1.1-py3-none-any.whl", hash = "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05"}, + {file = "email_validator-2.1.1.tar.gz", hash = "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84"}, ] [package.dependencies] @@ -398,13 +403,13 @@ idna = ">=2.0.0" [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, ] [package.extras] @@ -412,17 +417,17 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "1.2.0" +version = "2.0.1" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"}, - {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"}, + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, ] [package.extras] -tests = ["asttokens", "littleutils", "pytest", "rich"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] [[package]] name = "flake8" @@ -497,13 +502,13 @@ Flask = "*" [[package]] name = "flask-cors" -version = "4.0.0" +version = "4.0.1" description = "A Flask extension adding a decorator for CORS support" optional = false python-versions = "*" files = [ - {file = "Flask-Cors-4.0.0.tar.gz", hash = "sha256:f268522fcb2f73e2ecdde1ef45e2fd5c71cc48fe03cffb4b441c6d1b40684eb0"}, - {file = "Flask_Cors-4.0.0-py2.py3-none-any.whl", hash = "sha256:bc3492bfd6368d27cfe79c7821df5a8a319e1a6d5eab277a3794be19bdc51783"}, + {file = "Flask_Cors-4.0.1-py2.py3-none-any.whl", hash = "sha256:f2a704e4458665580c074b714c4627dd5a306b333deb9074d0b1794dfa2fb677"}, + {file = "flask_cors-4.0.1.tar.gz", hash = "sha256:eeb69b342142fdbf4766ad99357a7f3876a2ceb77689dc10ff912aac06c389e4"}, ] [package.dependencies] @@ -511,17 +516,17 @@ Flask = ">=0.9" [[package]] name = "flask-jwt-extended" -version = "4.5.2" +version = "4.6.0" description = "Extended JWT integration with Flask" optional = false python-versions = ">=3.7,<4" files = [ - {file = "Flask-JWT-Extended-4.5.2.tar.gz", hash = "sha256:ba56245ba43b71c8ae936784b867625dce8b9956faeedec2953222e57942fb0b"}, - {file = "Flask_JWT_Extended-4.5.2-py2.py3-none-any.whl", hash = "sha256:e0ef23d8c863746bd141046167073699e1a7b03c97169cbba70f05b8d9cd6b9e"}, + {file = "Flask-JWT-Extended-4.6.0.tar.gz", hash = "sha256:9215d05a9413d3855764bcd67035e75819d23af2fafb6b55197eb5a3313fdfb2"}, + {file = "Flask_JWT_Extended-4.6.0-py2.py3-none-any.whl", hash = "sha256:63a28fc9731bcc6c4b8815b6f954b5904caa534fc2ae9b93b1d3ef12930dca95"}, ] [package.dependencies] -Flask = ">=2.0,<3.0" +Flask = ">=2.0,<4.0" PyJWT = ">=2.0,<3.0" Werkzeug = ">=0.14" @@ -582,32 +587,32 @@ IPython = ">=5.0.0" [[package]] name = "flask-wtf" -version = "1.1.1" +version = "1.2.1" description = "Form rendering, validation, and CSRF protection for Flask with WTForms." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Flask-WTF-1.1.1.tar.gz", hash = "sha256:41c4244e9ae626d63bed42ae4785b90667b885b1535d5a4095e1f63060d12aa9"}, - {file = "Flask_WTF-1.1.1-py3-none-any.whl", hash = "sha256:7887d6f1ebb3e17bf648647422f0944c9a469d0fcf63e3b66fb9a83037e38b2c"}, + {file = "flask_wtf-1.2.1-py3-none-any.whl", hash = "sha256:fa6793f2fb7e812e0fe9743b282118e581fb1b6c45d414b8af05e659bd653287"}, + {file = "flask_wtf-1.2.1.tar.gz", hash = "sha256:8bb269eb9bb46b87e7c8233d7e7debdf1f8b74bf90cc1789988c29b37a97b695"}, ] [package.dependencies] -Flask = "*" +flask = "*" itsdangerous = "*" -WTForms = "*" +wtforms = "*" [package.extras] email = ["email-validator"] [[package]] name = "idna" -version = "3.4" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -623,22 +628,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "7.1.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {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)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "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 = "iniconfig" @@ -653,64 +658,61 @@ files = [ [[package]] name = "ipython" -version = "8.15.0" +version = "8.18.1" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.9" files = [ - {file = "ipython-8.15.0-py3-none-any.whl", hash = "sha256:45a2c3a529296870a97b7de34eda4a31bee16bc7bf954e07d39abe49caf8f887"}, - {file = "ipython-8.15.0.tar.gz", hash = "sha256:2baeb5be6949eeebf532150f81746f8333e2ccce02de1c7eedde3f23ed5e9f1e"}, + {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"}, + {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"}, ] [package.dependencies] -appnope = {version = "*", markers = "sys_platform == \"darwin\""} -backcall = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -pickleshare = "*" -prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5" typing-extensions = {version = "*", markers = "python_version < \"3.10\""} [package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"] [[package]] name = "itsdangerous" -version = "2.1.2" +version = "2.2.0" description = "Safely pass data to untrusted environments and back." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, - {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, + {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, + {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, ] [[package]] name = "jedi" -version = "0.19.0" +version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." optional = false python-versions = ">=3.6" files = [ - {file = "jedi-0.19.0-py2.py3-none-any.whl", hash = "sha256:cb8ce23fbccff0025e9386b5cf85e892f94c9b822378f8da49970471335ac64e"}, - {file = "jedi-0.19.0.tar.gz", hash = "sha256:bcf9894f1753969cbac8022a8c2eaee06bfa3724e4192470aaffe7eb6272b0c4"}, + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, ] [package.dependencies] @@ -719,17 +721,17 @@ parso = ">=0.8.3,<0.9.0" [package.extras] docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -740,13 +742,13 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jsonschema" -version = "4.19.0" +version = "4.22.0" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema-4.19.0-py3-none-any.whl", hash = "sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb"}, - {file = "jsonschema-4.19.0.tar.gz", hash = "sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f"}, + {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, + {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, ] [package.dependencies] @@ -761,96 +763,96 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-specifications" -version = "2023.7.1" +version = "2023.12.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema_specifications-2023.7.1-py3-none-any.whl", hash = "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1"}, - {file = "jsonschema_specifications-2023.7.1.tar.gz", hash = "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb"}, + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, ] [package.dependencies] -referencing = ">=0.28.0" +referencing = ">=0.31.0" [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] name = "matplotlib-inline" -version = "0.1.6" +version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, - {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, + {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, + {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, ] [package.dependencies] @@ -869,13 +871,13 @@ files = [ [[package]] name = "mistune" -version = "3.0.1" +version = "3.0.2" description = "A sane and fast Markdown parser with useful plugins and renderers" optional = false python-versions = ">=3.7" files = [ - {file = "mistune-3.0.1-py3-none-any.whl", hash = "sha256:b9b3e438efbb57c62b5beb5e134dab664800bdf1284a7ee09e8b12b13eb1aac6"}, - {file = "mistune-3.0.1.tar.gz", hash = "sha256:e912116c13aa0944f9dc530db38eb88f6a77087ab128f49f84a48f4c05ea163c"}, + {file = "mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205"}, + {file = "mistune-3.0.2.tar.gz", hash = "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8"}, ] [[package]] @@ -894,64 +896,53 @@ pymongo = ">=3.4,<5.0" [[package]] name = "packaging" -version = "23.1" +version = "24.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] name = "parso" -version = "0.8.3" +version = "0.8.4" description = "A Python Parser" optional = false python-versions = ">=3.6" files = [ - {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, - {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, ] [package.extras] -qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] -testing = ["docopt", "pytest (<6.0.0)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] [[package]] name = "pexpect" -version = "4.8.0" +version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" files = [ - {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, - {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, ] [package.dependencies] ptyprocess = ">=0.5" -[[package]] -name = "pickleshare" -version = "0.7.5" -description = "Tiny 'shelve'-like database with concurrency support" -optional = false -python-versions = "*" -files = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] - [[package]] name = "pluggy" -version = "1.3.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -960,13 +951,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "prompt-toolkit" -version = "3.0.39" +version = "3.0.44" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, - {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, + {file = "prompt_toolkit-3.0.44-py3-none-any.whl", hash = "sha256:205a20669633d042d3722a528b8e7cd3f4dbd9e1450935f596c2cc61166762dd"}, + {file = "prompt_toolkit-3.0.44.tar.gz", hash = "sha256:c1dfd082c4259964bc8bcce1f8460d9dbeb5d4a37bfc25b8082bc02cd41c8af6"}, ] [package.dependencies] @@ -999,13 +990,13 @@ tests = ["pytest"] [[package]] name = "pycodestyle" -version = "2.11.0" +version = "2.11.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" files = [ - {file = "pycodestyle-2.11.0-py2.py3-none-any.whl", hash = "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"}, - {file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"}, + {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, + {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, ] [[package]] @@ -1021,17 +1012,17 @@ files = [ [[package]] name = "pygments" -version = "2.16.1" +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.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {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 = "pyjwt" @@ -1052,114 +1043,94 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pymongo" -version = "4.5.0" +version = "4.7.2" description = "Python driver for MongoDB " optional = false python-versions = ">=3.7" files = [ - {file = "pymongo-4.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d4fa1b01fa7e5b7bb8d312e3542e211b320eb7a4e3d8dc884327039d93cb9e0"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux1_i686.whl", hash = "sha256:dfcd2b9f510411de615ccedd47462dae80e82fdc09fe9ab0f0f32f11cf57eeb5"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:3e33064f1984db412b34d51496f4ea785a9cff621c67de58e09fb28da6468a52"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux2014_i686.whl", hash = "sha256:33faa786cc907de63f745f587e9879429b46033d7d97a7b84b37f4f8f47b9b32"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux2014_ppc64le.whl", hash = "sha256:76a262c41c1a7cbb84a3b11976578a7eb8e788c4b7bfbd15c005fb6ca88e6e50"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux2014_s390x.whl", hash = "sha256:0f4b125b46fe377984fbaecf2af40ed48b05a4b7676a2ff98999f2016d66b3ec"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux2014_x86_64.whl", hash = "sha256:40d5f6e853ece9bfc01e9129b228df446f49316a4252bb1fbfae5c3c9dedebad"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:152259f0f1a60f560323aacf463a3642a65a25557683f49cfa08c8f1ecb2395a"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d64878d1659d2a5bdfd0f0a4d79bafe68653c573681495e424ab40d7b6d6d41"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1bb3a62395ffe835dbef3a1cbff48fbcce709c78bd1f52e896aee990928432b"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe48f50fb6348511a3268a893bfd4ab5f263f5ac220782449d03cd05964d1ae7"}, - {file = "pymongo-4.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7591a3beea6a9a4fa3080d27d193b41f631130e3ffa76b88c9ccea123f26dc59"}, - {file = "pymongo-4.5.0-cp310-cp310-win32.whl", hash = "sha256:3a7166d57dc74d679caa7743b8ecf7dc3a1235a9fd178654dddb2b2a627ae229"}, - {file = "pymongo-4.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:21b953da14549ff62ea4ae20889c71564328958cbdf880c64a92a48dda4c9c53"}, - {file = "pymongo-4.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ead4f19d0257a756b21ac2e0e85a37a7245ddec36d3b6008d5bfe416525967dc"}, - {file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aff6279e405dc953eeb540ab061e72c03cf38119613fce183a8e94f31be608f"}, - {file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd4c8d6aa91d3e35016847cbe8d73106e3d1c9a4e6578d38e2c346bfe8edb3ca"}, - {file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08819da7864f9b8d4a95729b2bea5fffed08b63d3b9c15b4fea47de655766cf5"}, - {file = "pymongo-4.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a253b765b7cbc4209f1d8ee16c7287c4268d3243070bf72d7eec5aa9dfe2a2c2"}, - {file = "pymongo-4.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8027c9063579083746147cf401a7072a9fb6829678076cd3deff28bb0e0f50c8"}, - {file = "pymongo-4.5.0-cp311-cp311-win32.whl", hash = "sha256:9d2346b00af524757576cc2406414562cced1d4349c92166a0ee377a2a483a80"}, - {file = "pymongo-4.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:c3c3525ea8658ee1192cdddf5faf99b07ebe1eeaa61bf32821126df6d1b8072b"}, - {file = "pymongo-4.5.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e5a27f348909235a106a3903fc8e70f573d89b41d723a500869c6569a391cff7"}, - {file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9a9a39b7cac81dca79fca8c2a6479ef4c7b1aab95fad7544cc0e8fd943595a2"}, - {file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:496c9cbcb4951183d4503a9d7d2c1e3694aab1304262f831d5e1917e60386036"}, - {file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23cc6d7eb009c688d70da186b8f362d61d5dd1a2c14a45b890bd1e91e9c451f2"}, - {file = "pymongo-4.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fff7d17d30b2cd45afd654b3fc117755c5d84506ed25fda386494e4e0a3416e1"}, - {file = "pymongo-4.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6422b6763b016f2ef2beedded0e546d6aa6ba87910f9244d86e0ac7690f75c96"}, - {file = "pymongo-4.5.0-cp312-cp312-win32.whl", hash = "sha256:77cfff95c1fafd09e940b3fdcb7b65f11442662fad611d0e69b4dd5d17a81c60"}, - {file = "pymongo-4.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:e57d859b972c75ee44ea2ef4758f12821243e99de814030f69a3decb2aa86807"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2b0176f9233a5927084c79ff80b51bd70bfd57e4f3d564f50f80238e797f0c8a"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:89b3f2da57a27913d15d2a07d58482f33d0a5b28abd20b8e643ab4d625e36257"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:5caee7bd08c3d36ec54617832b44985bd70c4cbd77c5b313de6f7fce0bb34f93"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:1d40ad09d9f5e719bc6f729cc6b17f31c0b055029719406bd31dde2f72fca7e7"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:076afa0a4a96ca9f77fec0e4a0d241200b3b3a1766f8d7be9a905ecf59a7416b"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:3fa3648e4f1e63ddfe53563ee111079ea3ab35c3b09cd25bc22dadc8269a495f"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:44ee985194c426ddf781fa784f31ffa29cb59657b2dba09250a4245431847d73"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b33c17d9e694b66d7e96977e9e56df19d662031483efe121a24772a44ccbbc7e"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d79ae3bb1ff041c0db56f138c88ce1dfb0209f3546d8d6e7c3f74944ecd2439"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d67225f05f6ea27c8dc57f3fa6397c96d09c42af69d46629f71e82e66d33fa4f"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41771b22dd2822540f79a877c391283d4e6368125999a5ec8beee1ce566f3f82"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a1f26bc1f5ce774d99725773901820dfdfd24e875028da4a0252a5b48dcab5c"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3236cf89d69679eaeb9119c840f5c7eb388a2110b57af6bb6baf01a1da387c18"}, - {file = "pymongo-4.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e1f61355c821e870fb4c17cdb318669cfbcf245a291ce5053b41140870c3e5cc"}, - {file = "pymongo-4.5.0-cp37-cp37m-win32.whl", hash = "sha256:49dce6957598975d8b8d506329d2a3a6c4aee911fa4bbcf5e52ffc6897122950"}, - {file = "pymongo-4.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2227a08b091bd41df5aadee0a5037673f691e2aa000e1968b1ea2342afc6880"}, - {file = "pymongo-4.5.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:435228d3c16a375274ac8ab9c4f9aef40c5e57ddb8296e20ecec9e2461da1017"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8e559116e4128630ad3b7e788e2e5da81cbc2344dee246af44471fa650486a70"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:840eaf30ccac122df260b6005f9dfae4ac287c498ee91e3e90c56781614ca238"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b4fe46b58010115514b842c669a0ed9b6a342017b15905653a5b1724ab80917f"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:a8127437ebc196a6f5e8fddd746bd0903a400dc6b5ae35df672dd1ccc7170a2a"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:2988ef5e6b360b3ff1c6d55c53515499de5f48df31afd9f785d788cdacfbe2d3"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:e249190b018d63c901678053b4a43e797ca78b93fb6d17633e3567d4b3ec6107"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:1240edc1a448d4ada4bf1a0e55550b6292420915292408e59159fd8bbdaf8f63"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6d2a56fc2354bb6378f3634402eec788a8f3facf0b3e7d468db5f2b5a78d763"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a0aade2b11dc0c326ccd429ee4134d2d47459ff68d449c6d7e01e74651bd255"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74c0da07c04d0781490b2915e7514b1adb265ef22af039a947988c331ee7455b"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3754acbd7efc7f1b529039fcffc092a15e1cf045e31f22f6c9c5950c613ec4d"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:631492573a1bef2f74f9ac0f9d84e0ce422c251644cd81207530af4aa2ee1980"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e2654d1278384cff75952682d17c718ecc1ad1d6227bb0068fd826ba47d426a5"}, - {file = "pymongo-4.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:168172ef7856e20ec024fe2a746bfa895c88b32720138e6438fd765ebd2b62dd"}, - {file = "pymongo-4.5.0-cp38-cp38-win32.whl", hash = "sha256:b25f7bea162b3dbec6d33c522097ef81df7c19a9300722fa6853f5b495aecb77"}, - {file = "pymongo-4.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:b520aafc6cb148bac09ccf532f52cbd31d83acf4d3e5070d84efe3c019a1adbf"}, - {file = "pymongo-4.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8543253adfaa0b802bfa88386db1009c6ebb7d5684d093ee4edc725007553d21"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:bc5d8c3647b8ae28e4312f1492b8f29deebd31479cd3abaa989090fb1d66db83"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:505f8519c4c782a61d94a17b0da50be639ec462128fbd10ab0a34889218fdee3"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:53f2dda54d76a98b43a410498bd12f6034b2a14b6844ca08513733b2b20b7ad8"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:9c04b9560872fa9a91251030c488e0a73bce9321a70f991f830c72b3f8115d0d"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:58a63a26a1e3dc481dd3a18d6d9f8bd1d576cd1ffe0d479ba7dd38b0aeb20066"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:f076b779aa3dc179aa3ed861be063a313ed4e48ae9f6a8370a9b1295d4502111"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:1b1d7d9aabd8629a31d63cd106d56cca0e6420f38e50563278b520f385c0d86e"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37df8f6006286a5896d1cbc3efb8471ced42e3568d38e6cb00857277047b0d63"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56320c401f544d762fc35766936178fbceb1d9261cd7b24fbfbc8fb6f67aa8a5"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bbd705d5f3c3d1ff2d169e418bb789ff07ab3c70d567cc6ba6b72b04b9143481"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80a167081c75cf66b32f30e2f1eaee9365af935a86dbd76788169911bed9b5d5"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c42748ccc451dfcd9cef6c5447a7ab727351fd9747ad431db5ebb18a9b78a4d"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf62da7a4cdec9a4b2981fcbd5e08053edffccf20e845c0b6ec1e77eb7fab61d"}, - {file = "pymongo-4.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b5bbb87fa0511bd313d9a2c90294c88db837667c2bda2ea3fa7a35b59fd93b1f"}, - {file = "pymongo-4.5.0-cp39-cp39-win32.whl", hash = "sha256:465fd5b040206f8bce7016b01d7e7f79d2fcd7c2b8e41791be9632a9df1b4999"}, - {file = "pymongo-4.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:63d8019eee119df308a075b8a7bdb06d4720bf791e2b73d5ab0e7473c115d79c"}, - {file = "pymongo-4.5.0.tar.gz", hash = "sha256:681f252e43b3ef054ca9161635f81b730f4d8cadd28b3f2b2004f5a72f853982"}, + {file = "pymongo-4.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:268d8578c0500012140c5460755ea405cbfe541ef47c81efa9d6744f0f99aeca"}, + {file = "pymongo-4.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:827611beb6c483260d520cfa6a49662d980dfa5368a04296f65fa39e78fccea7"}, + {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a754e366c404d19ff3f077ddeed64be31e0bb515e04f502bf11987f1baa55a16"}, + {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c44efab10d9a3db920530f7bcb26af8f408b7273d2f0214081d3891979726328"}, + {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35b3f0c7d49724859d4df5f0445818d525824a6cd55074c42573d9b50764df67"}, + {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e37faf298a37ffb3e0809e77fbbb0a32b6a2d18a83c59cfc2a7b794ea1136b0"}, + {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1bcd58669e56c08f1e72c5758868b5df169fe267501c949ee83c418e9df9155"}, + {file = "pymongo-4.7.2-cp310-cp310-win32.whl", hash = "sha256:c72d16fede22efe7cdd1f422e8da15760e9498024040429362886f946c10fe95"}, + {file = "pymongo-4.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:12d1fef77d25640cb78893d07ff7d2fac4c4461d8eec45bd3b9ad491a1115d6e"}, + {file = "pymongo-4.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fc5af24fcf5fc6f7f40d65446400d45dd12bea933d0299dc9e90c5b22197f1e9"}, + {file = "pymongo-4.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:730778b6f0964b164c187289f906bbc84cb0524df285b7a85aa355bbec43eb21"}, + {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47a1a4832ef2f4346dcd1a10a36ade7367ad6905929ddb476459abb4fd1b98cb"}, + {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6eab12c6385526d386543d6823b07187fefba028f0da216506e00f0e1855119"}, + {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37e9ea81fa59ee9274457ed7d59b6c27f6f2a5fe8e26f184ecf58ea52a019cb8"}, + {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e9d9d2c0aae73aa4369bd373ac2ac59f02c46d4e56c4b6d6e250cfe85f76802"}, + {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb6e00a79dff22c9a72212ad82021b54bdb3b85f38a85f4fc466bde581d7d17a"}, + {file = "pymongo-4.7.2-cp311-cp311-win32.whl", hash = "sha256:02efd1bb3397e24ef2af45923888b41a378ce00cb3a4259c5f4fc3c70497a22f"}, + {file = "pymongo-4.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:87bb453ac3eb44db95cb6d5a616fbc906c1c00661eec7f55696253a6245beb8a"}, + {file = "pymongo-4.7.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:12c466e02133b7f8f4ff1045c6b5916215c5f7923bc83fd6e28e290cba18f9f6"}, + {file = "pymongo-4.7.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f91073049c43d14e66696970dd708d319b86ee57ef9af359294eee072abaac79"}, + {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87032f818bf5052ab742812c715eff896621385c43f8f97cdd37d15b5d394e95"}, + {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6a87eef394039765679f75c6a47455a4030870341cb76eafc349c5944408c882"}, + {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d275596f840018858757561840767b39272ac96436fcb54f5cac6d245393fd97"}, + {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82102e353be13f1a6769660dd88115b1da382447672ba1c2662a0fbe3df1d861"}, + {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:194065c9d445017b3c82fb85f89aa2055464a080bde604010dc8eb932a6b3c95"}, + {file = "pymongo-4.7.2-cp312-cp312-win32.whl", hash = "sha256:db4380d1e69fdad1044a4b8f3bb105200542c49a0dde93452d938ff9db1d6d29"}, + {file = "pymongo-4.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:fadc6e8db7707c861ebe25b13ad6aca19ea4d2c56bf04a26691f46c23dadf6e4"}, + {file = "pymongo-4.7.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2cb77d09bd012cb4b30636e7e38d00b5f9be5eb521c364bde66490c45ee6c4b4"}, + {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56bf8b706946952acdea0fe478f8e44f1ed101c4b87f046859e6c3abe6c0a9f4"}, + {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcf337d1b252405779d9c79978d6ca15eab3cdaa2f44c100a79221bddad97c8a"}, + {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ffd1519edbe311df73c74ec338de7d294af535b2748191c866ea3a7c484cd15"}, + {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d59776f435564159196d971aa89422ead878174aff8fe18e06d9a0bc6d648c"}, + {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:347c49cf7f0ba49ea87c1a5a1984187ecc5516b7c753f31938bf7b37462824fd"}, + {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:84bc00200c3cbb6c98a2bb964c9e8284b641e4a33cf10c802390552575ee21de"}, + {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fcaf8c911cb29316a02356f89dbc0e0dfcc6a712ace217b6b543805690d2aefd"}, + {file = "pymongo-4.7.2-cp37-cp37m-win32.whl", hash = "sha256:b48a5650ee5320d59f6d570bd99a8d5c58ac6f297a4e9090535f6561469ac32e"}, + {file = "pymongo-4.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5239ef7e749f1326ea7564428bf861d5250aa39d7f26d612741b1b1273227062"}, + {file = "pymongo-4.7.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2dcf608d35644e8d276d61bf40a93339d8d66a0e5f3e3f75b2c155a421a1b71"}, + {file = "pymongo-4.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:25eeb2c18ede63891cbd617943dd9e6b9cbccc54f276e0b2e693a0cc40f243c5"}, + {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9349f0bb17a31371d4cacb64b306e4ca90413a3ad1fffe73ac7cd495570d94b5"}, + {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffd4d7cb2e6c6e100e2b39606d38a9ffc934e18593dc9bb326196afc7d93ce3d"}, + {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9a8bd37f5dabc86efceb8d8cbff5969256523d42d08088f098753dba15f3b37a"}, + {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c78f156edc59b905c80c9003e022e1a764c54fd40ac4fea05b0764f829790e2"}, + {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d892fb91e81cccb83f507cdb2ea0aa026ec3ced7f12a1d60f6a5bf0f20f9c1f"}, + {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:87832d6076c2c82f42870157414fd876facbb6554d2faf271ffe7f8f30ce7bed"}, + {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ce1a374ea0e49808e0380ffc64284c0ce0f12bd21042b4bef1af3eb7bdf49054"}, + {file = "pymongo-4.7.2-cp38-cp38-win32.whl", hash = "sha256:eb0642e5f0dd7e86bb358749cc278e70b911e617f519989d346f742dc9520dfb"}, + {file = "pymongo-4.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:4bdb5ffe1cd3728c9479671a067ef44dacafc3743741d4dc700c377c4231356f"}, + {file = "pymongo-4.7.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:743552033c63f0afdb56b9189ab04b5c1dbffd7310cf7156ab98eebcecf24621"}, + {file = "pymongo-4.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5239776633f7578b81207e5646245415a5a95f6ae5ef5dff8e7c2357e6264bfc"}, + {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:727ad07952c155cd20045f2ce91143c7dc4fb01a5b4e8012905a89a7da554b0c"}, + {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9385654f01a90f73827af4db90c290a1519f7d9102ba43286e187b373e9a78e9"}, + {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d833651f1ba938bb7501f13e326b96cfbb7d98867b2d545ca6d69c7664903e0"}, + {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf17ea9cea14d59b0527403dd7106362917ced7c4ec936c4ba22bd36c912c8e0"}, + {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cecd2df037249d1c74f0af86fb5b766104a5012becac6ff63d85d1de53ba8b98"}, + {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65b4c00dedbd333698b83cd2095a639a6f0d7c4e2a617988f6c65fb46711f028"}, + {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d9b6cbc037108ff1a0a867e7670d8513c37f9bcd9ee3d2464411bfabf70ca002"}, + {file = "pymongo-4.7.2-cp39-cp39-win32.whl", hash = "sha256:cf28430ec1924af1bffed37b69a812339084697fd3f3e781074a0148e6475803"}, + {file = "pymongo-4.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:e004527ea42a6b99a8b8d5b42b42762c3bdf80f88fbdb5c3a9d47f3808495b86"}, + {file = "pymongo-4.7.2.tar.gz", hash = "sha256:9024e1661c6e40acf468177bf90ce924d1bc681d2b244adda3ed7b2f4c4d17d7"}, ] [package.dependencies] dnspython = ">=1.16.0,<3.0.0" [package.extras] -aws = ["pymongo-auth-aws (<2.0.0)"] -encryption = ["certifi", "pymongo[aws]", "pymongocrypt (>=1.6.0,<2.0.0)"] +aws = ["pymongo-auth-aws (>=1.1.0,<2.0.0)"] +encryption = ["certifi", "pymongo-auth-aws (>=1.1.0,<2.0.0)", "pymongocrypt (>=1.6.0,<2.0.0)"] gssapi = ["pykerberos", "winkerberos (>=0.5.0)"] ocsp = ["certifi", "cryptography (>=2.5)", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"] snappy = ["python-snappy"] +test = ["pytest (>=7)"] zstd = ["zstandard"] [[package]] name = "pytest" -version = "7.4.2" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, - {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -1175,13 +1146,13 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -1189,13 +1160,13 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2023.3.post1" +version = "2024.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] [[package]] @@ -1223,6 +1194,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1259,13 +1231,13 @@ files = [ [[package]] name = "referencing" -version = "0.30.2" +version = "0.35.1" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.30.2-py3-none-any.whl", hash = "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf"}, - {file = "referencing-0.30.2.tar.gz", hash = "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0"}, + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, ] [package.dependencies] @@ -1274,13 +1246,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.31.0" +version = "2.32.2" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, + {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, ] [package.dependencies] @@ -1295,108 +1267,110 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rpds-py" -version = "0.10.3" +version = "0.18.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.10.3-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:485747ee62da83366a44fbba963c5fe017860ad408ccd6cd99aa66ea80d32b2e"}, - {file = "rpds_py-0.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c55f9821f88e8bee4b7a72c82cfb5ecd22b6aad04033334f33c329b29bfa4da0"}, - {file = "rpds_py-0.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3b52a67ac66a3a64a7e710ba629f62d1e26ca0504c29ee8cbd99b97df7079a8"}, - {file = "rpds_py-0.10.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3aed39db2f0ace76faa94f465d4234aac72e2f32b009f15da6492a561b3bbebd"}, - {file = "rpds_py-0.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:271c360fdc464fe6a75f13ea0c08ddf71a321f4c55fc20a3fe62ea3ef09df7d9"}, - {file = "rpds_py-0.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef5fddfb264e89c435be4adb3953cef5d2936fdeb4463b4161a6ba2f22e7b740"}, - {file = "rpds_py-0.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a771417c9c06c56c9d53d11a5b084d1de75de82978e23c544270ab25e7c066ff"}, - {file = "rpds_py-0.10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:52b5cbc0469328e58180021138207e6ec91d7ca2e037d3549cc9e34e2187330a"}, - {file = "rpds_py-0.10.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6ac3fefb0d168c7c6cab24fdfc80ec62cd2b4dfd9e65b84bdceb1cb01d385c33"}, - {file = "rpds_py-0.10.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8d54bbdf5d56e2c8cf81a1857250f3ea132de77af543d0ba5dce667183b61fec"}, - {file = "rpds_py-0.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cd2163f42868865597d89399a01aa33b7594ce8e2c4a28503127c81a2f17784e"}, - {file = "rpds_py-0.10.3-cp310-none-win32.whl", hash = "sha256:ea93163472db26ac6043e8f7f93a05d9b59e0505c760da2a3cd22c7dd7111391"}, - {file = "rpds_py-0.10.3-cp310-none-win_amd64.whl", hash = "sha256:7cd020b1fb41e3ab7716d4d2c3972d4588fdfbab9bfbbb64acc7078eccef8860"}, - {file = "rpds_py-0.10.3-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:1d9b5ee46dcb498fa3e46d4dfabcb531e1f2e76b477e0d99ef114f17bbd38453"}, - {file = "rpds_py-0.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:563646d74a4b4456d0cf3b714ca522e725243c603e8254ad85c3b59b7c0c4bf0"}, - {file = "rpds_py-0.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e626b864725680cd3904414d72e7b0bd81c0e5b2b53a5b30b4273034253bb41f"}, - {file = "rpds_py-0.10.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:485301ee56ce87a51ccb182a4b180d852c5cb2b3cb3a82f7d4714b4141119d8c"}, - {file = "rpds_py-0.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42f712b4668831c0cd85e0a5b5a308700fe068e37dcd24c0062904c4e372b093"}, - {file = "rpds_py-0.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c9141af27a4e5819d74d67d227d5047a20fa3c7d4d9df43037a955b4c748ec5"}, - {file = "rpds_py-0.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef750a20de1b65657a1425f77c525b0183eac63fe7b8f5ac0dd16f3668d3e64f"}, - {file = "rpds_py-0.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e1a0ffc39f51aa5f5c22114a8f1906b3c17eba68c5babb86c5f77d8b1bba14d1"}, - {file = "rpds_py-0.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f4c179a7aeae10ddf44c6bac87938134c1379c49c884529f090f9bf05566c836"}, - {file = "rpds_py-0.10.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:176287bb998fd1e9846a9b666e240e58f8d3373e3bf87e7642f15af5405187b8"}, - {file = "rpds_py-0.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6446002739ca29249f0beaaf067fcbc2b5aab4bc7ee8fb941bd194947ce19aff"}, - {file = "rpds_py-0.10.3-cp311-none-win32.whl", hash = "sha256:c7aed97f2e676561416c927b063802c8a6285e9b55e1b83213dfd99a8f4f9e48"}, - {file = "rpds_py-0.10.3-cp311-none-win_amd64.whl", hash = "sha256:8bd01ff4032abaed03f2db702fa9a61078bee37add0bd884a6190b05e63b028c"}, - {file = "rpds_py-0.10.3-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:4cf0855a842c5b5c391dd32ca273b09e86abf8367572073bd1edfc52bc44446b"}, - {file = "rpds_py-0.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:69b857a7d8bd4f5d6e0db4086da8c46309a26e8cefdfc778c0c5cc17d4b11e08"}, - {file = "rpds_py-0.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:975382d9aa90dc59253d6a83a5ca72e07f4ada3ae3d6c0575ced513db322b8ec"}, - {file = "rpds_py-0.10.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35fbd23c1c8732cde7a94abe7fb071ec173c2f58c0bd0d7e5b669fdfc80a2c7b"}, - {file = "rpds_py-0.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:106af1653007cc569d5fbb5f08c6648a49fe4de74c2df814e234e282ebc06957"}, - {file = "rpds_py-0.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce5e7504db95b76fc89055c7f41e367eaadef5b1d059e27e1d6eabf2b55ca314"}, - {file = "rpds_py-0.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aca759ada6b1967fcfd4336dcf460d02a8a23e6abe06e90ea7881e5c22c4de6"}, - {file = "rpds_py-0.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b5d4bdd697195f3876d134101c40c7d06d46c6ab25159ed5cbd44105c715278a"}, - {file = "rpds_py-0.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a657250807b6efd19b28f5922520ae002a54cb43c2401e6f3d0230c352564d25"}, - {file = "rpds_py-0.10.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:177c9dd834cdf4dc39c27436ade6fdf9fe81484758885f2d616d5d03c0a83bd2"}, - {file = "rpds_py-0.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e22491d25f97199fc3581ad8dd8ce198d8c8fdb8dae80dea3512e1ce6d5fa99f"}, - {file = "rpds_py-0.10.3-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:2f3e1867dd574014253b4b8f01ba443b9c914e61d45f3674e452a915d6e929a3"}, - {file = "rpds_py-0.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c22211c165166de6683de8136229721f3d5c8606cc2c3d1562da9a3a5058049c"}, - {file = "rpds_py-0.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40bc802a696887b14c002edd43c18082cb7b6f9ee8b838239b03b56574d97f71"}, - {file = "rpds_py-0.10.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e271dd97c7bb8eefda5cca38cd0b0373a1fea50f71e8071376b46968582af9b"}, - {file = "rpds_py-0.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:95cde244e7195b2c07ec9b73fa4c5026d4a27233451485caa1cd0c1b55f26dbd"}, - {file = "rpds_py-0.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08a80cf4884920863623a9ee9a285ee04cef57ebedc1cc87b3e3e0f24c8acfe5"}, - {file = "rpds_py-0.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:763ad59e105fca09705d9f9b29ecffb95ecdc3b0363be3bb56081b2c6de7977a"}, - {file = "rpds_py-0.10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:187700668c018a7e76e89424b7c1042f317c8df9161f00c0c903c82b0a8cac5c"}, - {file = "rpds_py-0.10.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5267cfda873ad62591b9332fd9472d2409f7cf02a34a9c9cb367e2c0255994bf"}, - {file = "rpds_py-0.10.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:2ed83d53a8c5902ec48b90b2ac045e28e1698c0bea9441af9409fc844dc79496"}, - {file = "rpds_py-0.10.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:255f1a10ae39b52122cce26ce0781f7a616f502feecce9e616976f6a87992d6b"}, - {file = "rpds_py-0.10.3-cp38-none-win32.whl", hash = "sha256:a019a344312d0b1f429c00d49c3be62fa273d4a1094e1b224f403716b6d03be1"}, - {file = "rpds_py-0.10.3-cp38-none-win_amd64.whl", hash = "sha256:efb9ece97e696bb56e31166a9dd7919f8f0c6b31967b454718c6509f29ef6fee"}, - {file = "rpds_py-0.10.3-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:570cc326e78ff23dec7f41487aa9c3dffd02e5ee9ab43a8f6ccc3df8f9327623"}, - {file = "rpds_py-0.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cff7351c251c7546407827b6a37bcef6416304fc54d12d44dbfecbb717064717"}, - {file = "rpds_py-0.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:177914f81f66c86c012311f8c7f46887ec375cfcfd2a2f28233a3053ac93a569"}, - {file = "rpds_py-0.10.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:448a66b8266de0b581246ca7cd6a73b8d98d15100fb7165974535fa3b577340e"}, - {file = "rpds_py-0.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bbac1953c17252f9cc675bb19372444aadf0179b5df575ac4b56faaec9f6294"}, - {file = "rpds_py-0.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dd9d9d9e898b9d30683bdd2b6c1849449158647d1049a125879cb397ee9cd12"}, - {file = "rpds_py-0.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c71ea77536149e36c4c784f6d420ffd20bea041e3ba21ed021cb40ce58e2c9"}, - {file = "rpds_py-0.10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16a472300bc6c83fe4c2072cc22b3972f90d718d56f241adabc7ae509f53f154"}, - {file = "rpds_py-0.10.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b9255e7165083de7c1d605e818025e8860636348f34a79d84ec533546064f07e"}, - {file = "rpds_py-0.10.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:53d7a3cd46cdc1689296348cb05ffd4f4280035770aee0c8ead3bbd4d6529acc"}, - {file = "rpds_py-0.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22da15b902f9f8e267020d1c8bcfc4831ca646fecb60254f7bc71763569f56b1"}, - {file = "rpds_py-0.10.3-cp39-none-win32.whl", hash = "sha256:850c272e0e0d1a5c5d73b1b7871b0a7c2446b304cec55ccdb3eaac0d792bb065"}, - {file = "rpds_py-0.10.3-cp39-none-win_amd64.whl", hash = "sha256:de61e424062173b4f70eec07e12469edde7e17fa180019a2a0d75c13a5c5dc57"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:af247fd4f12cca4129c1b82090244ea5a9d5bb089e9a82feb5a2f7c6a9fe181d"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ad59efe24a4d54c2742929001f2d02803aafc15d6d781c21379e3f7f66ec842"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642ed0a209ced4be3a46f8cb094f2d76f1f479e2a1ceca6de6346a096cd3409d"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:37d0c59548ae56fae01c14998918d04ee0d5d3277363c10208eef8c4e2b68ed6"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aad6ed9e70ddfb34d849b761fb243be58c735be6a9265b9060d6ddb77751e3e8"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8f94fdd756ba1f79f988855d948ae0bad9ddf44df296770d9a58c774cfbcca72"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77076bdc8776a2b029e1e6ffbe6d7056e35f56f5e80d9dc0bad26ad4a024a762"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:87d9b206b1bd7a0523375dc2020a6ce88bca5330682ae2fe25e86fd5d45cea9c"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8efaeb08ede95066da3a3e3c420fcc0a21693fcd0c4396d0585b019613d28515"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a4d9bfda3f84fc563868fe25ca160c8ff0e69bc4443c5647f960d59400ce6557"}, - {file = "rpds_py-0.10.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d27aa6bbc1f33be920bb7adbb95581452cdf23005d5611b29a12bb6a3468cc95"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ed8313809571a5463fd7db43aaca68ecb43ca7a58f5b23b6e6c6c5d02bdc7882"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:e10e6a1ed2b8661201e79dff5531f8ad4cdd83548a0f81c95cf79b3184b20c33"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:015de2ce2af1586ff5dc873e804434185199a15f7d96920ce67e50604592cae9"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae87137951bb3dc08c7d8bfb8988d8c119f3230731b08a71146e84aaa919a7a9"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0bb4f48bd0dd18eebe826395e6a48b7331291078a879295bae4e5d053be50d4c"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:09362f86ec201288d5687d1dc476b07bf39c08478cde837cb710b302864e7ec9"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821392559d37759caa67d622d0d2994c7a3f2fb29274948ac799d496d92bca73"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7170cbde4070dc3c77dec82abf86f3b210633d4f89550fa0ad2d4b549a05572a"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:5de11c041486681ce854c814844f4ce3282b6ea1656faae19208ebe09d31c5b8"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:4ed172d0c79f156c1b954e99c03bc2e3033c17efce8dd1a7c781bc4d5793dfac"}, - {file = "rpds_py-0.10.3-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:11fdd1192240dda8d6c5d18a06146e9045cb7e3ba7c06de6973000ff035df7c6"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:f602881d80ee4228a2355c68da6b296a296cd22bbb91e5418d54577bbf17fa7c"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:691d50c99a937709ac4c4cd570d959a006bd6a6d970a484c84cc99543d4a5bbb"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24cd91a03543a0f8d09cb18d1cb27df80a84b5553d2bd94cba5979ef6af5c6e7"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fc2200e79d75b5238c8d69f6a30f8284290c777039d331e7340b6c17cad24a5a"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea65b59882d5fa8c74a23f8960db579e5e341534934f43f3b18ec1839b893e41"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:829e91f3a8574888b73e7a3feb3b1af698e717513597e23136ff4eba0bc8387a"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eab75a8569a095f2ad470b342f2751d9902f7944704f0571c8af46bede438475"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:061c3ff1f51ecec256e916cf71cc01f9975af8fb3af9b94d3c0cc8702cfea637"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:39d05e65f23a0fe897b6ac395f2a8d48c56ac0f583f5d663e0afec1da89b95da"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:4eca20917a06d2fca7628ef3c8b94a8c358f6b43f1a621c9815243462dcccf97"}, - {file = "rpds_py-0.10.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e8d0f0eca087630d58b8c662085529781fd5dc80f0a54eda42d5c9029f812599"}, - {file = "rpds_py-0.10.3.tar.gz", hash = "sha256:fcc1ebb7561a3e24a6588f7c6ded15d80aec22c66a070c757559b57b17ffd1cb"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, + {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, + {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, + {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, + {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, + {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, + {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, + {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, + {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, + {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, + {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, + {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, ] [[package]] @@ -1423,20 +1397,20 @@ files = [ [[package]] name = "sphinx" -version = "7.2.6" +version = "7.3.7" description = "Python documentation generator" optional = false python-versions = ">=3.9" files = [ - {file = "sphinx-7.2.6-py3-none-any.whl", hash = "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560"}, - {file = "sphinx-7.2.6.tar.gz", hash = "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5"}, + {file = "sphinx-7.3.7-py3-none-any.whl", hash = "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3"}, + {file = "sphinx-7.3.7.tar.gz", hash = "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc"}, ] [package.dependencies] -alabaster = ">=0.7,<0.8" +alabaster = ">=0.7.14,<0.8.0" babel = ">=2.9" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18.1,<0.21" +docutils = ">=0.18.1,<0.22" imagesize = ">=1.3" importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} Jinja2 = ">=3.0" @@ -1450,11 +1424,12 @@ sphinxcontrib-htmlhelp = ">=2.0.0" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" sphinxcontrib-serializinghtml = ">=1.1.9" +tomli = {version = ">=2", markers = "python_version < \"3.11\""} [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] -test = ["cython (>=3.0)", "filelock", "html5lib", "pytest (>=4.6)", "setuptools (>=67.0)"] +lint = ["flake8 (>=3.5.0)", "importlib_metadata", "mypy (==1.9.0)", "pytest (>=6.0)", "ruff (==0.3.7)", "sphinx-lint", "tomli", "types-docutils", "types-requests"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=6.0)", "setuptools (>=67.0)"] [[package]] name = "sphinx-rtd-theme" @@ -1477,56 +1452,50 @@ dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.7" +version = "1.0.8" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_applehelp-1.0.7-py3-none-any.whl", hash = "sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d"}, - {file = "sphinxcontrib_applehelp-1.0.7.tar.gz", hash = "sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa"}, + {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, + {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.5" +version = "1.0.6" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_devhelp-1.0.5-py3-none-any.whl", hash = "sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f"}, - {file = "sphinxcontrib_devhelp-1.0.5.tar.gz", hash = "sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212"}, + {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, + {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.4" +version = "2.0.5" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_htmlhelp-2.0.4-py3-none-any.whl", hash = "sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9"}, - {file = "sphinxcontrib_htmlhelp-2.0.4.tar.gz", hash = "sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a"}, + {file = "sphinxcontrib_htmlhelp-2.0.5-py3-none-any.whl", hash = "sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04"}, + {file = "sphinxcontrib_htmlhelp-2.0.5.tar.gz", hash = "sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] @@ -1559,49 +1528,45 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.6" +version = "1.0.7" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_qthelp-1.0.6-py3-none-any.whl", hash = "sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4"}, - {file = "sphinxcontrib_qthelp-1.0.6.tar.gz", hash = "sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d"}, + {file = "sphinxcontrib_qthelp-1.0.7-py3-none-any.whl", hash = "sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182"}, + {file = "sphinxcontrib_qthelp-1.0.7.tar.gz", hash = "sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.9" +version = "1.1.10" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_serializinghtml-1.1.9-py3-none-any.whl", hash = "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1"}, - {file = "sphinxcontrib_serializinghtml-1.1.9.tar.gz", hash = "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54"}, + {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, + {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "stack-data" -version = "0.6.2" +version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" optional = false python-versions = "*" files = [ - {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"}, - {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"}, + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, ] [package.dependencies] @@ -1625,55 +1590,55 @@ files = [ [[package]] name = "traitlets" -version = "5.10.0" +version = "5.14.3" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.10.0-py3-none-any.whl", hash = "sha256:417745a96681fbb358e723d5346a547521f36e9bd0d50ba7ab368fff5d67aa54"}, - {file = "traitlets-5.10.0.tar.gz", hash = "sha256:f584ea209240466e66e91f3c81aa7d004ba4cf794990b0c775938a1544217cd1"}, + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.5.1)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.12.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, + {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, ] [[package]] name = "urllib3" -version = "2.0.4" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, - {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uwsgi" -version = "2.0.22" +version = "2.0.25.1" description = "The uWSGI server" optional = false python-versions = "*" files = [ - {file = "uwsgi-2.0.22.tar.gz", hash = "sha256:4cc4727258671ac5fa17ab422155e9aaef8a2008ebb86e4404b66deaae965db2"}, + {file = "uwsgi-2.0.25.1.tar.gz", hash = "sha256:d653d2d804c194c8cbe2585fa56efa2650313ae75c686a9d7931374d4dfbfc6e"}, ] [[package]] @@ -1688,13 +1653,13 @@ files = [ [[package]] name = "wcwidth" -version = "0.2.6" +version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, - {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, ] [[package]] @@ -1713,36 +1678,36 @@ watchdog = ["watchdog"] [[package]] name = "wtforms" -version = "3.0.1" +version = "3.1.2" description = "Form validation and rendering for Python web development." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "WTForms-3.0.1-py3-none-any.whl", hash = "sha256:837f2f0e0ca79481b92884962b914eba4e72b7a2daaf1f939c890ed0124b834b"}, - {file = "WTForms-3.0.1.tar.gz", hash = "sha256:6b351bbb12dd58af57ffef05bc78425d08d1914e0fd68ee14143b7ade023c5bc"}, + {file = "wtforms-3.1.2-py3-none-any.whl", hash = "sha256:bf831c042829c8cdbad74c27575098d541d039b1faa74c771545ecac916f2c07"}, + {file = "wtforms-3.1.2.tar.gz", hash = "sha256:f8d76180d7239c94c6322f7990ae1216dae3659b7aa1cee94b6318bdffb474b9"}, ] [package.dependencies] email-validator = {version = "*", optional = true, markers = "extra == \"email\""} -MarkupSafe = "*" +markupsafe = "*" [package.extras] email = ["email-validator"] [[package]] name = "zipp" -version = "3.16.2" +version = "3.19.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, - {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, + {file = "zipp-3.19.0-py3-none-any.whl", hash = "sha256:96dc6ad62f1441bcaccef23b274ec471518daf4fbbc580341204936a5a3dddec"}, + {file = "zipp-3.19.0.tar.gz", hash = "sha256:952df858fb3164426c976d9338d3961e8e8b3758e2e059e0f754b8c4262625ee"}, ] [package.extras] 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-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "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" From 0541ef41226ed043b3f8e783089391914b02ae21 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 28 May 2024 12:06:54 +0200 Subject: [PATCH 08/32] =?UTF-8?q?:bookmark:=20Bump=20version:=200.2.2=20?= =?UTF-8?q?=E2=86=92=200.3.0.dev0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- flask-data/smarter/__init__.py | 2 +- flask-data/smarter/app.py | 2 +- flask-data/smarter/docs/source/conf.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 987b550..14d6d06 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.2.2 +current_version = 0.3.0.dev0 commit = True tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\.(?P[a-z]+)(?P\d+))? diff --git a/flask-data/smarter/__init__.py b/flask-data/smarter/__init__.py index fe601ec..b7cefb1 100644 --- a/flask-data/smarter/__init__.py +++ b/flask-data/smarter/__init__.py @@ -13,7 +13,7 @@ __copyright__ = "Copyright 2021, IBBA-CNR" __credits__ = ["Paolo Cozzi, ..."] __license__ = "GNU General Public License v3" -__version__ = "0.2.2" +__version__ = "0.3.0.dev0" __maintainer__ = "Paolo Cozzi" __email__ = 'paolo.cozzi@ibba.cnr.it' __status__ = "Development" diff --git a/flask-data/smarter/app.py b/flask-data/smarter/app.py index b625285..4c97d05 100644 --- a/flask-data/smarter/app.py +++ b/flask-data/smarter/app.py @@ -24,7 +24,7 @@ from resources.routes import initialize_routes from commands import usersbp -__version__ = "0.2.2" +__version__ = "0.3.0.dev0" # https://flask.palletsprojects.com/en/2.0.x/logging/#basic-configuration dictConfig({ diff --git a/flask-data/smarter/docs/source/conf.py b/flask-data/smarter/docs/source/conf.py index ac3ee24..1956670 100644 --- a/flask-data/smarter/docs/source/conf.py +++ b/flask-data/smarter/docs/source/conf.py @@ -24,7 +24,7 @@ author = 'Paolo Cozzi' # The full version, including alpha/beta/rc tags -release = 'v0.2.2' +release = 'v0.3.0.dev0' # -- General configuration --------------------------------------------------- From be6120cc5bcb64e85f237dec4162f5f0404d4671 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 28 May 2024 12:10:39 +0200 Subject: [PATCH 09/32] :wrench: update bunmp2version configuration file --- .bumpversion.cfg | 8 ++++++-- pyproject.toml | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 14d6d06..6513224 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,7 +3,7 @@ current_version = 0.3.0.dev0 commit = True tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\.(?P[a-z]+)(?P\d+))? -serialize = +serialize = {major}.{minor}.{patch}.{release}{build} {major}.{minor}.{patch} message = :bookmark: Bump version: {current_version} → {new_version} @@ -11,7 +11,7 @@ message = :bookmark: Bump version: {current_version} → {new_version} [bumpversion:part:release] optional_value = prod first_value = dev -values = +values = dev prod @@ -27,4 +27,8 @@ replace = {new_version} search = {current_version} replace = {new_version} +[bumpversion:file:pyproject.toml] +search = {current_version} +replace = {new_version} + [bumpversion:part:build] diff --git a/pyproject.toml b/pyproject.toml index fd8b5b4..1116905 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "smarter-backend" -version = "0.3.0" +version = "0.3.0.dev0" description = "SMARTER Backend API" authors = ["Paolo Cozzi "] license = "GPLv3" From 60e09f6ac94e49fa94719f3f813662ad19f40071 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Fri, 14 Jun 2024 17:23:09 +0200 Subject: [PATCH 10/32] :arrow_up: update pymongo --- poetry.lock | 123 ++++++++++++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/poetry.lock b/poetry.lock index e1cfe73..17dfbdf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1043,71 +1043,71 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pymongo" -version = "4.7.2" +version = "4.7.3" description = "Python driver for MongoDB " optional = false python-versions = ">=3.7" files = [ - {file = "pymongo-4.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:268d8578c0500012140c5460755ea405cbfe541ef47c81efa9d6744f0f99aeca"}, - {file = "pymongo-4.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:827611beb6c483260d520cfa6a49662d980dfa5368a04296f65fa39e78fccea7"}, - {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a754e366c404d19ff3f077ddeed64be31e0bb515e04f502bf11987f1baa55a16"}, - {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c44efab10d9a3db920530f7bcb26af8f408b7273d2f0214081d3891979726328"}, - {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35b3f0c7d49724859d4df5f0445818d525824a6cd55074c42573d9b50764df67"}, - {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e37faf298a37ffb3e0809e77fbbb0a32b6a2d18a83c59cfc2a7b794ea1136b0"}, - {file = "pymongo-4.7.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1bcd58669e56c08f1e72c5758868b5df169fe267501c949ee83c418e9df9155"}, - {file = "pymongo-4.7.2-cp310-cp310-win32.whl", hash = "sha256:c72d16fede22efe7cdd1f422e8da15760e9498024040429362886f946c10fe95"}, - {file = "pymongo-4.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:12d1fef77d25640cb78893d07ff7d2fac4c4461d8eec45bd3b9ad491a1115d6e"}, - {file = "pymongo-4.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fc5af24fcf5fc6f7f40d65446400d45dd12bea933d0299dc9e90c5b22197f1e9"}, - {file = "pymongo-4.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:730778b6f0964b164c187289f906bbc84cb0524df285b7a85aa355bbec43eb21"}, - {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47a1a4832ef2f4346dcd1a10a36ade7367ad6905929ddb476459abb4fd1b98cb"}, - {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6eab12c6385526d386543d6823b07187fefba028f0da216506e00f0e1855119"}, - {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37e9ea81fa59ee9274457ed7d59b6c27f6f2a5fe8e26f184ecf58ea52a019cb8"}, - {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e9d9d2c0aae73aa4369bd373ac2ac59f02c46d4e56c4b6d6e250cfe85f76802"}, - {file = "pymongo-4.7.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb6e00a79dff22c9a72212ad82021b54bdb3b85f38a85f4fc466bde581d7d17a"}, - {file = "pymongo-4.7.2-cp311-cp311-win32.whl", hash = "sha256:02efd1bb3397e24ef2af45923888b41a378ce00cb3a4259c5f4fc3c70497a22f"}, - {file = "pymongo-4.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:87bb453ac3eb44db95cb6d5a616fbc906c1c00661eec7f55696253a6245beb8a"}, - {file = "pymongo-4.7.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:12c466e02133b7f8f4ff1045c6b5916215c5f7923bc83fd6e28e290cba18f9f6"}, - {file = "pymongo-4.7.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f91073049c43d14e66696970dd708d319b86ee57ef9af359294eee072abaac79"}, - {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87032f818bf5052ab742812c715eff896621385c43f8f97cdd37d15b5d394e95"}, - {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6a87eef394039765679f75c6a47455a4030870341cb76eafc349c5944408c882"}, - {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d275596f840018858757561840767b39272ac96436fcb54f5cac6d245393fd97"}, - {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82102e353be13f1a6769660dd88115b1da382447672ba1c2662a0fbe3df1d861"}, - {file = "pymongo-4.7.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:194065c9d445017b3c82fb85f89aa2055464a080bde604010dc8eb932a6b3c95"}, - {file = "pymongo-4.7.2-cp312-cp312-win32.whl", hash = "sha256:db4380d1e69fdad1044a4b8f3bb105200542c49a0dde93452d938ff9db1d6d29"}, - {file = "pymongo-4.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:fadc6e8db7707c861ebe25b13ad6aca19ea4d2c56bf04a26691f46c23dadf6e4"}, - {file = "pymongo-4.7.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2cb77d09bd012cb4b30636e7e38d00b5f9be5eb521c364bde66490c45ee6c4b4"}, - {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56bf8b706946952acdea0fe478f8e44f1ed101c4b87f046859e6c3abe6c0a9f4"}, - {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcf337d1b252405779d9c79978d6ca15eab3cdaa2f44c100a79221bddad97c8a"}, - {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ffd1519edbe311df73c74ec338de7d294af535b2748191c866ea3a7c484cd15"}, - {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d59776f435564159196d971aa89422ead878174aff8fe18e06d9a0bc6d648c"}, - {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:347c49cf7f0ba49ea87c1a5a1984187ecc5516b7c753f31938bf7b37462824fd"}, - {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:84bc00200c3cbb6c98a2bb964c9e8284b641e4a33cf10c802390552575ee21de"}, - {file = "pymongo-4.7.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fcaf8c911cb29316a02356f89dbc0e0dfcc6a712ace217b6b543805690d2aefd"}, - {file = "pymongo-4.7.2-cp37-cp37m-win32.whl", hash = "sha256:b48a5650ee5320d59f6d570bd99a8d5c58ac6f297a4e9090535f6561469ac32e"}, - {file = "pymongo-4.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:5239ef7e749f1326ea7564428bf861d5250aa39d7f26d612741b1b1273227062"}, - {file = "pymongo-4.7.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2dcf608d35644e8d276d61bf40a93339d8d66a0e5f3e3f75b2c155a421a1b71"}, - {file = "pymongo-4.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:25eeb2c18ede63891cbd617943dd9e6b9cbccc54f276e0b2e693a0cc40f243c5"}, - {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9349f0bb17a31371d4cacb64b306e4ca90413a3ad1fffe73ac7cd495570d94b5"}, - {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ffd4d7cb2e6c6e100e2b39606d38a9ffc934e18593dc9bb326196afc7d93ce3d"}, - {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9a8bd37f5dabc86efceb8d8cbff5969256523d42d08088f098753dba15f3b37a"}, - {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c78f156edc59b905c80c9003e022e1a764c54fd40ac4fea05b0764f829790e2"}, - {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d892fb91e81cccb83f507cdb2ea0aa026ec3ced7f12a1d60f6a5bf0f20f9c1f"}, - {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:87832d6076c2c82f42870157414fd876facbb6554d2faf271ffe7f8f30ce7bed"}, - {file = "pymongo-4.7.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ce1a374ea0e49808e0380ffc64284c0ce0f12bd21042b4bef1af3eb7bdf49054"}, - {file = "pymongo-4.7.2-cp38-cp38-win32.whl", hash = "sha256:eb0642e5f0dd7e86bb358749cc278e70b911e617f519989d346f742dc9520dfb"}, - {file = "pymongo-4.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:4bdb5ffe1cd3728c9479671a067ef44dacafc3743741d4dc700c377c4231356f"}, - {file = "pymongo-4.7.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:743552033c63f0afdb56b9189ab04b5c1dbffd7310cf7156ab98eebcecf24621"}, - {file = "pymongo-4.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5239776633f7578b81207e5646245415a5a95f6ae5ef5dff8e7c2357e6264bfc"}, - {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:727ad07952c155cd20045f2ce91143c7dc4fb01a5b4e8012905a89a7da554b0c"}, - {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9385654f01a90f73827af4db90c290a1519f7d9102ba43286e187b373e9a78e9"}, - {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d833651f1ba938bb7501f13e326b96cfbb7d98867b2d545ca6d69c7664903e0"}, - {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf17ea9cea14d59b0527403dd7106362917ced7c4ec936c4ba22bd36c912c8e0"}, - {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cecd2df037249d1c74f0af86fb5b766104a5012becac6ff63d85d1de53ba8b98"}, - {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65b4c00dedbd333698b83cd2095a639a6f0d7c4e2a617988f6c65fb46711f028"}, - {file = "pymongo-4.7.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d9b6cbc037108ff1a0a867e7670d8513c37f9bcd9ee3d2464411bfabf70ca002"}, - {file = "pymongo-4.7.2-cp39-cp39-win32.whl", hash = "sha256:cf28430ec1924af1bffed37b69a812339084697fd3f3e781074a0148e6475803"}, - {file = "pymongo-4.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:e004527ea42a6b99a8b8d5b42b42762c3bdf80f88fbdb5c3a9d47f3808495b86"}, - {file = "pymongo-4.7.2.tar.gz", hash = "sha256:9024e1661c6e40acf468177bf90ce924d1bc681d2b244adda3ed7b2f4c4d17d7"}, + {file = "pymongo-4.7.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e9580b4537b3cc5d412070caabd1dabdf73fdce249793598792bac5782ecf2eb"}, + {file = "pymongo-4.7.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:517243b2b189c98004570dd8fc0e89b1a48363d5578b3b99212fa2098b2ea4b8"}, + {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23b1e9dabd61da1c7deb54d888f952f030e9e35046cebe89309b28223345b3d9"}, + {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03e0f9901ad66c6fb7da0d303461377524d61dab93a4e4e5af44164c5bb4db76"}, + {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9a870824aa54453aee030bac08c77ebcf2fe8999400f0c2a065bebcbcd46b7f8"}, + {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfd7b3d3f4261bddbb74a332d87581bc523353e62bb9da4027cc7340f6fcbebc"}, + {file = "pymongo-4.7.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d719a643ea6da46d215a3ba51dac805a773b611c641319558d8576cbe31cef8"}, + {file = "pymongo-4.7.3-cp310-cp310-win32.whl", hash = "sha256:d8b1e06f361f3c66ee694cb44326e1a2e4f93bc9c3a4849ae8547889fca71154"}, + {file = "pymongo-4.7.3-cp310-cp310-win_amd64.whl", hash = "sha256:c450ab2f9397e2d5caa7fddeb4feb30bf719c47c13ae02c0bbb3b71bf4099c1c"}, + {file = "pymongo-4.7.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79cc6459209e885ba097779eaa0fe7f2fa049db39ab43b1731cf8d065a4650e8"}, + {file = "pymongo-4.7.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e2287f1e2cc35e73cd74a4867e398a97962c5578a3991c730ef78d276ca8e46"}, + {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:413506bd48d8c31ee100645192171e4773550d7cb940b594d5175ac29e329ea1"}, + {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cc1febf17646d52b7561caa762f60bdfe2cbdf3f3e70772f62eb624269f9c05"}, + {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8dfcf18a49955d50a16c92b39230bd0668ffc9c164ccdfe9d28805182b48fa72"}, + {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89872041196c008caddf905eb59d3dc2d292ae6b0282f1138418e76f3abd3ad6"}, + {file = "pymongo-4.7.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3ed97b89de62ea927b672ad524de0d23f3a6b4a01c8d10e3d224abec973fbc3"}, + {file = "pymongo-4.7.3-cp311-cp311-win32.whl", hash = "sha256:d2f52b38151e946011d888a8441d3d75715c663fc5b41a7ade595e924e12a90a"}, + {file = "pymongo-4.7.3-cp311-cp311-win_amd64.whl", hash = "sha256:4a4cc91c28e81c0ce03d3c278e399311b0af44665668a91828aec16527082676"}, + {file = "pymongo-4.7.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cb30c8a78f5ebaca98640943447b6a0afcb146f40b415757c9047bf4a40d07b4"}, + {file = "pymongo-4.7.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9cf2069f5d37c398186453589486ea98bb0312214c439f7d320593b61880dc05"}, + {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3564f423958fced8a8c90940fd2f543c27adbcd6c7c6ed6715d847053f6200a0"}, + {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a8af8a38fa6951fff73e6ff955a6188f829b29fed7c5a1b739a306b4aa56fe8"}, + {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a0e81c8dba6d825272867d487f18764cfed3c736d71d7d4ff5b79642acbed42"}, + {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88fc1d146feabac4385ea8ddb1323e584922922641303c8bf392fe1c36803463"}, + {file = "pymongo-4.7.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4225100b2c5d1f7393d7c5d256ceb8b20766830eecf869f8ae232776347625a6"}, + {file = "pymongo-4.7.3-cp312-cp312-win32.whl", hash = "sha256:5f3569ed119bf99c0f39ac9962fb5591eff02ca210fe80bb5178d7a1171c1b1e"}, + {file = "pymongo-4.7.3-cp312-cp312-win_amd64.whl", hash = "sha256:eb383c54c0c8ba27e7712b954fcf2a0905fee82a929d277e2e94ad3a5ba3c7db"}, + {file = "pymongo-4.7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a46cffe91912570151617d866a25d07b9539433a32231ca7e7cf809b6ba1745f"}, + {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c3cba427dac50944c050c96d958c5e643c33a457acee03bae27c8990c5b9c16"}, + {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a5fd893edbeb7fa982f8d44b6dd0186b6cd86c89e23f6ef95049ff72bffe46"}, + {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c168a2fadc8b19071d0a9a4f85fe38f3029fe22163db04b4d5c046041c0b14bd"}, + {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c59c2c9e70f63a7f18a31e367898248c39c068c639b0579623776f637e8f482"}, + {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08165fd82c89d372e82904c3268bd8fe5de44f92a00e97bb1db1785154397d9"}, + {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:397fed21afec4fdaecf72f9c4344b692e489756030a9c6d864393e00c7e80491"}, + {file = "pymongo-4.7.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f903075f8625e2d228f1b9b9a0cf1385f1c41e93c03fd7536c91780a0fb2e98f"}, + {file = "pymongo-4.7.3-cp37-cp37m-win32.whl", hash = "sha256:8ed1132f58c38add6b6138b771d0477a3833023c015c455d9a6e26f367f9eb5c"}, + {file = "pymongo-4.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:8d00a5d8fc1043a4f641cbb321da766699393f1b6f87c70fae8089d61c9c9c54"}, + {file = "pymongo-4.7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9377b868c38700c7557aac1bc4baae29f47f1d279cc76b60436e547fd643318c"}, + {file = "pymongo-4.7.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:da4a6a7b4f45329bb135aa5096823637bd5f760b44d6224f98190ee367b6b5dd"}, + {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:487e2f9277f8a63ac89335ec4f1699ae0d96ebd06d239480d69ed25473a71b2c"}, + {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db3d608d541a444c84f0bfc7bad80b0b897e0f4afa580a53f9a944065d9b633"}, + {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e90af2ad3a8a7c295f4d09a2fbcb9a350c76d6865f787c07fe843b79c6e821d1"}, + {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e28feb18dc559d50ededba27f9054c79f80c4edd70a826cecfe68f3266807b3"}, + {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f21ecddcba2d9132d5aebd8e959de8d318c29892d0718420447baf2b9bccbb19"}, + {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:26140fbb3f6a9a74bd73ed46d0b1f43d5702e87a6e453a31b24fad9c19df9358"}, + {file = "pymongo-4.7.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:94baa5fc7f7d22c3ce2ac7bd92f7e03ba7a6875f2480e3b97a400163d6eaafc9"}, + {file = "pymongo-4.7.3-cp38-cp38-win32.whl", hash = "sha256:92dd247727dd83d1903e495acc743ebd757f030177df289e3ba4ef8a8c561fad"}, + {file = "pymongo-4.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:1c90c848a5e45475731c35097f43026b88ef14a771dfd08f20b67adc160a3f79"}, + {file = "pymongo-4.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f598be401b416319a535c386ac84f51df38663f7a9d1071922bda4d491564422"}, + {file = "pymongo-4.7.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:35ba90477fae61c65def6e7d09e8040edfdd3b7fd47c3c258b4edded60c4d625"}, + {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9aa8735955c70892634d7e61b0ede9b1eefffd3cd09ccabee0ffcf1bdfe62254"}, + {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:82a97d8f7f138586d9d0a0cff804a045cdbbfcfc1cd6bba542b151e284fbbec5"}, + {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de3b9db558930efab5eaef4db46dcad8bf61ac3ddfd5751b3e5ac6084a25e366"}, + {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0e149217ef62812d3c2401cf0e2852b0c57fd155297ecc4dcd67172c4eca402"}, + {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3a8a1ef4a824f5feb793b3231526d0045eadb5eb01080e38435dfc40a26c3e5"}, + {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d14e5e89a4be1f10efc3d9dcb13eb7a3b2334599cb6bb5d06c6a9281b79c8e22"}, + {file = "pymongo-4.7.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6bfa29f032fd4fd7b129520f8cdb51ab71d88c2ba0567cccd05d325f963acb5"}, + {file = "pymongo-4.7.3-cp39-cp39-win32.whl", hash = "sha256:1421d0bd2ce629405f5157bd1aaa9b83f12d53a207cf68a43334f4e4ee312b66"}, + {file = "pymongo-4.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:f7ee974f8b9370a998919c55b1050889f43815ab588890212023fecbc0402a6d"}, + {file = "pymongo-4.7.3.tar.gz", hash = "sha256:6354a66b228f2cd399be7429685fb68e07f19110a3679782ecb4fdb68da03831"}, ] [package.dependencies] @@ -1194,7 +1194,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, From d244cc0739671aef424c4c6bb2aac9bf9ade484d Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Fri, 14 Jun 2024 17:25:05 +0200 Subject: [PATCH 11/32] :arrow_up: update dependencies --- poetry.lock | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/poetry.lock b/poetry.lock index 17dfbdf..4d9c876 100644 --- a/poetry.lock +++ b/poetry.lock @@ -118,13 +118,13 @@ typecheck = ["mypy"] [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.6.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, ] [[package]] @@ -896,13 +896,13 @@ pymongo = ">=3.4,<5.0" [[package]] name = "packaging" -version = "24.0" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -951,13 +951,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "prompt-toolkit" -version = "3.0.44" +version = "3.0.47" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.44-py3-none-any.whl", hash = "sha256:205a20669633d042d3722a528b8e7cd3f4dbd9e1450935f596c2cc61166762dd"}, - {file = "prompt_toolkit-3.0.44.tar.gz", hash = "sha256:c1dfd082c4259964bc8bcce1f8460d9dbeb5d4a37bfc25b8082bc02cd41c8af6"}, + {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, + {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, ] [package.dependencies] @@ -1245,13 +1245,13 @@ rpds-py = ">=0.7.0" [[package]] name = "requests" -version = "2.32.2" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"}, - {file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1604,13 +1604,13 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "typing-extensions" -version = "4.12.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, - {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] @@ -1632,12 +1632,12 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uwsgi" -version = "2.0.25.1" +version = "2.0.26" description = "The uWSGI server" optional = false python-versions = "*" files = [ - {file = "uwsgi-2.0.25.1.tar.gz", hash = "sha256:d653d2d804c194c8cbe2585fa56efa2650313ae75c686a9d7931374d4dfbfc6e"}, + {file = "uwsgi-2.0.26.tar.gz", hash = "sha256:86e6bfcd4dc20529665f5b7777193cdc48622fb2c59f0a7f1e3dc32b3882e7f9"}, ] [[package]] @@ -1695,18 +1695,18 @@ email = ["email-validator"] [[package]] name = "zipp" -version = "3.19.0" +version = "3.19.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.19.0-py3-none-any.whl", hash = "sha256:96dc6ad62f1441bcaccef23b274ec471518daf4fbbc580341204936a5a3dddec"}, - {file = "zipp-3.19.0.tar.gz", hash = "sha256:952df858fb3164426c976d9338d3961e8e8b3758e2e059e0f754b8c4262625ee"}, + {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, + {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, ] [package.extras] -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", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "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" From 3e60b88f2da7320d669cfcf2e84a59b1ebccfe7b Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Mon, 17 Jun 2024 12:08:56 +0200 Subject: [PATCH 12/32] :pencil2: fix typos --- .vscode/settings.json | 7 +- .../smarter/docs/source/accessing/r.rst | 104 +++++++++--------- flask-data/smarter/resources/breeds.py | 4 +- flask-data/smarter/resources/chips.py | 4 +- flask-data/smarter/resources/countries.py | 4 +- flask-data/smarter/resources/datasets.py | 4 +- flask-data/smarter/resources/samples.py | 4 +- flask-data/smarter/resources/variants.py | 4 +- 8 files changed, 70 insertions(+), 65 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 364455f..3a772a5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,8 @@ { - "esbonio.sphinx.confDir": "${workspaceFolder}/flask-data/smarter/docs/source" + "esbonio.sphinx.confDir": "${workspaceFolder}/flask-data/smarter/docs/source", + "cSpell.words": [ + "affymetrix", + "jsonify", + "reqparse" + ] } diff --git a/flask-data/smarter/docs/source/accessing/r.rst b/flask-data/smarter/docs/source/accessing/r.rst index dacb499..af37c34 100644 --- a/flask-data/smarter/docs/source/accessing/r.rst +++ b/flask-data/smarter/docs/source/accessing/r.rst @@ -5,7 +5,7 @@ Accessing data using R .. toctree:: :maxdepth: 4 -Here are some examples on how to interact with SMARTER-backend API using ``R``. +Here are some examples on how to interact with SMARTER-backend API using ``R``. You will need to set up some utility functions in order to save your time by avoiding repeating stuff. @@ -23,18 +23,18 @@ to install some of them first): library(dplyr) ``httr`` is required to send requests and get response from SMARTER-backend API; -``jsonlite`` is required to parse ``JSON`` output, which is the default format -of the API response. ``getPass`` is not strictly required, it will prompt for our -credentials in order to not store them in our code. ``dplyr`` is useful to manage +``jsonlite`` is required to parse ``JSON`` output, which is the default format +of the API response. ``getPass`` is not strictly required, it will prompt for our +credentials in order to not store them in our code. ``dplyr`` is useful to manage dataframes, for examples when they have different columns (like response from SMARTER-backend) Generate a JWT token with R --------------------------- -As stated in our :ref:`Authentication` section of this guide, you need to generate -a :ref:`JWT token ` in order to get full access to smarter -metadata. Here is an utility function to request a token by providing your +As stated in our :ref:`Authentication` section of this guide, you need to generate +a :ref:`JWT token ` in order to get full access to smarter +metadata. Here is an utility function to request a token by providing your credentials with a ``POST`` HTTP method: .. code-block:: r @@ -64,25 +64,25 @@ credentials with a ``POST`` HTTP method: token <- get_smarter_token() ``base_url`` is defined for simplicity in order to make all our request to the -same server. The ``get_smarter_token`` function requires *user* and *password* +same server. The ``get_smarter_token`` function requires *user* and *password* as parameters. The ``readline`` and ``getPass::getPass`` functions used as default values are not strictly required, we use them in order to not write -credentials in our code: the function will prompt for those values if not provided +credentials in our code: the function will prompt for those values if not provided during function call. The token string is parsed and written into ``token`` variable: This is the value we need to add to each requests *header* -.. hint:: +.. hint:: Rstudio has a dedicated section on `Securing Credentials `_. We recommend to follow their guidelines. - + Deal with data and pagination ----------------------------- Next, before starting query SMARTER-backend, we can define more utility functions (as suggested by `Best practices for API packages `_) -in order to deal with pagination and API errors. We will read our data with -``jsonlite`` package in order to **flatten** our results (read nested object and +in order to deal with pagination and API errors. We will read our data with +``jsonlite`` package in order to **flatten** our results (read nested object and add them as columns in the resulting dataframe): .. code-block:: r @@ -100,7 +100,7 @@ add them as columns in the resulting dataframe): # parse a JSON response. fromJSON to flatten results parsed <- jsonlite::fromJSON( - content(resp, "text", encoding = "utf-8"), + content(resp, "text", encoding = "utf-8"), flatten = TRUE ) @@ -149,17 +149,17 @@ add them as columns in the resulting dataframe): } -Our functions will take an ``url`` parameter, which will be our API endpoint, the +Our functions will take an ``url`` parameter, which will be our API endpoint, the ``token`` that will be added in the header request as described in :ref:`Authentication` -section of our documentation and ``query``, which will be a list of +section of our documentation and ``query``, which will be a list of parameters that will enhance our queries as described in :ref:`Query parameters` -Read data with R +Read data with R ---------------- -Next we can try to read data from our API by defining custom functions around -the desidered endpoint. This function will call the functions previously defined -and will return all the results in a *dataframe*. Here's a sample function to +Next we can try to read data from our API by defining custom functions around +the desired endpoint. This function will call the functions previously defined +and will return all the results in a *dataframe*. Here's a sample function to deal with datasets objects by querying the *datasets* endpoint: .. code-block:: r @@ -177,9 +177,9 @@ deal with datasets objects by querying the *datasets* endpoint: all_datasets <- get_smarter_datasets(token) By calling the defined ``get_smarter_datasets`` function and providing a valid -token as parameter you will retrieve all datasets and you will store them in -the ``all_datasets`` dataframe. Similarly, to deal with the Breed endpoint you could -define the ``get_smarter_breeds`` function: +token as parameter you will retrieve all datasets and you will store them in +the ``all_datasets`` dataframe. Similarly, to deal with the Breed endpoint you could +define the ``get_smarter_breeds`` function: .. code-block:: r @@ -197,18 +197,18 @@ define the ``get_smarter_breeds`` function: goat_breeds <- get_smarter_breeds(token, query = list(species = "Goat")) -``get_smarter_breeds`` and ``get_smarter_datasets`` functions can be used to return -all the SMARTER datasets and breeds. However you can pass additional parameters to -the endpoint using the ``query`` parameter (which need to be a ``list``). For +``get_smarter_breeds`` and ``get_smarter_datasets`` functions can be used to return +all the SMARTER datasets and breeds. However you can pass additional parameters to +the endpoint using the ``query`` parameter (which need to be a ``list``). For example, you could retrieve all the *genotypes* datasets using the ``type`` parameter: .. code-block:: r genotypes_datasets <- get_smarter_datasets(token, query = list(type="genotypes")) -Since query accepts ``list``, you can specify the same parameter multiple times -(if the endpoints supports this type of query, see `api docs `_ -to get more information). For example, if you need only the *foreground genotypes*, +Since query accepts ``list``, you can specify the same parameter multiple times +(if the endpoints supports this type of query, see `api docs `_ +to get more information). For example, if you need only the *foreground genotypes*, you can select dataset like this: .. code-block:: r @@ -217,34 +217,34 @@ you can select dataset like this: token, query = list(type="genotypes", type="foreground")) You can add other parameters to refine your query, for example -if you want to select only the *Goat* breeds, you can specify -``species = "Goat"`` in the ``query`` parameter. If you need also to search -for the *land* term in the *breed* name, you will call the same function +if you want to select only the *Goat* breeds, you can specify +``species = "Goat"`` in the ``query`` parameter. If you need also to search +for the *land* term in the *breed* name, you will call the same function by adding a new parameter: -.. code-block:: r +.. code-block:: r - search_goat_breeds <- + search_goat_breeds <- get_smarter_breeds(token, query = list( species = "Goat", search = "land") ) - + ``search_goat_breeds`` will be a dataframe with the same results of the query URL:: - + https://webserver.ibba.cnr.it/smarter-api/breeds?species=Goat&search=land -We can select only the column we need by subsetting dataframe columns, or using +We can select only the column we need by subsetting dataframe columns, or using dplyr `select `_: .. code-block:: r search_goat_breeds <- search_goat_breeds %>% select(name, code) -Breed code and names can be used to get from samples from the proper endpoint. -Let's define another function that could be used for sheep and goat samples +Breed code and names can be used to get from samples from the proper endpoint. +Let's define another function that could be used for sheep and goat samples endpoints relying on parameters: -.. code-block:: r +.. code-block:: r get_smarter_samples <- function(token, species, query = list()) { # mind that species is lowercase in endpoint url @@ -254,7 +254,7 @@ endpoints relying on parameters: modify_url(base_url, path = sprintf("/smarter-api/samples/%s", species)) data <- get_smarter_data(url, token, query) - + # returning only the results dataframe data$results } @@ -265,9 +265,9 @@ endpoints relying on parameters: query = list(breed_code = "LNR") ) -As for the breed example, we can refine our query, for example by selecting +As for the breed example, we can refine our query, for example by selecting Landrace goat samples which have a locations (GPS coordinates) and phenotypes -defined (mind to the double ``_`` in ``locations__exists`` and +defined (mind to the double ``_`` in ``locations__exists`` and ``phenotype__exists``): .. code-block:: r @@ -276,12 +276,12 @@ defined (mind to the double ``_`` in ``locations__exists`` and token, species = "Goat", query = list( - breed_code = "LNR", + breed_code = "LNR", locations__exists = TRUE, phenotype__exists = TRUE) ) -As before we can select the ``smarter_id`` columns, to have a list of our samples +As before we can select the ``smarter_id`` columns, to have a list of our samples in order to subset the full genotype file using ``plink``: .. code-block:: r @@ -289,10 +289,10 @@ in order to subset the full genotype file using ``plink``: selected_landrace_samples %>% select(smarter_id) The same could be applied on variants endpoins in order to get information on -variants. In the following example we will select the goat variants on chromosome +variants. In the following example we will select the goat variants on chromosome *1* within *1-1000000* position in *ARS1* assembly: -.. code-block:: r +.. code-block:: r get_smarter_variations <- function(token, species, query = list()) { # mind that species is lowercase in endpoint url @@ -318,14 +318,14 @@ variants. In the following example we will select the goat variants on chromosom ) ) -.. hint:: +.. hint:: We are planning to simplify the variants response by returning a SNP list of - the selected SNPs only, in order to be used when subsetting a genotype file + the selected SNPs only, in order to be used when subsetting a genotype file using plink -.. warning:: +.. warning:: - Be careful when using the variants endpoints: getting all the variants will - takes a lot of time and could fill all your available memory. Avoid to request + Be careful when using the variants endpoints: getting all the variants will + takes a lot of time and could fill all your available memory. Avoid to request all variants in your R session, unless you know what you are doing diff --git a/flask-data/smarter/resources/breeds.py b/flask-data/smarter/resources/breeds.py index 74b41b1..0922113 100644 --- a/flask-data/smarter/resources/breeds.py +++ b/flask-data/smarter/resources/breeds.py @@ -76,7 +76,7 @@ def get(self): in: query type: string enum: ['Sheep', 'Goat'] - description: The desidered species + description: The desired species - name: name in: query type: array @@ -127,7 +127,7 @@ def get(self, id_): required: true responses: '200': - description: The desidered breed + description: The desired breed content: application/json: schema: diff --git a/flask-data/smarter/resources/chips.py b/flask-data/smarter/resources/chips.py index d2cda21..3777412 100644 --- a/flask-data/smarter/resources/chips.py +++ b/flask-data/smarter/resources/chips.py @@ -33,7 +33,7 @@ def get(self, id_): required: true responses: '200': - description: The desidered chip + description: The desired chip content: application/json: schema: @@ -82,7 +82,7 @@ def get(self): in: query type: string enum: ['Sheep', 'Goat'] - description: The desidered species + description: The desired species - name: name in: query type: string diff --git a/flask-data/smarter/resources/countries.py b/flask-data/smarter/resources/countries.py index 060d94d..e75a029 100644 --- a/flask-data/smarter/resources/countries.py +++ b/flask-data/smarter/resources/countries.py @@ -91,7 +91,7 @@ def get(self): in: query type: string enum: ['Sheep', 'Goat'] - description: The desidered species + description: The desired species - name: name in: query type: string @@ -140,7 +140,7 @@ def get(self, id_): required: true responses: '200': - description: The desidered country + description: The desired country content: application/json: schema: diff --git a/flask-data/smarter/resources/datasets.py b/flask-data/smarter/resources/datasets.py index 1b280ba..a1a1a89 100644 --- a/flask-data/smarter/resources/datasets.py +++ b/flask-data/smarter/resources/datasets.py @@ -84,7 +84,7 @@ def get(self): in: query type: string enum: ['Sheep', 'Goat'] - description: The desidered species + description: The desired species - name: type in: query type: array @@ -136,7 +136,7 @@ def get(self, id_): required: true responses: '200': - description: The desidered dataset + description: The desired dataset content: application/json: schema: diff --git a/flask-data/smarter/resources/samples.py b/flask-data/smarter/resources/samples.py index 72fb4ee..dc8c10f 100644 --- a/flask-data/smarter/resources/samples.py +++ b/flask-data/smarter/resources/samples.py @@ -133,7 +133,7 @@ def get(self, id_): required: true responses: '200': - description: The desidered sample + description: The desired sample content: application/json: schema: @@ -288,7 +288,7 @@ def get(self, id_): required: true responses: '200': - description: The desidered sample + description: The desired sample content: application/json: schema: diff --git a/flask-data/smarter/resources/variants.py b/flask-data/smarter/resources/variants.py index e008304..6f7f909 100644 --- a/flask-data/smarter/resources/variants.py +++ b/flask-data/smarter/resources/variants.py @@ -162,7 +162,7 @@ def get(self, id_): required: true responses: '200': - description: The desidered SNP + description: The desired SNP content: application/json: schema: @@ -301,7 +301,7 @@ def get(self, id_): required: true responses: '200': - description: The desidered SNP + description: The desired SNP content: application/json: schema: From 8f9c63371b2acd6eceb6c84987d212bd810bfac8 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Mon, 17 Jun 2024 12:12:47 +0200 Subject: [PATCH 13/32] :passport_control: remove jwt related stuff from endpoints --- flask-data/smarter/app.py | 10 ---------- flask-data/smarter/resources/GeoJSON.py | 7 ------- flask-data/smarter/resources/breeds.py | 3 --- flask-data/smarter/resources/chips.py | 3 --- flask-data/smarter/resources/countries.py | 3 --- flask-data/smarter/resources/datasets.py | 3 --- flask-data/smarter/resources/info.py | 2 -- flask-data/smarter/resources/samples.py | 7 ------- flask-data/smarter/resources/variants.py | 7 ------- 9 files changed, 45 deletions(-) diff --git a/flask-data/smarter/app.py b/flask-data/smarter/app.py index 4c97d05..1d76b67 100644 --- a/flask-data/smarter/app.py +++ b/flask-data/smarter/app.py @@ -13,8 +13,6 @@ from flask import Flask, redirect, url_for from flask_restful import Api -from flask_bcrypt import Bcrypt -from flask_jwt_extended import JWTManager from flask.json import JSONEncoder from flask_cors import CORS from flasgger import Swagger @@ -72,15 +70,10 @@ def create_app(config={}): app = Flask(__name__) CORS(app) api = Api(app, errors=errors) - Bcrypt(app) - JWTManager(app) # deal with ObjectId in json responses app.json_encoder = CustomJSONEncoder - # workaround to make flasgger deal with jwt-token headers - app.config["JWT_AUTH_URL_RULE"] = True - # Swagger stuff swagger_template = { "swagger": "2.0", @@ -130,9 +123,6 @@ def create_app(config={}): app.logger.error(f"Setting custom host: {config['host']}") app.config['MONGODB_SETTINGS']['host'] = config['host'] - # https://flask-jwt-extended.readthedocs.io/en/stable/basic_usage/ - app.config["JWT_SECRET_KEY"] = os.getenv('JWT_SECRET_KEY') - # connect to database initialize_db(app) diff --git a/flask-data/smarter/resources/GeoJSON.py b/flask-data/smarter/resources/GeoJSON.py index 243d09d..d841375 100644 --- a/flask-data/smarter/resources/GeoJSON.py +++ b/flask-data/smarter/resources/GeoJSON.py @@ -11,7 +11,6 @@ from flask import jsonify, current_app from flask_restful import Resource, reqparse -from flask_jwt_extended import jwt_required from database.models import SampleSheep, SampleGoat from resources.errors import MongoEngineValidationError, ObjectsNotExistsError @@ -200,7 +199,6 @@ def get_context_data(self): class SampleSheepGeoJSONApi(GeoJSONMixin, Resource): model = SampleSheep - @jwt_required() def get(self, id_): """ Get a single GeoJSON for Sheep @@ -228,7 +226,6 @@ def get(self, id_): class SampleGoatGeoJSONApi(GeoJSONMixin, Resource): model = SampleGoat - @jwt_required() def get(self, id_): """ Get a single GeoJSON for Goat @@ -256,7 +253,6 @@ def get(self, id_): class SampleSheepGeoJSONListApi(GeoJSONListMixin, Resource): model = SampleSheep - @jwt_required() def get(self): """ Get a GeoJSON for Sheep samples @@ -316,7 +312,6 @@ def get(self): return self.get_context_data() - @jwt_required() def post(self): """ Get a GeoJSON for Sheep samples @@ -358,7 +353,6 @@ def post(self): class SampleGoatGeoJSONListApi(GeoJSONListMixin, Resource): model = SampleGoat - @jwt_required() def get(self): """ Get a GeoJSON for Goat samples @@ -418,7 +412,6 @@ def get(self): return self.get_context_data() - @jwt_required() def post(self): """ Get a GeoJSON for Sheep samples diff --git a/flask-data/smarter/resources/breeds.py b/flask-data/smarter/resources/breeds.py index 0922113..6d2ded1 100644 --- a/flask-data/smarter/resources/breeds.py +++ b/flask-data/smarter/resources/breeds.py @@ -11,7 +11,6 @@ from mongoengine.queryset import Q from flask import jsonify, current_app from flask_restful import reqparse -from flask_jwt_extended import jwt_required from database.models import Breed from common.views import ListView, ModelView @@ -63,7 +62,6 @@ def get_queryset(self): return queryset - @jwt_required() def get(self): """ Get information on breeds @@ -111,7 +109,6 @@ def get(self): class BreedApi(ModelView): model = Breed - @jwt_required() def get(self, id_): """ Fetch a single breed diff --git a/flask-data/smarter/resources/chips.py b/flask-data/smarter/resources/chips.py index 3777412..d32eeda 100644 --- a/flask-data/smarter/resources/chips.py +++ b/flask-data/smarter/resources/chips.py @@ -8,7 +8,6 @@ from flask import jsonify, current_app from flask_restful import reqparse -from flask_jwt_extended import jwt_required from database.models import SupportedChip from common.views import ListView, ModelView @@ -17,7 +16,6 @@ class SupportedChipApi(ModelView): model = SupportedChip - @jwt_required() def get(self, id_): """ Fetch a single chip @@ -69,7 +67,6 @@ def get_queryset(self): return queryset - @jwt_required() def get(self): """ Get information on chips diff --git a/flask-data/smarter/resources/countries.py b/flask-data/smarter/resources/countries.py index e75a029..c39136d 100644 --- a/flask-data/smarter/resources/countries.py +++ b/flask-data/smarter/resources/countries.py @@ -11,7 +11,6 @@ from mongoengine.queryset import Q from flask import jsonify, current_app from flask_restful import reqparse -from flask_jwt_extended import jwt_required from database.models import Country from common.views import ListView, ModelView @@ -78,7 +77,6 @@ def get_queryset(self): return queryset - @jwt_required() def get(self): """ Get information on Countries @@ -124,7 +122,6 @@ def get(self): class CountryApi(ModelView): model = Country - @jwt_required() def get(self, id_): """ Fetch a single Country diff --git a/flask-data/smarter/resources/datasets.py b/flask-data/smarter/resources/datasets.py index a1a1a89..2289a2f 100644 --- a/flask-data/smarter/resources/datasets.py +++ b/flask-data/smarter/resources/datasets.py @@ -11,7 +11,6 @@ from mongoengine.queryset import Q from flask import jsonify, current_app from flask_restful import reqparse -from flask_jwt_extended import jwt_required from database.models import Dataset from common.views import ListView, ModelView @@ -71,7 +70,6 @@ def get_queryset(self): return queryset - @jwt_required() def get(self): """ Get information on datasets @@ -120,7 +118,6 @@ def get(self): class DatasetApi(ModelView): model = Dataset - @jwt_required() def get(self, id_): """ Fetch a single dataset diff --git a/flask-data/smarter/resources/info.py b/flask-data/smarter/resources/info.py index 88f542f..f66cdb4 100644 --- a/flask-data/smarter/resources/info.py +++ b/flask-data/smarter/resources/info.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- from flask import jsonify -from flask_jwt_extended import jwt_required from database.models import SmarterInfo from common.views import ModelView @@ -9,7 +8,6 @@ class SmarterInfoApi(ModelView): model = SmarterInfo - @jwt_required() def get(self): """ Get information on SMARTER database diff --git a/flask-data/smarter/resources/samples.py b/flask-data/smarter/resources/samples.py index dc8c10f..fec5349 100644 --- a/flask-data/smarter/resources/samples.py +++ b/flask-data/smarter/resources/samples.py @@ -8,7 +8,6 @@ from flask import jsonify, current_app from flask_restful import reqparse -from flask_jwt_extended import jwt_required from database.models import SampleGoat, SampleSheep from common.views import ListView, ModelView @@ -117,7 +116,6 @@ def get_queryset(self): class SampleSheepApi(ModelView): model = SampleSheep - @jwt_required() def get(self, id_): """ Fetch a single Sheep sample @@ -147,7 +145,6 @@ class SampleSheepListApi(SampleListMixin, ListView): endpoint = 'samplesheeplistapi' model = SampleSheep - @jwt_required() def get(self): """ Get samples information for Sheep @@ -229,7 +226,6 @@ def get(self): data = self.get_context_data() return jsonify(**data) - @jwt_required() def post(self): """ Get samples information for Sheep @@ -272,7 +268,6 @@ def post(self): class SampleGoatApi(ModelView): model = SampleGoat - @jwt_required() def get(self, id_): """ Fetch a single Goat sample @@ -302,7 +297,6 @@ class SampleGoatListApi(SampleListMixin, ListView): endpoint = 'samplegoatlistapi' model = SampleGoat - @jwt_required() def get(self): """ Get samples information for Goat @@ -384,7 +378,6 @@ def get(self): data = self.get_context_data() return jsonify(**data) - @jwt_required() def post(self): """ Get samples information for Goat diff --git a/flask-data/smarter/resources/variants.py b/flask-data/smarter/resources/variants.py index 6f7f909..c549faa 100644 --- a/flask-data/smarter/resources/variants.py +++ b/flask-data/smarter/resources/variants.py @@ -12,7 +12,6 @@ from flask import jsonify, current_app from flask_restful import reqparse -from flask_jwt_extended import jwt_required from database.models import VariantGoat, VariantSheep, SmarterInfo from common.views import ListView, ModelView @@ -146,7 +145,6 @@ def __prepare_match(self, kwargs): class VariantSheepApi(ModelView): model = VariantSheep - @jwt_required() def get(self, id_): """ Fetch a single Sheep SNP @@ -177,7 +175,6 @@ class VariantSheepOAR3Api(VariantListMixin, ListView): model = VariantSheep assembly = "OAR3" - @jwt_required() def get(self): """ Get SNPs on Sheep OAR3 Assembly @@ -232,7 +229,6 @@ class VariantSheepOAR4Api(VariantListMixin, ListView): model = VariantSheep assembly = "OAR4" - @jwt_required() def get(self): """ Get SNPs on Sheep OAR4 Assembly @@ -285,7 +281,6 @@ def get(self): class VariantGoatApi(ModelView): model = VariantGoat - @jwt_required() def get(self, id_): """ Fetch a single Goat SNP @@ -316,7 +311,6 @@ class VariantGoatCHI1Api(VariantListMixin, ListView): model = VariantGoat assembly = "CHI1" - @jwt_required() def get(self): """ Get SNPs on Goat CHI1 Assembly @@ -371,7 +365,6 @@ class VariantGoatARS1Api(VariantListMixin, ListView): model = VariantGoat assembly = "ARS1" - @jwt_required() def get(self): """ Get SNPs on Goat ARS1 Assembly From 27b0c482d5a5ac9a83fc5367fb5c432d5e55b15a Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Mon, 17 Jun 2024 12:29:13 +0200 Subject: [PATCH 14/32] :clown_face: mock auth endpoint returning a standard message when querying the AUTH endpoint --- flask-data/smarter/resources/auth.py | 78 ++++---------------------- flask-data/smarter/resources/errors.py | 13 ----- 2 files changed, 11 insertions(+), 80 deletions(-) diff --git a/flask-data/smarter/resources/auth.py b/flask-data/smarter/resources/auth.py index 20bfbfb..1e75970 100644 --- a/flask-data/smarter/resources/auth.py +++ b/flask-data/smarter/resources/auth.py @@ -7,98 +7,42 @@ """ import json -import datetime from flask import Response, request, current_app -from flask_jwt_extended import create_access_token, decode_token from flask_restful import Resource -from mongoengine.errors import DoesNotExist -from database.models import User -from resources.errors import ( - UnauthorizedError, InternalServerError, SchemaValidationError) +from resources.errors import InternalServerError class LoginApi(Resource): def post(self): """ - User authenticate method. + Old User authenticate method. Has been removed after public release. --- tags: - Authorization - description: Authenticate user with supplied credentials. - parameters: - - in: body - name: body - description: JSON parameters. - schema: - required: - - username - - password - properties: - username: - type: string - description: Your username - password: - type: string - description: Your password + description: Return a message telling users to update their client + responses: 200: - description: User successfully logged in. - 401: - description: User login failed. + description: A standard message """ try: - body = request.get_json() - - username = body.get('username') - password = body.get('password') - - # TODO: use a flask_restful method - if not username or not password: - raise SchemaValidationError - - user = User.objects.get(username=username) - - # calling custom user function (which uses bcrypt) - authorized = user.check_password(password) - - if not authorized: - raise UnauthorizedError - - expires = datetime.timedelta(days=7) - - access_token = create_access_token( - identity=str(user.id), - expires_delta=expires) - - # read token data - claims = decode_token(access_token) - - current_app.logger.info(f"New token generated for '{username}'") + # consume request body but don't do anything with it + _ = request.get_json() response = Response( json.dumps({ - 'token': access_token, - 'expires': str( - datetime.datetime.fromtimestamp(claims['exp'])) + "token": "Token has been removed after public release", + "message": ( + "Please update your Smarter API client to the latest " + "version") }), mimetype="application/json", status=200) - # add token to response headers - so SwaggerUI can use it - response.headers.extend({'jwt-token': access_token}) - return response - except (UnauthorizedError, DoesNotExist) as e: - current_app.logger.error(e) - raise UnauthorizedError - - except SchemaValidationError as e: - current_app.logger.error(e) - raise SchemaValidationError - except Exception as e: current_app.logger.error(e) raise InternalServerError diff --git a/flask-data/smarter/resources/errors.py b/flask-data/smarter/resources/errors.py index 1c85f22..545ec7b 100644 --- a/flask-data/smarter/resources/errors.py +++ b/flask-data/smarter/resources/errors.py @@ -17,10 +17,6 @@ class SchemaValidationError(HTTPException): pass -class UnauthorizedError(HTTPException): - pass - - class MongoEngineValidationError(HTTPException): pass @@ -34,11 +30,6 @@ class ObjectsNotExistsError(HTTPException): "message": "Something went wrong", "status": 500 }, - # flask_jwt_extended.exceptions.NoAuthorizationError: - "NoAuthorizationError": { - "message": "Missing Authorization Header", - "status": 401 - }, "SchemaValidationError": { "message": "Request is missing required fields", "status": 400 @@ -55,9 +46,5 @@ class ObjectsNotExistsError(HTTPException): "ObjectsNotExistsError": { "message": "Object does not exist", "status": 404 - }, - "ExpiredSignatureError": { - "message": "Your token is expired", - "status": 401 } } From be41fa8b9a29bf48d03bc4d81d0afab5a11fb85a Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Mon, 17 Jun 2024 12:40:12 +0200 Subject: [PATCH 15/32] :white_check_mark: fix tests after removing credentials auth endpoint replies with 200 independently from received data --- flask-data/smarter/tests/base.py | 46 ++-------------------- flask-data/smarter/tests/test_GeoJSON.py | 10 ++--- flask-data/smarter/tests/test_breeds.py | 6 +-- flask-data/smarter/tests/test_chips.py | 6 +-- flask-data/smarter/tests/test_countries.py | 6 +-- flask-data/smarter/tests/test_datasets.py | 6 +-- flask-data/smarter/tests/test_info.py | 4 +- flask-data/smarter/tests/test_login.py | 20 ++++++---- flask-data/smarter/tests/test_samples.py | 10 ++--- flask-data/smarter/tests/test_variants.py | 14 +++---- 10 files changed, 47 insertions(+), 81 deletions(-) diff --git a/flask-data/smarter/tests/base.py b/flask-data/smarter/tests/base.py index 323805e..d7f513e 100644 --- a/flask-data/smarter/tests/base.py +++ b/flask-data/smarter/tests/base.py @@ -94,51 +94,11 @@ def setUpClass(cls): except BulkWriteError as e: logger.error(f"Cannot insert data: {e}") + # create and empty header attributes (for compatibility) + cls.headers = {} + @classmethod def tearDownClass(cls): # Delete Database collections after the test is complete for collection in cls.db.list_collection_names(): cls.db.drop_collection(collection) - - -class AuthMixin(): - test_endpoint = None - auth_endpoint = "/smarter-api/auth/login" - - @classmethod - def setUpClass(cls): - # need to call other methods (for example, load fixture for auth) - super().setUpClass() - - payload = json.dumps({ - 'username': 'test', - 'password': 'password' - }) - - # authenticate to database - response = cls.client.post( - cls.auth_endpoint, - headers={"Content-Type": "application/json"}, - data=payload) - - # read token and prepare headers - cls.token = response.json['token'] - - # don't set content-type: application/json if you aren't posting JSON - # https://stackoverflow.com/a/47286909/4385116 - cls.headers = { - "Authorization": f"Bearer {cls.token}" - } - - def test_without_login(self, method='get', data=None): - method = getattr(self.client, method) - - response = method( - self.test_endpoint, - headers={}, - data=data - ) - - self.assertEqual( - "Missing Authorization Header", response.json['message']) - self.assertEqual(401, response.status_code) diff --git a/flask-data/smarter/tests/test_GeoJSON.py b/flask-data/smarter/tests/test_GeoJSON.py index 1af2257..94a1aa4 100644 --- a/flask-data/smarter/tests/test_GeoJSON.py +++ b/flask-data/smarter/tests/test_GeoJSON.py @@ -9,12 +9,12 @@ import json import pathlib -from .base import BaseCase, AuthMixin +from .base import BaseCase FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures" -class SampleSheepTest(AuthMixin, BaseCase): +class SampleSheepTest(BaseCase): fixtures = [ 'user', 'sampleSheep' @@ -55,7 +55,7 @@ def test_get_sample_not_found(self): self.assertEqual(response.status_code, 404) -class SampleGoatTest(AuthMixin, BaseCase): +class SampleGoatTest(BaseCase): fixtures = [ 'user', 'sampleGoat' @@ -110,7 +110,7 @@ def test_get_sample_not_found(self): self.assertEqual(response.status_code, 404) -class SampleSheepListTest(AuthMixin, BaseCase): +class SampleSheepListTest(BaseCase): fixtures = [ 'user', 'sampleSheep' @@ -301,7 +301,7 @@ def test_get_samples_geo_within_sphere(self): self.check_no_results(response) -class SampleGoatListTest(AuthMixin, BaseCase): +class SampleGoatListTest(BaseCase): fixtures = [ 'user', 'sampleGoat' diff --git a/flask-data/smarter/tests/test_breeds.py b/flask-data/smarter/tests/test_breeds.py index c38a153..d109f69 100644 --- a/flask-data/smarter/tests/test_breeds.py +++ b/flask-data/smarter/tests/test_breeds.py @@ -11,12 +11,12 @@ from werkzeug.urls import url_encode -from .base import BaseCase, AuthMixin +from .base import BaseCase FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures" -class TestGetBreedList(AuthMixin, BaseCase): +class TestGetBreedList(BaseCase): fixtures = [ 'user', 'breeds' @@ -290,7 +290,7 @@ def test_get_breeds_unknown_arguments(self): "Unknown arguments: foo", response.json['message']) -class TestGetBreed(AuthMixin, BaseCase): +class TestGetBreed(BaseCase): fixtures = [ 'user', 'breeds' diff --git a/flask-data/smarter/tests/test_chips.py b/flask-data/smarter/tests/test_chips.py index fbc99b2..70277df 100644 --- a/flask-data/smarter/tests/test_chips.py +++ b/flask-data/smarter/tests/test_chips.py @@ -11,12 +11,12 @@ from werkzeug.urls import url_encode -from .base import BaseCase, AuthMixin +from .base import BaseCase FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures" -class SupportedChipTest(AuthMixin, BaseCase): +class SupportedChipTest(BaseCase): fixtures = [ 'user', 'supportedChips' @@ -69,7 +69,7 @@ def test_get_chip_not_found(self): self.assertEqual(response.status_code, 404) -class SupportedChipListTest(AuthMixin, BaseCase): +class SupportedChipListTest(BaseCase): fixtures = [ 'user', 'supportedChips' diff --git a/flask-data/smarter/tests/test_countries.py b/flask-data/smarter/tests/test_countries.py index 980d004..ad20925 100644 --- a/flask-data/smarter/tests/test_countries.py +++ b/flask-data/smarter/tests/test_countries.py @@ -11,12 +11,12 @@ from werkzeug.urls import url_encode -from .base import BaseCase, AuthMixin +from .base import BaseCase FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures" -class TestGetCountryList(AuthMixin, BaseCase): +class TestGetCountryList(BaseCase): fixtures = [ 'user', 'countries' @@ -224,7 +224,7 @@ def test_get_countries_unknown_arguments(self): "Unknown arguments: foo", response.json['message']) -class TestGetCountry(AuthMixin, BaseCase): +class TestGetCountry(BaseCase): fixtures = [ 'user', 'countries' diff --git a/flask-data/smarter/tests/test_datasets.py b/flask-data/smarter/tests/test_datasets.py index 162e985..e5dfae7 100644 --- a/flask-data/smarter/tests/test_datasets.py +++ b/flask-data/smarter/tests/test_datasets.py @@ -11,12 +11,12 @@ from werkzeug.urls import url_encode -from .base import BaseCase, AuthMixin +from .base import BaseCase FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures" -class TestGetDatasetList(AuthMixin, BaseCase): +class TestGetDatasetList(BaseCase): fixtures = [ 'user', 'dataset' @@ -243,7 +243,7 @@ def test_get_datasets_by_multiple_chip_names(self): self.assertEqual(response.status_code, 200) -class TestGetDataset(AuthMixin, BaseCase): +class TestGetDataset(BaseCase): fixtures = [ 'user', 'dataset' diff --git a/flask-data/smarter/tests/test_info.py b/flask-data/smarter/tests/test_info.py index a3483ac..70b65ea 100644 --- a/flask-data/smarter/tests/test_info.py +++ b/flask-data/smarter/tests/test_info.py @@ -2,12 +2,12 @@ import json import pathlib -from .base import BaseCase, AuthMixin +from .base import BaseCase FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures" -class TestSmarterInfo(AuthMixin, BaseCase): +class TestSmarterInfo(BaseCase): fixtures = [ 'user', 'smarterInfo' diff --git a/flask-data/smarter/tests/test_login.py b/flask-data/smarter/tests/test_login.py index 6bc326f..2cda26f 100644 --- a/flask-data/smarter/tests/test_login.py +++ b/flask-data/smarter/tests/test_login.py @@ -22,7 +22,7 @@ def test_successful_login(self): data=payload) # Then - self.assertEqual(str, type(response.json['token'])) + self.assertEqual(str, type(response.json['message'])) self.assertEqual(200, response.status_code) def test_login_with_invalid_user(self): @@ -42,8 +42,10 @@ def test_login_with_invalid_user(self): # Then self.assertEqual( - "Invalid username or password", response.json['message']) - self.assertEqual(401, response.status_code) + "Please update your Smarter API client to the latest version", + response.json['message'] + ) + self.assertEqual(200, response.status_code) def test_login_with_invalid_password(self): # Given @@ -62,8 +64,10 @@ def test_login_with_invalid_password(self): # Then self.assertEqual( - "Invalid username or password", response.json['message']) - self.assertEqual(401, response.status_code) + "Please update your Smarter API client to the latest version", + response.json['message'] + ) + self.assertEqual(200, response.status_code) def test_login_with_missing_fields(self): # Given @@ -80,5 +84,7 @@ def test_login_with_missing_fields(self): # Then self.assertEqual( - "Request is missing required fields", response.json['message']) - self.assertEqual(400, response.status_code) + "Please update your Smarter API client to the latest version", + response.json['message'] + ) + self.assertEqual(200, response.status_code) diff --git a/flask-data/smarter/tests/test_samples.py b/flask-data/smarter/tests/test_samples.py index ae0e096..c2ab2bc 100644 --- a/flask-data/smarter/tests/test_samples.py +++ b/flask-data/smarter/tests/test_samples.py @@ -9,12 +9,12 @@ import json import pathlib -from .base import BaseCase, AuthMixin +from .base import BaseCase FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures" -class SampleSheepTest(AuthMixin, BaseCase): +class SampleSheepTest(BaseCase): fixtures = [ 'user', 'sampleSheep' @@ -65,7 +65,7 @@ def test_get_sample_not_found(self): self.assertEqual(response.status_code, 404) -class SampleSheepListTest(AuthMixin, BaseCase): +class SampleSheepListTest(BaseCase): fixtures = [ 'user', 'sampleSheep' @@ -432,7 +432,7 @@ def test_get_samples_geo_within_polygon(self): self.assertListEqual(test['items'], []) -class SampleGoatTest(AuthMixin, BaseCase): +class SampleGoatTest(BaseCase): fixtures = [ 'user', 'sampleGoat' @@ -483,7 +483,7 @@ def test_get_sample_not_found(self): self.assertEqual(response.status_code, 404) -class SampleGoatListTest(AuthMixin, BaseCase): +class SampleGoatListTest(BaseCase): fixtures = [ 'user', 'sampleGoat' diff --git a/flask-data/smarter/tests/test_variants.py b/flask-data/smarter/tests/test_variants.py index 66401b2..7064e0a 100644 --- a/flask-data/smarter/tests/test_variants.py +++ b/flask-data/smarter/tests/test_variants.py @@ -12,7 +12,7 @@ from dateutil.parser import parse as parse_date from bson import json_util -from .base import BaseCase, AuthMixin +from .base import BaseCase FIXTURES_DIR = pathlib.Path(__file__).parent / "fixtures" @@ -43,7 +43,7 @@ def setUpClass(cls): cls.data = json.loads(tmp) -class VariantSheepTest(DateMixin, AuthMixin, BaseCase): +class VariantSheepTest(DateMixin, BaseCase): fixtures = [ 'user', 'variantSheep' @@ -89,7 +89,7 @@ def test_get_variant_not_found(self): self.assertEqual(response.status_code, 404) -class VariantSheepListMixin(DateMixin, AuthMixin): +class VariantSheepListMixin(DateMixin): # print out all the differences maxDiff = None @@ -361,7 +361,7 @@ def setUpClass(cls): cls.data[i] = variant -class VariantSheepOAR4Test(DateMixin, AuthMixin, BaseCase): +class VariantSheepOAR4Test(DateMixin, BaseCase): fixtures = [ 'user', 'smarterInfo', @@ -410,7 +410,7 @@ def test_get_variants(self): self.assertEqual(response.status_code, 200) -class VariantGoatTest(DateMixin, AuthMixin, BaseCase): +class VariantGoatTest(DateMixin, BaseCase): fixtures = [ 'user', 'variantGoat' @@ -456,7 +456,7 @@ def test_get_variant_not_found(self): self.assertEqual(response.status_code, 404) -class VariantGoatListMixin(DateMixin, AuthMixin): +class VariantGoatListMixin(DateMixin): # print out all the differences maxDiff = None @@ -620,7 +620,7 @@ def setUpClass(cls): cls.data[i] = variant -class VariantGoatCHI1Test(DateMixin, AuthMixin, BaseCase): +class VariantGoatCHI1Test(DateMixin, BaseCase): fixtures = [ 'user', 'smarterInfo', From 8b5d0e464f7f5ee07558c1ef7192be46af5b98f3 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Mon, 17 Jun 2024 12:48:21 +0200 Subject: [PATCH 16/32] :heavy_minus_sign: remove unused dependencies get rid of bcrypt and jwt --- poetry.lock | 96 ++------------------------------------------------ pyproject.toml | 2 -- 2 files changed, 3 insertions(+), 95 deletions(-) diff --git a/poetry.lock b/poetry.lock index 4d9c876..6d122f8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "alabaster" @@ -76,46 +76,6 @@ files = [ [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] -[[package]] -name = "bcrypt" -version = "4.1.3" -description = "Modern password hashing for your software and your servers" -optional = false -python-versions = ">=3.7" -files = [ - {file = "bcrypt-4.1.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:48429c83292b57bf4af6ab75809f8f4daf52aa5d480632e53707805cc1ce9b74"}, - {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a8bea4c152b91fd8319fef4c6a790da5c07840421c2b785084989bf8bbb7455"}, - {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d3b317050a9a711a5c7214bf04e28333cf528e0ed0ec9a4e55ba628d0f07c1a"}, - {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:094fd31e08c2b102a14880ee5b3d09913ecf334cd604af27e1013c76831f7b05"}, - {file = "bcrypt-4.1.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4fb253d65da30d9269e0a6f4b0de32bd657a0208a6f4e43d3e645774fb5457f3"}, - {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:193bb49eeeb9c1e2db9ba65d09dc6384edd5608d9d672b4125e9320af9153a15"}, - {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:8cbb119267068c2581ae38790e0d1fbae65d0725247a930fc9900c285d95725d"}, - {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6cac78a8d42f9d120b3987f82252bdbeb7e6e900a5e1ba37f6be6fe4e3848286"}, - {file = "bcrypt-4.1.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:01746eb2c4299dd0ae1670234bf77704f581dd72cc180f444bfe74eb80495b64"}, - {file = "bcrypt-4.1.3-cp37-abi3-win32.whl", hash = "sha256:037c5bf7c196a63dcce75545c8874610c600809d5d82c305dd327cd4969995bf"}, - {file = "bcrypt-4.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:8a893d192dfb7c8e883c4576813bf18bb9d59e2cfd88b68b725990f033f1b978"}, - {file = "bcrypt-4.1.3-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d4cf6ef1525f79255ef048b3489602868c47aea61f375377f0d00514fe4a78c"}, - {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5698ce5292a4e4b9e5861f7e53b1d89242ad39d54c3da451a93cac17b61921a"}, - {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec3c2e1ca3e5c4b9edb94290b356d082b721f3f50758bce7cce11d8a7c89ce84"}, - {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3a5be252fef513363fe281bafc596c31b552cf81d04c5085bc5dac29670faa08"}, - {file = "bcrypt-4.1.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5f7cd3399fbc4ec290378b541b0cf3d4398e4737a65d0f938c7c0f9d5e686611"}, - {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:c4c8d9b3e97209dd7111bf726e79f638ad9224b4691d1c7cfefa571a09b1b2d6"}, - {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:31adb9cbb8737a581a843e13df22ffb7c84638342de3708a98d5c986770f2834"}, - {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:551b320396e1d05e49cc18dd77d970accd52b322441628aca04801bbd1d52a73"}, - {file = "bcrypt-4.1.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6717543d2c110a155e6821ce5670c1f512f602eabb77dba95717ca76af79867d"}, - {file = "bcrypt-4.1.3-cp39-abi3-win32.whl", hash = "sha256:6004f5229b50f8493c49232b8e75726b568535fd300e5039e255d919fc3a07f2"}, - {file = "bcrypt-4.1.3-cp39-abi3-win_amd64.whl", hash = "sha256:2505b54afb074627111b5a8dc9b6ae69d0f01fea65c2fcaea403448c503d3991"}, - {file = "bcrypt-4.1.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:cb9c707c10bddaf9e5ba7cdb769f3e889e60b7d4fea22834b261f51ca2b89fed"}, - {file = "bcrypt-4.1.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9f8ea645eb94fb6e7bea0cf4ba121c07a3a182ac52876493870033141aa687bc"}, - {file = "bcrypt-4.1.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f44a97780677e7ac0ca393bd7982b19dbbd8d7228c1afe10b128fd9550eef5f1"}, - {file = "bcrypt-4.1.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d84702adb8f2798d813b17d8187d27076cca3cd52fe3686bb07a9083930ce650"}, - {file = "bcrypt-4.1.3.tar.gz", hash = "sha256:2ee15dd749f5952fe3f0430d0ff6b74082e159c50332a1413d51b5689cf06623"}, -] - -[package.extras] -tests = ["pytest (>=3.2.1,!=3.3.0)"] -typecheck = ["mypy"] - [[package]] name = "certifi" version = "2024.6.2" @@ -485,21 +445,6 @@ Werkzeug = ">=2.0" async = ["asgiref (>=3.2)"] dotenv = ["python-dotenv"] -[[package]] -name = "flask-bcrypt" -version = "1.0.1" -description = "Brcrypt hashing for Flask." -optional = false -python-versions = "*" -files = [ - {file = "Flask-Bcrypt-1.0.1.tar.gz", hash = "sha256:f07b66b811417ea64eb188ae6455b0b708a793d966e1a80ceec4a23bc42a4369"}, - {file = "Flask_Bcrypt-1.0.1-py3-none-any.whl", hash = "sha256:062fd991dc9118d05ac0583675507b9fe4670e44416c97e0e6819d03d01f808a"}, -] - -[package.dependencies] -bcrypt = ">=3.1.1" -Flask = "*" - [[package]] name = "flask-cors" version = "4.0.1" @@ -514,25 +459,6 @@ files = [ [package.dependencies] Flask = ">=0.9" -[[package]] -name = "flask-jwt-extended" -version = "4.6.0" -description = "Extended JWT integration with Flask" -optional = false -python-versions = ">=3.7,<4" -files = [ - {file = "Flask-JWT-Extended-4.6.0.tar.gz", hash = "sha256:9215d05a9413d3855764bcd67035e75819d23af2fafb6b55197eb5a3313fdfb2"}, - {file = "Flask_JWT_Extended-4.6.0-py2.py3-none-any.whl", hash = "sha256:63a28fc9731bcc6c4b8815b6f954b5904caa534fc2ae9b93b1d3ef12930dca95"}, -] - -[package.dependencies] -Flask = ">=2.0,<4.0" -PyJWT = ">=2.0,<3.0" -Werkzeug = ">=0.14" - -[package.extras] -asymmetric-crypto = ["cryptography (>=3.3.1)"] - [[package]] name = "flask-mongoengine" version = "1.0.0" @@ -1024,23 +950,6 @@ files = [ [package.extras] windows-terminal = ["colorama (>=0.4.6)"] -[[package]] -name = "pyjwt" -version = "2.8.0" -description = "JSON Web Token implementation in Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, - {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, -] - -[package.extras] -crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] - [[package]] name = "pymongo" version = "4.7.3" @@ -1194,6 +1103,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1711,4 +1621,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "8cf55d7c1b83365e2d9a98a9e5edd331b1d30e003c9f6c5090b658afe2fcb1bd" +content-hash = "1a838ca9b70e986c0c54c2705d088bf7db569d4d9f6e809061955637b5562859" diff --git a/pyproject.toml b/pyproject.toml index 1116905..ceae3e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,8 +12,6 @@ python = "^3.9" uwsgi = "^2.0.22" uwsgitop = "^0.11" flask-restful = "^0.3.10" -flask-bcrypt = "^1.0.1" -flask-jwt-extended = "^4.5.2" flask-cors = "^4.0.0" python-dateutil = "^2.8.2" flake8 = "^6.1.0" From 80f0a6f86fa418696c0535380bd6d0524f14e2a2 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Mon, 17 Jun 2024 12:48:39 +0200 Subject: [PATCH 17/32] :fire: remove user and user blueprint --- flask-data/smarter/app.py | 4 --- flask-data/smarter/commands.py | 41 --------------------- flask-data/smarter/database/models.py | 15 -------- flask-data/smarter/tests/test_commands.py | 43 ----------------------- 4 files changed, 103 deletions(-) delete mode 100644 flask-data/smarter/commands.py delete mode 100644 flask-data/smarter/tests/test_commands.py diff --git a/flask-data/smarter/app.py b/flask-data/smarter/app.py index 1d76b67..3cdd843 100644 --- a/flask-data/smarter/app.py +++ b/flask-data/smarter/app.py @@ -20,7 +20,6 @@ from database.db import initialize_db, DB_ALIAS from resources.errors import errors from resources.routes import initialize_routes -from commands import usersbp __version__ = "0.3.0.dev0" @@ -129,9 +128,6 @@ def create_app(config={}): app.logger.debug("Database initialized") app.logger.debug(f"Got encoder {app.json_encoder}") - # you MUST register the blueprint - app.register_blueprint(usersbp) - # add resources initialize_routes(api) diff --git a/flask-data/smarter/commands.py b/flask-data/smarter/commands.py deleted file mode 100644 index 5446b7f..0000000 --- a/flask-data/smarter/commands.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Created on Wed May 26 15:57:49 2021 - -@author: Paolo Cozzi -""" - -import getpass - -import click -from flask import Blueprint -from flask_bcrypt import generate_password_hash - -from database.models import User - -usersbp = Blueprint('users', __name__) - -# https://github.com/pallets/flask/issues/3608#issuecomment-628627335 -usersbp.cli.short_help = "Manage users" - - -@usersbp.cli.command('create') -@click.argument('name') -def create_user(name): - """ Creates a user """ - - pass1 = getpass.getpass("Please enter a password: ") - pass2 = getpass.getpass("Please confirm your password: ") - - if pass1 != pass2: - raise Exception("Password doesn't match") - - # generate password hash - password = generate_password_hash(pass1).decode('utf8') - - # prepare to insert - user = User(username=name, password=password) - user.save() - - print(f"User '{name}' added ({user.id})") diff --git a/flask-data/smarter/database/models.py b/flask-data/smarter/database/models.py index 94899c9..6d5844b 100644 --- a/flask-data/smarter/database/models.py +++ b/flask-data/smarter/database/models.py @@ -10,8 +10,6 @@ from enum import Enum -from flask_bcrypt import check_password_hash - from .db import db, DB_ALIAS # Get an instance of a logger @@ -39,19 +37,6 @@ class SmarterDBException(Exception): pass -class User(db.Document): - username = db.StringField(required=True, unique=True) - password = db.StringField(required=True, min_length=6) - - def check_password(self, password): - return check_password_hash(self.password, password) - - meta = { - 'db_alias': DB_ALIAS, - 'collection': 'user' - } - - class SmarterInfo(db.Document): """A class to track database status informations""" diff --git a/flask-data/smarter/tests/test_commands.py b/flask-data/smarter/tests/test_commands.py deleted file mode 100644 index 856e584..0000000 --- a/flask-data/smarter/tests/test_commands.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Created on Thu May 27 17:39:44 2021 - -@author: Paolo Cozzi -""" - -from unittest.mock import patch - -from commands import create_user -from database.models import User - -from .base import BaseCase - - -class TestUserCreate(BaseCase): - @classmethod - def setUpClass(cls): - # calling base methods - super().setUpClass() - - # get a test cli runner, as described at - # https://flask.palletsprojects.com/en/2.0.x/testing/#testing-cli - cls.runner = cls.app.test_cli_runner() - - def test_help(self): - result = self.runner.invoke(create_user, ['--help']) - self.assertRegex(result.output, r'create .OPTIONS. NAME') - - @patch('getpass.getpass', return_value="password") - def test_create(self, my_getpass): - # test command - result = self.runner.invoke(create_user, ['smarter']) - self.assertEqual(result.exit_code, 0) - - # test user in db - qs = User.objects.filter(username="smarter") - self.assertEqual(qs.count(), 1) - - # test password encryption - user = qs.get() - self.assertTrue(user.check_password('password')) From 508d8e030454835437110befb8f03a785321fdbb Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Mon, 17 Jun 2024 13:02:36 +0200 Subject: [PATCH 18/32] :memo: update README --- .vscode/settings.json | 11 ++++++++++- README.md | 19 +++---------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3a772a5..4f6cdc5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,16 @@ "esbonio.sphinx.confDir": "${workspaceFolder}/flask-data/smarter/docs/source", "cSpell.words": [ "affymetrix", + "exitfirst", + "iname", + "INITDB", "jsonify", - "reqparse" + "mongodump", + "mongorestore", + "pytest", + "reqparse", + "showlocals", + "uwsgi", + "uwsgitop" ] } diff --git a/README.md b/README.md index 954a3d6..edc3cbb 100644 --- a/README.md +++ b/README.md @@ -18,24 +18,12 @@ MONGODB_ROOT_USER= MONGODB_ROOT_PASS= MONGODB_SMARTER_USER= MONGODB_SMARTER_PASS= -JWT_SECRET_KEY= ``` > *TODO*: manage sensitive data using secret in docker-compose, as described [here](https://docs.docker.com/engine/swarm/secrets/#use-secrets-in-compose) and [here](https://docs.docker.com/compose/compose-file/#secrets) -### Genereate the JWT secret key - -[Here](https://stackoverflow.com/a/23728630/4385116) you can find hints on -how to define a secret key with python: - -```python -import string -import secrets -print(''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(50))) -``` - ## Setting the proper permissions Set `mongodb-home` folder permissions with: @@ -53,12 +41,11 @@ cd flask-data/ find . -type f -iname "*.py" -exec chmod g-w {} \; ``` -## Add a smarter user - -Add a smarter user by calling a *flask script*: +## Build and run the application ```bash -docker-compose run --rm uwsgi flask users create smarter +docker-compose build +docker-compose up ``` ## Connect to mongodb From 2fd2106a855b3353fa4394d18a4981551d64d7e8 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Mon, 17 Jun 2024 16:04:20 +0200 Subject: [PATCH 19/32] :memo: remove authorization stuff from RTD documentation --- flask-data/smarter/docs/source/accessing.rst | 73 ++++------ .../smarter/docs/source/accessing/r.rst | 137 ++++++------------ flask-data/smarter/docs/source/conf.py | 4 +- flask-data/smarter/docs/source/index.rst | 35 ++--- .../smarter/docs/source/introduction.rst | 121 +++++++--------- 5 files changed, 143 insertions(+), 227 deletions(-) diff --git a/flask-data/smarter/docs/source/accessing.rst b/flask-data/smarter/docs/source/accessing.rst index e86af6a..3fc3a02 100644 --- a/flask-data/smarter/docs/source/accessing.rst +++ b/flask-data/smarter/docs/source/accessing.rst @@ -1,41 +1,32 @@ Accessing SMARTER-backend ========================= - -Authentication --------------- - -In the following sections you will find examples on how to interact with the -SMARTER-backend in different ways. Regardless the method your prefer, you are -required to generate a :ref:`JWT Token ` before accessing data. -This token need to be added to each **header** request made to any SMARTER-backend -endpoint, with the following format:: - - Authorization: Bearer - -Please remeber that the token is valid only for 7 days, then you will need to -generate a new JWT token in order to access SMARTER metadata. +The SMARTER-backend is a RESTful API, which means that it's a web service that +provides access to its resources via HTTP requests. The API is designed to be +simple and easy to use, and it's based on the `JSON `_ +data format, which is a lightweight data-interchange format that is easy for +humans to read and write and easy for machines to parse and generate. Query parameters ---------------- -The :ref:`API endpoints` described in the :ref:`Introduction` return by default -all the SMARTER objects they managed. However it's possible to filter out the -results returned using ``GET`` parameters (also called URL parameters or -`query strings `_) which are usually -name-value pairs, separated by an ``=`` sign. For example, by submitting a request +The :ref:`API endpoints` described in the :ref:`Introduction` return by default +all the SMARTER objects they managed. However it's possible to filter out the +results returned using ``GET`` parameters (also called URL parameters or +`query strings `_) which are usually +name-value pairs, separated by an ``=`` sign. For example, by submitting a request to:: https://webserver.ibba.cnr.it/smarter-api/breeds -You will get all the Breeds stored in smarter database, but you can filter out +You will get all the Breeds stored in smarter database, but you can filter out the results by species by passing ``species=Goat`` parameter:: https://webserver.ibba.cnr.it/smarter-api/breeds?species=Goat -Please note that parameters are not part of the API endpoint: The question mark -is used as a separator, and divide the endpoint from the ``GET`` parameter. You -can provide multiple parameters by joining them with the ``&`` character, for +Please note that parameters are not part of the API endpoint: The question mark +is used as a separator, and divide the endpoint from the ``GET`` parameter. You +can provide multiple parameters by joining them with the ``&`` character, for example:: https://webserver.ibba.cnr.it/smarter-api/breeds?species=Goat&search=land @@ -45,19 +36,19 @@ for example, but also *Rangeland*) .. hint:: - The page https://webserver.ibba.cnr.it/smarter-api/docs/ describes every API - endpoints with their own set of parameters, see the proper endpoint + The page https://webserver.ibba.cnr.it/smarter-api/docs/ describes every API + endpoints with their own set of parameters, see the proper endpoint documentation to have a list of the allowed parameters and what they do. Pagination ---------- -API queries could returned thousands of results, so to improve performance and -lower traffic between client and server, all the API endpoints implements pagination. -This means that each query returns a limited set of results, but it returns also -the total number of objects with informations useful to collect the next batch -of objects. For example, if you analyze the breed API response while search for -all the objects (``https://webserver.ibba.cnr.it/smarter-api/breeds``), you will +API queries could returned thousands of results, so to improve performance and +lower traffic between client and server, all the API endpoints implements pagination. +This means that each query returns a limited set of results, but it returns also +the total number of objects with informations useful to collect the next batch +of objects. For example, if you analyze the breed API response while search for +all the objects (``https://webserver.ibba.cnr.it/smarter-api/breeds``), you will see a reply like this:: { @@ -72,25 +63,25 @@ see a reply like this:: "total": 257 } -Where in the ``items`` array there will be ``size`` Breed objects (default 10, -omitted here to better describe the response); in the ``next`` attribute there -will be the URLs to be used to get the next batch of objects, if you -get the next page, you will get a ``prev`` attribute for the previous page; -The ``total`` stands for the total number of breed objects and the ``page`` -stands for the current batch page number. By default, the behaviour is to +Where in the ``items`` array there will be ``size`` Breed objects (default 10, +omitted here to better describe the response); in the ``next`` attribute there +will be the URLs to be used to get the next batch of objects, if you +get the next page, you will get a ``prev`` attribute for the previous page; +The ``total`` stands for the total number of breed objects and the ``page`` +stands for the current batch page number. By default, the behaviour is to display 10 results per page, however you could change this by setting a different page size with a get parameter, for example ``size=20``. -.. warning:: +.. warning:: - Please remember that pagination helps to better manage resources, don't - try to retrieve all the results for a single query request: there could be + Please remember that pagination helps to better manage resources, don't + try to retrieve all the results for a single query request: there could be a size limit or you can have issues in retrieve / process the results Examples -------- -Here we list some patterns on how to interact with the SMARTER-backend, feel free +Here we list some patterns on how to interact with the SMARTER-backend, feel free to follow the method you prefer: .. toctree:: diff --git a/flask-data/smarter/docs/source/accessing/r.rst b/flask-data/smarter/docs/source/accessing/r.rst index af37c34..65f0718 100644 --- a/flask-data/smarter/docs/source/accessing/r.rst +++ b/flask-data/smarter/docs/source/accessing/r.rst @@ -5,6 +5,11 @@ Accessing data using R .. toctree:: :maxdepth: 4 +.. hint:: + + We have a *R* package that can be used to interact with SMARTER-backend API, + see `SMARTER R package `_ for more information. + Here are some examples on how to interact with SMARTER-backend API using ``R``. You will need to set up some utility functions in order to save your time by avoiding repeating stuff. @@ -19,63 +24,14 @@ to install some of them first): library(httr) library(jsonlite) - library(getPass) library(dplyr) ``httr`` is required to send requests and get response from SMARTER-backend API; ``jsonlite`` is required to parse ``JSON`` output, which is the default format -of the API response. ``getPass`` is not strictly required, it will prompt for our -credentials in order to not store them in our code. ``dplyr`` is useful to manage +of the API response. ``dplyr`` is useful to manage dataframes, for examples when they have different columns (like response from SMARTER-backend) -Generate a JWT token with R ---------------------------- - -As stated in our :ref:`Authentication` section of this guide, you need to generate -a :ref:`JWT token ` in order to get full access to smarter -metadata. Here is an utility function to request a token by providing your -credentials with a ``POST`` HTTP method: - -.. code-block:: r - - base_url <- "https://webserver.ibba.cnr.it" - - get_smarter_token <- - function(username = readline(prompt = "Username ? "), - password = getPass::getPass("Password ? ")) { - auth_url <- - httr::modify_url(base_url, path = "/smarter-api/auth/login") - - resp <- - POST( - auth_url, - body = list(username = username, password = password), - encode = "json" - ) - - # this will read a JSON by default - data <- httr::content(resp) - - # returning only the token as a string - return(data$token) - } - - token <- get_smarter_token() - -``base_url`` is defined for simplicity in order to make all our request to the -same server. The ``get_smarter_token`` function requires *user* and *password* -as parameters. The ``readline`` and ``getPass::getPass`` functions used as -default values are not strictly required, we use them in order to not write -credentials in our code: the function will prompt for those values if not provided -during function call. The token string is parsed and written into ``token`` variable: -This is the value we need to add to each requests *header* - -.. hint:: - - Rstudio has a dedicated section on `Securing Credentials `_. - We recommend to follow their guidelines. - Deal with data and pagination ----------------------------- @@ -87,10 +43,10 @@ add them as columns in the resulting dataframe): .. code-block:: r - read_url <- function(url, token, query = list()) { - # in this request, we add the token to the request header section + read_url <- function(url, query = list()) { + # make a GET request to the API by combining parameters (if any) resp <- - GET(url, query = query, add_headers(Authorization = paste("Bearer", token))) + httr::GET(url, query = query) # check errors: SMARTER-backend is supposed to return JSON objects if (http_type(resp) != "application/json") { @@ -105,13 +61,13 @@ add them as columns in the resulting dataframe): ) # deal with API errors: not "200 Ok" status - if (http_error(resp)) { + if (httr::http_error(resp)) { stop( sprintf( - "SMARTER API returned an error [%s]: '%s'", - status_code(resp), - parsed$message - ), + "SMARTER API returned an error [%s]: '%s'", + status_code(resp), + parsed$message + ), call. = FALSE ) } @@ -120,9 +76,9 @@ add them as columns in the resulting dataframe): } - get_smarter_data <- function(url, token, query = list()) { + get_smarter_data <- function(url, query = list()) { # do the request and parse data with our function - parsed <- read_url(url, token, query) + parsed <- read_url(url, query) # track results in df results <- parsed$items @@ -133,7 +89,7 @@ add them as columns in the resulting dataframe): next_url <- httr::modify_url(base_url, path = parsed$`next`) # query arguments are already in url: get next page - parsed <- read_url(next_url, token) + parsed <- read_url(next_url) # append new results to df. Deal with different columns results <- dplyr::bind_rows(results, parsed$items) @@ -149,10 +105,9 @@ add them as columns in the resulting dataframe): } -Our functions will take an ``url`` parameter, which will be our API endpoint, the -``token`` that will be added in the header request as described in :ref:`Authentication` -section of our documentation and ``query``, which will be a list of -parameters that will enhance our queries as described in :ref:`Query parameters` +Our functions will take an ``url`` parameter, which will be our API endpoint, +and a ``query`` parameter, which will be a list of parameters that will enhance our queries +as described in :ref:`Query parameters` Read data with R ---------------- @@ -164,38 +119,41 @@ deal with datasets objects by querying the *datasets* endpoint: .. code-block:: r - get_smarter_datasets <- function(token, query=list()) { + base_url <- "https://webserver.ibba.cnr.it" + + get_smarter_datasets <- function(query=list()) { url <- - modify_url(base_url, path = "/smarter-api/datasets") + httr::modify_url(base_url, path = "/smarter-api/datasets") - data <- get_smarter_data(url, token, query) + data <- get_smarter_data(url, query) # returning only the results dataframe data$results } - all_datasets <- get_smarter_datasets(token) + all_datasets <- get_smarter_datasets() -By calling the defined ``get_smarter_datasets`` function and providing a valid -token as parameter you will retrieve all datasets and you will store them in -the ``all_datasets`` dataframe. Similarly, to deal with the Breed endpoint you could -define the ``get_smarter_breeds`` function: +``base_url`` is defined for simplicity in order to make all our request to the +same server. +By calling the defined ``get_smarter_datasets`` function you will retrieve all +datasets and you will store them in the ``all_datasets`` dataframe. Similarly, +to deal with the Breed endpoint you could define the ``get_smarter_breeds`` function: .. code-block:: r - get_smarter_breeds <- function(token, query = list()) { + get_smarter_breeds <- function(query = list()) { # setting the URL endpoint url <- httr::modify_url(base_url, path = "/smarter-api/breeds") # reading our data - data <- get_smarter_data(url, token, query) + data <- get_smarter_data(url, query) # returning only the results dataframe data$results } goat_breeds <- - get_smarter_breeds(token, query = list(species = "Goat")) + get_smarter_breeds(query = list(species = "Goat")) ``get_smarter_breeds`` and ``get_smarter_datasets`` functions can be used to return all the SMARTER datasets and breeds. However you can pass additional parameters to @@ -204,7 +162,7 @@ example, you could retrieve all the *genotypes* datasets using the ``type`` para .. code-block:: r - genotypes_datasets <- get_smarter_datasets(token, query = list(type="genotypes")) + genotypes_datasets <- get_smarter_datasets(query = list(type="genotypes")) Since query accepts ``list``, you can specify the same parameter multiple times (if the endpoints supports this type of query, see `api docs `_ @@ -214,7 +172,7 @@ you can select dataset like this: .. code-block:: r foreground_genotypes_datasets <- get_smarter_datasets( - token, query = list(type="genotypes", type="foreground")) + query = list(type="genotypes", type="foreground")) You can add other parameters to refine your query, for example if you want to select only the *Goat* breeds, you can specify @@ -225,7 +183,7 @@ by adding a new parameter: .. code-block:: r search_goat_breeds <- - get_smarter_breeds(token, query = list( + get_smarter_breeds(query = list( species = "Goat", search = "land") ) @@ -234,7 +192,7 @@ by adding a new parameter: https://webserver.ibba.cnr.it/smarter-api/breeds?species=Goat&search=land We can select only the column we need by subsetting dataframe columns, or using -dplyr `select `_: +``dplyr`` `select `_: .. code-block:: r @@ -246,21 +204,20 @@ endpoints relying on parameters: .. code-block:: r - get_smarter_samples <- function(token, species, query = list()) { + get_smarter_samples <- function(species, query = list()) { # mind that species is lowercase in endpoint url species <- tolower(species) url <- modify_url(base_url, path = sprintf("/smarter-api/samples/%s", species)) - data <- get_smarter_data(url, token, query) + data <- get_smarter_data(url, query) # returning only the results dataframe data$results } landrace_samples <- get_smarter_samples( - token, species = "Goat", query = list(breed_code = "LNR") ) @@ -273,7 +230,6 @@ defined (mind to the double ``_`` in ``locations__exists`` and .. code-block:: r selected_landrace_samples <- get_smarter_samples( - token, species = "Goat", query = list( breed_code = "LNR", @@ -281,20 +237,20 @@ defined (mind to the double ``_`` in ``locations__exists`` and phenotype__exists = TRUE) ) -As before we can select the ``smarter_id`` columns, to have a list of our samples -in order to subset the full genotype file using ``plink``: +As before we can select the ``smarter_id`` and ``breed_code`` columns, +to have a list of our samples in order to subset the full genotype file using ``plink``: .. code-block:: r - selected_landrace_samples %>% select(smarter_id) + selected_landrace_samples %>% select(smarter_id, breed_code) -The same could be applied on variants endpoins in order to get information on +The same could be applied on variants endpoints in order to get information on variants. In the following example we will select the goat variants on chromosome *1* within *1-1000000* position in *ARS1* assembly: .. code-block:: r - get_smarter_variations <- function(token, species, query = list()) { + get_smarter_variations <- function(species, assembly, query = list()) { # mind that species is lowercase in endpoint url species <- tolower(species) assembly <- toupper(assembly) @@ -302,14 +258,13 @@ variants. In the following example we will select the goat variants on chromosom url <- modify_url(base_url, path = sprintf("/smarter-api/variants/%s/%s", species, assembly)) - data <- get_smarter_data(url, token, query) + data <- get_smarter_data(url, query) # returning only the results dataframe data$results } selected_goat_variations <- get_smarter_variations( - token, species = "Goat", assembly = "ARS1", query = list( diff --git a/flask-data/smarter/docs/source/conf.py b/flask-data/smarter/docs/source/conf.py index 1956670..2212698 100644 --- a/flask-data/smarter/docs/source/conf.py +++ b/flask-data/smarter/docs/source/conf.py @@ -20,7 +20,7 @@ # -- Project information ----------------------------------------------------- project = 'SMARTER-backend' -copyright = '2021, Paolo Cozzi' +copyright = '2021-2024, Paolo Cozzi' author = 'Paolo Cozzi' # The full version, including alpha/beta/rc tags @@ -52,7 +52,7 @@ # Link to other projects’ documentation intersphinx_mapping = { - 'python': ('https://docs.python.org/3.9', None), + 'python': ('https://docs.python.org/3.11', None), 'mongoengine': ('https://docs.mongoengine.org/', None), 'pymongo': ('https://pymongo.readthedocs.io/en/stable/', None) } diff --git a/flask-data/smarter/docs/source/index.rst b/flask-data/smarter/docs/source/index.rst index 5748452..ac11439 100644 --- a/flask-data/smarter/docs/source/index.rst +++ b/flask-data/smarter/docs/source/index.rst @@ -6,34 +6,27 @@ Welcome to SMARTER-backend's documentation! =========================================== -This documentation describes how to install and interact with the SMARTER database -backend. Briefly, the SMARTER database created and maintained with the -`SMARTER-database `_ project is -made accessible to SMARTER partners using this API. This API is the same used -by the `SMARTER-frontend `_ in +This documentation describes how to install and interact with the SMARTER database +backend. Briefly, the SMARTER database created and maintained with the +`SMARTER-database `_ project is +made accessible to SMARTER partners using this API. This API is the same used +by the `SMARTER-frontend `_ in order to access and browse SMARTER data using a web browser. -If you are partner of the `SMARTER `_ project, and -member of WP4 group, you should have received the credentials to access the smarter -API. If you aren't a SMARTER partner, you cannot access to SMARTER data using API, -however this API with the WEB frontend (and the genotypes) will be made available to -the public at the end of the project. If you are member of WP4 SMARTER project but -you don't have the credentials yet, please send an email to the WP coordinators. - -SMARTER-backend is a `flask-API `_ +SMARTER-backend is a `flask-API `_ application developed on top of a `MongoDB `_ instance. -The application works inside `Docker `_ containers -managed with `docker-compose `_. SMARTER WP4 -users who need to subset or retrieve genotypes from the entire genotypes dataset -need to retrieve variants and samples according their needs, in order to filter out +The application works inside `Docker `_ containers +managed with `docker-compose `_. +Users who need to subset or retrieve genotypes from the entire genotypes dataset +need to retrieve first variants and samples according their needs, in order to filter out the data they need using a `PLINK `_ command line. Documentation is organized as following: in :ref:`Introduction` we describe what SMARTER-backend is and we provide general information. In :ref:`Backend installation` -we describe how to install a local instance of SMARTER-backend. Then in -:ref:`Accessing SMARTER-backend` we describe how to programmatically access to data -or how to inspect data using applications like `Postman `_ -or `Talend Api Tester `_ +we describe how to install a local instance of SMARTER-backend. Then in +:ref:`Accessing SMARTER-backend` we describe how to programmatically access to data +or how to inspect data using applications like `Postman `_ +or `Talend Api Tester `_ google-chrome extension. .. toctree:: diff --git a/flask-data/smarter/docs/source/introduction.rst b/flask-data/smarter/docs/source/introduction.rst index e82792c..edeae8b 100644 --- a/flask-data/smarter/docs/source/introduction.rst +++ b/flask-data/smarter/docs/source/introduction.rst @@ -8,23 +8,23 @@ Introduction The SMARTER-backend is a `REST API service `_ developed on top of the `SMARTER-database `_ which provide methods to interact and access with SMARTER data using web resources. -By using SMARTER-backend, you can develop softwares or scripts which get access to +By using SMARTER-backend, you can develop softwares or scripts which get access to SMARTER data through web, without have a local instance of the SMARTER-database. -In a similar way a web-server receives a request from a web-browser and returns -text and images that could be rendered in a page, a REST API receives requests over the HTTP -protocol and returns data that could be readed and manipolated by user softwares. +In a similar way a web-server receives a request from a web-browser and returns +text and images that could be rendered in a page, a REST API receives requests over the HTTP +protocol and returns data that could be read and manipulated by user softwares. API endpoints ------------- -SMARTER-backend receives requests over the internet and returns SMARTER data in -JSON objects. There could be different data types that could be returned by -SMARTER-backend, for example Breed, Variant, Sample or Dataset. In order to access -to each different data types you have to make a request to the proper API +SMARTER-backend receives requests over the internet and returns SMARTER data in +JSON objects. There could be different data types that could be returned by +SMARTER-backend, for example Breed, Variant, Sample or Dataset. In order to access +to each different data types you have to make a request to the proper API `endpoint `_, which is the mean from which the API can access the resources requested. An API endpoint is an URL, to which HTTP requests are submitted, and from which the response is thus expected. -For example, to retrieve information on all the Breeds stored in SMARTER database, +For example, to retrieve information on all the Breeds stored in SMARTER database, you should make a request to the breed endpoint which is:: https://webserver.ibba.cnr.it/smarter-api/breeds @@ -34,15 +34,15 @@ endpoint, which is:: https://webserver.ibba.cnr.it/smarter-api/samples/goat -If you inspect the two previous URL, you may notice that these two endpoint have -a prefix in common (``https://webserver.ibba.cnr.it/smarter-api``), while the last -part of the URL changes relying on the data they provide. There are a few endpoints +If you inspect the two previous URL, you may notice that these two endpoint have +a prefix in common (``https://webserver.ibba.cnr.it/smarter-api``), while the last +part of the URL changes relying on the data they provide. There are a few endpoints available by SMARTER-backend: +------------------------+---------------+-----------------------------------------------+ | Suffix | Data type | Description | +========================+===============+===============================================+ -| /auth/login | Users | user authentication | +| /auth/login | Users | user authentication (No more required) | +------------------------+---------------+-----------------------------------------------+ | /breeds | Breeds | returns a list of the available breeds | +------------------------+---------------+-----------------------------------------------+ @@ -70,58 +70,58 @@ available by SMARTER-backend: | /variants/goat/CHI1 | VariantGoat | returns a list of goat SNPs in CHI1 assembly | +------------------------+---------------+-----------------------------------------------+ -So if you require to retrieve all the sheep SNPs in OAR3 assembly, +So if you require to retrieve all the sheep SNPs in OAR3 assembly, you can append the suffix ``/variants/sheep/OAR3`` -to the common prefix ``https://webserver.ibba.cnr.it/smarter-api`` to obtain the +to the common prefix ``https://webserver.ibba.cnr.it/smarter-api`` to obtain the final endpoint:: https://webserver.ibba.cnr.it/smarter-api/variants/sheep/OAR3 -Every endpoints described provide a list of results, however you could retrieve a +Every endpoints described provide a list of results, however you could retrieve a specific object by appending the proper ObjectId to the endpoint, for example:: https://webserver.ibba.cnr.it/smarter-api/datasets/604f75a61a08c53cebd09b5b will retrieve the dataset with ObjectId ``604f75a61a08c53cebd09b5b``. -.. warning:: - - Please note that ObjectId could change over time, since they rely on the time - they are added into database. If you require a particular data, +.. warning:: + + Please note that ObjectId could change over time, since they rely on the time + they are added into database. If you require a particular data, you should use the proper API endpoint by providing the appropriate parameters - as arguments, for example ``file=`` to retrieve the dataset relying + as arguments, for example ``file=`` to retrieve the dataset relying on provided file name. HTTP Verbs ---------- -An endpoint can act differently relying on the -`HTTP Verb `_ used when -making a request. For SMARTER-backend, only two HTTP Verbs (or methods) are currently +An endpoint can act differently relying on the +`HTTP Verb `_ used when +making a request. For SMARTER-backend, only two HTTP Verbs (or methods) are currently supported, ``GET`` and ``POST``: -+-----------+--------+----------------------------------------------------+ -| Http Verb | CRUD | | -+===========+========+====================================================+ -| GET | Read | Retrieve a list of objects or a single object | -+-----------+--------+----------------------------------------------------+ -| POST | Create | Create a new auth token / add a payload to a query | -+-----------+--------+----------------------------------------------------+ ++-----------+--------+-----------------------------------------------+ +| Http Verb | CRUD | | ++===========+========+===============================================+ +| GET | Read | Retrieve a list of objects or a single object | ++-----------+--------+-----------------------------------------------+ +| POST | Create | add a payload to a query | ++-----------+--------+-----------------------------------------------+ -More precisely, SMARTER data through the SMARTER-backend are read-only and +More precisely, SMARTER data through the SMARTER-backend are read-only and ``GET`` and ``POST`` method are allowed in order to retrieve any type of SMARTER -data object from the API. ``POST`` method are required during the authentication -step, and to submit a complex queries by providing a payload to certain endpoints. +data object from the API. ``POST`` method are required to submit complex queries +by providing a payload to certain endpoints. Status codes ------------ -SMARTER-backend API uses standard response status code to show the outcome of -each HTTP request. Briefly, replies with a status code like ``2xx`` are successful -requests, ``4xx`` codes means errors in client side (you are using the API in the -wrong way) and ``5xx`` means errors on the server side (you should get in touch -with API maintainer and describe what went wrong). -You can find a complete reference on HTTP status codes +SMARTER-backend API uses standard response status code to show the outcome of +each HTTP request. Briefly, replies with a status code like ``2xx`` are successful +requests, ``4xx`` codes means errors in client side (you are using the API in the +wrong way) and ``5xx`` means errors on the server side (you should get in touch +with API maintainer and describe what went wrong). +You can find a complete reference on HTTP status codes `here `_. +----------------------------+-----------------------------------------------------+ @@ -132,44 +132,21 @@ You can find a complete reference on HTTP status codes || 400 Bad request || The request was malformed. The response body will | || || include an error providing further information | +----------------------------+-----------------------------------------------------+ -|| 401 UnAuthorized || Request lacks of the required authorization header | -|| || or token is expired | -+----------------------------+-----------------------------------------------------+ | 404 Not Found | Requested object or endpoint doesn't exist | +----------------------------+-----------------------------------------------------+ || 500 Internal Server Error || The server encountered an unexpected condition | || || which prevented it from fulfilling the request | +----------------------------+-----------------------------------------------------+ -JWT Authentication ------------------- - -.. epigraph:: - - JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and - self-contained way for securely transmitting information between parties as a - JSON object. This information can be verified and trusted because it is - digitally signed (``_) +Authentication (No more required) +--------------------------------- -SMARTER data aren't available to the public yet, only SMARTER WP4 should have the -credentials to use the SMARTER-backend API. If you are a WP4 member and you don't -have the required credentials, please get in touch with WP4 group leaders. -In order to get access to SMARTER data, you are required to generate a JWT token -by providing your credentials as a ``POST`` request to the API authentication endpoint, -which is:: +After the public release of SMARTER data, the authentication process has been +removed and now you can access to SMARTER data without providing any credentials. +The *auth* endpoint is still available, but it will return a 200 status code +with a standard message regardless of the credentials you provide. This is +required to maintain compatibility with the previous version of the API clients, +but it is not required to generate a token to get access to SMARTER data. +The old endpoint is available at the following URL by providing a ``POST`` request:: https://webserver.ibba.cnr.it/smarter-api/auth/login - -If you credentials are valid, you will receive a JSON object with your generated -token and an expires date. By default a token will be valid for 7 days after it was -generated. You need to add this token as an Authorization header to all of your -API requests. The format is ``Authorization: Bearer ``. In the -:ref:`Accessing SMARTER-backend` section you will find furter instructions on -how to generate your token and how you could interact with the SMARTER-backend -API. - -.. danger:: - - Please don't share your API credentials or the generated token with anyone, - this includes also code that could be shared using github: credentials or - generated tokens should be never stored in your code From fc255d75d909d4cde98c33caae47064237fac6f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 22:06:57 +0000 Subject: [PATCH 20/32] :arrow_up: Bump urllib3 from 2.0.4 to 2.2.2 Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.0.4 to 2.2.2. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/2.0.4...2.2.2) --- updated-dependencies: - dependency-name: urllib3 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- poetry.lock | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 88363e2..779c2d5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "alabaster" @@ -1087,6 +1087,7 @@ files = [ {file = "pymongo-4.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6422b6763b016f2ef2beedded0e546d6aa6ba87910f9244d86e0ac7690f75c96"}, {file = "pymongo-4.5.0-cp312-cp312-win32.whl", hash = "sha256:77cfff95c1fafd09e940b3fdcb7b65f11442662fad611d0e69b4dd5d17a81c60"}, {file = "pymongo-4.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:e57d859b972c75ee44ea2ef4758f12821243e99de814030f69a3decb2aa86807"}, + {file = "pymongo-4.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8443f3a8ab2d929efa761c6ebce39a6c1dca1c9ac186ebf11b62c8fe1aef53f4"}, {file = "pymongo-4.5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2b0176f9233a5927084c79ff80b51bd70bfd57e4f3d564f50f80238e797f0c8a"}, {file = "pymongo-4.5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:89b3f2da57a27913d15d2a07d58482f33d0a5b28abd20b8e643ab4d625e36257"}, {file = "pymongo-4.5.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:5caee7bd08c3d36ec54617832b44985bd70c4cbd77c5b313de6f7fce0bb34f93"}, @@ -1223,6 +1224,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1651,18 +1653,18 @@ files = [ [[package]] name = "urllib3" -version = "2.0.4" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, - {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] From 79ec988e6eb24b42f2526fd5e6ecd66f2c5164cd Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 18 Jun 2024 11:35:57 +0200 Subject: [PATCH 21/32] :whale: update poetry version update poetry version and remove version from docker-compose file --- docker-compose.yml | 2 -- uwsgi/Dockerfile | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7b30daa..bab9fa3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,5 @@ # User/password credentials are stored in .env file -version: '3.8' - services: mongo: diff --git a/uwsgi/Dockerfile b/uwsgi/Dockerfile index 7882485..27faf40 100644 --- a/uwsgi/Dockerfile +++ b/uwsgi/Dockerfile @@ -15,7 +15,7 @@ ARG APP_NAME=SMARTER-backend ARG APP_PATH=/opt/$APP_NAME ARG PYTHON_VERSION=3.11 -ARG POETRY_VERSION=1.6.1 +ARG POETRY_VERSION=1.8.3 FROM python:${PYTHON_VERSION} From 020dfe62e77dc3f4ead05a7dcb0ca25ea35757fc Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Tue, 18 Jun 2024 15:36:27 +0200 Subject: [PATCH 22/32] :bug: fix swagger documentation for POST endpoints --- flask-data/smarter/resources/GeoJSON.py | 46 ++++++++++++++++--------- flask-data/smarter/resources/auth.py | 22 +++++++++++- flask-data/smarter/resources/samples.py | 44 ++++++++++++++--------- 3 files changed, 78 insertions(+), 34 deletions(-) diff --git a/flask-data/smarter/resources/GeoJSON.py b/flask-data/smarter/resources/GeoJSON.py index d841375..896857e 100644 --- a/flask-data/smarter/resources/GeoJSON.py +++ b/flask-data/smarter/resources/GeoJSON.py @@ -318,7 +318,9 @@ def post(self): --- tags: - GeoJSON - description: Query SMARTER data about samples + + description: Query SMARTER data about sheep samples + parameters: - in: body name: body @@ -337,14 +339,18 @@ def post(self): type: object geo_within_sphere: type: array - description: A list with coordinates and radius in Km + description: + A list with coordinates and radius in Km + like [[9.18, 45.46], 10] + items: [] + responses: - '200': - description: Samples to be returned - content: - application/json: - schema: - type: array + 200: + description: Samples to be returned + content: + application/json: + schema: + type: array """ return self.get_context_data() @@ -414,11 +420,13 @@ def get(self): def post(self): """ - Get a GeoJSON for Sheep samples + Get a GeoJSON for Goat samples --- tags: - GeoJSON - description: Query SMARTER data about samples + + description: Query SMARTER data about Goat samples + parameters: - in: body name: body @@ -437,14 +445,18 @@ def post(self): type: object geo_within_sphere: type: array - description: A list with coordinates and radius in Km + description: + A list with coordinates and radius in Km + like [[9.18, 45.46], 10] + items: [] + responses: - '200': - description: Samples to be returned - content: - application/json: - schema: - type: array + 200: + description: Samples to be returned + content: + application/json: + schema: + type: array """ return self.get_context_data() diff --git a/flask-data/smarter/resources/auth.py b/flask-data/smarter/resources/auth.py index 1e75970..2a85cf2 100644 --- a/flask-data/smarter/resources/auth.py +++ b/flask-data/smarter/resources/auth.py @@ -21,7 +21,27 @@ def post(self): --- tags: - Authorization - description: Return a message telling users to update their client + + description: + This method is used to authenticate a user. It has been removed + after public release. Please update your Smarter API client to the + latest version. + + parameters: + - in: body + name: body + description: JSON parameters. + schema: + required: + - username + - password + properties: + username: + type: string + description: Your username + password: + type: string + description: Your password responses: 200: diff --git a/flask-data/smarter/resources/samples.py b/flask-data/smarter/resources/samples.py index fec5349..3e1d5aa 100644 --- a/flask-data/smarter/resources/samples.py +++ b/flask-data/smarter/resources/samples.py @@ -232,7 +232,9 @@ def post(self): --- tags: - Samples - description: Query SMARTER data about samples + + description: Query SMARTER data about Sheep samples + parameters: - in: body name: body @@ -251,14 +253,18 @@ def post(self): type: object geo_within_sphere: type: array - description: A list with coordinates and radius in Km + description: + A list with coordinates and radius in Km + like [[9.18, 45.46], 10] + items: [] + responses: - '200': - description: Samples to be returned - content: - application/json: - schema: - type: array + 200: + description: A list of samples in the given area + content: + application/json: + schema: + type: array """ self.object_list = self.get_queryset() data = self.get_context_data() @@ -384,7 +390,9 @@ def post(self): --- tags: - Samples - description: Query SMARTER data about samples + + description: Query SMARTER data about Goat samples + parameters: - in: body name: body @@ -403,14 +411,18 @@ def post(self): type: object geo_within_sphere: type: array - description: A list with coordinates and radius in Km + description: + A list with coordinates and radius in Km + like [[9.18, 45.46], 10] + items: [] + responses: - '200': - description: Samples to be returned - content: - application/json: - schema: - type: array + 200: + description: A list of samples in the given area + content: + application/json: + schema: + type: array """ self.object_list = self.get_queryset() data = self.get_context_data() From 0473eba9295be36087ea8ba71f488e4d649196a1 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Wed, 19 Jun 2024 11:16:15 +0200 Subject: [PATCH 23/32] :memo: document the installation process --- flask-data/smarter/docs/source/installing.rst | 90 ++++++++++++++++--- 1 file changed, 80 insertions(+), 10 deletions(-) diff --git a/flask-data/smarter/docs/source/installing.rst b/flask-data/smarter/docs/source/installing.rst index 6d809d0..312d99b 100644 --- a/flask-data/smarter/docs/source/installing.rst +++ b/flask-data/smarter/docs/source/installing.rst @@ -5,13 +5,83 @@ Backend installation .. toctree:: :maxdepth: 4 -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper, urna non -tincidunt accumsan, metus tortor vehicula arcu, ac ultrices mauris dolor id lacus. -Vivamus hendrerit interdum ullamcorper. Nullam vitae vehicula justo, nec lacinia diam. -Donec dapibus gravida felis eget tincidunt. Nam eu tempus augue. Etiam magna est, -egestas ut eleifend interdum, interdum sit amet magna. Aliquam ultricies tempor lacinia. -Suspendisse facilisis nibh vitae eros blandit tincidunt. Donec sit amet euismod ligula. -Quisque erat enim, scelerisque vitae augue id, commodo accumsan neque. Praesent -egestas finibus mauris, rutrum pharetra orci. Quisque ullamcorper enim et mauris -interdum, et scelerisque nunc molestie. Pellentesque id turpis id nibh rhoncus -imperdiet vitae porta lorem. +Download SMARTER-backend from GitHub +------------------------------------ + +SMARTER-backend is available on `GitHub `_. +You can download the latest version of the code by running the following command: + +.. code-block:: bash + + git clone https://github.com/cnr-ibba/SMARTER-backend.git + +Install docker and docker-compose +--------------------------------- + +SMARTER-backend is a dockerized application. To run it, you need to install +`docker `_ and +`docker-compose `_. Please follow the +official installation instructions for your operating system. + +Create a .env file +------------------ + +Before running the application, you need to create a .env file in the root directory +of the project. This is required to set the environment variables needed by the +application, like the database connection string. Create a .env file in the root +directory of the project with the following content: + +.. code-block:: bash + + MONGODB_ROOT_USER= + MONGODB_ROOT_PASS= + MONGODB_SMARTER_USER= + MONGODB_SMARTER_PASS= + +Build the docker images +----------------------- + +To build the docker images, run the following command: + +.. code-block:: bash + + docker-compose build + +Fix folder permissions +---------------------- + +Before running the application, you need to fix the permissions of the folders +where the application will store the data. Run the following command: + +.. code-block:: bash + + chmod 777 mongodb-home/ + chmod o+t mongodb-home/ + docker-compose run --no-deps --rm uwsgi sh -c 'chgrp -R www-data .' + cd flask-data/ + find . -type f -iname "*.py" -exec chmod g-w {} \; + +Restore the database +-------------------- + +To restore the database, you need to download the latest dump from the +`SMARTER-database `_ +from the `FTP site `_. +Next, you have to place the dump in the `mongodb-home` folder and run +the following command: + +.. code-block:: bash + + docker-compose run --rm mongo sh -c 'mongorestore --host mongo --username="${MONGO_INITDB_ROOT_USERNAME}" --password="${MONGO_INITDB_ROOT_PASSWORD}" --authenticationDatabase admin --db=smarter --drop --preserveUUID --gzip --archive= --archive=/home/mongodb/' + +Where ```` is the name of the mongodb dump file downloaded +from the FTP site. + +Start the application +--------------------- + +To start the application, run the following command: + +.. code-block:: bash + + docker-compose up -d From 7e9d9a593e79bdb068d7eb7cd3b48360f7b9e578 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Wed, 19 Jun 2024 11:19:32 +0200 Subject: [PATCH 24/32] :fire: remove thirdy-party software from documentation --- flask-data/smarter/docs/source/accessing.rst | 1 - .../docs/source/accessing/thirdy-party.rst | 17 ----------------- 2 files changed, 18 deletions(-) delete mode 100644 flask-data/smarter/docs/source/accessing/thirdy-party.rst diff --git a/flask-data/smarter/docs/source/accessing.rst b/flask-data/smarter/docs/source/accessing.rst index 3fc3a02..f7209aa 100644 --- a/flask-data/smarter/docs/source/accessing.rst +++ b/flask-data/smarter/docs/source/accessing.rst @@ -87,6 +87,5 @@ to follow the method you prefer: .. toctree:: :maxdepth: 4 - accessing/thirdy-party accessing/python accessing/r diff --git a/flask-data/smarter/docs/source/accessing/thirdy-party.rst b/flask-data/smarter/docs/source/accessing/thirdy-party.rst deleted file mode 100644 index a9870be..0000000 --- a/flask-data/smarter/docs/source/accessing/thirdy-party.rst +++ /dev/null @@ -1,17 +0,0 @@ - -Accessing data using Third party softwares -========================================== - -.. toctree:: - :maxdepth: 4 - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper, urna non -tincidunt accumsan, metus tortor vehicula arcu, ac ultrices mauris dolor id lacus. -Vivamus hendrerit interdum ullamcorper. Nullam vitae vehicula justo, nec lacinia diam. -Donec dapibus gravida felis eget tincidunt. Nam eu tempus augue. Etiam magna est, -egestas ut eleifend interdum, interdum sit amet magna. Aliquam ultricies tempor lacinia. -Suspendisse facilisis nibh vitae eros blandit tincidunt. Donec sit amet euismod ligula. -Quisque erat enim, scelerisque vitae augue id, commodo accumsan neque. Praesent -egestas finibus mauris, rutrum pharetra orci. Quisque ullamcorper enim et mauris -interdum, et scelerisque nunc molestie. Pellentesque id turpis id nibh rhoncus -imperdiet vitae porta lorem. From 0984fa6eb17901149cea95b2b074232f1006ba52 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Wed, 19 Jun 2024 15:50:15 +0200 Subject: [PATCH 25/32] :memo: complete the example documentation with python stuff --- flask-data/smarter/docs/source/accessing.rst | 8 +- .../smarter/docs/source/accessing/python.rst | 218 +++++++++++++++++- .../smarter/docs/source/accessing/r.rst | 29 ++- flask-data/smarter/docs/source/modules.rst | 3 + 4 files changed, 230 insertions(+), 28 deletions(-) diff --git a/flask-data/smarter/docs/source/accessing.rst b/flask-data/smarter/docs/source/accessing.rst index f7209aa..c73919f 100644 --- a/flask-data/smarter/docs/source/accessing.rst +++ b/flask-data/smarter/docs/source/accessing.rst @@ -78,8 +78,8 @@ page size with a get parameter, for example ``size=20``. try to retrieve all the results for a single query request: there could be a size limit or you can have issues in retrieve / process the results -Examples --------- +Examples with code +------------------ Here we list some patterns on how to interact with the SMARTER-backend, feel free to follow the method you prefer: @@ -89,3 +89,7 @@ to follow the method you prefer: accessing/python accessing/r + +We have also a custom `R package `_ +that you can use to interact with the SMARTER-backend, you can find it on +`GitHub `_. diff --git a/flask-data/smarter/docs/source/accessing/python.rst b/flask-data/smarter/docs/source/accessing/python.rst index 1b04b2e..fccc526 100644 --- a/flask-data/smarter/docs/source/accessing/python.rst +++ b/flask-data/smarter/docs/source/accessing/python.rst @@ -5,13 +5,211 @@ Accessing data using Python .. toctree:: :maxdepth: 4 -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper, urna non -tincidunt accumsan, metus tortor vehicula arcu, ac ultrices mauris dolor id lacus. -Vivamus hendrerit interdum ullamcorper. Nullam vitae vehicula justo, nec lacinia diam. -Donec dapibus gravida felis eget tincidunt. Nam eu tempus augue. Etiam magna est, -egestas ut eleifend interdum, interdum sit amet magna. Aliquam ultricies tempor lacinia. -Suspendisse facilisis nibh vitae eros blandit tincidunt. Donec sit amet euismod ligula. -Quisque erat enim, scelerisque vitae augue id, commodo accumsan neque. Praesent -egestas finibus mauris, rutrum pharetra orci. Quisque ullamcorper enim et mauris -interdum, et scelerisque nunc molestie. Pellentesque id turpis id nibh rhoncus -imperdiet vitae porta lorem. +Here are some examples of how to access data using Python. You can find a similar +example for ``R`` in the :ref:`Accessing data using R` section. + +Importing packages +------------------ + +First we need to import the packages we will be using. We will be using ``requests`` +to download the data from the internet and some utility functions to deal with +urls. Eventually, we will transform data into a ``pandas`` DataFrame. + +.. code-block:: python + + import json + import requests + + import pandas as pd + from urllib.parse import urljoin + +Deal with data and pagination in python +--------------------------------------- + +We can define some utility functions to deal with data and pagination: + +.. code-block:: python + + base_url = "https://webserver.ibba.cnr.it" + session = requests.Session() + + + def read_url(session, url, params={}): + response = session.get(url, params=params) + + # check errors: SMARTER-backend is supposed to return JSON objects + if response.headers['Content-Type'] != 'application/json': + raise Exception("API did not return json") + + # parse json data + parsed = response.json() + + # check for errors + if response.status_code != 200: + raise Exception( + f"SMARTER API returned an error [{response.status_code}]: " + f"'{parsed['message']}'") + + return parsed + + + def get_smarter_data(url, params={}, session=session): + # do the request and parse data with our function + parsed = read_url(session, url, params) + + # track results + results = parsed["items"] + + # check for pagination + while parsed["next"]: + # append next value to base url + url = urljoin(base_url, parsed["next"]) + + # query arguments are already in url: get next page + parsed = read_url(session, url) + + # append new results to results list + results += parsed["items"] + + return results + + +``base_url`` is the base url of the SMARTER API. We define a ``session`` to keep track of +the cookies and headers of the requests. We define a function ``read_url`` that +parses the response of the API and checks for errors. We define a function +``get_smarter_data`` that gets the data from the API and checks for pagination. + +Read data with Python +--------------------- + +Now we can read data from the API using the functions we defined before. We can +get the data from the API and transform it into a pandas DataFrame. We can define +a custom function in order to call the API with different parameters: + +.. code-block:: python + + def get_smarter_datasets(params={}): + url = urljoin(base_url, "smarter-api/datasets") + results = get_smarter_data(url, params) + if not results: + print("No results found") + return None + return pd.json_normalize(results) + +By calling the function ``get_smarter_datasets`` we can get the data from the API +and transform it into a pandas DataFrame to collect all the *datasets* object from +the *Dataset* endpoint. Similarly, we can define a function to get the data from the +*Breed* endpoint: + +.. code-block:: python + + def get_smarter_breeds(params={}): + url = urljoin(base_url, "smarter-api/breeds") + results = get_smarter_data(url, params) + if not results: + print("No results found") + return None + return pd.json_normalize(results) + +``get_smarter_breeds`` and ``get_smarter_datasets`` functions can be used to return +all the SMARTER *datasets* and *breeds*. However you can pass additional parameters to +the endpoint using the ``params`` parameter (which can be a dictionary or a list +of tuples, when specifying the same parameter multiple times). For +example, you could retrieve all goats breeds using the ``species`` option: + +.. code-block:: python + + goat_breeds = get_smarter_breeds(params={'species': 'Goat'}) + +Here's another example on how to get the *foreground genotypes* from the *Dataset* +endpoint using the functions we defined before: here we are passing a list of tuples +to the function since the parameter ``type`` is required for both terms and you +cannot define a python *dict* with the same key multiple times: + +.. code-block:: python + + foreground_genotypes = get_smarter_datasets( + params=[('type', 'genotypes'), ('type', 'foreground')]) + +To have a full list of the available parameters for all the available endpoints +you can check the API documentation at ``_. +Let's define another function that could be used for sheep and goat samples +endpoints relying on parameters, and then do a simple query relying on ``species`` +and ``breed_code`` parameters: + +.. code-block:: python + + def get_smarter_samples(species, params={}): + # mind that species is lowercase in endpoint url + species = species.lower() + url = urljoin(base_url, f"smarter-api/samples/{species}") + results = get_smarter_data(url, params) + if not results: + print("No results found") + return None + return pd.json_normalize(results) + + goat_landrace = get_smarter_samples( + "Goat", params={'breed_code': "LNR"}) + +We can refine the query by adding more parameters to the query. For example, we +can get the goat samples which have a locations (GPS coordinates) and phenotypes +defined (mind to the double ``_`` in ``locations__exists`` and +``phenotype__exists``): + +.. code-block:: python + + goat_landrace = get_smarter_samples( + "Goat", + params={ + 'breed_code': "LNR", + 'locations__exists': True, + 'phenotype__exists': True} + ) + +from the results dataframe, we can extract the ``smarter_id`` and ``breed_code`` columns, +to have a list of our samples in order to subset the full genotype file using ``plink``: + +.. code-block:: python + + samples = goat_landrace[['smarter_id', 'breed_code']] + samples.to_csv("samples.csv", index=False) + +Here's another example that could be applied in order to get information on +variants. In this case we will select the goat variants on chromosome +*1* within *1-1000000* positions in *ARS1* assembly: + +.. code-block:: python + + def get_smarter_variations(species, assembly, params = {}): + # mind that species is lowercase in endpoint url, while assembly is uppercase + species = species.lower() + assembly = assembly.upper() + + url = urljoin(base_url, f"smarter-api/variants/{species}/{assembly}") + results = get_smarter_data(url, params) + if not results: + print("No results found") + return None + return pd.json_normalize(results) + + selected_goat_variations = get_smarter_variations( + species = "Goat", + assembly = "ARS1", + params = { + "size": 100, + "region": "1:1-1000000" + } + ) + +.. hint:: + + We are planning to simplify the variants response by returning a SNP list of + the selected SNPs only, in order to be used when subsetting a genotype file + using plink + +.. warning:: + + Be careful when using the variants endpoints: getting all the variants will + takes a lot of time and could fill all your available memory. Avoid to request + all variants in your R session, unless you know what you are doing diff --git a/flask-data/smarter/docs/source/accessing/r.rst b/flask-data/smarter/docs/source/accessing/r.rst index 65f0718..224792a 100644 --- a/flask-data/smarter/docs/source/accessing/r.rst +++ b/flask-data/smarter/docs/source/accessing/r.rst @@ -11,8 +11,7 @@ Accessing data using R see `SMARTER R package `_ for more information. Here are some examples on how to interact with SMARTER-backend API using ``R``. -You will need to set up some utility functions in order to save your time by avoiding -repeating stuff. +You can find a similar example for ``Python`` in the :ref:`Accessing data using Python` section. Importing R libraries --------------------- @@ -32,8 +31,8 @@ of the API response. ``dplyr`` is useful to manage dataframes, for examples when they have different columns (like response from SMARTER-backend) -Deal with data and pagination ------------------------------ +Deal with data and pagination in R +---------------------------------- Next, before starting query SMARTER-backend, we can define more utility functions (as suggested by `Best practices for API packages `_) @@ -43,6 +42,8 @@ add them as columns in the resulting dataframe): .. code-block:: r + base_url <- "https://webserver.ibba.cnr.it" + read_url <- function(url, query = list()) { # make a GET request to the API by combining parameters (if any) resp <- @@ -75,7 +76,6 @@ add them as columns in the resulting dataframe): return(parsed) } - get_smarter_data <- function(url, query = list()) { # do the request and parse data with our function parsed <- read_url(url, query) @@ -104,7 +104,8 @@ add them as columns in the resulting dataframe): class = "smarter_api") } - +``base_url`` is defined for simplicity in order to make all our request to the +same server. Our functions will take an ``url`` parameter, which will be our API endpoint, and a ``query`` parameter, which will be a list of parameters that will enhance our queries as described in :ref:`Query parameters` @@ -119,8 +120,6 @@ deal with datasets objects by querying the *datasets* endpoint: .. code-block:: r - base_url <- "https://webserver.ibba.cnr.it" - get_smarter_datasets <- function(query=list()) { url <- httr::modify_url(base_url, path = "/smarter-api/datasets") @@ -133,11 +132,9 @@ deal with datasets objects by querying the *datasets* endpoint: all_datasets <- get_smarter_datasets() -``base_url`` is defined for simplicity in order to make all our request to the -same server. By calling the defined ``get_smarter_datasets`` function you will retrieve all datasets and you will store them in the ``all_datasets`` dataframe. Similarly, -to deal with the Breed endpoint you could define the ``get_smarter_breeds`` function: +to deal with the *Breed* endpoint you could define the ``get_smarter_breeds`` function: .. code-block:: r @@ -156,7 +153,7 @@ to deal with the Breed endpoint you could define the ``get_smarter_breeds`` func get_smarter_breeds(query = list(species = "Goat")) ``get_smarter_breeds`` and ``get_smarter_datasets`` functions can be used to return -all the SMARTER datasets and breeds. However you can pass additional parameters to +all the SMARTER *datasets* and *breeds*. However you can pass additional parameters to the endpoint using the ``query`` parameter (which need to be a ``list``). For example, you could retrieve all the *genotypes* datasets using the ``type`` parameter: @@ -244,14 +241,14 @@ to have a list of our samples in order to subset the full genotype file using `` selected_landrace_samples %>% select(smarter_id, breed_code) -The same could be applied on variants endpoints in order to get information on -variants. In the following example we will select the goat variants on chromosome -*1* within *1-1000000* position in *ARS1* assembly: +Here's another example that could be applied in order to get information on +variants. In this case we will select the goat variants on chromosome +*1* within *1-1000000* positions in *ARS1* assembly: .. code-block:: r get_smarter_variations <- function(species, assembly, query = list()) { - # mind that species is lowercase in endpoint url + # mind that species is lowercase in endpoint url, while assembly is uppercase species <- tolower(species) assembly <- toupper(assembly) diff --git a/flask-data/smarter/docs/source/modules.rst b/flask-data/smarter/docs/source/modules.rst index 5be82d6..0f95f9a 100644 --- a/flask-data/smarter/docs/source/modules.rst +++ b/flask-data/smarter/docs/source/modules.rst @@ -2,6 +2,9 @@ Backend Module Documentation ============================ +Here's a description of the backend modules. The backend is the part of the +application that is responsible for the business logic and the data storage. + .. toctree:: :maxdepth: 4 From 56d175bf860b2d3dd6040d5f508c33cf5c0d607c Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Wed, 19 Jun 2024 17:02:31 +0200 Subject: [PATCH 26/32] :green_heart: update readthedocs CI config --- .readthedocs.yml => .readthedocs.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename .readthedocs.yml => .readthedocs.yaml (76%) diff --git a/.readthedocs.yml b/.readthedocs.yaml similarity index 76% rename from .readthedocs.yml rename to .readthedocs.yaml index f0d661d..f65b949 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yaml @@ -8,18 +8,18 @@ version: 2 build: os: "ubuntu-22.04" tools: - python: "3.10" + python: "3.11" jobs: post_create_environment: # Install poetry # https://python-poetry.org/docs/#installing-manually - pip install poetry - # Tell poetry to not use a virtual environment - - poetry config virtualenvs.create false post_install: # Install dependencies with 'docs' dependency group # https://python-poetry.org/docs/managing-dependencies/#dependency-groups - - poetry install + # VIRTUAL_ENV needs to be set manually for now. + # See https://github.com/readthedocs/readthedocs.org/pull/11152/ + - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --no-root # Build documentation in the docs/ directory with Sphinx sphinx: From 159033b02617eb67616460b07f62247f2fcdac91 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Thu, 20 Jun 2024 11:23:21 +0200 Subject: [PATCH 27/32] :memo: minor changes in RTD documentation --- flask-data/smarter/docs/source/accessing/python.rst | 9 +++++---- flask-data/smarter/docs/source/accessing/r.rst | 2 +- flask-data/smarter/docs/source/index.rst | 9 +++------ flask-data/smarter/docs/source/installing.rst | 4 ++-- flask-data/smarter/docs/source/introduction.rst | 5 ++++- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/flask-data/smarter/docs/source/accessing/python.rst b/flask-data/smarter/docs/source/accessing/python.rst index fccc526..baa0b1d 100644 --- a/flask-data/smarter/docs/source/accessing/python.rst +++ b/flask-data/smarter/docs/source/accessing/python.rst @@ -26,7 +26,8 @@ urls. Eventually, we will transform data into a ``pandas`` DataFrame. Deal with data and pagination in python --------------------------------------- -We can define some utility functions to deal with data and pagination: +We can define some utility functions to deal with data and pagination. Those +functions are general and can be used to access any endpoint of the SMARTER API: .. code-block:: python @@ -83,7 +84,7 @@ Read data with Python --------------------- Now we can read data from the API using the functions we defined before. We can -get the data from the API and transform it into a pandas DataFrame. We can define +get the data from the API and transform it into a ``pandas.DataFrame`` by creating a custom function in order to call the API with different parameters: .. code-block:: python @@ -97,7 +98,7 @@ a custom function in order to call the API with different parameters: return pd.json_normalize(results) By calling the function ``get_smarter_datasets`` we can get the data from the API -and transform it into a pandas DataFrame to collect all the *datasets* object from +and transform it into a ``pandas.DataFrame`` to collect all the *datasets* object from the *Dataset* endpoint. Similarly, we can define a function to get the data from the *Breed* endpoint: @@ -113,7 +114,7 @@ the *Dataset* endpoint. Similarly, we can define a function to get the data from ``get_smarter_breeds`` and ``get_smarter_datasets`` functions can be used to return all the SMARTER *datasets* and *breeds*. However you can pass additional parameters to -the endpoint using the ``params`` parameter (which can be a dictionary or a list +the endpoints using the ``params`` parameter (which can be a dictionary or a list of tuples, when specifying the same parameter multiple times). For example, you could retrieve all goats breeds using the ``species`` option: diff --git a/flask-data/smarter/docs/source/accessing/r.rst b/flask-data/smarter/docs/source/accessing/r.rst index 224792a..895b44e 100644 --- a/flask-data/smarter/docs/source/accessing/r.rst +++ b/flask-data/smarter/docs/source/accessing/r.rst @@ -219,7 +219,7 @@ endpoints relying on parameters: query = list(breed_code = "LNR") ) -As for the breed example, we can refine our query, for example by selecting +We can refine our query, for example by selecting Landrace goat samples which have a locations (GPS coordinates) and phenotypes defined (mind to the double ``_`` in ``locations__exists`` and ``phenotype__exists``): diff --git a/flask-data/smarter/docs/source/index.rst b/flask-data/smarter/docs/source/index.rst index ac11439..f087f7f 100644 --- a/flask-data/smarter/docs/source/index.rst +++ b/flask-data/smarter/docs/source/index.rst @@ -9,8 +9,8 @@ Welcome to SMARTER-backend's documentation! This documentation describes how to install and interact with the SMARTER database backend. Briefly, the SMARTER database created and maintained with the `SMARTER-database `_ project is -made accessible to SMARTER partners using this API. This API is the same used -by the `SMARTER-frontend `_ in +made accessible to the community using this API. This API is the same used +by the `SMARTER-frontend `_ in order to access and browse SMARTER data using a web browser. SMARTER-backend is a `flask-API `_ @@ -24,10 +24,7 @@ the data they need using a `PLINK `_ command Documentation is organized as following: in :ref:`Introduction` we describe what SMARTER-backend is and we provide general information. In :ref:`Backend installation` we describe how to install a local instance of SMARTER-backend. Then in -:ref:`Accessing SMARTER-backend` we describe how to programmatically access to data -or how to inspect data using applications like `Postman `_ -or `Talend Api Tester `_ -google-chrome extension. +:ref:`Accessing SMARTER-backend` we describe how to programmatically access to data. .. toctree:: :maxdepth: 2 diff --git a/flask-data/smarter/docs/source/installing.rst b/flask-data/smarter/docs/source/installing.rst index 312d99b..7e376b9 100644 --- a/flask-data/smarter/docs/source/installing.rst +++ b/flask-data/smarter/docs/source/installing.rst @@ -26,9 +26,9 @@ official installation instructions for your operating system. Create a .env file ------------------ -Before running the application, you need to create a .env file in the root directory +Before running the application, you need to create a ``.env`` file in the root directory of the project. This is required to set the environment variables needed by the -application, like the database connection string. Create a .env file in the root +application, like the database connection string. Create a ``.env`` file in the root directory of the project with the following content: .. code-block:: bash diff --git a/flask-data/smarter/docs/source/introduction.rst b/flask-data/smarter/docs/source/introduction.rst index edeae8b..9665384 100644 --- a/flask-data/smarter/docs/source/introduction.rst +++ b/flask-data/smarter/docs/source/introduction.rst @@ -111,7 +111,10 @@ supported, ``GET`` and ``POST``: More precisely, SMARTER data through the SMARTER-backend are read-only and ``GET`` and ``POST`` method are allowed in order to retrieve any type of SMARTER data object from the API. ``POST`` method are required to submit complex queries -by providing a payload to certain endpoints. +by providing a payload to certain endpoints, for example to retrieve samples +relying on GPS data. For a detailed list of the available endpoints and the +HTTP methods they support, please refer to the +`swagger documentation `_ available. Status codes ------------ From 7b03a73113ba252f47e508761cb32b01f0fdece7 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Thu, 20 Jun 2024 12:09:20 +0200 Subject: [PATCH 28/32] :heavy_plus_sign: add python decouple --- poetry.lock | 13 ++++++++++++- pyproject.toml | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 215d3be..2b99e3d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1067,6 +1067,17 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "python-decouple" +version = "3.8" +description = "Strict separation of settings from code." +optional = false +python-versions = "*" +files = [ + {file = "python-decouple-3.8.tar.gz", hash = "sha256:ba6e2657d4f376ecc46f77a3a615e058d93ba5e465c01bbe57289bfb7cce680f"}, + {file = "python_decouple-3.8-py3-none-any.whl", hash = "sha256:d0d45340815b25f4de59c974b855bb38d03151d81b037d9e3f463b0c9f8cbd66"}, +] + [[package]] name = "pytz" version = "2024.1" @@ -1621,4 +1632,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "1a838ca9b70e986c0c54c2705d088bf7db569d4d9f6e809061955637b5562859" +content-hash = "8380a6f0371425fd3719d9d4138af708876073c033f3eb249cc26974ae5f9256" diff --git a/pyproject.toml b/pyproject.toml index ceae3e8..be6f443 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ flask-mongoengine = "^1.0.0" werkzeug = "~2.0" coveralls = "^3.3.1" coverage = "5.*" +python-decouple = "^3.8" [build-system] requires = ["poetry-core"] From e6368381cdd9181f17976194e428a7e0d6761f0a Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Thu, 20 Jun 2024 12:10:57 +0200 Subject: [PATCH 29/32] :recycle: configure stuff with decouple --- flask-data/smarter/app.py | 26 +++++++++++--------------- flask-data/smarter/tests/base.py | 6 ++++-- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/flask-data/smarter/app.py b/flask-data/smarter/app.py index 3cdd843..00bf620 100644 --- a/flask-data/smarter/app.py +++ b/flask-data/smarter/app.py @@ -6,11 +6,11 @@ @author: Paolo Cozzi """ -import os - from bson import ObjectId +import logging from logging.config import dictConfig +from decouple import config from flask import Flask, redirect, url_for from flask_restful import Api from flask.json import JSONEncoder @@ -51,17 +51,14 @@ def default(self, obj): # https://stackoverflow.com/a/56474420/4385116 -def create_app(config={}): +def create_app(): """This function create Flask app. Is required by wsgi because it need to be called after service is started and forked, not when importing the module during initialization. To start the flask app, first import the module and then create all the stuff by invoking this function - You need call the run method on the returned values to start acception + You need call the run method on the returned values to start accepting requests - Args: - config (dict): pass parameters to this app (not yet defined) - Returns: Flask: a flask initialized application """ @@ -70,6 +67,10 @@ def create_app(config={}): CORS(app) api = Api(app, errors=errors) + # check debug mode + if config('DEBUG', cast=bool, default=True): + app.debug = True + # deal with ObjectId in json responses app.json_encoder = CustomJSONEncoder @@ -107,9 +108,9 @@ def create_app(config={}): # http://docs.mongoengine.org/projects/flask-mongoengine/en/latest/#configuration app.config['MONGODB_SETTINGS'] = { - 'host': 'mongodb://mongo/smarter', - 'username': os.getenv("MONGODB_SMARTER_USER"), - 'password': os.getenv("MONGODB_SMARTER_PASS"), + 'host': config('MONGODB_SMARTER_DB', default='mongodb://mongo/smarter'), + 'username': config('MONGODB_SMARTER_USER'), + 'password': config("MONGODB_SMARTER_PASS"), 'authentication_source': 'admin', 'alias': DB_ALIAS, # NOTE: This fixes "UserWarning: MongoClient opened before fork." @@ -117,11 +118,6 @@ def create_app(config={}): 'connect': False } - # override configuration with custom values - if 'host' in config: - app.logger.error(f"Setting custom host: {config['host']}") - app.config['MONGODB_SETTINGS']['host'] = config['host'] - # connect to database initialize_db(app) diff --git a/flask-data/smarter/tests/base.py b/flask-data/smarter/tests/base.py index d7f513e..9e674ec 100644 --- a/flask-data/smarter/tests/base.py +++ b/flask-data/smarter/tests/base.py @@ -6,6 +6,7 @@ @author: Paolo Cozzi """ +import os import json import logging import unittest @@ -18,8 +19,9 @@ from app import create_app from database.db import db, DB_ALIAS -# start application with custom values -app = create_app(config={'host': 'mongodb://mongo/test'}) +# start application an override the default configuration +os.environ['MONGODB_SMARTER_DB'] = 'mongodb://mongo/test' +app = create_app() # Get an instance of a logger logger = logging.getLogger(__name__) From a5701d88a8bd977a13a25d22626a6a8405a04eec Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Thu, 20 Jun 2024 13:05:05 +0200 Subject: [PATCH 30/32] :sparkles: send error messages to admins --- flask-data/smarter/app.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/flask-data/smarter/app.py b/flask-data/smarter/app.py index 00bf620..0c77723 100644 --- a/flask-data/smarter/app.py +++ b/flask-data/smarter/app.py @@ -9,6 +9,7 @@ from bson import ObjectId import logging from logging.config import dictConfig +from logging.handlers import SMTPHandler from decouple import config from flask import Flask, redirect, url_for @@ -40,6 +41,26 @@ } }) +mail_handler = SMTPHandler( + mailhost=( + config('EMAIL_HOST', default='localhost'), + config('EMAIL_PORT', cast=int, default=1025) + ), + fromaddr=config('DEFAULT_FROM_EMAIL', default="server-error@example.com"), + toaddrs=[email.strip() for email in config( + 'ADMINS', default="admin@example.com").split(',')], + subject='SMARTER-backend Application Error', + credentials=( + config('EMAIL_HOST_USER', default=None), + config('EMAIL_HOST_PASSWORD', default=None) + ), + secure=() +) +mail_handler.setLevel(logging.ERROR) +mail_handler.setFormatter(logging.Formatter( + '[%(asctime)s] %(levelname)s in %(module)s: %(message)s' +)) + class CustomJSONEncoder(JSONEncoder): def default(self, obj): @@ -108,7 +129,10 @@ def create_app(): # http://docs.mongoengine.org/projects/flask-mongoengine/en/latest/#configuration app.config['MONGODB_SETTINGS'] = { - 'host': config('MONGODB_SMARTER_DB', default='mongodb://mongo/smarter'), + 'host': config( + 'MONGODB_SMARTER_DB', + default='mongodb://mongo/smarter' + ), 'username': config('MONGODB_SMARTER_USER'), 'password': config("MONGODB_SMARTER_PASS"), 'authentication_source': 'admin', @@ -129,6 +153,9 @@ def create_app(): app.logger.debug("Routes initialized") + if not app.debug: + app.logger.addHandler(mail_handler) + # add a redirect for the index page @app.route('/smarter-api/') def index(): From 841f5deb0ad415bf32cb3de4c918098ae7123f95 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Thu, 20 Jun 2024 13:17:37 +0200 Subject: [PATCH 31/32] :sparkles: add requests to logging messages add requests to logging messages when sending emails --- flask-data/smarter/app.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/flask-data/smarter/app.py b/flask-data/smarter/app.py index 0c77723..c401e04 100644 --- a/flask-data/smarter/app.py +++ b/flask-data/smarter/app.py @@ -12,7 +12,8 @@ from logging.handlers import SMTPHandler from decouple import config -from flask import Flask, redirect, url_for +from flask import Flask, redirect, url_for, has_request_context, request +from flask.logging import default_handler from flask_restful import Api from flask.json import JSONEncoder from flask_cors import CORS @@ -57,9 +58,26 @@ secure=() ) mail_handler.setLevel(logging.ERROR) -mail_handler.setFormatter(logging.Formatter( - '[%(asctime)s] %(levelname)s in %(module)s: %(message)s' -)) + + +class RequestFormatter(logging.Formatter): + def format(self, record): + if has_request_context(): + record.url = request.url + record.remote_addr = request.remote_addr + else: + record.url = None + record.remote_addr = None + + return super().format(record) + + +formatter = RequestFormatter( + '[%(asctime)s] %(remote_addr)s requested %(url)s\n' + '%(levelname)s in %(module)s: %(message)s' +) +mail_handler.setFormatter(formatter) +default_handler.setFormatter(formatter) class CustomJSONEncoder(JSONEncoder): @@ -90,6 +108,7 @@ def create_app(): # check debug mode if config('DEBUG', cast=bool, default=True): + # in debug mode, the default logging will be set to DEBUG level app.debug = True # deal with ObjectId in json responses From f4adf544f8bc5dda81d95c63cf24697279838449 Mon Sep 17 00:00:00 2001 From: Paolo Cozzi Date: Thu, 27 Jun 2024 21:14:29 +0200 Subject: [PATCH 32/32] :loud_sound: add logs to geojson endpoint --- flask-data/smarter/resources/GeoJSON.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/flask-data/smarter/resources/GeoJSON.py b/flask-data/smarter/resources/GeoJSON.py index 896857e..bac5b9e 100644 --- a/flask-data/smarter/resources/GeoJSON.py +++ b/flask-data/smarter/resources/GeoJSON.py @@ -9,7 +9,7 @@ from bson import ObjectId from bson.errors import InvalidId -from flask import jsonify, current_app +from flask import jsonify, current_app, request from flask_restful import Resource, reqparse from database.models import SampleSheep, SampleGoat @@ -108,6 +108,9 @@ class GeoJSONListMixin(Resource): def parse_args(self) -> list: # reading request parameters kwargs = self.parser.parse_args(strict=True) + + current_app.logger.debug(f"Got kwargs: {kwargs}") + args = [] # filter args @@ -122,6 +125,8 @@ def parse_args(self) -> list: # get the geometry field geometry = kwargs.pop('geo_within_polygon')['geometry'] + current_app.logger.debug(f"Got geometry: {geometry}") + if 'locations' not in kwargs: kwargs['locations'] = {} @@ -459,4 +464,6 @@ def post(self): type: array """ + current_app.logger.debug(f"Got a POST request: {request.json}") + return self.get_context_data()