├── .github ├── dependabot.yml └── workflows │ ├── ci.yaml │ └── release.yml ├── .gitignore ├── .mergify.yml ├── .semgrepignore ├── LICENSE ├── README.md ├── poe.toml ├── poetry.lock ├── pyproject.toml ├── requirements-poetry.txt ├── sql_compare ├── __init__.py └── py.typed ├── tests ├── __init__.py └── test_sql_compare.py └── tools └── poetry-install.sh /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "09:00" 8 | timezone: Europe/Paris 9 | open-pull-requests-limit: 10 10 | - package-ecosystem: github-actions 11 | directory: / 12 | schedule: 13 | interval: daily 14 | time: "09:00" 15 | timezone: Europe/Paris 16 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | permissions: read-all 3 | 4 | on: 5 | pull_request: 6 | branches: 7 | - main 8 | - devs/** 9 | 10 | jobs: 11 | test: 12 | name: "Test with Python ${{ matrix.python-version }}" 13 | timeout-minutes: 5 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | python-version: ["3.9", "3.10", "3.11", "3.12"] 18 | steps: 19 | - uses: actions/checkout@v4.2.2 20 | - uses: actions/setup-python@v5.6.0 21 | with: 22 | python-version: "${{ matrix.python-version }}" 23 | - run: | 24 | pip install -r requirements-poetry.txt 25 | poetry sync 26 | poetry run poe linters 27 | poetry run poe test 28 | poetry build 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Upload release to PyPI 2 | on: 3 | release: 4 | types: 5 | - published 6 | 7 | jobs: 8 | pypi-publish: 9 | name: Upload release to PyPI 10 | runs-on: ubuntu-latest 11 | environment: release 12 | permissions: 13 | id-token: write 14 | contents: write 15 | steps: 16 | - uses: actions/checkout@v4.2.2 17 | - uses: actions/setup-python@v5.6.0 18 | with: 19 | python-version: 3.12 20 | - run: | 21 | pip install -r requirements-poetry.txt 22 | poetry sync 23 | poetry build 24 | - name: Publish package distributions to PyPI 25 | uses: pypa/gh-action-pypi-publish@release/v1 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .pytest_cache 3 | .mypy_cache 4 | .git 5 | .venv 6 | dist 7 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | extends: .github 2 | 3 | queue_rules: 4 | - name: default 5 | allow_inplace_checks: true 6 | queue_conditions: 7 | - and: &CheckRuns 8 | - check-success=Test with Python 3.9 9 | - check-success=Test with Python 3.10 10 | - check-success=Test with Python 3.11 11 | - check-success=Test with Python 3.12 12 | - "#approved-reviews-by>=1" 13 | - "#changes-requested-reviews-by=0" 14 | - "#review-threads-unresolved=0" 15 | - "#review-requested=0" 16 | commit_message_template: | 17 | {{ title }} (#{{ number }}) 18 | 19 | {{ body }} 20 | merge_method: squash 21 | 22 | - name: lowprio 23 | allow_inplace_checks: true 24 | queue_conditions: 25 | - and: *CheckRuns 26 | - "#commits=1" 27 | - author=dependabot[bot] 28 | merge_method: merge 29 | batch_size: 7 30 | batch_max_wait_time: 5min 31 | commit_message_template: 32 | queue_branch_merge_method: fast-forward 33 | pull_request_rules: 34 | - name: automatic merge 35 | conditions: 36 | - base=main 37 | - label!=manual merge 38 | actions: 39 | queue: 40 | 41 | - name: request review 42 | conditions: 43 | - -author=dependabot[bot] 44 | - -merged 45 | - -closed 46 | - and: *CheckRuns 47 | - "#approved-reviews-by=0" 48 | - "#changes-requested-reviews-by=0" 49 | - "review-requested!=@devs" 50 | actions: 51 | request_reviews: 52 | teams: 53 | - devs 54 | 55 | merge_queue: 56 | max_parallel_checks: 5 57 | priority_rules: 58 | - name: priority for queue `default` 59 | conditions: 60 | - "#approved-reviews-by>=1" 61 | - "#changes-requested-reviews-by=0" 62 | - "#review-threads-unresolved=0" 63 | - "#review-requested=0" 64 | priority: 2250 65 | -------------------------------------------------------------------------------- /.semgrepignore: -------------------------------------------------------------------------------- 1 | :include .gitignore 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SQL Compare 2 | 3 | Compare SQL schemas. 4 | 5 | This package allows to compare two SQL files (or strings) to know whether their 6 | statements are the same or not. The comparison doesn't care about the order of 7 | the columns in a table or the order of the values in an enumerator. It also 8 | excludes irrelevant data like comments. 9 | 10 | Its main usage is to compare the schemas of two databases (e.g. staging and 11 | production). See this [blog post](https://blog.mergify.com/ensuring-seamless-sql-migrations-in-production/) 12 | that tells about the creation of the package. 13 | 14 | ## Installation 15 | 16 | ```bash 17 | $ pip install sql-compare 18 | ``` 19 | 20 | ## Usage 21 | 22 | Compare two SQL schemas using strings. 23 | 24 | ```python 25 | import sql_compare 26 | 27 | assert sql_compare.compare(first_schema, second_schema) 28 | ``` 29 | 30 | Compare two SQL schemas using files. 31 | 32 | ```python 33 | import pathlib 34 | import sql_compare 35 | 36 | first_schema = pathlib.Path("/path/to/schema.sql") 37 | second_schema = pathlib.Path("/path/to/other/schema.sql") 38 | 39 | assert sql_compare.compare_files(first_schema, second_schema) 40 | ``` 41 | 42 | ## Dependencies 43 | 44 | SQL Compare relies on [`sqlparse`](https://sqlparse.readthedocs.io/en/latest/) 45 | to parse SQL statements. 46 | -------------------------------------------------------------------------------- /poe.toml: -------------------------------------------------------------------------------- 1 | [tool.poe.executor] 2 | type = "poetry" 3 | 4 | [tool.poe.tasks.setup] 5 | help = "Install poetry virtual environment" 6 | executor = { type = "simple" } 7 | cmd = "./tools/poetry-install.sh" 8 | 9 | [tool.poe.tasks.linters] 10 | deps = ["setup"] 11 | help = "Run linters" 12 | default_item_type = "cmd" 13 | sequence = ["ruff check .", "ruff format --check .", "deptry .", "mypy"] 14 | 15 | [tool.poe.tasks.semgrep] 16 | deps = ["setup"] 17 | help = "Run SAST tools" 18 | cmd = "semgrep --config=auto --error --timeout=15" 19 | 20 | [tool.poe.tasks.test] 21 | deps = ["setup"] 22 | help = "Run test suite" 23 | cmd = "pytest" 24 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "attrs" 5 | version = "23.2.0" 6 | description = "Classes Without Boilerplate" 7 | optional = false 8 | python-versions = ">=3.7" 9 | groups = ["dev"] 10 | files = [ 11 | {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, 12 | {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, 13 | ] 14 | 15 | [package.extras] 16 | cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] 17 | dev = ["attrs[tests]", "pre-commit"] 18 | docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] 19 | tests = ["attrs[tests-no-zope]", "zope-interface"] 20 | tests-mypy = ["mypy (>=1.6) ; platform_python_implementation == \"CPython\" and python_version >= \"3.8\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.8\""] 21 | tests-no-zope = ["attrs[tests-mypy]", "cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] 22 | 23 | [[package]] 24 | name = "boltons" 25 | version = "21.0.0" 26 | description = "When they're not builtins, they're boltons." 27 | optional = false 28 | python-versions = "*" 29 | groups = ["dev"] 30 | files = [ 31 | {file = "boltons-21.0.0-py2.py3-none-any.whl", hash = "sha256:b9bb7b58b2b420bbe11a6025fdef6d3e5edc9f76a42fb467afe7ca212ef9948b"}, 32 | {file = "boltons-21.0.0.tar.gz", hash = "sha256:65e70a79a731a7fe6e98592ecfb5ccf2115873d01dbc576079874629e5c90f13"}, 33 | ] 34 | 35 | [[package]] 36 | name = "bracex" 37 | version = "2.4" 38 | description = "Bash style brace expander." 39 | optional = false 40 | python-versions = ">=3.8" 41 | groups = ["dev"] 42 | files = [ 43 | {file = "bracex-2.4-py3-none-any.whl", hash = "sha256:efdc71eff95eaff5e0f8cfebe7d01adf2c8637c8c92edaf63ef348c241a82418"}, 44 | {file = "bracex-2.4.tar.gz", hash = "sha256:a27eaf1df42cf561fed58b7a8f3fdf129d1ea16a81e1fadd1d17989bc6384beb"}, 45 | ] 46 | 47 | [[package]] 48 | name = "certifi" 49 | version = "2024.7.4" 50 | description = "Python package for providing Mozilla's CA Bundle." 51 | optional = false 52 | python-versions = ">=3.6" 53 | groups = ["dev"] 54 | files = [ 55 | {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, 56 | {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, 57 | ] 58 | 59 | [[package]] 60 | name = "charset-normalizer" 61 | version = "3.3.2" 62 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 63 | optional = false 64 | python-versions = ">=3.7.0" 65 | groups = ["dev"] 66 | files = [ 67 | {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, 68 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, 69 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, 70 | {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, 71 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, 72 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, 73 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, 74 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, 75 | {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, 76 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, 77 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, 78 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, 79 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, 80 | {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, 81 | {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, 82 | {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, 83 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, 84 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, 85 | {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, 86 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, 87 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, 88 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, 89 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, 90 | {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, 91 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, 92 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, 93 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, 94 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, 95 | {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, 96 | {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, 97 | {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, 98 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, 99 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, 100 | {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, 101 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, 102 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, 103 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, 104 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, 105 | {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, 106 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, 107 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, 108 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, 109 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, 110 | {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, 111 | {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, 112 | {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, 113 | {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, 114 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, 115 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, 116 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, 117 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, 118 | {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, 119 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, 120 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, 121 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, 122 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, 123 | {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, 124 | {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, 125 | {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, 126 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, 127 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, 128 | {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, 129 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, 130 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, 131 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, 132 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, 133 | {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, 134 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, 135 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, 136 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, 137 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, 138 | {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, 139 | {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, 140 | {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, 141 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, 142 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, 143 | {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, 144 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, 145 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, 146 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, 147 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, 148 | {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, 149 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, 150 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, 151 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, 152 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, 153 | {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, 154 | {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, 155 | {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, 156 | {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, 157 | ] 158 | 159 | [[package]] 160 | name = "click" 161 | version = "8.1.8" 162 | description = "Composable command line interface toolkit" 163 | optional = false 164 | python-versions = ">=3.7" 165 | groups = ["dev"] 166 | files = [ 167 | {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, 168 | {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, 169 | ] 170 | 171 | [package.dependencies] 172 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 173 | 174 | [[package]] 175 | name = "click-option-group" 176 | version = "0.5.6" 177 | description = "Option groups missing in Click" 178 | optional = false 179 | python-versions = ">=3.6,<4" 180 | groups = ["dev"] 181 | files = [ 182 | {file = "click-option-group-0.5.6.tar.gz", hash = "sha256:97d06703873518cc5038509443742b25069a3c7562d1ea72ff08bfadde1ce777"}, 183 | {file = "click_option_group-0.5.6-py3-none-any.whl", hash = "sha256:38a26d963ee3ad93332ddf782f9259c5bdfe405e73408d943ef5e7d0c3767ec7"}, 184 | ] 185 | 186 | [package.dependencies] 187 | Click = ">=7.0,<9" 188 | 189 | [package.extras] 190 | docs = ["Pallets-Sphinx-Themes", "m2r2", "sphinx"] 191 | tests = ["pytest"] 192 | tests-cov = ["coverage", "coveralls", "pytest", "pytest-cov"] 193 | 194 | [[package]] 195 | name = "colorama" 196 | version = "0.4.6" 197 | description = "Cross-platform colored terminal text." 198 | optional = false 199 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 200 | groups = ["dev"] 201 | files = [ 202 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 203 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 204 | ] 205 | 206 | [[package]] 207 | name = "defusedxml" 208 | version = "0.7.1" 209 | description = "XML bomb protection for Python stdlib modules" 210 | optional = false 211 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 212 | groups = ["dev"] 213 | files = [ 214 | {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, 215 | {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, 216 | ] 217 | 218 | [[package]] 219 | name = "deprecated" 220 | version = "1.2.14" 221 | description = "Python @deprecated decorator to deprecate old python classes, functions or methods." 222 | optional = false 223 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 224 | groups = ["dev"] 225 | files = [ 226 | {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, 227 | {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, 228 | ] 229 | 230 | [package.dependencies] 231 | wrapt = ">=1.10,<2" 232 | 233 | [package.extras] 234 | dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] 235 | 236 | [[package]] 237 | name = "deptry" 238 | version = "0.23.0" 239 | description = "A command line utility to check for unused, missing and transitive dependencies in a Python project." 240 | optional = false 241 | python-versions = ">=3.9" 242 | groups = ["dev"] 243 | files = [ 244 | {file = "deptry-0.23.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:1f2a6817a37d76e8f6b667381b7caf6ea3e6d6c18b5be24d36c625f387c79852"}, 245 | {file = "deptry-0.23.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:9601b64cc0aed42687fdd5c912d5f1e90d7f7333fb589b14e35bfdfebae866f3"}, 246 | {file = "deptry-0.23.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6172b2205f6e84bcc9df25226693d4deb9576a6f746c2ace828f6d13401d357"}, 247 | {file = "deptry-0.23.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1cfa4b3a46ee8a026eaa38e4b9ba43fe6036a07fe16bf0a663cb611b939f6af8"}, 248 | {file = "deptry-0.23.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9d03cc99a61c348df92074a50e0a71b28f264f0edbf686084ca90e6fd44e3abe"}, 249 | {file = "deptry-0.23.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9a46f78098f145100dc582a59af8548b26cdfa16cf0fbd85d2d44645e724cb6a"}, 250 | {file = "deptry-0.23.0-cp39-abi3-win_amd64.whl", hash = "sha256:d53e803b280791d89a051b6183d9dc40411200e22a8ab7e6c32c6b169822a664"}, 251 | {file = "deptry-0.23.0-cp39-abi3-win_arm64.whl", hash = "sha256:da7678624f4626d839c8c03675452cefc59d6cf57d25c84a9711dae514719279"}, 252 | {file = "deptry-0.23.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:40706dcbed54141f2d23afa70a272171c8c46531cd6f0f9c8ef482c906b3cee2"}, 253 | {file = "deptry-0.23.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:889541844092f18e7b48631852195f36c25c5afd4d7e074b19ba824b430add50"}, 254 | {file = "deptry-0.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aff9156228eb16cd81792f920c1623c00cb59091ae572600ba0eac587da33c0c"}, 255 | {file = "deptry-0.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:583154732cfd438a4a090b7d13d8b2016f1ac2732534f34fb689345768d8538b"}, 256 | {file = "deptry-0.23.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:736e7bc557aec6118b2a4d454f0d81f070782faeaa9d8d3c9a15985c9f265372"}, 257 | {file = "deptry-0.23.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5f7e4b1a5232ed6d352fca7173750610a169377d1951d3e9782947191942a765"}, 258 | {file = "deptry-0.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:04afae204654542406318fd3dd6f4a6697579597f37195437daf84a53ee0ebbf"}, 259 | {file = "deptry-0.23.0.tar.gz", hash = "sha256:4915a3590ccf38ad7a9176aee376745aa9de121f50f8da8fb9ccec87fa93e676"}, 260 | ] 261 | 262 | [package.dependencies] 263 | click = ">=8.0.0,<9" 264 | colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} 265 | packaging = ">=23.2" 266 | requirements-parser = ">=0.11.0,<1" 267 | tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} 268 | 269 | [[package]] 270 | name = "exceptiongroup" 271 | version = "1.2.1" 272 | description = "Backport of PEP 654 (exception groups)" 273 | optional = false 274 | python-versions = ">=3.7" 275 | groups = ["dev"] 276 | files = [ 277 | {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, 278 | {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, 279 | ] 280 | 281 | [package.extras] 282 | test = ["pytest (>=6)"] 283 | 284 | [[package]] 285 | name = "face" 286 | version = "22.0.0" 287 | description = "A command-line application framework (and CLI parser). Friendly for users, full-featured for developers." 288 | optional = false 289 | python-versions = "*" 290 | groups = ["dev"] 291 | files = [ 292 | {file = "face-22.0.0-py3-none-any.whl", hash = "sha256:344fe31562d0f6f444a45982418f3793d4b14f9abb98ccca1509d22e0a3e7e35"}, 293 | {file = "face-22.0.0.tar.gz", hash = "sha256:d5d692f90bc8f5987b636e47e36384b9bbda499aaf0a77aa0b0bbe834c76923d"}, 294 | ] 295 | 296 | [package.dependencies] 297 | boltons = ">=20.0.0" 298 | 299 | [[package]] 300 | name = "glom" 301 | version = "22.1.0" 302 | description = "A declarative object transformer and formatter, for conglomerating nested data." 303 | optional = false 304 | python-versions = "*" 305 | groups = ["dev"] 306 | files = [ 307 | {file = "glom-22.1.0-py2.py3-none-any.whl", hash = "sha256:5339da206bf3532e01a83a35aca202960ea885156986d190574b779598e9e772"}, 308 | {file = "glom-22.1.0.tar.gz", hash = "sha256:1510c6587a8f9c64a246641b70033cbc5ebde99f02ad245693678038e821aeb5"}, 309 | ] 310 | 311 | [package.dependencies] 312 | attrs = "*" 313 | boltons = ">=19.3.0" 314 | face = ">=20.1.0" 315 | 316 | [package.extras] 317 | yaml = ["PyYAML"] 318 | 319 | [[package]] 320 | name = "googleapis-common-protos" 321 | version = "1.63.2" 322 | description = "Common protobufs used in Google APIs" 323 | optional = false 324 | python-versions = ">=3.7" 325 | groups = ["dev"] 326 | files = [ 327 | {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, 328 | {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, 329 | ] 330 | 331 | [package.dependencies] 332 | protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" 333 | 334 | [package.extras] 335 | grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] 336 | 337 | [[package]] 338 | name = "idna" 339 | version = "3.7" 340 | description = "Internationalized Domain Names in Applications (IDNA)" 341 | optional = false 342 | python-versions = ">=3.5" 343 | groups = ["dev"] 344 | files = [ 345 | {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, 346 | {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, 347 | ] 348 | 349 | [[package]] 350 | name = "importlib-metadata" 351 | version = "7.1.0" 352 | description = "Read metadata from Python packages" 353 | optional = false 354 | python-versions = ">=3.8" 355 | groups = ["dev"] 356 | files = [ 357 | {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, 358 | {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, 359 | ] 360 | 361 | [package.dependencies] 362 | zipp = ">=0.5" 363 | 364 | [package.extras] 365 | docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 366 | perf = ["ipython"] 367 | testing = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy ; platform_python_implementation != \"PyPy\"", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] 368 | 369 | [[package]] 370 | name = "iniconfig" 371 | version = "2.0.0" 372 | description = "brain-dead simple config-ini parsing" 373 | optional = false 374 | python-versions = ">=3.7" 375 | groups = ["dev"] 376 | files = [ 377 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 378 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 379 | ] 380 | 381 | [[package]] 382 | name = "jsonschema" 383 | version = "4.22.0" 384 | description = "An implementation of JSON Schema validation for Python" 385 | optional = false 386 | python-versions = ">=3.8" 387 | groups = ["dev"] 388 | files = [ 389 | {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, 390 | {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, 391 | ] 392 | 393 | [package.dependencies] 394 | attrs = ">=22.2.0" 395 | jsonschema-specifications = ">=2023.03.6" 396 | referencing = ">=0.28.4" 397 | rpds-py = ">=0.7.1" 398 | 399 | [package.extras] 400 | format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] 401 | format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] 402 | 403 | [[package]] 404 | name = "jsonschema-specifications" 405 | version = "2023.12.1" 406 | description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" 407 | optional = false 408 | python-versions = ">=3.8" 409 | groups = ["dev"] 410 | files = [ 411 | {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, 412 | {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, 413 | ] 414 | 415 | [package.dependencies] 416 | referencing = ">=0.31.0" 417 | 418 | [[package]] 419 | name = "markdown-it-py" 420 | version = "3.0.0" 421 | description = "Python port of markdown-it. Markdown parsing, done right!" 422 | optional = false 423 | python-versions = ">=3.8" 424 | groups = ["dev"] 425 | files = [ 426 | {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, 427 | {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, 428 | ] 429 | 430 | [package.dependencies] 431 | mdurl = ">=0.1,<1.0" 432 | 433 | [package.extras] 434 | benchmarking = ["psutil", "pytest", "pytest-benchmark"] 435 | code-style = ["pre-commit (>=3.0,<4.0)"] 436 | compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] 437 | linkify = ["linkify-it-py (>=1,<3)"] 438 | plugins = ["mdit-py-plugins"] 439 | profiling = ["gprof2dot"] 440 | rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] 441 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] 442 | 443 | [[package]] 444 | name = "mdurl" 445 | version = "0.1.2" 446 | description = "Markdown URL utilities" 447 | optional = false 448 | python-versions = ">=3.7" 449 | groups = ["dev"] 450 | files = [ 451 | {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, 452 | {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, 453 | ] 454 | 455 | [[package]] 456 | name = "mypy" 457 | version = "1.16.0" 458 | description = "Optional static typing for Python" 459 | optional = false 460 | python-versions = ">=3.9" 461 | groups = ["dev"] 462 | files = [ 463 | {file = "mypy-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7909541fef256527e5ee9c0a7e2aeed78b6cda72ba44298d1334fe7881b05c5c"}, 464 | {file = "mypy-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e71d6f0090c2256c713ed3d52711d01859c82608b5d68d4fa01a3fe30df95571"}, 465 | {file = "mypy-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:936ccfdd749af4766be824268bfe22d1db9eb2f34a3ea1d00ffbe5b5265f5491"}, 466 | {file = "mypy-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4086883a73166631307fdd330c4a9080ce24913d4f4c5ec596c601b3a4bdd777"}, 467 | {file = "mypy-1.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:feec38097f71797da0231997e0de3a58108c51845399669ebc532c815f93866b"}, 468 | {file = "mypy-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:09a8da6a0ee9a9770b8ff61b39c0bb07971cda90e7297f4213741b48a0cc8d93"}, 469 | {file = "mypy-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9f826aaa7ff8443bac6a494cf743f591488ea940dd360e7dd330e30dd772a5ab"}, 470 | {file = "mypy-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:82d056e6faa508501af333a6af192c700b33e15865bda49611e3d7d8358ebea2"}, 471 | {file = "mypy-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:089bedc02307c2548eb51f426e085546db1fa7dd87fbb7c9fa561575cf6eb1ff"}, 472 | {file = "mypy-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6a2322896003ba66bbd1318c10d3afdfe24e78ef12ea10e2acd985e9d684a666"}, 473 | {file = "mypy-1.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:021a68568082c5b36e977d54e8f1de978baf401a33884ffcea09bd8e88a98f4c"}, 474 | {file = "mypy-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:54066fed302d83bf5128632d05b4ec68412e1f03ef2c300434057d66866cea4b"}, 475 | {file = "mypy-1.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c5436d11e89a3ad16ce8afe752f0f373ae9620841c50883dc96f8b8805620b13"}, 476 | {file = "mypy-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f2622af30bf01d8fc36466231bdd203d120d7a599a6d88fb22bdcb9dbff84090"}, 477 | {file = "mypy-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d045d33c284e10a038f5e29faca055b90eee87da3fc63b8889085744ebabb5a1"}, 478 | {file = "mypy-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b4968f14f44c62e2ec4a038c8797a87315be8df7740dc3ee8d3bfe1c6bf5dba8"}, 479 | {file = "mypy-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb14a4a871bb8efb1e4a50360d4e3c8d6c601e7a31028a2c79f9bb659b63d730"}, 480 | {file = "mypy-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:bd4e1ebe126152a7bbaa4daedd781c90c8f9643c79b9748caa270ad542f12bec"}, 481 | {file = "mypy-1.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a9e056237c89f1587a3be1a3a70a06a698d25e2479b9a2f57325ddaaffc3567b"}, 482 | {file = "mypy-1.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b07e107affb9ee6ce1f342c07f51552d126c32cd62955f59a7db94a51ad12c0"}, 483 | {file = "mypy-1.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c6fb60cbd85dc65d4d63d37cb5c86f4e3a301ec605f606ae3a9173e5cf34997b"}, 484 | {file = "mypy-1.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7e32297a437cc915599e0578fa6bc68ae6a8dc059c9e009c628e1c47f91495d"}, 485 | {file = "mypy-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:afe420c9380ccec31e744e8baff0d406c846683681025db3531b32db56962d52"}, 486 | {file = "mypy-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:55f9076c6ce55dd3f8cd0c6fff26a008ca8e5131b89d5ba6d86bd3f47e736eeb"}, 487 | {file = "mypy-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f56236114c425620875c7cf71700e3d60004858da856c6fc78998ffe767b73d3"}, 488 | {file = "mypy-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:15486beea80be24ff067d7d0ede673b001d0d684d0095803b3e6e17a886a2a92"}, 489 | {file = "mypy-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f2ed0e0847a80655afa2c121835b848ed101cc7b8d8d6ecc5205aedc732b1436"}, 490 | {file = "mypy-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eb5fbc8063cb4fde7787e4c0406aa63094a34a2daf4673f359a1fb64050e9cb2"}, 491 | {file = "mypy-1.16.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a5fcfdb7318c6a8dd127b14b1052743b83e97a970f0edb6c913211507a255e20"}, 492 | {file = "mypy-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:2e7e0ad35275e02797323a5aa1be0b14a4d03ffdb2e5f2b0489fa07b89c67b21"}, 493 | {file = "mypy-1.16.0-py3-none-any.whl", hash = "sha256:29e1499864a3888bca5c1542f2d7232c6e586295183320caa95758fc84034031"}, 494 | {file = "mypy-1.16.0.tar.gz", hash = "sha256:84b94283f817e2aa6350a14b4a8fb2a35a53c286f97c9d30f53b63620e7af8ab"}, 495 | ] 496 | 497 | [package.dependencies] 498 | mypy_extensions = ">=1.0.0" 499 | pathspec = ">=0.9.0" 500 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 501 | typing_extensions = ">=4.6.0" 502 | 503 | [package.extras] 504 | dmypy = ["psutil (>=4.0)"] 505 | faster-cache = ["orjson"] 506 | install-types = ["pip"] 507 | mypyc = ["setuptools (>=50)"] 508 | reports = ["lxml"] 509 | 510 | [[package]] 511 | name = "mypy-extensions" 512 | version = "1.0.0" 513 | description = "Type system extensions for programs checked with the mypy type checker." 514 | optional = false 515 | python-versions = ">=3.5" 516 | groups = ["dev"] 517 | files = [ 518 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 519 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 520 | ] 521 | 522 | [[package]] 523 | name = "opentelemetry-api" 524 | version = "1.25.0" 525 | description = "OpenTelemetry Python API" 526 | optional = false 527 | python-versions = ">=3.8" 528 | groups = ["dev"] 529 | files = [ 530 | {file = "opentelemetry_api-1.25.0-py3-none-any.whl", hash = "sha256:757fa1aa020a0f8fa139f8959e53dec2051cc26b832e76fa839a6d76ecefd737"}, 531 | {file = "opentelemetry_api-1.25.0.tar.gz", hash = "sha256:77c4985f62f2614e42ce77ee4c9da5fa5f0bc1e1821085e9a47533a9323ae869"}, 532 | ] 533 | 534 | [package.dependencies] 535 | deprecated = ">=1.2.6" 536 | importlib-metadata = ">=6.0,<=7.1" 537 | 538 | [[package]] 539 | name = "opentelemetry-exporter-otlp-proto-common" 540 | version = "1.25.0" 541 | description = "OpenTelemetry Protobuf encoding" 542 | optional = false 543 | python-versions = ">=3.8" 544 | groups = ["dev"] 545 | files = [ 546 | {file = "opentelemetry_exporter_otlp_proto_common-1.25.0-py3-none-any.whl", hash = "sha256:15637b7d580c2675f70246563363775b4e6de947871e01d0f4e3881d1848d693"}, 547 | {file = "opentelemetry_exporter_otlp_proto_common-1.25.0.tar.gz", hash = "sha256:c93f4e30da4eee02bacd1e004eb82ce4da143a2f8e15b987a9f603e0a85407d3"}, 548 | ] 549 | 550 | [package.dependencies] 551 | opentelemetry-proto = "1.25.0" 552 | 553 | [[package]] 554 | name = "opentelemetry-exporter-otlp-proto-http" 555 | version = "1.25.0" 556 | description = "OpenTelemetry Collector Protobuf over HTTP Exporter" 557 | optional = false 558 | python-versions = ">=3.8" 559 | groups = ["dev"] 560 | files = [ 561 | {file = "opentelemetry_exporter_otlp_proto_http-1.25.0-py3-none-any.whl", hash = "sha256:2eca686ee11b27acd28198b3ea5e5863a53d1266b91cda47c839d95d5e0541a6"}, 562 | {file = "opentelemetry_exporter_otlp_proto_http-1.25.0.tar.gz", hash = "sha256:9f8723859e37c75183ea7afa73a3542f01d0fd274a5b97487ea24cb683d7d684"}, 563 | ] 564 | 565 | [package.dependencies] 566 | deprecated = ">=1.2.6" 567 | googleapis-common-protos = ">=1.52,<2.0" 568 | opentelemetry-api = ">=1.15,<2.0" 569 | opentelemetry-exporter-otlp-proto-common = "1.25.0" 570 | opentelemetry-proto = "1.25.0" 571 | opentelemetry-sdk = ">=1.25.0,<1.26.0" 572 | requests = ">=2.7,<3.0" 573 | 574 | [[package]] 575 | name = "opentelemetry-instrumentation" 576 | version = "0.46b0" 577 | description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" 578 | optional = false 579 | python-versions = ">=3.8" 580 | groups = ["dev"] 581 | files = [ 582 | {file = "opentelemetry_instrumentation-0.46b0-py3-none-any.whl", hash = "sha256:89cd721b9c18c014ca848ccd11181e6b3fd3f6c7669e35d59c48dc527408c18b"}, 583 | {file = "opentelemetry_instrumentation-0.46b0.tar.gz", hash = "sha256:974e0888fb2a1e01c38fbacc9483d024bb1132aad92d6d24e2e5543887a7adda"}, 584 | ] 585 | 586 | [package.dependencies] 587 | opentelemetry-api = ">=1.4,<2.0" 588 | setuptools = ">=16.0" 589 | wrapt = ">=1.0.0,<2.0.0" 590 | 591 | [[package]] 592 | name = "opentelemetry-instrumentation-requests" 593 | version = "0.46b0" 594 | description = "OpenTelemetry requests instrumentation" 595 | optional = false 596 | python-versions = ">=3.8" 597 | groups = ["dev"] 598 | files = [ 599 | {file = "opentelemetry_instrumentation_requests-0.46b0-py3-none-any.whl", hash = "sha256:a8c2472800d8686f3f286cd524b8746b386154092e85a791ba14110d1acc9b81"}, 600 | {file = "opentelemetry_instrumentation_requests-0.46b0.tar.gz", hash = "sha256:ef0ad63bfd0d52631daaf7d687e763dbd89b465f5cb052f12a4e67e5e3d181e4"}, 601 | ] 602 | 603 | [package.dependencies] 604 | opentelemetry-api = ">=1.12,<2.0" 605 | opentelemetry-instrumentation = "0.46b0" 606 | opentelemetry-semantic-conventions = "0.46b0" 607 | opentelemetry-util-http = "0.46b0" 608 | 609 | [package.extras] 610 | instruments = ["requests (>=2.0,<3.0)"] 611 | 612 | [[package]] 613 | name = "opentelemetry-proto" 614 | version = "1.25.0" 615 | description = "OpenTelemetry Python Proto" 616 | optional = false 617 | python-versions = ">=3.8" 618 | groups = ["dev"] 619 | files = [ 620 | {file = "opentelemetry_proto-1.25.0-py3-none-any.whl", hash = "sha256:f07e3341c78d835d9b86665903b199893befa5e98866f63d22b00d0b7ca4972f"}, 621 | {file = "opentelemetry_proto-1.25.0.tar.gz", hash = "sha256:35b6ef9dc4a9f7853ecc5006738ad40443701e52c26099e197895cbda8b815a3"}, 622 | ] 623 | 624 | [package.dependencies] 625 | protobuf = ">=3.19,<5.0" 626 | 627 | [[package]] 628 | name = "opentelemetry-sdk" 629 | version = "1.25.0" 630 | description = "OpenTelemetry Python SDK" 631 | optional = false 632 | python-versions = ">=3.8" 633 | groups = ["dev"] 634 | files = [ 635 | {file = "opentelemetry_sdk-1.25.0-py3-none-any.whl", hash = "sha256:d97ff7ec4b351692e9d5a15af570c693b8715ad78b8aafbec5c7100fe966b4c9"}, 636 | {file = "opentelemetry_sdk-1.25.0.tar.gz", hash = "sha256:ce7fc319c57707ef5bf8b74fb9f8ebdb8bfafbe11898410e0d2a761d08a98ec7"}, 637 | ] 638 | 639 | [package.dependencies] 640 | opentelemetry-api = "1.25.0" 641 | opentelemetry-semantic-conventions = "0.46b0" 642 | typing-extensions = ">=3.7.4" 643 | 644 | [[package]] 645 | name = "opentelemetry-semantic-conventions" 646 | version = "0.46b0" 647 | description = "OpenTelemetry Semantic Conventions" 648 | optional = false 649 | python-versions = ">=3.8" 650 | groups = ["dev"] 651 | files = [ 652 | {file = "opentelemetry_semantic_conventions-0.46b0-py3-none-any.whl", hash = "sha256:6daef4ef9fa51d51855d9f8e0ccd3a1bd59e0e545abe99ac6203804e36ab3e07"}, 653 | {file = "opentelemetry_semantic_conventions-0.46b0.tar.gz", hash = "sha256:fbc982ecbb6a6e90869b15c1673be90bd18c8a56ff1cffc0864e38e2edffaefa"}, 654 | ] 655 | 656 | [package.dependencies] 657 | opentelemetry-api = "1.25.0" 658 | 659 | [[package]] 660 | name = "opentelemetry-util-http" 661 | version = "0.46b0" 662 | description = "Web util for OpenTelemetry" 663 | optional = false 664 | python-versions = ">=3.8" 665 | groups = ["dev"] 666 | files = [ 667 | {file = "opentelemetry_util_http-0.46b0-py3-none-any.whl", hash = "sha256:8dc1949ce63caef08db84ae977fdc1848fe6dc38e6bbaad0ae3e6ecd0d451629"}, 668 | {file = "opentelemetry_util_http-0.46b0.tar.gz", hash = "sha256:03b6e222642f9c7eae58d9132343e045b50aca9761fcb53709bd2b663571fdf6"}, 669 | ] 670 | 671 | [[package]] 672 | name = "packaging" 673 | version = "24.1" 674 | description = "Core utilities for Python packages" 675 | optional = false 676 | python-versions = ">=3.8" 677 | groups = ["dev"] 678 | files = [ 679 | {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, 680 | {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, 681 | ] 682 | 683 | [[package]] 684 | name = "pastel" 685 | version = "0.2.1" 686 | description = "Bring colors to your terminal." 687 | optional = false 688 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 689 | groups = ["dev"] 690 | files = [ 691 | {file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"}, 692 | {file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"}, 693 | ] 694 | 695 | [[package]] 696 | name = "pathspec" 697 | version = "0.12.1" 698 | description = "Utility library for gitignore style pattern matching of file paths." 699 | optional = false 700 | python-versions = ">=3.8" 701 | groups = ["dev"] 702 | files = [ 703 | {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, 704 | {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, 705 | ] 706 | 707 | [[package]] 708 | name = "peewee" 709 | version = "3.17.5" 710 | description = "a little orm" 711 | optional = false 712 | python-versions = "*" 713 | groups = ["dev"] 714 | files = [ 715 | {file = "peewee-3.17.5.tar.gz", hash = "sha256:e1b6a64192207fd3ddb4e1188054820f42aef0aadfa749e3981af3c119a76420"}, 716 | ] 717 | 718 | [[package]] 719 | name = "pluggy" 720 | version = "1.5.0" 721 | description = "plugin and hook calling mechanisms for python" 722 | optional = false 723 | python-versions = ">=3.8" 724 | groups = ["dev"] 725 | files = [ 726 | {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, 727 | {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, 728 | ] 729 | 730 | [package.extras] 731 | dev = ["pre-commit", "tox"] 732 | testing = ["pytest", "pytest-benchmark"] 733 | 734 | [[package]] 735 | name = "poethepoet" 736 | version = "0.34.0" 737 | description = "A task runner that works well with poetry." 738 | optional = false 739 | python-versions = ">=3.9" 740 | groups = ["dev"] 741 | files = [ 742 | {file = "poethepoet-0.34.0-py3-none-any.whl", hash = "sha256:c472d6f0fdb341b48d346f4ccd49779840c15b30dfd6bc6347a80d6274b5e34e"}, 743 | {file = "poethepoet-0.34.0.tar.gz", hash = "sha256:86203acce555bbfe45cb6ccac61ba8b16a5784264484195874da457ddabf5850"}, 744 | ] 745 | 746 | [package.dependencies] 747 | pastel = ">=0.2.1,<0.3.0" 748 | pyyaml = ">=6.0.2,<7.0" 749 | tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} 750 | 751 | [package.extras] 752 | poetry-plugin = ["poetry (>=1.2.0,<3.0.0) ; python_version < \"4.0\""] 753 | 754 | [[package]] 755 | name = "protobuf" 756 | version = "4.25.3" 757 | description = "" 758 | optional = false 759 | python-versions = ">=3.8" 760 | groups = ["dev"] 761 | files = [ 762 | {file = "protobuf-4.25.3-cp310-abi3-win32.whl", hash = "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa"}, 763 | {file = "protobuf-4.25.3-cp310-abi3-win_amd64.whl", hash = "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8"}, 764 | {file = "protobuf-4.25.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c"}, 765 | {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019"}, 766 | {file = "protobuf-4.25.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d"}, 767 | {file = "protobuf-4.25.3-cp38-cp38-win32.whl", hash = "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2"}, 768 | {file = "protobuf-4.25.3-cp38-cp38-win_amd64.whl", hash = "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4"}, 769 | {file = "protobuf-4.25.3-cp39-cp39-win32.whl", hash = "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4"}, 770 | {file = "protobuf-4.25.3-cp39-cp39-win_amd64.whl", hash = "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c"}, 771 | {file = "protobuf-4.25.3-py3-none-any.whl", hash = "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9"}, 772 | {file = "protobuf-4.25.3.tar.gz", hash = "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c"}, 773 | ] 774 | 775 | [[package]] 776 | name = "pygments" 777 | version = "2.18.0" 778 | description = "Pygments is a syntax highlighting package written in Python." 779 | optional = false 780 | python-versions = ">=3.8" 781 | groups = ["dev"] 782 | files = [ 783 | {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, 784 | {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, 785 | ] 786 | 787 | [package.extras] 788 | windows-terminal = ["colorama (>=0.4.6)"] 789 | 790 | [[package]] 791 | name = "pytest" 792 | version = "8.4.0" 793 | description = "pytest: simple powerful testing with Python" 794 | optional = false 795 | python-versions = ">=3.9" 796 | groups = ["dev"] 797 | files = [ 798 | {file = "pytest-8.4.0-py3-none-any.whl", hash = "sha256:f40f825768ad76c0977cbacdf1fd37c6f7a468e460ea6a0636078f8972d4517e"}, 799 | {file = "pytest-8.4.0.tar.gz", hash = "sha256:14d920b48472ea0dbf68e45b96cd1ffda4705f33307dcc86c676c1b5104838a6"}, 800 | ] 801 | 802 | [package.dependencies] 803 | colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} 804 | exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} 805 | iniconfig = ">=1" 806 | packaging = ">=20" 807 | pluggy = ">=1.5,<2" 808 | pygments = ">=2.7.2" 809 | tomli = {version = ">=1", markers = "python_version < \"3.11\""} 810 | 811 | [package.extras] 812 | dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] 813 | 814 | [[package]] 815 | name = "pyyaml" 816 | version = "6.0.2" 817 | description = "YAML parser and emitter for Python" 818 | optional = false 819 | python-versions = ">=3.8" 820 | groups = ["dev"] 821 | files = [ 822 | {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, 823 | {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, 824 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, 825 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, 826 | {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, 827 | {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, 828 | {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, 829 | {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, 830 | {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, 831 | {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, 832 | {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, 833 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, 834 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, 835 | {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, 836 | {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, 837 | {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, 838 | {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, 839 | {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, 840 | {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, 841 | {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, 842 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, 843 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, 844 | {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, 845 | {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, 846 | {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, 847 | {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, 848 | {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, 849 | {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, 850 | {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, 851 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, 852 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, 853 | {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, 854 | {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, 855 | {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, 856 | {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, 857 | {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, 858 | {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, 859 | {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, 860 | {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, 861 | {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, 862 | {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, 863 | {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, 864 | {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, 865 | {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, 866 | {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, 867 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, 868 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, 869 | {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, 870 | {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, 871 | {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, 872 | {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, 873 | {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, 874 | {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, 875 | ] 876 | 877 | [[package]] 878 | name = "referencing" 879 | version = "0.35.1" 880 | description = "JSON Referencing + Python" 881 | optional = false 882 | python-versions = ">=3.8" 883 | groups = ["dev"] 884 | files = [ 885 | {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, 886 | {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, 887 | ] 888 | 889 | [package.dependencies] 890 | attrs = ">=22.2.0" 891 | rpds-py = ">=0.7.0" 892 | 893 | [[package]] 894 | name = "requests" 895 | version = "2.32.3" 896 | description = "Python HTTP for Humans." 897 | optional = false 898 | python-versions = ">=3.8" 899 | groups = ["dev"] 900 | files = [ 901 | {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, 902 | {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, 903 | ] 904 | 905 | [package.dependencies] 906 | certifi = ">=2017.4.17" 907 | charset-normalizer = ">=2,<4" 908 | idna = ">=2.5,<4" 909 | urllib3 = ">=1.21.1,<3" 910 | 911 | [package.extras] 912 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 913 | use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] 914 | 915 | [[package]] 916 | name = "requirements-parser" 917 | version = "0.11.0" 918 | description = "This is a small Python module for parsing Pip requirement files." 919 | optional = false 920 | python-versions = "<4.0,>=3.8" 921 | groups = ["dev"] 922 | files = [ 923 | {file = "requirements_parser-0.11.0-py3-none-any.whl", hash = "sha256:50379eb50311834386c2568263ae5225d7b9d0867fb55cf4ecc93959de2c2684"}, 924 | {file = "requirements_parser-0.11.0.tar.gz", hash = "sha256:35f36dc969d14830bf459803da84f314dc3d17c802592e9e970f63d0359e5920"}, 925 | ] 926 | 927 | [package.dependencies] 928 | packaging = ">=23.2" 929 | types-setuptools = ">=69.1.0" 930 | 931 | [[package]] 932 | name = "rich" 933 | version = "13.5.3" 934 | description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" 935 | optional = false 936 | python-versions = ">=3.7.0" 937 | groups = ["dev"] 938 | files = [ 939 | {file = "rich-13.5.3-py3-none-any.whl", hash = "sha256:9257b468badc3d347e146a4faa268ff229039d4c2d176ab0cffb4c4fbc73d5d9"}, 940 | {file = "rich-13.5.3.tar.gz", hash = "sha256:87b43e0543149efa1253f485cd845bb7ee54df16c9617b8a893650ab84b4acb6"}, 941 | ] 942 | 943 | [package.dependencies] 944 | markdown-it-py = ">=2.2.0" 945 | pygments = ">=2.13.0,<3.0.0" 946 | 947 | [package.extras] 948 | jupyter = ["ipywidgets (>=7.5.1,<9)"] 949 | 950 | [[package]] 951 | name = "rpds-py" 952 | version = "0.18.1" 953 | description = "Python bindings to Rust's persistent data structures (rpds)" 954 | optional = false 955 | python-versions = ">=3.8" 956 | groups = ["dev"] 957 | files = [ 958 | {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, 959 | {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, 960 | {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, 961 | {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, 962 | {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, 963 | {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, 964 | {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, 965 | {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, 966 | {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, 967 | {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, 968 | {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, 969 | {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, 970 | {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, 971 | {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, 972 | {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, 973 | {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, 974 | {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, 975 | {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, 976 | {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, 977 | {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, 978 | {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, 979 | {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, 980 | {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, 981 | {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, 982 | {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, 983 | {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, 984 | {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, 985 | {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, 986 | {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, 987 | {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, 988 | {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, 989 | {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, 990 | {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, 991 | {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, 992 | {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, 993 | {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, 994 | {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, 995 | {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, 996 | {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, 997 | {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, 998 | {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, 999 | {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, 1000 | {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, 1001 | {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, 1002 | {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, 1003 | {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, 1004 | {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, 1005 | {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, 1006 | {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, 1007 | {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, 1008 | {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, 1009 | {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, 1010 | {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, 1011 | {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, 1012 | {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, 1013 | {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, 1014 | {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, 1015 | {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, 1016 | {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, 1017 | {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, 1018 | {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, 1019 | {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, 1020 | {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, 1021 | {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, 1022 | {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, 1023 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, 1024 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, 1025 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, 1026 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, 1027 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, 1028 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, 1029 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, 1030 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, 1031 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, 1032 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, 1033 | {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, 1034 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, 1035 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, 1036 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, 1037 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, 1038 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, 1039 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, 1040 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, 1041 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, 1042 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, 1043 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, 1044 | {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, 1045 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, 1046 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, 1047 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, 1048 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, 1049 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, 1050 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, 1051 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, 1052 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, 1053 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, 1054 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, 1055 | {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, 1056 | {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, 1057 | ] 1058 | 1059 | [[package]] 1060 | name = "ruamel-yaml" 1061 | version = "0.18.10" 1062 | description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" 1063 | optional = false 1064 | python-versions = ">=3.7" 1065 | groups = ["dev"] 1066 | files = [ 1067 | {file = "ruamel.yaml-0.18.10-py3-none-any.whl", hash = "sha256:30f22513ab2301b3d2b577adc121c6471f28734d3d9728581245f1e76468b4f1"}, 1068 | {file = "ruamel.yaml-0.18.10.tar.gz", hash = "sha256:20c86ab29ac2153f80a428e1254a8adf686d3383df04490514ca3b79a362db58"}, 1069 | ] 1070 | 1071 | [package.dependencies] 1072 | "ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} 1073 | 1074 | [package.extras] 1075 | docs = ["mercurial (>5.7)", "ryd"] 1076 | jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] 1077 | 1078 | [[package]] 1079 | name = "ruamel-yaml-clib" 1080 | version = "0.2.8" 1081 | description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" 1082 | optional = false 1083 | python-versions = ">=3.6" 1084 | groups = ["dev"] 1085 | markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\"" 1086 | files = [ 1087 | {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, 1088 | {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, 1089 | {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, 1090 | {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, 1091 | {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, 1092 | {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, 1093 | {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, 1094 | {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, 1095 | {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, 1096 | {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, 1097 | {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, 1098 | {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, 1099 | {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, 1100 | {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, 1101 | {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, 1102 | {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, 1103 | {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, 1104 | {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, 1105 | {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, 1106 | {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, 1107 | {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, 1108 | {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, 1109 | {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, 1110 | {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, 1111 | {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, 1112 | {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, 1113 | {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, 1114 | {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, 1115 | {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, 1116 | {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, 1117 | {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, 1118 | {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, 1119 | {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, 1120 | {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, 1121 | {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, 1122 | {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, 1123 | {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, 1124 | {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, 1125 | {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, 1126 | {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, 1127 | {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, 1128 | {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, 1129 | {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, 1130 | {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, 1131 | {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, 1132 | {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, 1133 | {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, 1134 | {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, 1135 | {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, 1136 | {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, 1137 | ] 1138 | 1139 | [[package]] 1140 | name = "ruff" 1141 | version = "0.11.13" 1142 | description = "An extremely fast Python linter and code formatter, written in Rust." 1143 | optional = false 1144 | python-versions = ">=3.7" 1145 | groups = ["dev"] 1146 | files = [ 1147 | {file = "ruff-0.11.13-py3-none-linux_armv6l.whl", hash = "sha256:4bdfbf1240533f40042ec00c9e09a3aade6f8c10b6414cf11b519488d2635d46"}, 1148 | {file = "ruff-0.11.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aef9c9ed1b5ca28bb15c7eac83b8670cf3b20b478195bd49c8d756ba0a36cf48"}, 1149 | {file = "ruff-0.11.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53b15a9dfdce029c842e9a5aebc3855e9ab7771395979ff85b7c1dedb53ddc2b"}, 1150 | {file = "ruff-0.11.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab153241400789138d13f362c43f7edecc0edfffce2afa6a68434000ecd8f69a"}, 1151 | {file = "ruff-0.11.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c51f93029d54a910d3d24f7dd0bb909e31b6cd989a5e4ac513f4eb41629f0dc"}, 1152 | {file = "ruff-0.11.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1808b3ed53e1a777c2ef733aca9051dc9bf7c99b26ece15cb59a0320fbdbd629"}, 1153 | {file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d28ce58b5ecf0f43c1b71edffabe6ed7f245d5336b17805803312ec9bc665933"}, 1154 | {file = "ruff-0.11.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55e4bc3a77842da33c16d55b32c6cac1ec5fb0fbec9c8c513bdce76c4f922165"}, 1155 | {file = "ruff-0.11.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:633bf2c6f35678c56ec73189ba6fa19ff1c5e4807a78bf60ef487b9dd272cc71"}, 1156 | {file = "ruff-0.11.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ffbc82d70424b275b089166310448051afdc6e914fdab90e08df66c43bb5ca9"}, 1157 | {file = "ruff-0.11.13-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a9ddd3ec62a9a89578c85842b836e4ac832d4a2e0bfaad3b02243f930ceafcc"}, 1158 | {file = "ruff-0.11.13-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d237a496e0778d719efb05058c64d28b757c77824e04ffe8796c7436e26712b7"}, 1159 | {file = "ruff-0.11.13-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26816a218ca6ef02142343fd24c70f7cd8c5aa6c203bca284407adf675984432"}, 1160 | {file = "ruff-0.11.13-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:51c3f95abd9331dc5b87c47ac7f376db5616041173826dfd556cfe3d4977f492"}, 1161 | {file = "ruff-0.11.13-py3-none-win32.whl", hash = "sha256:96c27935418e4e8e77a26bb05962817f28b8ef3843a6c6cc49d8783b5507f250"}, 1162 | {file = "ruff-0.11.13-py3-none-win_amd64.whl", hash = "sha256:29c3189895a8a6a657b7af4e97d330c8a3afd2c9c8f46c81e2fc5a31866517e3"}, 1163 | {file = "ruff-0.11.13-py3-none-win_arm64.whl", hash = "sha256:b4385285e9179d608ff1d2fb9922062663c658605819a6876d8beef0c30b7f3b"}, 1164 | {file = "ruff-0.11.13.tar.gz", hash = "sha256:26fa247dc68d1d4e72c179e08889a25ac0c7ba4d78aecfc835d49cbfd60bf514"}, 1165 | ] 1166 | 1167 | [[package]] 1168 | name = "semgrep" 1169 | version = "1.124.0" 1170 | description = "Lightweight static analysis for many languages. Find bug variants with patterns that look like source code." 1171 | optional = false 1172 | python-versions = ">=3.9" 1173 | groups = ["dev"] 1174 | files = [ 1175 | {file = "semgrep-1.124.0-cp39.cp310.cp311.py39.py310.py311-none-macosx_10_14_x86_64.whl", hash = "sha256:f7c6b8411dcb320ee2654c13e02b96acbaef47641efc52a6d503fc57d2d88a87"}, 1176 | {file = "semgrep-1.124.0-cp39.cp310.cp311.py39.py310.py311-none-macosx_11_0_arm64.whl", hash = "sha256:8328c01c4c26adf36d5ea9e42690074008b5b84a3748b2686bac264d3d5842ac"}, 1177 | {file = "semgrep-1.124.0-cp39.cp310.cp311.py39.py310.py311-none-musllinux_1_0_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97bec7d774af2d838d770f42c5abee080942d037501f2e30ca2481d7c4945614"}, 1178 | {file = "semgrep-1.124.0-cp39.cp310.cp311.py39.py310.py311-none-musllinux_1_0_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c8dd1ef2b269c02d86d98a518b407e7ee0f0802dffed5ba9aaf7d1706f033f2"}, 1179 | {file = "semgrep-1.124.0-cp39.cp310.cp311.py39.py310.py311-none-win_amd64.whl", hash = "sha256:ad6b862b96ea7a1c291dba7b97bdb219b0da35d71ae78d5ab344133c364c0f67"}, 1180 | {file = "semgrep-1.124.0.tar.gz", hash = "sha256:ddc36e31127cb8bc1ed1a9437c1a6113405313f3747e566dc5de473b020505d9"}, 1181 | ] 1182 | 1183 | [package.dependencies] 1184 | attrs = ">=21.3" 1185 | boltons = ">=21.0,<22.0" 1186 | click = ">=8.1.8,<8.2.0" 1187 | click-option-group = ">=0.5,<1.0" 1188 | colorama = ">=0.4.0,<0.5.0" 1189 | defusedxml = ">=0.7.1,<0.8.0" 1190 | exceptiongroup = ">=1.2.0,<1.3.0" 1191 | glom = ">=22.1,<23.0" 1192 | jsonschema = ">=4.6,<5.0" 1193 | opentelemetry-api = ">=1.25.0,<1.26.0" 1194 | opentelemetry-exporter-otlp-proto-http = ">=1.25.0,<1.26.0" 1195 | opentelemetry-instrumentation-requests = ">=0.46b0,<1.0" 1196 | opentelemetry-sdk = ">=1.25.0,<1.26.0" 1197 | packaging = ">=21.0" 1198 | peewee = ">=3.14,<4.0" 1199 | requests = ">=2.22,<3.0" 1200 | rich = ">=13.5.2,<13.6.0" 1201 | "ruamel.yaml" = ">=0.18.5" 1202 | tomli = ">=2.0.1,<2.1.0" 1203 | typing-extensions = ">=4.2,<5.0" 1204 | urllib3 = ">=2.0,<3.0" 1205 | wcmatch = ">=8.3,<9.0" 1206 | 1207 | [[package]] 1208 | name = "setuptools" 1209 | version = "78.1.1" 1210 | description = "Easily download, build, install, upgrade, and uninstall Python packages" 1211 | optional = false 1212 | python-versions = ">=3.9" 1213 | groups = ["dev"] 1214 | files = [ 1215 | {file = "setuptools-78.1.1-py3-none-any.whl", hash = "sha256:c3a9c4211ff4c309edb8b8c4f1cbfa7ae324c4ba9f91ff254e3d305b9fd54561"}, 1216 | {file = "setuptools-78.1.1.tar.gz", hash = "sha256:fcc17fd9cd898242f6b4adfaca46137a9edef687f43e6f78469692a5e70d851d"}, 1217 | ] 1218 | 1219 | [package.extras] 1220 | check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] 1221 | core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] 1222 | cover = ["pytest-cov"] 1223 | doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] 1224 | enabler = ["pytest-enabler (>=2.2)"] 1225 | test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] 1226 | type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] 1227 | 1228 | [[package]] 1229 | name = "sqlparse" 1230 | version = "0.5.3" 1231 | description = "A non-validating SQL parser." 1232 | optional = false 1233 | python-versions = ">=3.8" 1234 | groups = ["main"] 1235 | files = [ 1236 | {file = "sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca"}, 1237 | {file = "sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272"}, 1238 | ] 1239 | 1240 | [package.extras] 1241 | dev = ["build", "hatch"] 1242 | doc = ["sphinx"] 1243 | 1244 | [[package]] 1245 | name = "tomli" 1246 | version = "2.0.1" 1247 | description = "A lil' TOML parser" 1248 | optional = false 1249 | python-versions = ">=3.7" 1250 | groups = ["dev"] 1251 | files = [ 1252 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 1253 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 1254 | ] 1255 | 1256 | [[package]] 1257 | name = "types-setuptools" 1258 | version = "80.7.0.20250516" 1259 | description = "Typing stubs for setuptools" 1260 | optional = false 1261 | python-versions = ">=3.9" 1262 | groups = ["dev"] 1263 | files = [ 1264 | {file = "types_setuptools-80.7.0.20250516-py3-none-any.whl", hash = "sha256:c1da6c11698139c8307c6df5987592df940e956912c204e42d844ba821dd2741"}, 1265 | {file = "types_setuptools-80.7.0.20250516.tar.gz", hash = "sha256:57274b58e05434de42088a86074c9e630e5786f759cf9cc1e3015e886297ca21"}, 1266 | ] 1267 | 1268 | [[package]] 1269 | name = "typing-extensions" 1270 | version = "4.12.2" 1271 | description = "Backported and Experimental Type Hints for Python 3.8+" 1272 | optional = false 1273 | python-versions = ">=3.8" 1274 | groups = ["dev"] 1275 | files = [ 1276 | {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, 1277 | {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, 1278 | ] 1279 | 1280 | [[package]] 1281 | name = "urllib3" 1282 | version = "2.2.2" 1283 | description = "HTTP library with thread-safe connection pooling, file post, and more." 1284 | optional = false 1285 | python-versions = ">=3.8" 1286 | groups = ["dev"] 1287 | files = [ 1288 | {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, 1289 | {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, 1290 | ] 1291 | 1292 | [package.extras] 1293 | brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] 1294 | h2 = ["h2 (>=4,<5)"] 1295 | socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] 1296 | zstd = ["zstandard (>=0.18.0)"] 1297 | 1298 | [[package]] 1299 | name = "wcmatch" 1300 | version = "8.5.2" 1301 | description = "Wildcard/glob file name matcher." 1302 | optional = false 1303 | python-versions = ">=3.8" 1304 | groups = ["dev"] 1305 | files = [ 1306 | {file = "wcmatch-8.5.2-py3-none-any.whl", hash = "sha256:17d3ad3758f9d0b5b4dedc770b65420d4dac62e680229c287bf24c9db856a478"}, 1307 | {file = "wcmatch-8.5.2.tar.gz", hash = "sha256:a70222b86dea82fb382dd87b73278c10756c138bd6f8f714e2183128887b9eb2"}, 1308 | ] 1309 | 1310 | [package.dependencies] 1311 | bracex = ">=2.1.1" 1312 | 1313 | [[package]] 1314 | name = "wrapt" 1315 | version = "1.16.0" 1316 | description = "Module for decorators, wrappers and monkey patching." 1317 | optional = false 1318 | python-versions = ">=3.6" 1319 | groups = ["dev"] 1320 | files = [ 1321 | {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, 1322 | {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, 1323 | {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, 1324 | {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, 1325 | {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, 1326 | {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, 1327 | {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, 1328 | {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, 1329 | {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, 1330 | {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, 1331 | {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, 1332 | {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, 1333 | {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, 1334 | {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, 1335 | {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, 1336 | {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, 1337 | {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, 1338 | {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, 1339 | {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, 1340 | {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, 1341 | {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, 1342 | {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, 1343 | {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, 1344 | {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, 1345 | {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, 1346 | {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, 1347 | {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, 1348 | {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, 1349 | {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, 1350 | {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, 1351 | {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, 1352 | {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, 1353 | {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, 1354 | {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, 1355 | {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, 1356 | {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, 1357 | {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, 1358 | {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, 1359 | {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, 1360 | {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, 1361 | {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, 1362 | {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, 1363 | {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, 1364 | {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, 1365 | {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, 1366 | {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, 1367 | {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, 1368 | {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, 1369 | {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, 1370 | {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, 1371 | {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, 1372 | {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, 1373 | {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, 1374 | {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, 1375 | {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, 1376 | {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, 1377 | {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, 1378 | {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, 1379 | {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, 1380 | {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, 1381 | {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, 1382 | {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, 1383 | {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, 1384 | {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, 1385 | {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, 1386 | {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, 1387 | {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, 1388 | {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, 1389 | {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, 1390 | {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, 1391 | ] 1392 | 1393 | [[package]] 1394 | name = "zipp" 1395 | version = "3.19.2" 1396 | description = "Backport of pathlib-compatible object wrapper for zip files" 1397 | optional = false 1398 | python-versions = ">=3.8" 1399 | groups = ["dev"] 1400 | files = [ 1401 | {file = "zipp-3.19.2-py3-none-any.whl", hash = "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c"}, 1402 | {file = "zipp-3.19.2.tar.gz", hash = "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19"}, 1403 | ] 1404 | 1405 | [package.extras] 1406 | doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 1407 | test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "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)"] 1408 | 1409 | [metadata] 1410 | lock-version = "2.1" 1411 | python-versions = "^3.9" 1412 | content-hash = "666a9f54ca74769921ce1d620714f8b9c97674a3cbcec834a9647c60145e3499" 1413 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "sql-compare" 3 | description = "Compare SQL schemas" 4 | authors = [{ name = "Charly Laurent", email = "charly.laurent@mergify.com" }] 5 | maintainers = [{ name = "Mergify", email = "engineering@mergify.com" }] 6 | readme = "README.md" 7 | license = { text = "Apache-2.0" } 8 | keywords = ["sql", "database", "schema", "compare", "diff", "migration"] 9 | classifiers = [ 10 | "Development Status :: 5 - Production/Stable", 11 | "Intended Audience :: Developers", 12 | "License :: OSI Approved :: Apache Software License", 13 | "Natural Language :: English", 14 | "Operating System :: OS Independent", 15 | "Programming Language :: Python", 16 | "Programming Language :: Python :: 3", 17 | "Programming Language :: Python :: 3 :: Only", 18 | "Programming Language :: Python :: 3.9", 19 | "Programming Language :: Python :: 3.10", 20 | "Programming Language :: Python :: 3.11", 21 | "Programming Language :: Python :: 3.12", 22 | "Programming Language :: Python :: Implementation :: CPython", 23 | "Programming Language :: Python :: Implementation :: PyPy", 24 | "Topic :: Database", 25 | "Topic :: Software Development", 26 | "Topic :: Software Development :: Testing", 27 | "Topic :: Software Development :: Testing :: Unit", 28 | ] 29 | requires-python = ">=3.9" 30 | dynamic = ["version"] 31 | 32 | [project.urls] 33 | repository = "https://github.com/Mergifyio/sql-compare" 34 | "Bug Tracker" = "https://github.com/Mergifyio/sql-compare/issues" 35 | 36 | [tool.poetry] 37 | version = "0.0.0" 38 | 39 | [tool.poetry.dependencies] 40 | python = "^3.9" 41 | sqlparse = ">=0.5.0" 42 | 43 | [tool.poetry.group.dev.dependencies] 44 | ruff = ">=0.4.8,<0.12.0" 45 | mypy = "^1.16.0" 46 | pytest = "^8.4.0" 47 | poethepoet = ">=0.26.1,<0.35.0" 48 | deptry = ">=0.16.1,<0.24.0" 49 | semgrep = "^1.124.0" 50 | 51 | [tool.poetry.requires-plugins] 52 | poetry-dynamic-versioning = { version = ">=1.0.0,<2.0.0", extras = ["plugin"] } 53 | 54 | [tool.poetry-dynamic-versioning] 55 | enable = true 56 | vcs = "git" 57 | pattern = "^(?P\\d+(\\.\\d+)*)" 58 | format = "{base}" 59 | 60 | [build-system] 61 | requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"] 62 | build-backend = "poetry_dynamic_versioning.backend" 63 | 64 | [tool.poe] 65 | include = ["poe.toml"] 66 | 67 | [tool.pytest.ini_options] 68 | filterwarnings = ["error"] 69 | 70 | [tool.ruff] 71 | line-length = 88 72 | indent-width = 4 73 | target-version = "py312" 74 | 75 | [tool.ruff.lint] 76 | preview = true 77 | select = [ 78 | "F", 79 | "E", 80 | "W", 81 | "C90", 82 | "I", 83 | "N", 84 | "D", 85 | "UP", 86 | "YTT", 87 | "ANN", 88 | "ASYNC", 89 | "S", 90 | "BLE", 91 | "FBT", 92 | "B", 93 | "A", 94 | "COM", 95 | "CPY", 96 | "C4", 97 | "DTZ", 98 | "EM", 99 | "FA", 100 | "ISC", 101 | "ICN", 102 | "LOG", 103 | "G", 104 | "INP", 105 | "PIE", 106 | "T20", 107 | "PYI", 108 | "PT", 109 | "Q", 110 | "RSE", 111 | "RET", 112 | "SLF", 113 | "SLOT", 114 | "SIM", 115 | "TID", 116 | "TCH", 117 | "INT", 118 | "ARG", 119 | "PTH", 120 | "TD", 121 | "ERA", 122 | "PGH", 123 | "PL", 124 | "TRY", 125 | "FLY", 126 | "PERF", 127 | "FURB", 128 | "RUF", 129 | ] 130 | ignore = [ 131 | # NOTE(charly): line-length is up to the formatter 132 | "E501", 133 | # NOTE(charly): `one-blank-line-before-class` (D203) and 134 | # `no-blank-line-before-class` (D211) are incompatible 135 | "D203", 136 | # NOTE(charly): `multi-line-summary-first-line` (D212) and 137 | # `multi-line-summary-second-line` (D213) are incompatible 138 | "D213", 139 | ] 140 | 141 | [tool.ruff.lint.per-file-ignores] 142 | "tests/**/*.py" = ["S101", "D"] 143 | 144 | [tool.ruff.lint.isort] 145 | force-single-line = true 146 | force-sort-within-sections = true 147 | lines-after-imports = 2 148 | known-first-party = ["sql_compare"] 149 | required-imports = ["from __future__ import annotations"] 150 | 151 | [tool.ruff.lint.flake8-tidy-imports] 152 | ban-relative-imports = "all" 153 | 154 | [tool.mypy] 155 | strict = true 156 | warn_unreachable = true 157 | exclude = [".venv"] 158 | files = ["sql_compare", "tests"] 159 | show_error_codes = true 160 | 161 | [[tool.mypy.overrides]] 162 | module = "sqlparse" 163 | ignore_missing_imports = true 164 | 165 | [tool.deptry] 166 | extend_exclude = ["tests"] 167 | -------------------------------------------------------------------------------- /requirements-poetry.txt: -------------------------------------------------------------------------------- 1 | poetry==2.1.3 2 | -------------------------------------------------------------------------------- /sql_compare/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2024-2024 Mergify SAS 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | """Compare SQL schemas.""" 17 | 18 | from __future__ import annotations 19 | 20 | import dataclasses 21 | import itertools 22 | import typing 23 | 24 | import sqlparse 25 | 26 | 27 | if typing.TYPE_CHECKING: 28 | from collections.abc import Generator 29 | import pathlib 30 | 31 | 32 | def compare_files(first_file: pathlib.Path, second_file: pathlib.Path) -> bool: 33 | """Compare two SQL files.""" 34 | return compare(first_file.read_text(), second_file.read_text()) 35 | 36 | 37 | def compare(first_sql: str, second_sql: str) -> bool: 38 | """Compare two SQL strings.""" 39 | first_sql_statements = [Statement(t) for t in sqlparse.parse(first_sql)] 40 | second_sql_statements = [Statement(t) for t in sqlparse.parse(second_sql)] 41 | return first_sql_statements == second_sql_statements 42 | 43 | 44 | def get_diff( 45 | first_sql: str, 46 | second_sql: str, 47 | ) -> list[list[list[str]]]: 48 | """Show the difference between two SQL schemas, ignoring differences due to column order and other non-significant SQL changes.""" 49 | first_set = {Statement(t) for t in sqlparse.parse(first_sql)} 50 | second_set = {Statement(t) for t in sqlparse.parse(second_sql)} 51 | first_diffs = sorted([stmt.str_tokens for stmt in first_set - second_set]) 52 | second_diffs = sorted([stmt.str_tokens for stmt in second_set - first_set]) 53 | 54 | return [first_diffs, second_diffs] 55 | 56 | 57 | @dataclasses.dataclass 58 | class Token: 59 | """Wrapper around `sqlparse.sql.Token`.""" 60 | 61 | token: sqlparse.sql.Token 62 | 63 | def __repr__(self) -> str: 64 | """Return the hash.""" 65 | return f'"{self.token.normalized}"' 66 | 67 | @property 68 | def hash(self) -> str: 69 | """Return the normalized token value.""" 70 | return str(self.token.normalized) 71 | 72 | @property 73 | def ignore(self) -> bool: 74 | """Return whether the token should be ignored.""" 75 | return self.token.is_whitespace or self.is_comment 76 | 77 | @property 78 | def is_comment(self) -> bool: 79 | """Return whether the token is a comment.""" 80 | return isinstance(self.token, sqlparse.sql.Comment) 81 | 82 | @property 83 | def is_separator(self) -> bool: 84 | """Return whether the token is a separator.""" 85 | return bool( 86 | self.token.ttype == sqlparse.tokens.Punctuation 87 | and self.token.normalized == ",", 88 | ) 89 | 90 | @property 91 | def str_tokens(self) -> list[str]: 92 | """Return the token value.""" 93 | if self.hash.strip(): 94 | return [self.hash] 95 | return [] 96 | 97 | 98 | @dataclasses.dataclass 99 | class TokenList: 100 | """Wrapper around `sqlparse.sql.TokenList`.""" 101 | 102 | token_list: sqlparse.sql.TokenList 103 | parent: TokenList | None = None 104 | 105 | def __eq__(self, other: object) -> bool: 106 | """Compare two list of tokens.""" 107 | if not isinstance(other, TokenList): 108 | return NotImplemented 109 | 110 | return self.hash == other.hash 111 | 112 | def __hash__(self) -> int: 113 | """Return the hash of the `TokenList` instance.""" 114 | return hash(self.hash) 115 | 116 | @property 117 | def hash(self) -> str: 118 | """Return the hash of the `TokenList` instance.""" 119 | return "".join(t.hash for t in self.tokens if not t.ignore) 120 | 121 | @property 122 | def ignore(self) -> bool: 123 | """Return whether the token list should be ignored.""" 124 | return self.is_comment 125 | 126 | @property 127 | def is_comment(self) -> bool: 128 | """Return whether the token list is a comment.""" 129 | return isinstance(self.token_list, sqlparse.sql.Comment) 130 | 131 | @property 132 | def tokens(self) -> Generator[Token | TokenList, None, None]: 133 | """Yield relevant tokens in a deterministic order.""" 134 | for token in self.token_list.tokens: 135 | if token.is_group: 136 | if UnorderedTokenList.is_unordered(token, self.statement_type): 137 | yield UnorderedTokenList(token, parent=self) 138 | else: 139 | yield TokenList(token, parent=self) 140 | else: 141 | yield Token(token) 142 | 143 | @property 144 | def statement_type(self) -> str: 145 | """Return the type of SQL statement.""" 146 | if self.parent: 147 | return self.parent.statement_type 148 | 149 | return Statement.UNKNOWN_TYPE 150 | 151 | @property 152 | def str_tokens(self) -> list[str]: 153 | """Return the reconstructed SQL statement from tokens as a list of strings.""" 154 | return [t.hash for t in self.tokens if not t.ignore] 155 | 156 | 157 | class Statement(TokenList): 158 | """SQL statement.""" 159 | 160 | UNKNOWN_TYPE = "UNKNOWN" 161 | 162 | @property 163 | def statement_type(self) -> str: 164 | """Return the type of SQL statement.""" 165 | keywords: list[str] = [ 166 | t.normalized for t in self.token_list.tokens if t.is_keyword 167 | ] 168 | 169 | # No keywords found 170 | if not keywords: 171 | return self.UNKNOWN_TYPE 172 | 173 | # Need 2 keywords to determine the statement type (e.g.: CREATE TABLE) 174 | if keywords[0] in {"CREATE", "ALTER", "DROP"}: 175 | return " ".join(keywords[:2]) 176 | 177 | # Only one keyword (e.g.: SELECT, INSERT, DELETE, etc.) 178 | return keywords[0] 179 | 180 | @property 181 | def str_tokens(self) -> list[str]: 182 | """Return the reconstructed SQL statement from tokens as a list of strings.""" 183 | return [t for token in self.tokens for t in token.str_tokens] 184 | 185 | 186 | class UnorderedTokenList(TokenList): 187 | """Unordered token list.""" 188 | 189 | STATEMENT_TYPES: typing.ClassVar[tuple[str, ...]] = ("CREATE TABLE", "CREATE TYPE") 190 | 191 | @staticmethod 192 | def is_unordered(token_list: sqlparse.sql.TokenList, statement_type: str) -> bool: 193 | """Return whether the token list order is important or not.""" 194 | return ( 195 | isinstance(token_list, sqlparse.sql.Parenthesis) 196 | and statement_type in UnorderedTokenList.STATEMENT_TYPES 197 | ) 198 | 199 | @property 200 | def tokens(self) -> Generator[Token | TokenList, None, None]: 201 | """Yield relevant tokens in a deterministic order.""" 202 | filtered_tokens = [t for t in self.flatten_tokens if not t.ignore] 203 | 204 | # Split punctuations and identifiers (columns, types, etc.) 205 | split_result = self._split_identifiers(filtered_tokens) 206 | 207 | # Tokens are "()", no need to sort them 208 | if not split_result.identifier_groups and not split_result.separators: 209 | yield from filtered_tokens 210 | 211 | # Sort identifier groups by their hash 212 | split_result.identifier_groups.sort(key=lambda g: "".join(t.hash for t in g)) 213 | # Join back the tokens in the expected order 214 | sorted_tokens = self._join_identifiers(split_result) 215 | 216 | yield from sorted_tokens 217 | 218 | @property 219 | def flatten_tokens(self) -> Generator[Token, None, None]: 220 | """Yield all tokens in the token tree.""" 221 | yield from (Token(t) for t in self.token_list.flatten()) 222 | 223 | @staticmethod 224 | def _split_identifiers(tokens: list[Token]) -> SplitIdentifierResult: 225 | """Split tokens into identifier groups. 226 | 227 | Example: 228 | ------- 229 | >>> tokens = ["(", "id", "INT", ",", "name", "TEXT", ")"] 230 | >>> self._split_identifiers(tokens) 231 | SplitIdentifierResult( 232 | opening_parenthesis="(", 233 | identifier_groups=[ 234 | ["id", "INT"], 235 | ["name", "TEXT"], 236 | ], 237 | separators=[","], 238 | closing_parenthesis=")", 239 | ) 240 | 241 | """ 242 | opening_parenthesis, closing_parenthesis = tokens.pop(0), tokens.pop(-1) 243 | 244 | # No identifier groups 245 | if not tokens: 246 | return SplitIdentifierResult( 247 | opening_parenthesis, 248 | [], 249 | [], 250 | closing_parenthesis, 251 | ) 252 | 253 | separators: list[Token] = [] 254 | identifier_groups: list[list[Token]] = [] 255 | last_identifier_group: list[Token] = [] 256 | 257 | for token in tokens: 258 | if token.is_separator: 259 | separators.append(token) 260 | if last_identifier_group: 261 | identifier_groups.append(last_identifier_group.copy()) 262 | last_identifier_group.clear() 263 | else: 264 | last_identifier_group.append(token) 265 | 266 | if last_identifier_group: 267 | identifier_groups.append(last_identifier_group.copy()) 268 | 269 | # We expect to have one less separator than identifier groups 270 | # e.g.: (id INT, name TEXT) 271 | # ^ 272 | if len(separators) != len(identifier_groups) - 1: 273 | error_message = f"Unbalanced separators ({separators}) and identifier groups ({identifier_groups})" 274 | raise RuntimeError(error_message) 275 | 276 | return SplitIdentifierResult( 277 | opening_parenthesis, 278 | identifier_groups, 279 | separators, 280 | closing_parenthesis, 281 | ) 282 | 283 | @staticmethod 284 | def _join_identifiers(split_result: SplitIdentifierResult) -> list[Token]: 285 | """Join identifier groups back into a list of tokens. 286 | 287 | Example: 288 | ------- 289 | >>> split_result = SplitIdentifierResult( 290 | opening_parenthesis="(", 291 | identifier_groups=[ 292 | ["id", "INT"], 293 | ["name", "TEXT"], 294 | ], 295 | separators=[","], 296 | closing_parenthesis=")", 297 | ) 298 | >>> self._join_identifiers(split_result) 299 | ["(", "id", "INT", ",", "name", "TEXT", ")"] 300 | 301 | """ 302 | tokens = [split_result.opening_parenthesis] 303 | 304 | for group, separator in itertools.zip_longest( 305 | split_result.identifier_groups, 306 | split_result.separators, 307 | ): 308 | tokens.extend(group) 309 | if separator: 310 | tokens.append(separator) 311 | 312 | return tokens 313 | 314 | 315 | class SplitIdentifierResult(typing.NamedTuple): 316 | """Result of the `UnorderedTokenList._split_identifiers` method.""" 317 | 318 | opening_parenthesis: Token 319 | identifier_groups: list[list[Token]] 320 | separators: list[Token] 321 | closing_parenthesis: Token 322 | -------------------------------------------------------------------------------- /sql_compare/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mergifyio/sql-compare/b54810ae5f3d741f8b91cc72dc3d7f07eeabbb60/sql_compare/py.typed -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2024-2024 Mergify SAS 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | -------------------------------------------------------------------------------- /tests/test_sql_compare.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2024-2024 Mergify SAS 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 5 | # not use this file except in compliance with the License. You may obtain 6 | # a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | # License for the specific language governing permissions and limitations 14 | # under the License. 15 | 16 | from __future__ import annotations 17 | 18 | import pytest 19 | import sqlparse 20 | 21 | import sql_compare 22 | 23 | 24 | @pytest.mark.parametrize( 25 | ("first_sql", "second_sql"), 26 | [ 27 | # CREATE TABLE 28 | ("CREATE TABLE foo (id INT)", "CREATE TABLE foo (id INT)"), 29 | # Quoted column name 30 | ( 31 | 'CREATE TABLE foo ("authorization" jsonb NOT NULL)', 32 | 'CREATE TABLE foo ("authorization" jsonb NOT NULL)', 33 | ), 34 | # Ignore whitespace 35 | ("CREATE TABLE foo(id INT)", "CREATE TABLE foo (id INT)"), 36 | # Ignore comment 37 | ("-- hello\nCREATE TABLE foo (id INT)", "CREATE TABLE foo (id INT)"), 38 | # Ignore column order 39 | ( 40 | "CREATE TABLE foo (id INT, name TEXT)", 41 | "CREATE TABLE foo (name TEXT, id INT)", 42 | ), 43 | ( 44 | "CREATE TABLE foo (bar JSON, baz JSONB)", 45 | "CREATE TABLE foo (baz JSONB, bar JSON)", 46 | ), 47 | ( 48 | "CREATE TABLE foo (at timestamp with time zone DEFAULT now() NOT NULL, id bigint NOT NULL)", 49 | "CREATE TABLE foo (id bigint NOT NULL, at timestamp with time zone DEFAULT now() NOT NULL)", 50 | ), 51 | # CREATE ENUM 52 | ( 53 | "CREATE TYPE public.colors AS ENUM ('RED', 'GREEN', 'BLUE')", 54 | "CREATE TYPE public.colors AS ENUM ('RED', 'GREEN', 'BLUE')", 55 | ), 56 | # Ignore values order in ENUM 57 | ( 58 | "CREATE TYPE public.colors AS ENUM ('RED', 'GREEN', 'BLUE')", 59 | "CREATE TYPE public.colors AS ENUM ('RED', 'BLUE', 'GREEN')", 60 | ), 61 | # CREATE FUNCTION 62 | ( 63 | "CREATE FUNCTION foo() RETURNS trigger LANGUAGE plpgsql AS $$BEGIN SELECT 1; END;$$;", 64 | "CREATE FUNCTION foo() RETURNS trigger LANGUAGE plpgsql AS $$BEGIN SELECT 1; END;$$;", 65 | ), 66 | # CREATE SEQUENCE 67 | ( 68 | "CREATE SEQUENCE foo.bar START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;", 69 | "CREATE SEQUENCE foo.bar START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;", 70 | ), 71 | # ALTER TABLE SET DEFAULT 72 | ( 73 | "ALTER TABLE ONLY foo.bar ALTER COLUMN id SET DEFAULT nextval('foo.bar_id_seq'::regclass);", 74 | "ALTER TABLE ONLY foo.bar ALTER COLUMN id SET DEFAULT nextval('foo.bar_id_seq'::regclass);", 75 | ), 76 | # ALTER TABLE ADD CONSTRAINT 77 | ( 78 | "ALTER TABLE ONLY foo ADD CONSTRAINT foo_pkey PRIMARY KEY (id1, id2);", 79 | "ALTER TABLE ONLY foo ADD CONSTRAINT foo_pkey PRIMARY KEY (id1, id2);", 80 | ), 81 | # CREATE INDEX 82 | ( 83 | "CREATE INDEX foo_idx ON foo (id1, id2)", 84 | "CREATE INDEX foo_idx ON foo (id1, id2)", 85 | ), 86 | ], 87 | ) 88 | def test_compare_eq(first_sql: str, second_sql: str) -> None: 89 | assert sql_compare.compare(first_sql, second_sql) 90 | 91 | 92 | @pytest.mark.parametrize( 93 | ("first_sql", "second_sql"), 94 | [ 95 | # Different table name 96 | ("CREATE TABLE foo (id INT)", "CREATE TABLE bar (id INT)"), 97 | # Different column name 98 | ("CREATE TABLE foo (id INT)", "CREATE TABLE foo (ident INT)"), 99 | # Different column constraint 100 | ("CREATE TABLE foo (id INT)", "CREATE TABLE foo (id INT NOT NULL)"), 101 | # Different column type 102 | ("CREATE TABLE foo (id INT)", "CREATE TABLE foo (id TEXT)"), 103 | # Different column type 104 | ("CREATE TABLE foo (bar JSONB)", "CREATE TABLE foo (bar JSON)"), 105 | # Different column types (JSON and JSONB mixed) 106 | ( 107 | "CREATE TABLE foo (bar JSONB, baz JSON)", 108 | "CREATE TABLE foo (bar JSON, baz JSONB)", 109 | ), 110 | # Different values in ENUM 111 | ( 112 | "CREATE TYPE public.colors AS ENUM ('RED', 'GREEN', 'BLUE')", 113 | "CREATE TYPE public.colors AS ENUM ('RED', 'GREEN')", 114 | ), 115 | ( 116 | "CREATE TYPE public.colors AS ENUM ('RED', 'GREEN', 'BLUE')", 117 | "CREATE TYPE public.colors AS ENUM ('red', 'green', 'blue')", 118 | ), 119 | # Different function body 120 | ( 121 | "CREATE FUNCTION foo() RETURNS trigger LANGUAGE plpgsql AS $$BEGIN SELECT 1; END;$$;", 122 | "CREATE FUNCTION foo() RETURNS trigger LANGUAGE plpgsql AS $$BEGIN SELECT 2; END;$$;", 123 | ), 124 | # Different sequence arguments 125 | ( 126 | "CREATE SEQUENCE foo.bar START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;", 127 | "CREATE SEQUENCE foo.bar START WITH 2 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;", 128 | ), 129 | ( 130 | "CREATE SEQUENCE foo.bar START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;", 131 | "CREATE SEQUENCE foo.bar START WITH 1 INCREMENT BY 2 NO MINVALUE NO MAXVALUE CACHE 1;", 132 | ), 133 | # Different ALTER TABLE SET DEFAULT 134 | ( 135 | "ALTER TABLE ONLY foo.bar ALTER COLUMN id SET DEFAULT nextval('foo.bar_id_seq'::regclass);", 136 | "ALTER TABLE ONLY foo.bar ALTER COLUMN id SET DEFAULT nextval('foo.another_id_seq'::regclass);", 137 | ), 138 | # Different primary key columns 139 | ( 140 | "ALTER TABLE ONLY foo ADD CONSTRAINT foo_pkey PRIMARY KEY (id1, id2);", 141 | "ALTER TABLE ONLY foo ADD CONSTRAINT foo_pkey PRIMARY KEY (id2, id1);", 142 | ), 143 | # Different CREATE INDEX columns 144 | ( 145 | "CREATE INDEX foo_idx ON foo (id1, id2)", 146 | "CREATE INDEX foo_idx ON foo (id2, id1)", 147 | ), 148 | ], 149 | ) 150 | def test_compare_neq(first_sql: str, second_sql: str) -> None: 151 | assert not sql_compare.compare(first_sql, second_sql) 152 | 153 | 154 | @pytest.mark.parametrize( 155 | ("sql", "expected_type"), 156 | [ 157 | ("SELECT id FROM foo", "SELECT"), 158 | ("INSERT INTO foo (id) VALUES (1)", "INSERT"), 159 | ("UPDATE foo SET id = 1", "UPDATE"), 160 | ("DELETE FROM foo WHERE id = 1", "DELETE"), 161 | ("CREATE TABLE foo (id INT)", "CREATE TABLE"), 162 | ("CREATE TYPE public.colors AS ENUM ('RED', 'GREEN', 'BLUE')", "CREATE TYPE"), 163 | ( 164 | "CREATE FUNCTION foo() RETURNS trigger LANGUAGE plpgsql AS $$BEGIN SELECT 1; END;$$;", 165 | "CREATE FUNCTION", 166 | ), 167 | ( 168 | "CREATE SEQUENCE foo.bar START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;", 169 | "CREATE SEQUENCE", 170 | ), 171 | ("CREATE INDEX foo_idx ON foo (id)", "CREATE INDEX"), 172 | ( 173 | "ALTER TABLE ONLY foo.bar ALTER COLUMN id SET DEFAULT nextval('foo.bar_id_seq'::regclass);", 174 | "ALTER TABLE", 175 | ), 176 | ( 177 | "ALTER TABLE ONLY foo ADD CONSTRAINT foo_pkey PRIMARY KEY (id1, id2);", 178 | "ALTER TABLE", 179 | ), 180 | ("DROP TABLE foo", "DROP TABLE"), 181 | ("DROP INDEX foo_idx", "DROP INDEX"), 182 | ], 183 | ) 184 | def test_statement_type(sql: str, expected_type: str) -> None: 185 | statement = sql_compare.Statement(sqlparse.parse(sql)[0]) 186 | assert statement.statement_type == expected_type 187 | 188 | 189 | @pytest.mark.parametrize( 190 | ("first_sql", "second_sql", "expected_diff"), 191 | [ 192 | ( 193 | "CREATE TABLE foo (id INT PRIMARY KEY)", 194 | "CREATE TABLE foo (id INT UNIQUE)", 195 | [ 196 | [["CREATE", "TABLE", "foo", "(", "id", "INT", "PRIMARY KEY"]], 197 | [["CREATE", "TABLE", "foo", "(", "id", "INT", "UNIQUE"]], 198 | ], 199 | ), 200 | ( 201 | "CREATE TYPE public.colors AS ENUM ('RED', 'GREEN', 'BLUE')", 202 | "CREATE TYPE public.colors AS ENUM ('BLUE', 'GREEN', 'RED')", 203 | [[], []], 204 | ), 205 | ( 206 | "CREATE TYPE public.colors AS ENUM ('RED', 'GREEN', 'BLUE')", 207 | "CREATE TYPE public.colors AS ENUM ('YELLOW', 'BLUE', 'RED')", 208 | [ 209 | [ 210 | [ 211 | "CREATE", 212 | "TYPE", 213 | "public", 214 | ".", 215 | "colors", 216 | "AS", 217 | "ENUM", 218 | "(", 219 | "'BLUE'", 220 | ",", 221 | "'GREEN'", 222 | ",", 223 | "'RED'", 224 | ], 225 | ], 226 | [ 227 | [ 228 | "CREATE", 229 | "TYPE", 230 | "public", 231 | ".", 232 | "colors", 233 | "AS", 234 | "ENUM", 235 | "(", 236 | "'BLUE'", 237 | ",", 238 | "'RED'", 239 | ",", 240 | "'YELLOW'", 241 | ], 242 | ], 243 | ], 244 | ), 245 | ( 246 | """ 247 | CREATE TYPE public.status AS ENUM ('PENDING', 'APPROVED', 'REJECTED'); 248 | CREATE TABLE users (id INT, name VARCHAR(100), status public.status); 249 | CREATE INDEX user_status_idx ON users (status); 250 | """, 251 | """ 252 | CREATE TYPE public.status AS ENUM ('PENDING', 'APPROVED', 'ARCHIVED'); 253 | CREATE TABLE logs (id INT, message TEXT); 254 | CREATE TABLE users (id INT, name VARCHAR(100), status public.status); 255 | CREATE INDEX user_status_idx ON users (status); 256 | """, 257 | [ 258 | [ 259 | [ 260 | "CREATE", 261 | "TYPE", 262 | "public", 263 | ".", 264 | "status", 265 | "AS", 266 | "ENUM", 267 | "(", 268 | "'APPROVED'", 269 | ",", 270 | "'PENDING'", 271 | ",", 272 | "'REJECTED'", 273 | ";", 274 | ], 275 | ], 276 | [ 277 | [ 278 | "CREATE", 279 | "TABLE", 280 | "logs", 281 | "(", 282 | "id", 283 | "INT", 284 | ",", 285 | "message", 286 | "TEXT", 287 | ";", 288 | ], 289 | [ 290 | "CREATE", 291 | "TYPE", 292 | "public", 293 | ".", 294 | "status", 295 | "AS", 296 | "ENUM", 297 | "(", 298 | "'APPROVED'", 299 | ",", 300 | "'ARCHIVED'", 301 | ",", 302 | "'PENDING'", 303 | ";", 304 | ], 305 | ], 306 | ], 307 | ), 308 | ], 309 | ) 310 | def test_get_diff( 311 | first_sql: str, 312 | second_sql: str, 313 | expected_diff: list[list[list[str]]], 314 | ) -> None: 315 | result = sql_compare.get_diff(first_sql, second_sql) 316 | assert result == expected_diff 317 | -------------------------------------------------------------------------------- /tools/poetry-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | if [ "$CI" ]; then 5 | export POETRY_VIRTUALENVS_OPTIONS_NO_PIP=true 6 | export POETRY_VIRTUALENVS_OPTIONS_NO_SETUPTOOLS=true 7 | poetry sync --no-cache 8 | else 9 | poetry sync 10 | fi 11 | --------------------------------------------------------------------------------