diff --git a/docs/grvt/grvt-pysdk-main/.github/workflows/ci.yml b/docs/grvt/grvt-pysdk-main/.github/workflows/ci.yml deleted file mode 100644 index 0561eee..0000000 --- a/docs/grvt/grvt-pysdk-main/.github/workflows/ci.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: ci - -on: - push: - branches: - - main - -env: - UV_VERSION: "0.4.0" - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - build: - env: - UV_CACHE_DIR: /tmp/.uv-cache - runs-on: ubuntu-24.04 - steps: - - name: Checkout source code - uses: actions/checkout@v4 - - name: Set up python - id: setup-python - uses: actions/setup-python@v5 - with: - python-version-file: ".python-version" - - name: Set up uv - run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh - - name: Restore uv cache - uses: actions/cache@v4 - with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} - - name: Install dependencies - run: uv sync --all-extras --dev --frozen - - name: Test with pytest - run: uv run pytest tests --cov=src - - name: Minimize uv cache - run: uv cache prune --ci - - build-image: - runs-on: ubuntu-24.04 - - steps: - - name: Checkout source code - uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Build docker image - uses: docker/build-push-action@v6 - with: - context: . - push: false diff --git a/docs/grvt/grvt-pysdk-main/.github/workflows/codeql.yml b/docs/grvt/grvt-pysdk-main/.github/workflows/codeql.yml deleted file mode 100644 index 9d24571..0000000 --- a/docs/grvt/grvt-pysdk-main/.github/workflows/codeql.yml +++ /dev/null @@ -1,39 +0,0 @@ -# name: "codeql" - -# on: -# push: -# branches: ["main"] -# pull_request: -# branches: ["main"] - -# jobs: -# analyze: -# name: Analyze -# runs-on: ubuntu-24.04 -# permissions: -# actions: read -# contents: read -# security-events: write - -# strategy: -# fail-fast: false -# matrix: -# language: [python] - -# steps: -# - name: Checkout -# uses: actions/checkout@v4 - -# - name: Initialize CodeQL -# uses: github/codeql-action/init@v3 -# with: -# languages: ${{ matrix.language }} -# queries: +security-and-quality - -# - name: Autobuild -# uses: github/codeql-action/autobuild@v3 - -# - name: Perform CodeQL Analysis -# uses: github/codeql-action/analyze@v3 -# with: -# category: "/language:${{ matrix.language }}" diff --git a/docs/grvt/grvt-pysdk-main/.github/workflows/pr.yml b/docs/grvt/grvt-pysdk-main/.github/workflows/pr.yml deleted file mode 100644 index e29f558..0000000 --- a/docs/grvt/grvt-pysdk-main/.github/workflows/pr.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: pr - -on: - pull_request: - branches: - - "**" - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - build: - env: - UV_CACHE_DIR: /tmp/.uv-cache - runs-on: ubuntu-24.04 - strategy: - matrix: - python-version: ["3.10.15", "3.10.x"] - uv-version: ["0.3.5", "0.4.0"] - fail-fast: false - - steps: - - name: Checkout source code - uses: actions/checkout@v4 - - name: Set up python - id: setup-python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - architecture: x64 - - name: Set up uv - run: curl -LsSf https://astral.sh/uv/${{ matrix.uv-version }}/install.sh | sh - - name: Restore uv cache - uses: actions/cache@v4 - with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} - - name: Install dependencies - run: uv sync --all-extras --dev --frozen - - name: Test with pytest - run: uv run pytest tests --cov=src - - name: Minimize uv cache - run: uv cache prune --ci - - build-image: - runs-on: ubuntu-24.04 - - steps: - - name: Checkout source code - uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Build docker image - uses: docker/build-push-action@v6 - with: - context: . - push: false diff --git a/docs/grvt/grvt-pysdk-main/.gitignore b/docs/grvt/grvt-pysdk-main/.gitignore deleted file mode 100644 index 33c82b6..0000000 --- a/docs/grvt/grvt-pysdk-main/.gitignore +++ /dev/null @@ -1,287 +0,0 @@ -# Created by https://www.toptal.com/developers/gitignore/api/python,pycharm+all,visualstudiocode -# Edit at https://www.toptal.com/developers/gitignore?templates=python,pycharm+all,visualstudiocode - -### PyCharm+all ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# SonarLint plugin -.idea/sonarlint/ - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### PyCharm+all Patch ### -# Ignore everything but code style settings and run configurations -# that are supposed to be shared within teams. - -.idea/* - -!.idea/codeStyles -!.idea/runConfigurations - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -### Python Patch ### -# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration -poetry.toml - -# ruff -.ruff_cache/ - -# LSP config files -pyrightconfig.json - -### VisualStudioCode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -!.vscode/*.code-snippets - -# Local History for Visual Studio Code -.history/ - -# Built Visual Studio Code Extensions -*.vsix - -### VisualStudioCode Patch ### -# Ignore all local history of files -.history -.ionide - -# Tests -test_results.csv -test_results_sync.csv - -# End of https://www.toptal.com/developers/gitignore/api/python,pycharm+all,visualstudiocode diff --git a/docs/grvt/grvt-pysdk-main/.pre-commit-config.yaml b/docs/grvt/grvt-pysdk-main/.pre-commit-config.yaml deleted file mode 100644 index 072d7c8..0000000 --- a/docs/grvt/grvt-pysdk-main/.pre-commit-config.yaml +++ /dev/null @@ -1,79 +0,0 @@ -ci: - skip: [pytest] - -default_language_version: - python: python3.10 - -repos: - # general checks (see here: https://pre-commit.com/hooks.html) - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 - hooks: - - id: check-yaml - args: [--allow-multiple-documents] - - id: end-of-file-fixer - - id: trailing-whitespace - - # ruff - linting + formatting - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.6.3" - hooks: - - id: ruff - name: ruff - - id: ruff-format - name: ruff-format - - # mypy - lint-like type checking - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.2 - hooks: - - id: mypy - name: mypy - - # docformatter - formats docstrings to follow PEP 257 - - repo: https://github.com/pycqa/docformatter - rev: v1.7.5 - hooks: - - id: docformatter - name: docformatter - args: - [ - -r, - -i, - --pre-summary-newline, - --make-summary-multi-line, - --wrap-summaries, - "90", - --wrap-descriptions, - "90", - src, - tests, - ] - exclude: ^(artifacts/.*)$ - - # bandit - find common security issues - - repo: https://github.com/pycqa/bandit - rev: 1.7.9 - hooks: - - id: bandit - name: bandit - exclude: ^tests/ - args: - - -r - - src - - - repo: local - hooks: - - id: pytest - name: pytest - entry: uv run pytest tests --cov=src - language: system - types: [python] - pass_filenames: false - - # prettier - formatting JS, CSS, JSON, Markdown, ... - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.1.0 - hooks: - - id: prettier - exclude: ^(uv.lock)$ diff --git a/docs/grvt/grvt-pysdk-main/.python-version b/docs/grvt/grvt-pysdk-main/.python-version deleted file mode 100644 index c8cfe39..0000000 --- a/docs/grvt/grvt-pysdk-main/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.10 diff --git a/docs/grvt/grvt-pysdk-main/.renovaterc.json b/docs/grvt/grvt-pysdk-main/.renovaterc.json deleted file mode 100644 index 09da1a9..0000000 --- a/docs/grvt/grvt-pysdk-main/.renovaterc.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": [ - "config:base", - "schedule:daily", - "group:all", - ":prConcurrentLimitNone", - ":prHourlyLimitNone", - ":prImmediately" - ], - "labels": ["dependencies"] -} diff --git a/docs/grvt/grvt-pysdk-main/CHANGELOG.md b/docs/grvt/grvt-pysdk-main/CHANGELOG.md deleted file mode 100644 index 2b487da..0000000 --- a/docs/grvt/grvt-pysdk-main/CHANGELOG.md +++ /dev/null @@ -1,78 +0,0 @@ -# Changelog - -## Version [0.2.1] - 2025-07-24 - -### Changes in 0.2.1 - -- New methods in ccxt-compatible code for Strategy (Vault) managers to view investment history and current redemption queue of a Vault. - - Classes `GrvtCcxt` and `GrvtCcxtPro` - - Methods `fetch_vault_manager_investor_history` and `fetch_vault_redemption_queue` - -## Version [0.2.0] - 2025-07-16 - -### Changes in 0.2.0 - -- additional fixes for removal of explicit enums in `grvt_raw_types.py` -- Note: this update would `break existing integrations` for `non-create-order flows` (e.g., transfer/withdrawal history, transfer, get open orders, get-instrument filters) to handle currency strings directly instead of enums. -- users will be losing the currency enum when they upgrade, so they would need to call the currencies endpoin ( ), for which the support has been added in PySDK (`get_currency_v1()` in grvt_raw_async.py and grvt_raw_sync.py), for the metadata attached to the currency strings. - -## Version [0.1.32] - 2025-07-15 - -### Changes in 0.1.32 - -- removed explicit enums in `grvt_raw_types.py` (no need to update SDK for when new coins are listed) -- added vault-related functionality - -## Version [0.1.31] - 2025-07-08 - -### Changes in 0.1.31 - -- added AVAX in the raw code (testing purposes) - -## Version [0.1.30] - 2025-07-08 - -### Changes in 0.1.30 - -- added `H` in the **raw** code - -## Version [0.1.29] - 2025-06-30 - -### Changes in 0.1.29 - -- Added new currencies: `HYPE, UNI, MOODENG, LAUNCHCOIN` in the **raw** code -- Improvements and type fixes in `fetch_funding_rate_history()` methods of GrvtCcxt and GrvtCcxtPro. - -## Version [0.1.28] - 2025-06-02 - -### Changes in 0.1.28 - -- Renamed currency name `AI_16_Z` into `AI16Z` in the **raw** code to match the exchange currency name. - -## Version [0.1.27] - 2025-05-19 - -### Changes in 0.1.27 - -- `GrvtCcxt` and `GrvtCcxtPro` classes: - - - renamed method `fetch_balances()` to `fetch_balance()` as defined in ccxt. - -## Version [0.1.26] - 2025-05-15 - -### Added in 0.1.26 - -- `GrvtCcxt` and `GrvtCcxtPro` classes: - - - new method `describe()` - returns a list of public method names - - new method `fetch_balances()` - returns dict with balances in ccxt format. - - constructor parameter `order_book_ccxt_format: bool = False` . If = True then order book snapshots from `fetch_order_book()` are in ccxt format. - -### Fixed in 0.1.26 - -- Issues with typing and lynting errors - -## Version [0.1.25] - 2025-04-25 - -### Fixed in 0.1.25 - -- Issues with typing and lynting errors -- Fixed bug in test_grvt_ccxt.py diff --git a/docs/grvt/grvt-pysdk-main/LICENSE b/docs/grvt/grvt-pysdk-main/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/docs/grvt/grvt-pysdk-main/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/docs/grvt/grvt-pysdk-main/Makefile b/docs/grvt/grvt-pysdk-main/Makefile deleted file mode 100644 index b2c789b..0000000 --- a/docs/grvt/grvt-pysdk-main/Makefile +++ /dev/null @@ -1,59 +0,0 @@ -# A Self-Documenting Makefile: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html -.PHONY: help -help: ## Show this help - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sed -e 's/^Makefile://' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - - -.PHONY: run -run: ## Run the project - uv run python -m pysdk.main - -.PHONY: test -test: ## Run the tests - uv run pytest tests --cov=src - -.PHONY: precommit -precommit: ## Run the pre-commit hooks - bash .git/hooks/pre-commit - -.PHONY: lint -lint: ## Run the linter - uv run ruff check . - -.PHONY: lint-fix -lint-fix: ## Run the linter and fix the issues - uv run ruff check --fix --unsafe-fixes . - -.PHONY: format -format: ## Run the formatter - uv run ruff format . - -.PHONY: typecheck -typecheck: ## Run the type checker - uv run mypy . - -.PHONY: security -security: ## Run the security checker - uv run bandit . - -.PHONY: clean -clean: ## Clean the project - uv run ruff clean . - -.PHONY: install -install: ## Install the project - uv sync --all-extras --dev --frozen - -.PHONY: build -build: ## Build the project - uv build - -.PHONY: publish -publish: ## Publish the project - python3 build_readme.py - make build - uv run twine upload --skip-existing dist/* - -# ============================================================================== -# always make sure the following is the last line on this file -.DEFAULT_GOAL := help diff --git a/docs/grvt/grvt-pysdk-main/README.md b/docs/grvt/grvt-pysdk-main/README.md deleted file mode 100644 index e6038cc..0000000 --- a/docs/grvt/grvt-pysdk-main/README.md +++ /dev/null @@ -1,300 +0,0 @@ -

- uv logo - pre-commit logo - ruff logo - bandit logo - pytest logo -

- -

- Docker logo - GitHub Actions logo -

- -# GRVT Python SDK - -[![CodeQL](https://github.com/smarlhens/python-boilerplate/workflows/codeql/badge.svg)](https://github.com/smarlhens/python-boilerplate/actions/workflows/codeql.yml) -[![GitHub CI](https://github.com/smarlhens/python-boilerplate/workflows/ci/badge.svg)](https://github.com/smarlhens/python-boilerplate/actions/workflows/ci.yml) -[![GitHub license](https://img.shields.io/github/license/smarlhens/python-boilerplate)](https://github.com/smarlhens/python-boilerplate) - ---- - -## Table of Contents - -- [GRVT Python SDK](#grvt-python-sdk) - - [Table of Contents](#table-of-contents) - - [What's in the library](#whats-in-the-library) - - [Environments](#environments) - - [Files](#files) - - [Installation via pip](#installation-via-pip) - - [Configuration](#configuration) - - [Usage](#usage) - - [Contributor's guide](#contributors-guide) - - [Prerequisites](#prerequisites) - - [Installation of a source code](#installation-of-a-source-code) - - [Manually run example files](#manually-run-example-files) - - [What's in the box ?](#whats-in-the-box-) - - [uv](#uv) - - [pre-commit](#pre-commit) - - [ruff](#ruff) - - [mypy](#mypy) - - [bandit](#bandit) - - [docformatter](#docformatter) - - [Testing](#testing) - - [Makefile](#makefile) - ---- - -## What's in the library - -GRVT Python SDK library provides Python classes and utility methods for easy access to GRVT API endpoints across all environments. - -### Environments - -- `prod` - Production environment. -- `testnet` - Testnet environment. -- `staging` - Development Integration environment. -- `dev` - Development environment. - -SDK Library provides two types of classes: - -1. **Raw** - thin wrapper classes around Rest API. -2. **Ccxt-compatible** - classes with ccxt-like methods. Provide access to both Rest API and WebSockets. - -### Files - -Raw access: - -- `grvt_raw_base.py` - base classes for Rest API access. -- `grvt_raw_env.py` - definitions of environments for raw access. -- `grvt_raw_signing.py` - utility methods for signing orders. -- `grvt_raw_sync.py` - class for raw synchronous calls to Rest API. -- `grvt_raw_async.py` - class for raw asynchronous calls to Rest API. - -CCXT-compatible access: - -- `grvt_ccxt_utils.py` - utility methods for signing orders. -- `grvt_ccxt_env.py` - definitions of environments for ccxt-like access. -- `grvt_ccxt_base.py` - base class for Rest API access. -- `grvt_ccxt.py` - class for synchronous calls to Rest API. -- `grvt_ccxt_pro.py` - class for asynchronous calls to Rest API. -- `grvt_ccxt_ws.py` - class for WebSocket calls. - -## Installation via pip - -```bash -pip install grvt-pysdk -``` - -### Configuration - -Setup these environment variables: - -```bash -export GRVT_PRIVATE_KEY="`Secret Private Key` in API setup" -export GRVT_API_KEY="`API Key` in API setup" -export GRVT_TRADING_ACCOUNT_ID=<`Trading account ID` in API> -export GRVT_ENV="testnet" -export GRVT_END_POINT_VERSION="v1" -export GRVT_WS_STREAM_VERSION="v1" -``` - -## Usage - -**Examples of how to use various methods to connect to GRVT API:** - -- [GRVT CCXT](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_ccxt.py) - Example of usage of CCXT-compatible Python class `GrvtCcxt` with `synchronous` Rest API calls. -- [GRVT CCXT Pro](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_ccxt_pro.py) - Example of usage of CCXT.PRO-compatible Python class `GrvtCcxtPro` with `asynchronous` Rest API calls. -- [GRVT CCXT WS](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_ccxt_ws.py) - Example of usage of CCXT.PRO-compatible Python class `GrvtCcxtWS` with `asynchronous` Rest API calls + Web Socket subscriptions + JSON RPC calls over Web Sockets. -- [GRVT API Sync](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_raw_sync.py) - Synchronous API client for GRVT -- [GRVT API Async](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_raw_async.py) - Asynchronous API client for GRVT - -## Contributor's guide - -### Prerequisites - -- [Python](https://www.python.org/downloads/) **>=3.10.0 < 3.13** (_tested with 3.10.15_) -- [pre-commit](https://pre-commit.com/#install) -- [uv](https://docs.astral.sh/uv/getting-started/installation/) **>=0.3.3** (_tested with 0.4.0_) -- [docker](https://docs.docker.com/get-docker/) (_optional_) - -### Installation of a source code - -1. Clone the git repository - - ```bash - git clone https://github.com/grvt-technologies/grvt-pysdk.git - ``` - -2. Go into the project directory - - ```bash - cd grvt-pysdk/ - ``` - -3. Checkout working branch - - ```bash - git checkout - ``` - -4. Install dependencies - - ```bash - make install - ``` - -5. Enable pre-commit hooks - - ```bash - pre-commit install - ``` - ---- - -### Manually run example files - -Example files run extensive testing of the SDK API classes and log details about details of using GRVT API. - -1. Change to tests folder - - ```bash - cd tests/pysdk - ``` - -2. Run example of using synchronous CCXT-compatible calls to `Rest API` via `grvt_ccxt.py`, class `GrvtCcxt` - - ```bash - uv run python3 test_grvt_ccxt.py - ``` - -3. Run example of using asynchronous CCXT-compatible calls to `Rest API` via `grvt_ccxt_pro.py`, class `GrvtCcxtPro` - - ```bash - uv run python3 test_grvt_ccxt_pro.py - ``` - -4. Run example of using WebSockets subscriptions and JSON RPC calls via `grvt_ccxt_ws.py`, class `GrvtCcxtWS` - - ```bash - uv run python3 test_grvt_ccxt_ws.py - ``` - -### What's in the box ? - -#### uv - -[uv](https://github.com/astral-sh/uv) is an extremely fast Python package and project manager, written in Rust. - -**pyproject.toml file** ([`pyproject.toml`](pyproject.toml)): orchestrate your project and its dependencies -**uv.lock file** ([`uv.lock`](uv.lock)): ensure that the package versions are consistent for everyone -working on your project - -For more configuration options and details, see the [configuration docs](https://docs.astral.sh/uv/). - -#### pre-commit - -[pre-commit](https://pre-commit.com/) is a framework for managing and maintaining multi-language pre-commit hooks. - -**.pre-commit-config.yaml file** ([`.pre-commit-config.yaml`](.pre-commit-config.yaml)): describes what repositories and -hooks are installed - -For more configuration options and details, see the [configuration docs](https://pre-commit.com/). - -#### ruff - -[ruff](https://github.com/astral-sh/ruff) is an extremely fast Python linter, written in Rust. - -Rules are defined in the [`pyproject.toml`](pyproject.toml). - -For more configuration options and details, see the [configuration docs](https://github.com/astral-sh/ruff#configuration). - -#### mypy - -[mypy](http://mypy-lang.org/) is an optional static type checker for Python that aims to combine the benefits of -dynamic (or "duck") typing and static typing. - -Rules are defined in the [`pyproject.toml`](pyproject.toml). - -For more configuration options and details, see the [configuration docs](https://mypy.readthedocs.io/). - -#### bandit - -[bandit](https://bandit.readthedocs.io/) is a tool designed to find common security issues in Python code. - -Rules are defined in the [`pyproject.toml`](pyproject.toml). - -For more configuration options and details, see the [configuration docs](https://bandit.readthedocs.io/). - -#### docformatter - -[docformatter](https://github.com/PyCQA/docformatter) is a tool designed to format docstrings to -follow [PEP 257](https://peps.python.org/pep-0257/). - -Options are defined in the [`.pre-commit-config.yaml`](.pre-commit-config.yaml). - ---- - -#### Testing - -We are using [pytest](https://docs.pytest.org/) & [pytest-cov](https://github.com/pytest-dev/pytest-cov) to write tests. - -To run tests with coverage: - -```bash -make test -``` - -```text -Name Stmts Miss Cover -------------------------------------------------------------- -src/pysdk/__init__.py 0 0 100% -src/pysdk/grvt_ccxt.py 238 21 91% -src/pysdk/grvt_ccxt_base.py 196 57 71% -src/pysdk/grvt_ccxt_env.py 48 12 75% -src/pysdk/grvt_ccxt_logging_selector.py 15 7 53% -src/pysdk/grvt_ccxt_pro.py 245 69 72% -src/pysdk/grvt_ccxt_test_utils.py 30 4 87% -src/pysdk/grvt_ccxt_types.py 41 0 100% -src/pysdk/grvt_ccxt_utils.py 237 89 62% -src/pysdk/grvt_ccxt_ws.py 275 238 13% -src/pysdk/grvt_raw_async.py 149 109 27% -src/pysdk/grvt_raw_base.py 154 69 55% -src/pysdk/grvt_raw_env.py 27 5 81% -src/pysdk/grvt_raw_signing.py 33 17 48% -src/pysdk/grvt_raw_sync.py 149 109 27% -src/pysdk/grvt_raw_types.py 1031 0 100% -------------------------------------------------------------- -TOTAL 2868 806 72% - - -=================================================================================================== 8 passed in 58.20s ==================================================================================================== -``` - -#### Makefile - -We are using [Makefile](https://www.gnu.org/software/make/manual/make.html) to manage the project. - -To see the list of commands: - -```bash -make -``` - -```bash -➜ grvt-pysdk git:(main) ✗ make -help Show this help -run Run the project -test Run the tests -precommit Run the pre-commit hooks -lint Run the linter -format Run the formatter -typecheck Run the type checker -security Run the security checker -clean Clean the project -install Install the project -build Build the project -publish Publish the project -``` - ---- diff --git a/docs/grvt/grvt-pysdk-main/README_PYPI.md b/docs/grvt/grvt-pysdk-main/README_PYPI.md deleted file mode 100644 index 3dae020..0000000 --- a/docs/grvt/grvt-pysdk-main/README_PYPI.md +++ /dev/null @@ -1,382 +0,0 @@ -

- uv logo - pre-commit logo - ruff logo - bandit logo - pytest logo -

- -

- Docker logo - GitHub Actions logo -

- -# GRVT Python SDK - -[![CodeQL](https://github.com/smarlhens/python-boilerplate/workflows/codeql/badge.svg)](https://github.com/smarlhens/python-boilerplate/actions/workflows/codeql.yml) -[![GitHub CI](https://github.com/smarlhens/python-boilerplate/workflows/ci/badge.svg)](https://github.com/smarlhens/python-boilerplate/actions/workflows/ci.yml) -[![GitHub license](https://img.shields.io/github/license/smarlhens/python-boilerplate)](https://github.com/smarlhens/python-boilerplate) - ---- - -## Table of Contents - -- [GRVT Python SDK](#grvt-python-sdk) - - [Table of Contents](#table-of-contents) - - [What's in the library](#whats-in-the-library) - - [Environments](#environments) - - [Files](#files) - - [Installation via pip](#installation-via-pip) - - [Configuration](#configuration) - - [Usage](#usage) - - [Contributor's guide](#contributors-guide) - - [Prerequisites](#prerequisites) - - [Installation of a source code](#installation-of-a-source-code) - - [Manually run example files](#manually-run-example-files) - - [What's in the box ?](#whats-in-the-box-) - - [uv](#uv) - - [pre-commit](#pre-commit) - - [ruff](#ruff) - - [mypy](#mypy) - - [bandit](#bandit) - - [docformatter](#docformatter) - - [Testing](#testing) - - [Makefile](#makefile) - ---- - -## What's in the library - -GRVT Python SDK library provides Python classes and utility methods for easy access to GRVT API endpoints across all environments. - -### Environments - -- `prod` - Production environment. -- `testnet` - Testnet environment. -- `staging` - Development Integration environment. -- `dev` - Development environment. - -SDK Library provides two types of classes: - -1. **Raw** - thin wrapper classes around Rest API. -2. **Ccxt-compatible** - classes with ccxt-like methods. Provide access to both Rest API and WebSockets. - -### Files - -Raw access: - -- `grvt_raw_base.py` - base classes for Rest API access. -- `grvt_raw_env.py` - definitions of environments for raw access. -- `grvt_raw_signing.py` - utility methods for signing orders. -- `grvt_raw_sync.py` - class for raw synchronous calls to Rest API. -- `grvt_raw_async.py` - class for raw asynchronous calls to Rest API. - -CCXT-compatible access: - -- `grvt_ccxt_utils.py` - utility methods for signing orders. -- `grvt_ccxt_env.py` - definitions of environments for ccxt-like access. -- `grvt_ccxt_base.py` - base class for Rest API access. -- `grvt_ccxt.py` - class for synchronous calls to Rest API. -- `grvt_ccxt_pro.py` - class for asynchronous calls to Rest API. -- `grvt_ccxt_ws.py` - class for WebSocket calls. - -## Installation via pip - -```bash -pip install grvt-pysdk -``` - -### Configuration - -Setup these environment variables: - -```bash -export GRVT_PRIVATE_KEY="`Secret Private Key` in API setup" -export GRVT_API_KEY="`API Key` in API setup" -export GRVT_TRADING_ACCOUNT_ID=<`Trading account ID` in API> -export GRVT_ENV="testnet" -export GRVT_END_POINT_VERSION="v1" -export GRVT_WS_STREAM_VERSION="v1" -``` - -## Usage - -**Examples of how to use various methods to connect to GRVT API:** - -- [GRVT CCXT](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_ccxt.py) - Example of usage of CCXT-compatible Python class `GrvtCcxt` with `synchronous` Rest API calls. -- [GRVT CCXT Pro](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_ccxt_pro.py) - Example of usage of CCXT.PRO-compatible Python class `GrvtCcxtPro` with `asynchronous` Rest API calls. -- [GRVT CCXT WS](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_ccxt_ws.py) - Example of usage of CCXT.PRO-compatible Python class `GrvtCcxtWS` with `asynchronous` Rest API calls + Web Socket subscriptions + JSON RPC calls over Web Sockets. -- [GRVT API Sync](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_raw_sync.py) - Synchronous API client for GRVT -- [GRVT API Async](https://github.com/gravity-technologies/grvt-pysdk/blob/main/tests/pysdk/test_grvt_raw_async.py) - Asynchronous API client for GRVT - -## Contributor's guide - -### Prerequisites - -- [Python](https://www.python.org/downloads/) **>=3.10.0 < 3.13** (_tested with 3.10.15_) -- [pre-commit](https://pre-commit.com/#install) -- [uv](https://docs.astral.sh/uv/getting-started/installation/) **>=0.3.3** (_tested with 0.4.0_) -- [docker](https://docs.docker.com/get-docker/) (_optional_) - -### Installation of a source code - -1. Clone the git repository - - ```bash - git clone https://github.com/grvt-technologies/grvt-pysdk.git - ``` - -2. Go into the project directory - - ```bash - cd grvt-pysdk/ - ``` - -3. Checkout working branch - - ```bash - git checkout - ``` - -4. Install dependencies - - ```bash - make install - ``` - -5. Enable pre-commit hooks - - ```bash - pre-commit install - ``` - ---- - -### Manually run example files - -Example files run extensive testing of the SDK API classes and log details about details of using GRVT API. - -1. Change to tests folder - - ```bash - cd tests/pysdk - ``` - -2. Run example of using synchronous CCXT-compatible calls to `Rest API` via `grvt_ccxt.py`, class `GrvtCcxt` - - ```bash - uv run python3 test_grvt_ccxt.py - ``` - -3. Run example of using asynchronous CCXT-compatible calls to `Rest API` via `grvt_ccxt_pro.py`, class `GrvtCcxtPro` - - ```bash - uv run python3 test_grvt_ccxt_pro.py - ``` - -4. Run example of using WebSockets subscriptions and JSON RPC calls via `grvt_ccxt_ws.py`, class `GrvtCcxtWS` - - ```bash - uv run python3 test_grvt_ccxt_ws.py - ``` - -### What's in the box ? - -#### uv - -[uv](https://github.com/astral-sh/uv) is an extremely fast Python package and project manager, written in Rust. - -**pyproject.toml file** ([`pyproject.toml`](pyproject.toml)): orchestrate your project and its dependencies -**uv.lock file** ([`uv.lock`](uv.lock)): ensure that the package versions are consistent for everyone -working on your project - -For more configuration options and details, see the [configuration docs](https://docs.astral.sh/uv/). - -#### pre-commit - -[pre-commit](https://pre-commit.com/) is a framework for managing and maintaining multi-language pre-commit hooks. - -**.pre-commit-config.yaml file** ([`.pre-commit-config.yaml`](.pre-commit-config.yaml)): describes what repositories and -hooks are installed - -For more configuration options and details, see the [configuration docs](https://pre-commit.com/). - -#### ruff - -[ruff](https://github.com/astral-sh/ruff) is an extremely fast Python linter, written in Rust. - -Rules are defined in the [`pyproject.toml`](pyproject.toml). - -For more configuration options and details, see the [configuration docs](https://github.com/astral-sh/ruff#configuration). - -#### mypy - -[mypy](http://mypy-lang.org/) is an optional static type checker for Python that aims to combine the benefits of -dynamic (or "duck") typing and static typing. - -Rules are defined in the [`pyproject.toml`](pyproject.toml). - -For more configuration options and details, see the [configuration docs](https://mypy.readthedocs.io/). - -#### bandit - -[bandit](https://bandit.readthedocs.io/) is a tool designed to find common security issues in Python code. - -Rules are defined in the [`pyproject.toml`](pyproject.toml). - -For more configuration options and details, see the [configuration docs](https://bandit.readthedocs.io/). - -#### docformatter - -[docformatter](https://github.com/PyCQA/docformatter) is a tool designed to format docstrings to -follow [PEP 257](https://peps.python.org/pep-0257/). - -Options are defined in the [`.pre-commit-config.yaml`](.pre-commit-config.yaml). - ---- - -#### Testing - -We are using [pytest](https://docs.pytest.org/) & [pytest-cov](https://github.com/pytest-dev/pytest-cov) to write tests. - -To run tests with coverage: - -```bash -make test -``` - -```text -Name Stmts Miss Cover -------------------------------------------------------------- -src/pysdk/__init__.py 0 0 100% -src/pysdk/grvt_ccxt.py 238 21 91% -src/pysdk/grvt_ccxt_base.py 196 57 71% -src/pysdk/grvt_ccxt_env.py 48 12 75% -src/pysdk/grvt_ccxt_logging_selector.py 15 7 53% -src/pysdk/grvt_ccxt_pro.py 245 69 72% -src/pysdk/grvt_ccxt_test_utils.py 30 4 87% -src/pysdk/grvt_ccxt_types.py 41 0 100% -src/pysdk/grvt_ccxt_utils.py 237 89 62% -src/pysdk/grvt_ccxt_ws.py 275 238 13% -src/pysdk/grvt_raw_async.py 149 109 27% -src/pysdk/grvt_raw_base.py 154 69 55% -src/pysdk/grvt_raw_env.py 27 5 81% -src/pysdk/grvt_raw_signing.py 33 17 48% -src/pysdk/grvt_raw_sync.py 149 109 27% -src/pysdk/grvt_raw_types.py 1031 0 100% -------------------------------------------------------------- -TOTAL 2868 806 72% - - -=================================================================================================== 8 passed in 58.20s ==================================================================================================== -``` - -#### Makefile - -We are using [Makefile](https://www.gnu.org/software/make/manual/make.html) to manage the project. - -To see the list of commands: - -```bash -make -``` - -```bash -➜ grvt-pysdk git:(main) ✗ make -help Show this help -run Run the project -test Run the tests -precommit Run the pre-commit hooks -lint Run the linter -format Run the formatter -typecheck Run the type checker -security Run the security checker -clean Clean the project -install Install the project -build Build the project -publish Publish the project -``` - ---- - - -## Changelog - -# Changelog - -## Version [0.2.1] - 2025-07-24 - -### Changes in 0.2.1 - -- New methods in ccxt-compatible code for Strategy (Vault) managers to view investment history and current redemption queue of a Vault. - - Classes `GrvtCcxt` and `GrvtCcxtPro` - - Methods `fetch_vault_manager_investor_history` and `fetch_vault_redemption_queue` - -## Version [0.2.0] - 2025-07-16 - -### Changes in 0.2.0 - -- additional fixes for removal of explicit enums in `grvt_raw_types.py` -- Note: this update would `break existing integrations` for `non-create-order flows` (e.g., transfer/withdrawal history, transfer, get open orders, get-instrument filters) to handle currency strings directly instead of enums. -- users will be losing the currency enum when they upgrade, so they would need to call the currencies endpoin ( ), for which the support has been added in PySDK (`get_currency_v1()` in grvt_raw_async.py and grvt_raw_sync.py), for the metadata attached to the currency strings. - -## Version [0.1.32] - 2025-07-15 - -### Changes in 0.1.32 - -- removed explicit enums in `grvt_raw_types.py` (no need to update SDK for when new coins are listed) -- added vault-related functionality - -## Version [0.1.31] - 2025-07-08 - -### Changes in 0.1.31 - -- added AVAX in the raw code (testing purposes) - -## Version [0.1.30] - 2025-07-08 - -### Changes in 0.1.30 - -- added `H` in the **raw** code - -## Version [0.1.29] - 2025-06-30 - -### Changes in 0.1.29 - -- Added new currencies: `HYPE, UNI, MOODENG, LAUNCHCOIN` in the **raw** code -- Improvements and type fixes in `fetch_funding_rate_history()` methods of GrvtCcxt and GrvtCcxtPro. - -## Version [0.1.28] - 2025-06-02 - -### Changes in 0.1.28 - -- Renamed currency name `AI_16_Z` into `AI16Z` in the **raw** code to match the exchange currency name. - -## Version [0.1.27] - 2025-05-19 - -### Changes in 0.1.27 - -- `GrvtCcxt` and `GrvtCcxtPro` classes: - - - renamed method `fetch_balances()` to `fetch_balance()` as defined in ccxt. - -## Version [0.1.26] - 2025-05-15 - -### Added in 0.1.26 - -- `GrvtCcxt` and `GrvtCcxtPro` classes: - - - new method `describe()` - returns a list of public method names - - new method `fetch_balances()` - returns dict with balances in ccxt format. - - constructor parameter `order_book_ccxt_format: bool = False` . If = True then order book snapshots from `fetch_order_book()` are in ccxt format. - -### Fixed in 0.1.26 - -- Issues with typing and lynting errors - -## Version [0.1.25] - 2025-04-25 - -### Fixed in 0.1.25 - -- Issues with typing and lynting errors -- Fixed bug in test_grvt_ccxt.py diff --git a/docs/grvt/grvt-pysdk-main/build_readme.py b/docs/grvt/grvt-pysdk-main/build_readme.py deleted file mode 100644 index c23bd8d..0000000 --- a/docs/grvt/grvt-pysdk-main/build_readme.py +++ /dev/null @@ -1,9 +0,0 @@ -from pathlib import Path - -readme = Path("README.md").read_text() -changelog = Path("CHANGELOG.md").read_text() - -combined = f"{readme}\n\n## Changelog\n\n{changelog}" - -Path("README_PYPI.md").write_text(combined) -print("✅ Combined README.md and CHANGELOG.md into README_PYPI.md") diff --git a/docs/grvt/grvt-pysdk-main/pyproject.toml b/docs/grvt/grvt-pysdk-main/pyproject.toml deleted file mode 100644 index 99fea3a..0000000 --- a/docs/grvt/grvt-pysdk-main/pyproject.toml +++ /dev/null @@ -1,106 +0,0 @@ -[project] -name = "grvt-pysdk" -version = "0.2.1" - -description = "GRVT Python SDK" -requires-python = ">=3.10" -license = { file = "LICENSE" } -authors = [ - { name = "GRVT", email = "contact@grvt.io" }, -] -readme = { file = "README_PYPI.md", content-type = "text/markdown" } -dependencies = [ - "aiohttp>=3.10.11", - "backports-weakref>=1.0.post1", - "dacite>=1.8.1", - "dataclasses-json>=0.6.7", - "eth-account>=0.13.4", - "inflection>=0.5.1", - "requests>=2.32.3", - "websockets==13.1", -] - -[project.urls] -homepage = "https://github.com/gravity-technologies/grvt-pysdk" -repository = "https://github.com/gravity-technologies/grvt-pysdk" - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["src/pysdk"] - -[tool.uv] -dev-dependencies = [ - "pytest>=8.3.2", - "pytest-cov>=5.0.0", - "mypy>=1.11.2", - "bandit>=1.7.9", - "docformatter>=1.7.5", - "ruff>=0.6.2", - "twine>=5.1.1", -] - -[tool.pytest.ini_options] -addopts = "-vvv" -testpaths = "tests" - -[tool.ruff] -extend-exclude = [ - "__pycache__", - "build", - "dist", -] -target-version = "py312" -line-length = 90 -src = ["src", "tests"] - -[tool.ruff.lint] -extend-select = [ - "C4", - "D200", - "D201", - "D204", - "D205", - "D206", - "D210", - "D211", - "D213", - "D300", - "D400", - "D402", - "D403", - "D404", - "D419", - "E", - "F", - "G010", - "I001", - "INP001", - "N805", - "PERF101", - "PERF102", - "PERF401", - "PERF402", - "PGH004", - "PGH005", - "PIE794", - "PIE796", - "PIE807", - "PIE810", - "RET502", - "RET503", - "RET504", - "RET505", - "RUF015", - "RUF100", - "S101", - "T20", - "UP", - "W", -] - -[tool.mypy] -files = ["src", "tests"] -strict = "true" diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/__init__.py b/docs/grvt/grvt-pysdk-main/src/pysdk/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt.py deleted file mode 100644 index 5f5d7ec..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt.py +++ /dev/null @@ -1,812 +0,0 @@ -# ruff: noqa: D200 -# ruff: noqa: D204 -# ruff: noqa: D205 -# ruff: noqa: D404 -# ruff: noqa: W291 -# ruff: noqa: D400 -# ruff: noqa: E501 -import json -import logging -from typing import Any, Literal - -import requests - -from .grvt_ccxt_base import GrvtCcxtBase -from .grvt_ccxt_env import GrvtEnv, get_grvt_endpoint -from .grvt_ccxt_types import ( - Amount, - GrvtInstrumentKind, - GrvtInvalidOrder, - GrvtOrderSide, - GrvtOrderType, - Num, -) -from .grvt_ccxt_utils import ( - EnumEncoder, - GrvtOrder, - get_cookie_with_expiration, - get_grvt_order, - get_order_payload, -) - - -class GrvtCcxt(GrvtCcxtBase): - """ - GrvtCcxt class to interact with Grvt Rest API in synchronous mode. - - Args: - env: GrvtEnv (DEV, TESTNET, PROD) - logger: logging.Logger - parameters: dict with trading_account_id, private_key, api_key etc - - Examples: - >>> from grvt_api import GrvtCcxt - >>> from grvt_env import GrvtEnv - >>> grvt = GrvtCcxt(env=GrvtEnv.TESTNET) - >>> grvt.fetch_markets() - """ - - def __init__( - self, - env: GrvtEnv, - logger: logging.Logger | None = None, - parameters: dict = {}, - order_book_ccxt_format: bool = False, - ): - """Initialize the GrvtCcxt instance.""" - super().__init__(env, logger, parameters, order_book_ccxt_format) - self._clsname: str = type(self).__name__ - self._session: requests.Session = requests.Session() - self._session.headers.update({"Content-Type": "application/json"}) - self.refresh_cookie() - # Assign markets here - self.markets: dict[str, dict] = self.load_markets() - - def refresh_cookie(self) -> dict | None: - """Refresh the session cookie.""" - if not self.should_refresh_cookie(): - return self._cookie - path = get_grvt_endpoint(self.env, "AUTH") - self._cookie = get_cookie_with_expiration(path, self._api_key) - self._path_return_value_map[path] = self._cookie - if self._cookie: - self._session.cookies.update({"gravity": self._cookie["gravity"]}) - if self._cookie["X-Grvt-Account-Id"]: - self._session.headers.update( - {"X-Grvt-Account-Id": self._cookie["X-Grvt-Account-Id"]} - ) - self.logger.info( - f"refresh_cookie {self._cookie=} {self._session.cookies=} {self._session.headers=}" - ) - return self._cookie - - # PRIVATE API CALLS - def _auth_and_post(self, path: str, payload: dict) -> dict: - FN = f"_auth_and_post {path=}" - MAX_LEN_TO_LOG = 1280 - response: dict = {} - if not path: - self.logger.warning(f"{FN} Invalid path {path=} {payload=}") - raise GrvtInvalidOrder(f"{FN} Invalid path {path=} {payload=}") - # Always see if need to referesh cookie before sending a request - self.refresh_cookie() - payload_json = json.dumps(payload, cls=EnumEncoder) - self.logger.info(f"{FN} {payload=}\n{payload_json=}") - return_value = self._session.post(path, data=payload_json, timeout=5) - return_text: str = "" - try: - return_text = return_value.text - response = return_value.json() - except Exception as err: - self.logger.warning(f"{FN} Unable to parse {return_value=} as json. {err=}") - if not return_value.ok: - self.logger.warning(f"{FN} ERROR {payload_json=}\n{return_value=}\n{response=}") - else: - if len(return_text) > MAX_LEN_TO_LOG: - self.logger.debug(f"{FN} OK {return_value=} {response=}") - self.logger.info(f"{FN} OK {return_value=} response=**TOO LONG**") - else: - self.logger.info(f"{FN} OK {return_value=} {response=}") - self._path_return_value_map[path] = response - return response - - def _create_grvt_order(self, order: GrvtOrder) -> dict: - """ - Send a GrvtOrder object to the exchange. - :param order: The GrvtOrder object. - Return: dictionary representing the order response. - """ - FN = f"{self._clsname} _create_grvt_order cloid:{order.metadata.client_order_id}" - order_payload = get_order_payload( - order, - private_key=self._private_key, - env=self.env, - instruments=self.markets, - ) - path = get_grvt_endpoint(self.env, "CREATE_ORDER") - self.logger.info(f"{FN} {path=} {order_payload=}") - response: dict = self._auth_and_post(path, payload=order_payload) - if response.get("result") is None: - self.logger.error(f"{FN} Error: {response}") - return {} - self.logger.info( - f"{FN} Order created:" - f"{response.get('result', {}).get('metadata', {}).get('client_order_id')}" - ) - return response.get("result", {}) - - def create_order( - self, - symbol: str, - order_type: GrvtOrderType, - side: GrvtOrderSide, - amount: Amount, - price: Num = None, - params={}, - ) -> dict: - """Ccxt compliant signature.""" - self._check_account_auth() - self._check_valid_symbol(symbol) - # Validate order fields - self._check_order_arguments(order_type, side, amount, price) - # create GrvtOrder object - order_duration_secs = params.get("order_duration_secs", 24 * 60 * 60) - order = get_grvt_order( - sub_account_id=self.get_trading_account_id(), - symbol=symbol, - order_type=order_type, - side=side, - amount=amount, - limit_price=price, - order_duration_secs=order_duration_secs, - params=params, - ) - return self._create_grvt_order(order) - - def create_limit_order( - self, - symbol: str, - side: GrvtOrderSide, - amount: Amount, - price: Num = None, - params={}, - ) -> dict: - return self.create_order(symbol, "limit", side, amount, price, params) - - def cancel_all_orders( - self, - params: dict = {}, - ) -> bool: - """ - Ccxt compliant signature BUT lacks symbol - Cancel all orders for a sub-account. - params: dictionary with parameters. Valid keys:
- `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
- `quote` (str): quote currency. Defaults to all.
- """ - self._check_account_auth() - FN = f"{self._clsname} cancel_all_orders" - payload: dict = self._get_payload_cancel_all_orders(params) - path = get_grvt_endpoint(self.env, "CANCEL_ALL_ORDERS") - response: dict = self._auth_and_post(path, payload) - cancel_ack = response.get("result", {}).get("ack") - - if not cancel_ack: - self.logger.warning(f"{FN} failed to cancel orders: {response=}") - return False - self.logger.info(f"{FN} Cancelled {response=}") - return True - - def cancel_order( - self, - id: str | None = None, - symbol: str | None = None, - params: dict = {}, - ) -> bool: - """ - Ccxt compliant signature - Cancel specific order for the account.
- Private call requires authorization.
- See [Cancel order](https://api-docs.grvt.io/trading_api/#cancel-order) - for details.
. - - Args: - id (str): exchange assigned order ID
- symbol (str): trading symbol
- params: - * client_order_id (str): client assigned order ID
- * time_to_live_ms (str): lifetime of cancel requiest in millisecs
- Returns: - True if cancel request was acked by exchange. False otherwise.
- """ - FN = f"{self._clsname} cancel_order" - self._check_account_auth() - payload: dict = { - "sub_account_id": self.get_trading_account_id(), - } - if id: - payload["order_id"] = str(id) - elif "client_order_id" in params: - payload["client_order_id"] = str(params["client_order_id"]) - else: - raise GrvtInvalidOrder(f"{FN} requires either order_id or client_order_id") - - if "time_to_live_ms" in params: - payload["time_to_live_ms"] = str(params["time_to_live_ms"]) - - path = get_grvt_endpoint(self.env, "CANCEL_ORDER") - self.logger.info( - f"{FN} Send cancel {payload=} for trading_account_id={self.get_trading_account_id()}" - ) - response: dict = self._auth_and_post(path, payload) - cancel_ack = response.get("result", {}).get("ack") - - if not cancel_ack: - self.logger.warning(f"{FN} failed to cancel order: {response=}") - return False - self.logger.info(f"{FN} Cancelled {response=}") - return True - - def set_derisk_mm_ratio(self, ratio: str) -> bool: - """ - Ccxt compliant signature - Set the Derisk to Maintenance marginb ratio for the account. - Private call requires authorization. - See [Set Derisk M M ratio](https://api-docs.grvt.io/trading_api/#set-derisk-m-m-ratio) - for details. - - Args: - ratio (Amount): The new derisking market making ratio. - - Returns: - True if the request was acknowledged by the exchange. False otherwise. - """ - FN = f"{self._clsname} set_derisk_mm_ratio" - self._check_account_auth() - payload: dict[str, str | dict] = self._get_set_derisk_mm_ratio_payload(str(ratio)) - path = get_grvt_endpoint(self.env, "SET_DERISK_MM_RATIO") - self.logger.info( - f"{FN} Send {payload=} for trading_account_id={self.get_trading_account_id()}" - ) - response: dict = self._auth_and_post(path, payload) - # set_ack = response.get("result", {}).get("ack") - # if not set_ack: - # self.logger.warning(f"{FN} failed to set derisk_mm_ratio: {response=}") - # return False - self.logger.info(f"{FN} Set derisk_mm_ratio {response=}") - return True - - def fetch_open_orders( - self, - symbol: str | None = None, - since: int | None = None, - limit: int | None = None, - params: dict = {}, - ) -> list[dict]: - """ - Ccxt compliant signature - Fetch open orders for the account.
- Private call requires authorization.
- See [Open orders](https://api-docs.grvt.io/trading_api/#open-orders) - for details.
. - - Args: - symbol: (str) get orders for this symbol only.
- since: ccxt-compliant argument, NOT SUPPORTED.
- limit: ccxt-compliant argument, NOT SUPPORTED.
- params: dictionary with parameters. Valid keys:
- `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
- `quote` (str): quote currency. Defaults to all.
- Returns: - a list of dictionaries, each dict represent an order.
- """ - self._check_account_auth() - # Prepare request payload - payload = self._get_payload_fetch_open_orders(symbol, params) - # Post payload and parse the response - path = get_grvt_endpoint(self.env, "GET_OPEN_ORDERS") - response: dict = self._auth_and_post(path, payload) - open_orders: list = response.get("result", []) - if symbol: - open_orders = [ - o for o in open_orders if o.get("legs") and o["legs"][0].get("instrument") == symbol - ] - return open_orders - - def fetch_order( - self, - id: str | None = None, - params: dict = {}, - ) -> dict: - """ - Ccxt compliant signature - Get Order status by order_id or client_order_id - Private call requires authorization.
- See [Open orders](https://api-docs.grvt.io/trading_api/#open-orders) - for details.
- Args: - id: (str) order_id to fetch.
- params: dictionary with parameters. Valid keys:
- `client_order_id` (int): client assigned order ID.
- Return: dict with order's details or {} if order was NOT found. - """ - self._check_account_auth() - payload = { - "sub_account_id": self.get_trading_account_id(), - } - if id: - payload["order_id"] = id - elif "client_order_id" in params: - payload["client_order_id"] = str(params["client_order_id"]) - else: - raise GrvtInvalidOrder( - f"{self._clsname} fetch_order() requires order_id or params['client_order_id']" - ) - path = get_grvt_endpoint(self.env, "GET_ORDER") - response: dict = self._auth_and_post(path, payload) - return response - - def fetch_order_history(self, params: dict = {}) -> dict: - """ - Ccxt compliant signature, HISTORICAL data.
- Get Order status by order_id or client_order_id - Private call requires authorization.
- See [Order History](https://api-docs.grvt.io/trading_api/#order-history) - for details.
- Args: - params: dictionary with parameters. Valid keys:
- `kind`: (str) - The kind filter to apply. Defaults to all kinds.
- `base`: (str) - The base currency filter. Defaults to all base currencies.
- `quote`: (str) - The quote currency filter. Defaults to all quote currencies.
- `expiration`: (int) The expiration time in nanoseconds. Defaults to all.
- `strike_price`: (str) The strike price to apply. Defaults to all strike prices.
- `limit`: (int) The limit to query for. Defaults to 500; Max 1000.
- `cursor`: (str) The cursor to use for pagination. If nil, return the first page.
- Return: a dictionary with keys: - `total` : total number of account history snapshots.
- `next` : cursor for the next page.
- `result` : a list of dictionaries, each dict represent an order state.
. - """ - self._check_account_auth() - payload = self._get_payload_fetch_order_history(params) - path = get_grvt_endpoint(self.env, "GET_ORDER_HISTORY") - response: dict = self._auth_and_post(path, payload) - return response - - def get_account_summary( - self, type: Literal["sub-account", "funding", "aggregated"] = "sub-account" - ) -> dict: - """ - Return: The account summary. - Private call requires authorization.
- See [Account Summary](https://api-docs.grvt.io/trading_api/#sub-account_summary) - for details.
- Returns: dictionary with account data.
. - """ - FN = f"{self._clsname} get_account_summary {type=}" - self._check_account_auth() - payload = {} - if type == "sub-account": - path = get_grvt_endpoint(self.env, "GET_ACCOUNT_SUMMARY") - payload = {"sub_account_id": self.get_trading_account_id()} - elif type == "funding": - path = get_grvt_endpoint(self.env, "GET_FUNDING_ACCOUNT_SUMMARY") - elif type == "aggregated": - path = get_grvt_endpoint(self.env, "GET_AGGREGATED_ACCOUNT_SUMMARY") - else: - raise GrvtInvalidOrder(f"{FN} Invalid account summary type {type}") - - response: dict = self._auth_and_post(path, payload=payload) - sub_account: dict = response.get("result", {}) - if not sub_account: - self.logger.info(f"{FN} No account summary for {path=} {payload=}") - return sub_account - - def fetch_balance( - self, type: Literal["sub-account", "funding", "aggregated"] = "sub-account" - ) -> dict: - """ - Ccxt compliant signature - Fetch balances for the account.
- Private call requires authorization.
- See [Account Summary](https://api-docs.grvt.io/trading_api/#sub-account_summary) - for details.
. - - Args: - type: (str) - The type of account to fetch balances for. Defaults to 'sub-account'. - Valid values: 'sub-account', 'funding', 'aggregated'. - - Returns: dictionary with ccxt-compliant balance data https://docs.ccxt.com/#/README?id=account-balance.
. - """ - account_summary: dict = self.get_account_summary(type) - return self._get_balances_from_account_summary(account_summary) - - def fetch_account_history(self, params: dict = {}, limit: int = 500) -> dict: - """ - HISTORICAL data.
- Get account history.
- Private call requires authorization.
- See [Account History](https://api-docs.grvt.io/trading_api/#account-history) - for details.
. - - Args: - limit: maximum number of account snapshots per page to fetch.
- params: dictionary with parameters. Valid keys:
- `start_time` (int): fetch orders since this timestamp in nanoseconds.
- `end_time` (int): fetch orders until this timestamp in nanoseconds.
- `cursor` (str): cursor for the pagination. If cursor is present then we ignore - `start_time` and `end_time`.
- Returns: - a dictionary with keys: - `total` : total number of account history snapshots.
- `next` : cursor for the next page.
- `result` : list of account history snapshots.
- """ - self._check_account_auth() - # Prepare request payload - payload = self._get_payload_fetch_account_history(limit, params) - # Post payload and parse the response - path = get_grvt_endpoint(self.env, "GET_ACCOUNT_HISTORY") - response: dict = self._auth_and_post(path, payload=payload) - return response - - def fetch_positions(self, symbols: list[str] = [], params={}): - """ - Ccxt compliant signature - Fetch positions for the account.
- Private call requires authorization.
- See [Positions](https://api-docs.grvt.io/trading_api/#positions) - for details.
. - - Args: - symbols: list(str) get positions for these symbols only.
- - Returns: list of dictionaries, each dict represent a position.
- """ - self._check_account_auth() - # Prepare request payload - payload = self._get_payload_fetch_positions(symbols, params) - # Post payload and parse the response - path = get_grvt_endpoint(self.env, "GET_POSITIONS") - response: dict = self._auth_and_post(path, payload) - positions: list = response.get("result", []) - if symbols: - self.logger.info(f"fetch_positions filter positions by {symbols=}") - positions = [p for p in positions if p.get("instrument") in symbols] - return positions - - def fetch_my_trades( - self, - symbol: str | None = None, - since: int | None = None, - limit: int | None = None, - params: dict = {}, - ) -> dict: - """ - Ccxt compliant signature, HISTORICAL data.
- Fetch past trades for the account.
- Private call requires authorization.
- See [Private Trade History](https://api-docs.grvt.io/trading_api/#private-trade-history) - for details.
. - - Args: - symbol: get trades for this symbol only.
- since: fetch trades since this timestamp in nanoseconds.
- limit: maximum number of trades to fetch.
- params: dictionary with parameters. Valid keys:
- `cursor` (str): cursor for the pagination. - If cursor is present then we ignore other filters.
- `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
- `quote` (str): quote currency. Default: 'USDT'.
- - Returns: - a dictionary with keys: - `total` : total number of account history snapshots.
- `next` : cursor for the next page.
- `result` : a list of dictionaries, each dict represent a trade.
- """ - self._check_account_auth() - # Prepare request payload - payload = self._get_payload_fetch_my_trades(symbol, since, limit, params) - # Post payload and parse the response - path = get_grvt_endpoint(self.env, "GET_FILL_HISTORY") - response: dict = self._auth_and_post(path, payload=payload) - if symbol: - # filter result by symbol - trades: list = response.get("result", []) - trades = [t for t in trades if t.get("instrument") == symbol] - response["result"] = trades - return response - - # **************** PUBLIC API CALLS - def load_markets(self) -> dict[str, dict]: - self.logger.info("load_markets START") - instruments = self.fetch_markets( - params={ - "kind": GrvtInstrumentKind.PERPETUAL, - # "base": "BTC", - # "quote": "USDT", - } - ) - if instruments: - self.markets = { - str(i.get("instrument", "")): i for i in instruments if i.get("instrument") - } - self.logger.info(f"load_markets: loaded {len(self.markets)} markets.") - else: - self.logger.warning("load_markets: No markets found.") - return self.markets - - def fetch_markets( - self, - params: dict = {}, - ) -> list[dict]: - """ - Ccxt compliant signature - Retrieve the list of all instruments of matching kind, base and quote - supported by the exchange. - - Params: dict with keys:
- `is_active` (bool) - defaults to True.
- `limit` (int) - defaiults to 20.
- `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
- `quote` (str): quote currency. Default: 'USDT'.
- - Returns: list of dictionaries per instrument with keys:
- `instrument`: symbol e.g. 'BTC_USDT_Perp'.
- `instrument_hash`: hashed symbol for order signing e.g. '0x030501'.
- `base`: base currency e.g. 'BTC'.
- `quote`: quote currency e.g. 'USDT'.
- `kind`: kind of instrument 'PERPETUAL'/'FUTURE'.
- 'base_decimals': size multiplier for order signing.
- `tick_size`: price tick size.
- `min_size`: minimum order size.
- """ - # Prepare request payload - payload = self._get_payload_fetch_markets(params) - # Make the POST request to get all instruments - path = get_grvt_endpoint(self.env, "GET_INSTRUMENTS") - response: dict = self._auth_and_post(path, payload) - return response.get("result", []) - - def fetch_all_markets( - self, - is_active: bool | None = True, - ) -> list[dict]: - """ - Retrieve the list of all instruments supported by the exchange.
- Params:
- `is_active` (bool) - defaults to True.
. - - Returns: list of dictionaries per instrument. See fetch_markets().
- """ - # Prepare request payload - payload = {"is_active": is_active} - # Make the POST request to get all instruments - path = get_grvt_endpoint(self.env, "GET_ALL_INSTRUMENTS") - response: dict = self._auth_and_post(path, payload) - return response.get("result", []) - - def fetch_market(self, symbol: str) -> dict: - """ - Retrieve the instrument object for a given symbol. - :param symbol: The symbol of the instrument. - """ - # Make the POST request to get all instruments - path = get_grvt_endpoint(self.env, "GET_INSTRUMENT") - response: dict = self._auth_and_post(path, payload={"instrument": symbol}) - return response.get("result", []) - - def fetch_ticker(self, symbol: str, params: dict = {}) -> dict: - """ - Ccxt compliant signature - Retrieve the ticker of a given symbol. - :param symbol: The instrument name. - :return: The ticker dictionary of the instrument. - """ - # {'event_time': '1724252426000000000', 'instrument': 'BTC_USDT_Perp', - # 'mark_price': '59373870996065', 'index_price': '59395287961367', - # 'last_price': '99000000000000', 'last_size': '9917000000', 'mid_price': '59569850000000', - # 'best_bid_price': '59866000000000', 'best_bid_size': '23705000000', 'best_ask_price': - # '592737000', 'best_ask_size': '21678', 'funding_rate_curr': 2544, 'funding_rate_avg': 0, - # 'interest_rate': 0, 'forward_price': '0', 'buy_volume_u': '401930000000', - # 'sell_volume_u': '1218289000000', 'buy_volume_q': '34637817515500', - # 'sell_volume_q': '68764000329900', 'high_price': '3435450000', 'low_price': '100000', - # 'open_price': '32554000000000', 'open_interest': '8174350000000', - # 'long_short_ratio': 1.0948905} - path = get_grvt_endpoint(self.env, "GET_TICKER") - response: dict = self._auth_and_post(path, payload={"instrument": symbol}) - return response.get("result", []) - - def fetch_mini_ticker(self, symbol: str) -> dict: - """ - Retrieve the mini-ticker of a given symbol. - :param symbol: The instrument name. - :return: The mini-ticker dictionary of the instrument. - """ - # {'event_time': '1724252426000000000', 'instrument': 'BTC_USDT_Perp', - # 'mark_price': '59373870996065', 'index_price': '59395287961367', - # 'last_price': '99000000000000', 'last_size': '9917000000', 'mid_price': '59569850000000', - # 'best_bid_price': '59866000000000', 'best_bid_size': '23705000000', 'best_ask_price': - # '59273700000000', 'best_ask_size': '21678000000'} - path = get_grvt_endpoint(self.env, "GET_MINI_TICKER") - response: dict = self._auth_and_post(path, payload={"instrument": symbol}) - return response.get("result", []) - - def fetch_order_book(self, symbol: str, limit: int = 10, params={}) -> dict: - """ - Ccxt compliant signature - Retrieve the order book of a given symbol. - :param symbol: The instrument name. - :return: The order book dictionary of the instrument. - """ - # {'event_time': '0', 'instrument': 'BTC_USDT_Perp', - # 'bids': [{'price': '100000000', 'size': '86353000000', 'num_orders': 4},...] - # 'asks': [{'price': '59273700000000', 'size': '21678000000', 'num_orders': 1}, ...] - payload = {"instrument": symbol, "aggregate": 1} - if limit: - payload["depth"] = limit - path = get_grvt_endpoint(self.env, "GET_ORDER_BOOK") - response: dict = self._auth_and_post(path, payload=payload) - if self.is_order_book_ccxt_format(): - # Convert to ccxt format - return self.convert_grvt_ob_to_ccxt(response.get("result", {})) - return response.get("result", {}) - - def fetch_recent_trades( - self, - symbol: str, - limit: int | None = None, - ) -> list: - """ - Retrieve recent trades of a given instrument. - :param symbol: The instrument name. - :return: The list of trades for the instrument. - """ - # List of {'event_time': '1724248876870635916', 'instrument': 'ETH_USDT_Perp', - # 'is_taker_buyer': True, 'size': '24000000000', 'price': '2600000000000', - # 'mark_price': '2591055564869', 'index_price': '2592459142472', 'interest_rate': 0, - # 'forward_price': '0', 'trade_id': '729726', 'venue': 'ORDERBOOK'} - payload: dict[str, str | int] = {"instrument": symbol} - if limit: - payload["limit"] = limit - path = get_grvt_endpoint(self.env, "GET_TRADES") - response: dict = self._auth_and_post(path, payload=payload) - return response.get("result", []) - - def fetch_trades( - self, - symbol: str, - since: int | None = None, - limit: int = 10, - params: dict = {}, - ) -> dict: - """ - Ccxt compliant signature, HISTORICAL data.
- Retrieve trade history of a given instrument. - :param symbol: The instrument name. - :return: dict with field 'result' containing a list of trades. - """ - # List of {'event_time': '1724248876870635916', 'instrument': 'ETH_USDT_Perp', - # 'is_taker_buyer': True, 'size': '24000000000', 'price': '2600000000000', - # 'mark_price': '2591055564869', 'index_price': '2592459142472', 'interest_rate': 0, - # 'forward_price': '0', 'trade_id': '729726', 'venue': 'ORDERBOOK'} - payload: dict = self._get_payload_fetch_trades( - symbol, - since=since, - limit=limit, - params=params, - ) - path: str = get_grvt_endpoint(self.env, "GET_TRADE_HISTORY") - response: dict = self._auth_and_post(path, payload=payload) - return response - - def fetch_funding_rate_history( - self, - symbol: str, - since: int = 0, - limit: int = 1_000, - params: dict = {}, - ) -> dict: - """ - Ccxt compliant signature, HISTORICAL data.
- Retrieve the funding rates history of a given instrument.
- Args: - symbol (str): The instrument name.
- since (int): fetch trades since this timestamp in nanoseconds.
- limit: int - maximum number of trades to fetch.
- params: dictionary with parameters. Valid keys:
- `cursor` (str): cursor for the pagination. - If cursor is present then we ignore other filters.
- `end_time` (int): end time in nanoseconds.
- Returns: - dict with field 'result' containing list of dictionaries repesenting funding rate - at a point in time with fields:
- `instrument` (str): instrument name.
- 'funding_rate' (float): funding rate.
- 'funding_time' (int): funding time in nanoseconds.
- 'mark_price' (float): mark price.
. - """ - payload: dict[str, str | int] = {"instrument": symbol} - if params.get("cursor"): - payload["cursor"] = params["cursor"] - else: - if since: - payload["start_time"] = str(since) - if params.get("end_time"): - payload["end_time"] = str(params["end_time"]) - if limit: - payload["limit"] = int(limit) - path = get_grvt_endpoint(self.env, "GET_FUNDING") - response: dict = self._auth_and_post(path, payload=payload) - return response - - def fetch_ohlcv( - self, - symbol: str, - timeframe="1m", - since: int = 0, - limit: int = 10, - params={}, - ) -> dict: - """ - Ccxt compliant signature, HISTORICAL data. - - Retrieve the ohlc history of a given instrument. - - Args: - symbol: The instrument name. - timeframe: The timeframe of the ohlc. See `ccxt_interval_to_grvt_candlestick_interval`. - since: fetch ohlc since this timestamp in nanoseconds. - limit: maximum number of ohlc to fetch. - params: dictionary with parameters. Valid keys: - `cursor` (str): cursor for the pagination. - If cursor is present then we ignore other filters. - `end_time` (int): end time in nanoseconds. - `candle_type` (str): candle type. Valid values: 'TRADE', 'MARK', 'INDEX'. - Returns: - dict with field 'result' containing a list of dictionaries, each dict representing a candlestick with fields:
- `instrument` - instrument name.
- `open_time` - start of interval in nanoseconds.
- `close_time` - end of interval in nanoseconds.
- `open` - opening price.
- `close` - closing price.
- `high` - highest price.
- `low` - lowest price.
- `volume_u` - volume in units.
- `volume_q` - volume in quote(USDT).
- `trades` - number of trades.
- """ - FN = f"{self._clsname} fetch_ohlcv" - payload: dict[str, Any] = self._get_payload_fetch_ohlcv( - symbol, timeframe, since, limit, params - ) - self.logger.info(f"{FN} {payload=}") - path = get_grvt_endpoint(self.env, "GET_CANDLESTICK") - return self._auth_and_post(path, payload=payload) - - # Vault Management APIs - def fetch_vault_manager_investor_history(self, only_own_investments: bool = False) -> dict: - payload: dict = self._get_fetch_vault_manager_investor_history_payload( - vault_id=self.get_trading_account_id(), - only_own_investments=only_own_investments, # Default to False to fetch all investments - ) - path: str = get_grvt_endpoint(self.env, "GET_VAULT_MANAGER_INVESTOR_HISTORY") - # path = "https://trades.grvt.io/full/v1/vault_manager_investor_history" - return self._auth_and_post(path, payload=payload) - - def fetch_vault_redemption_queue(self): - payload: dict = self._get_fetch_vault_redemption_queue_payload( - vault_id=self.get_trading_account_id() - ) - path: str = get_grvt_endpoint(self.env, "GET_VAULT_REDEMPTION_QUEUE") - # path = "https://trades.grvt.io/full/v1/vault_view_redemption_queue" - return self._auth_and_post(path, payload=payload) diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_base.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_base.py deleted file mode 100644 index 03e8530..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_base.py +++ /dev/null @@ -1,586 +0,0 @@ -# ruff: noqa: D200 -# ruff: noqa: D204 -# ruff: noqa: D205 -# ruff: noqa: D404 -# ruff: noqa: W291 -# ruff: noqa: D400 -# ruff: noqa: E501 - -import logging -import time -from datetime import datetime -from decimal import Decimal -from typing import Any, get_args - -from .grvt_ccxt_env import GrvtEnv -from .grvt_ccxt_types import ( - CandlestickInterval, - CandlestickType, - GrvtInvalidOrder, - GrvtOrderSide, - GrvtOrderType, - Num, - ccxt_interval_to_grvt_candlestick_interval, -) -from .grvt_ccxt_utils import get_kuq_from_symbol, sign_derisk_mm_ratio_request - -# COOKIE_REFRESH_INTERVAL_SECS = 60 * 60 # 30 minutes - - -class GrvtCcxtBase: - """ - GrvtCcxtBase is an abstract class for other Grvt Rest - and WebSocket connectivity classes. - - Args: - env: GrvtCcxtBase (DEV, TESTNET, PROD) - logger (logging.Logger, optional). Defaults to None. - parameters: (dict, optional). Dict with trading_account_id, private_key, api_key etc - defaults to empty. - """ - - def __init__( - self, - env: GrvtEnv, - logger: logging.Logger | None = None, - parameters: dict = {}, - order_book_ccxt_format: bool = False, - ): - """Initialize the GrvtCcxtBase part.""" - self.name: str = "GRVT" - self.logger = logger or logging.getLogger(__name__) - self.env: GrvtEnv = env - self._trading_account_id: str | None = parameters.get("trading_account_id") - self._private_key: str = str(parameters.get("private_key", "")) - self._api_key: str = str(parameters.get("api_key", "")) - self._order_book_ccxt_format: bool = order_book_ccxt_format - - self._path_return_value_map: dict = {} - self._cookie: dict | None = None - self.markets: dict = {} - self._clsname: str = type(self).__name__ - self.logger.info(f"GrvtCcxtBase: {self.env=}, {self._trading_account_id=}") - - def describe(self) -> list[str]: - """Returns the description of the class methods.""" - return [ - "create_order", - "create_limit_order", - "cancel_all_orders", - "cancel_order", - "fetch_balance", - "fetch_open_orders", - "fetch_order", - "fetch_order_history", - "get_account_summary", - "fetch_account_history", - "fetch_positions", - "fetch_my_trades", - "load_markets", - "fetch_markets", - "fetch_all_markets", - "fetch_market", - "fetch_ticker", - "fetch_mini_ticker", - "fetch_order_book", - "fetch_recent_trades", - "fetch_trades", - "fetch_funding_rate_history", - "fetch_ohlcv", - ] - - def get_trading_account_id(self) -> str: - """Returns the trading account id.""" - return self._trading_account_id or "" - - def is_order_book_ccxt_format(self) -> bool: - """Returns True if order book should be returned in CCXT format.""" - return self._order_book_ccxt_format - - def should_refresh_cookie(self) -> bool: - """ - Retuns: - True if this object has API key and the session cookie should be refreshed. - False - otherwise. - """ - if not self._api_key: - return False - time_till_expiration = None - if self._cookie and "expires" in self._cookie: - time_till_expiration = self._cookie["expires"] - time.time() - is_cookie_fresh = time_till_expiration is not None and time_till_expiration > 5 - if not is_cookie_fresh: - self.logger.info( - f"cookie should be refreshed {self._cookie=} now={time.time()}" - f" {time_till_expiration=} secs" - ) - return not is_cookie_fresh - - def get_path_return_value_map(self) -> dict: - """Returns the path return value map.""" - return self._path_return_value_map - - def get_endpoint_return_value(self, endpoint: str) -> dict: - """Returns the return value for the endpoint.""" - return self._path_return_value_map.get(endpoint, {}) - - def was_path_called(self, path: str) -> bool: - """Returns True if the path was called.""" - return path in self._path_return_value_map - - # PRIVATE API CALLS - - def _check_order_arguments( - self, order_type: GrvtOrderType, side: GrvtOrderSide, amount: Num, price: Num - ) -> None: - FN = f"{self._clsname} _check_order_arguments" - if order_type not in get_args(GrvtOrderType): - raise GrvtInvalidOrder(f"{FN}: order_type should be one of {get_args(GrvtOrderType)}") - if side not in get_args(GrvtOrderSide): - raise GrvtInvalidOrder(f"{FN}: side should be one of {get_args(GrvtOrderSide)}") - if order_type == "limit": - if price is None or Decimal(price) <= Decimal("0"): - raise GrvtInvalidOrder(f"{FN}: requires a price argument for a limit order") - elif order_type == "market": - if price: - raise GrvtInvalidOrder( - f"{FN}: should not have a positive price argument for a market order" - ) - if not amount or Decimal(amount) < Decimal("0"): - raise GrvtInvalidOrder(f"{FN}: amount should be above 0") - - def _check_account_auth(self) -> bool: - if not self.get_trading_account_id(): - raise GrvtInvalidOrder(f"{self._clsname}: this action requires a trading_account_id") - return True - - def _check_valid_symbol(self, symbol: str) -> bool: - if not self.markets: - raise GrvtInvalidOrder(f"{self._clsname}: markets not loaded") - market = self.markets.get(symbol) - if not market: - raise GrvtInvalidOrder(f"{self._clsname}: {symbol=} not found") - return True - - def _get_payload_cancel_all_orders( - self, - params: dict = {}, - ) -> dict: - """ - Prepares payload for fetch_order_history() method.
. - - Args: - params: (dict) with possible keys as:.
- `kind`: (str) - The kind filter to apply. Defaults to all kinds.
- `base`: (str) - The base currency filter. Defaults to all base currencies.
- `quote`: (str) - The quote currency filter. Defaults to all quote currencies.
- Returns: a dictionary with a payload for Rest API call to cancel all orders.
- """ - payload: dict[str, str | int | bool | list] = { - "sub_account_id": str(self.get_trading_account_id()) - } - - if "kind" in params: - payload["kind"] = [params["kind"]] - if "base" in params: - payload["base"] = [params["base"]] - if "quote" in params: - payload["quote"] = [params["quote"]] - return payload - - def _get_payload_fetch_markets(self, params: dict) -> dict: - payload: dict[str, str | int | bool | list] = {} - if params.get("kind"): - payload["kind"] = [params.get("kind")] - if params.get("base"): - payload["base"] = [params.get("base")] - if params.get("quote"): - payload["quote"] = [params.get("quote")] - payload["limit"] = int(params.get("limit", 1_000)) - payload["is_active"] = bool(params.get("is_active", True)) - return payload - - def _get_payload_fetch_my_trades( - self, - symbol: str | None = None, - since: int | None = None, - limit: int | None = None, - params: dict = {}, - ) -> dict: - """ - Prepares payload for fetch_my_trades() method.
. - - Args: - symbol: get trades for this symbol only.
- since: fetch trades since this timestamp in nanoseconds.
- limit: maximum number of trades to fetch.
- params: dictionary with parameters. Valid keys:
- `cursor` (str): cursor for the pagination. - If cursor is present then we ignore other filters.
- `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
- `quote` (str): quote currency. Default: 'USDT'.
- `end_time` (int): fetch trades until this timestamp in nanoseconds.
- - Returns: - a dictionary with a payload for Rest API call to fetch trades.
- """ - payload: dict[str, str | int | list] = { - "sub_account_id": str(self.get_trading_account_id()) - } - if params.get("cursor"): - payload["cursor"] = params["cursor"] - else: - if symbol: - payload["instrument"] = symbol - else: - if "kind" in params: - payload["kind"] = [params["kind"]] - if "base" in params: - payload["base"] = [params["base"]] - if "quote" in params: - payload["quote"] = [params["quote"]] - if since: - payload["start_time"] = str(since) - if params.get("end_time"): - payload["end_time"] = str(params["end_time"]) - if limit: - payload["limit"] = int(limit) - return payload - - def _get_payload_fetch_trades( - self, - symbol: str, - since: int | None = None, - limit: int = 1_000, - params: dict = {}, - ) -> dict: - """ - Prepares payload for fetch_trades() method.
. - - Args: - symbol: get trades for this symbol only.
- since: fetch trades since this timestamp in nanoseconds.
- limit: maximum number of trades to fetch.
- params: dictionary with parameters. Valid keys:
- `cursor` (str): cursor for the pagination. - If cursor is present then we ignore other filters.
- `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
- `quote` (str): quote currency. Default: 'USDT'.
- - Returns: - a dictionary with a payload for Rest API call to fetch trades.
- """ - payload: dict[str, str | int] = { - "sub_account_id": str(self.get_trading_account_id()), - "instrument": symbol, - } - if params.get("cursor"): - payload["cursor"] = params["cursor"] - else: - if since: - payload["start_time"] = str(since) - if params.get("end_time"): - payload["end_time"] = str(params["end_time"]) - payload["limit"] = limit - return payload - - def _get_payload_fetch_account_history( - self, - # since: int | None = None, - limit: int = 500, - params: dict = {}, - ) -> dict: - """ - Prepares payload for fetch_account_history() method.
. - - Args: - limit: maximum number of trades to fetch.
- params: dictionary with parameters. Valid keys:
- `start_time` (int): fetch orders since this timestamp in nanoseconds.
- `end_time` (int): fetch orders until this timestamp in nanoseconds.
- `cursor` (int):cursor for the pagination. If cursor is present then we ignore - `start_time` and `end_time`.
- Returns: - a dictionary with a payload for Rest API call to fetch account history.
- """ - payload: dict[str, str | int] = {"sub_account_id": str(self.get_trading_account_id())} - - if params.get("cursor"): - payload["cursor"] = params["cursor"] - else: - start_time = params.get("start_time") - end_time = params.get("end_time") - if start_time: - payload["start_time"] = str(start_time) - if end_time: - payload["end_time"] = str(end_time) - payload["limit"] = limit | 500 - return payload - - def _get_payload_fetch_positions(self, symbols: list[str] = [], params={}) -> dict: - """ - Prepares payload for fetch_positions() method.
. - - Args: - symbols: list(str) get positions for these symbols only.
- - Returns: a dictionary with a payload for Rest API call to fetch positions.
- """ - payload: dict[str, str | int | bool | list] = { - "sub_account_id": str(self.get_trading_account_id()) - } - if symbols: - ks, us, qs = [], [], [] - for symbol in symbols: - try: - k, u, q = get_kuq_from_symbol(symbol) - ks.append(k) - us.append(u) - qs.append(q) - except Exception as e: - raise GrvtInvalidOrder(f"Invalid symbol {symbol} in fetch_positions {e}") - payload["kind"] = list(set(ks)) - payload["base"] = list(set(us)) - payload["quote"] = list(set(qs)) - else: - if "kind" in params: - payload["kind"] = [params["kind"]] - if "base" in params: - payload["base"] = [params["base"]] - if "quote" in params: - payload["quote"] = [params["quote"]] - return payload - - def _get_payload_fetch_order_history( - self, - params: dict, - ) -> dict: - """ - Prepares payload for fetch_order_history() method.
. - - Args: - params: (dict) with possible keys as:.
- `kind`: (str) - The kind filter to apply. Defaults to all kinds.
- `base`: (str) - The base currency filter. Defaults to all base currencies.
- `quote`: (str) - The quote currency filter. Defaults to all quote currencies.
- `expiration`: (int) The expiration time in nanoseconds. Defaults to all.
- `strike_price`: (str) The strike price to apply. Defaults to all strike prices.
- `limit`: (int) The limit to query for. Defaults to 500; Max 1000.
- `cursor`: (str) The cursor to use for pagination. If nil, return the first page.
- Returns: a dictionary with a payload for Rest API call to fetch order history.
- """ - payload: dict[str, str | int | bool | list] = { - "sub_account_id": str(self.get_trading_account_id()) - } - if "limit" in params: - payload["limit"] = params["limit"] - if params.get("cursor"): - payload["cursor"] = params["cursor"] - else: - if "kind" in params: - payload["kind"] = [params["kind"]] - if "base" in params: - payload["base"] = [params["base"]] - if "quote" in params: - payload["quote"] = [params["quote"]] - if "expiration" in params: - payload["expiration"] = [params["expiration"]] - if "strike_price" in params: - payload["strike_price"] = [params["strike_price"]] - return payload - - def _get_payload_fetch_open_orders( - self, - symbol: str | None = None, - params: dict = {}, - ) -> dict: - """ - Prepares payload for fetch_order_history() method.
. - - Args: - params: (dict) with possible keys as:.
- `kind`: (str) - The kind filter to apply. Defaults to all kinds.
- `base`: (str) - The base currency filter. Defaults to all base currencies.
- `quote`: (str) - The quote currency filter. Defaults to all quote currencies.
- Returns: a dictionary with a payload for Rest API call to fetch order history.
- """ - payload: dict[str, str | int | bool | list] = { - "sub_account_id": str(self.get_trading_account_id()) - } - if symbol: - try: - k, u, q = get_kuq_from_symbol(symbol) - payload["kind"] = [k] - payload["base"] = [u] - payload["quote"] = [q] - except Exception as e: - raise GrvtInvalidOrder(f"Invalid symbol {symbol} in fetch_open_orders {e}") - else: - if "kind" in params: - payload["kind"] = [params["kind"]] - if "base" in params: - payload["base"] = [params["base"]] - if "quote" in params: - payload["quote"] = [params["quote"]] - return payload - - def _get_payload_fetch_ohlcv( - self, - symbol: str, - timeframe: str, - since: int, - limit: int, - params={}, - ) -> dict: - """ - Prepares payload for fetch_ohlcv() method.
. - - Args: - symbol: The instrument name.
- timeframe: The timeframe of the ohlc. - See `ccxt_interval_to_grvt_candlestick_interval`.
- since: fetch ohlc since this timestamp in nanoseconds.
- limit: maximum number of ohlc to fetch.
- params: dictionary with parameters. Valid keys:
- `cursor` (str): cursor for the pagination. - If cursor is present then we ignore other filters.
- `end_time` (int): end time in nanoseconds.
- `candle_type` (str): candle type. Valid values: 'TRADE', 'MARK', 'INDEX'.
- - Returns: a dictionary with a payload for Rest API call to fetch_ohlcv.
- See [Candlestick] (https://api-docs.grvt.io/market_data_api/#candlestick_1) - for more details.
- """ - if timeframe not in ccxt_interval_to_grvt_candlestick_interval: - raise ValueError(f"Invalid timeframe {timeframe}") - - interval: CandlestickInterval = ccxt_interval_to_grvt_candlestick_interval[timeframe] - payload: dict[str, str | int | bool | list] = {"instrument": symbol} - if params.get("cursor"): - payload["cursor"] = params["cursor"] - else: - if interval: - payload["interval"] = interval.value - candle_type = CandlestickType.TRADE - if "candle_type" in params: - candle_type = CandlestickType[params["candle_type"]] - payload["type"] = candle_type.value - if since: - payload["start_time"] = str(since) - if "end_time" in params: - payload["end_time"] = str(params["end_time"]) - if limit: - payload["limit"] = int(limit) - return payload - - def _get_balances_from_account_summary(self, account_summary: dict) -> dict: - balances: dict = {} - balances["info"] = account_summary.get("spot_balances", []) - balances["timestamp"] = int(int(account_summary.get("event_time", 0)) / 1_000_000) - balances["datetime"] = ( - datetime.fromtimestamp(balances["timestamp"] / 1_000).strftime("%Y-%m-%dT%H:%M:%S.%f")[ - :-3 - ] - + "Z" - ) - balances["total"] = {} - balances["free"] = {} - balances["used"] = {} - for currency_balance in account_summary.get("spot_balances", []): - if not currency_balance or not isinstance(currency_balance, dict): - continue - currency: str = currency_balance.get("currency", "") - if not currency: - continue - balances[currency] = {"total": currency_balance.get("balance", "0.0")} - balances["total"][currency] = balances[currency]["total"] - if currency == "USDT": - balances[currency]["free"] = account_summary.get("available_balance", "0.0") - balances[currency]["used"] = str( - Decimal(balances[currency]["total"]) - Decimal(balances[currency]["free"]) - ) - else: - balances[currency]["free"] = balances[currency]["total"] - balances[currency]["used"] = "0.0" - - balances["free"][currency] = balances[currency]["free"] - balances["used"][currency] = balances[currency]["used"] - return balances - - def _get_set_derisk_mm_ratio_payload( - self, - ratio: str, - ) -> dict[str, str | dict]: - """ - Returns a payload for setting the derisking market making ratio. - """ - payload: dict[str, str | dict] = { - "sub_account_id": self.get_trading_account_id(), - "ratio": str(ratio), - } - signature: dict = sign_derisk_mm_ratio_request( - self.env, int(self.get_trading_account_id()), str(ratio), self._private_key - ) - payload["signature"] = signature - return payload - - def convert_grvt_ob_to_ccxt(self, order_book: dict) -> dict: - """ - Converts GRVT-specific order book format to CCXT format. - """ - ob_time_ms: int = int(order_book["event_time"]) // 1_000_000 - ccxt_ob = { - "symbol": order_book["instrument"], - "bids": [], - "asks": [], - "timestamp": ob_time_ms, - "datetime": datetime.fromtimestamp(ob_time_ms / 1_000).strftime("%Y-%m-%dT%H:%M:%S.%f")[ - :-3 - ] - + "Z", - "nonce": int(order_book["event_time"]), - } - ccxt_ob["bids"] = [[bid["price"], bid["size"]] for bid in order_book["bids"]] - ccxt_ob["asks"] = [[ask["price"], ask["size"]] for ask in order_book["asks"]] - return ccxt_ob - - # Vault Management APIs - def _get_fetch_vault_manager_investor_history_payload( - self, - vault_id: str, - only_own_investments: bool = False, - ) -> dict: - """ - Prepares payload for fetch_vault_manager_investor_history() method.
. - - Args: - vault_id: The vault id to fetch history for.
- only_own_investments: If True, fetch only investments by the manager.
- - Returns: - A dictionary with a payload for Rest API call to fetch vault investor history. - """ - payload: dict[str, str | bool] = { - "vault_id": vault_id, - "only_own_investments": only_own_investments, - } - return payload - - def _get_fetch_vault_redemption_queue_payload( - self, - vault_id: str, - ) -> dict: - """ - Prepares payload for fetch_vault_redemption_queue() method.
. - - Args: - vault_id: The vault id to fetch redemption queue for.
- - Returns: - A dictionary with a payload for Rest API call to fetch vault redemption queue. - """ - return {"vault_id": vault_id} diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_env.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_env.py deleted file mode 100644 index 1771ba0..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_env.py +++ /dev/null @@ -1,195 +0,0 @@ -# ruff: noqa: D200 -# ruff: noqa: D204 -# ruff: noqa: D205 -# ruff: noqa: D404 -# ruff: noqa: W291 -# ruff: noqa: D400 -# ruff: noqa: E501 - -import os -from enum import Enum - - -class GrvtEnv(str, Enum): - PROD = "prod" - TESTNET = "testnet" - STAGING = "staging" - DEV = "dev" - -# GrvtEndpointType defines the root path for a family of endpoints -class GrvtEndpointType(str, Enum): - EDGE = "edge" - TRADE_DATA = "tdg" - MARKET_DATA = "mdg" - - -class GrvtWSEndpointType(str, Enum): - TRADE_DATA = "tdg" - MARKET_DATA = "mdg" - TRADE_DATA_RPC_FULL = "tdg_rpc_full" - MARKET_DATA_RPC_FULL = "mdg_rpc_full" - - -END_POINT_VERSION = os.getenv("GRVT_END_POINT_VERSION", "v1") - - -def get_grvt_endpoint_domains(env_name: str) -> dict[GrvtEndpointType, str]: - if env_name == GrvtEnv.PROD.value: - return { - GrvtEndpointType.EDGE: "https://edge.grvt.io", - GrvtEndpointType.TRADE_DATA: "https://trades.grvt.io", - GrvtEndpointType.MARKET_DATA: "https://market-data.grvt.io", - } - if env_name == GrvtEnv.TESTNET.value: - return { - GrvtEndpointType.EDGE: f"https://edge.{env_name}.grvt.io", - GrvtEndpointType.TRADE_DATA: f"https://trades.{env_name}.grvt.io", - GrvtEndpointType.MARKET_DATA: f"https://market-data.{env_name}.grvt.io", - } - if env_name == GrvtEnv.STAGING.value: - return { - GrvtEndpointType.EDGE: f"https://edge.{env_name}.gravitymarkets.io", - GrvtEndpointType.TRADE_DATA: f"https://trades.{env_name}.gravitymarkets.io", - GrvtEndpointType.MARKET_DATA: f"https://market-data.{env_name}.gravitymarkets.io", - } - if env_name == GrvtEnv.DEV.value: - return { - GrvtEndpointType.EDGE: f"https://edge.{env_name}.gravitymarkets.io", - GrvtEndpointType.TRADE_DATA: f"https://trades.{env_name}.gravitymarkets.io", - GrvtEndpointType.MARKET_DATA: f"https://market-data.{env_name}.gravitymarkets.io", - } - return {} - - -def get_grvt_ws_endpoint( - env: str, - endpoint_type: GrvtWSEndpointType, -) -> str: - """Returns string pointing to WS endpoint for given environment and endpoint type.""" - if env == GrvtEnv.PROD.value: - return { - GrvtWSEndpointType.TRADE_DATA: "wss://trades.grvt.io/ws", - GrvtWSEndpointType.MARKET_DATA: "wss://market-data.grvt.io/ws", - GrvtWSEndpointType.TRADE_DATA_RPC_FULL: "wss://trades.grvt.io/ws/full", - GrvtWSEndpointType.MARKET_DATA_RPC_FULL: "wss://market-data.grvt.io/ws/full", - }.get(endpoint_type, "") - if env == GrvtEnv.TESTNET.value: - return { - GrvtWSEndpointType.TRADE_DATA: f"wss://trades.{env}.grvt.io/ws", - GrvtWSEndpointType.MARKET_DATA: f"wss://market-data.{env}.grvt.io/ws", - GrvtWSEndpointType.TRADE_DATA_RPC_FULL: f"wss://trades.{env}.grvt.io/ws/full", - GrvtWSEndpointType.MARKET_DATA_RPC_FULL: f"wss://market-data.{env}.grvt.io/ws/full", - }.get(endpoint_type, "") - if env == GrvtEnv.STAGING.value: - return { - GrvtWSEndpointType.TRADE_DATA: f"wss://trades.{env}.gravitymarkets.io/ws", - GrvtWSEndpointType.MARKET_DATA: f"wss://market-data.{env}.gravitymarkets.io/ws", - GrvtWSEndpointType.TRADE_DATA_RPC_FULL: f"wss://trades.{env}.gravitymarkets.io/ws/full", - GrvtWSEndpointType.MARKET_DATA_RPC_FULL: f"wss://market-data.{env}.gravitymarkets.io/ws/full", - }.get(endpoint_type, "") - if env == GrvtEnv.DEV.value: - return { - GrvtWSEndpointType.TRADE_DATA: f"wss://trades.{env}.gravitymarkets.io/ws", - GrvtWSEndpointType.MARKET_DATA: f"wss://market-data.{env}.gravitymarkets.io/ws", - GrvtWSEndpointType.TRADE_DATA_RPC_FULL: f"wss://trades.{env}.gravitymarkets.io/ws/full", - GrvtWSEndpointType.MARKET_DATA_RPC_FULL: f"wss://market-data.{env}.gravitymarkets.io/ws/full", - }.get(endpoint_type, "") - return "" - -# Mapping of WS stream names to DEFAULT endpoint types -GRVT_WS_STREAMS = { - # ******* Market Data ******** - "mini.s": GrvtWSEndpointType.MARKET_DATA, - "mini.d": GrvtWSEndpointType.MARKET_DATA, - "ticker.s": GrvtWSEndpointType.MARKET_DATA, - "ticker.d": GrvtWSEndpointType.MARKET_DATA, - "book.s": GrvtWSEndpointType.MARKET_DATA, - "book.d": GrvtWSEndpointType.MARKET_DATA, - "trade": GrvtWSEndpointType.MARKET_DATA, - "candle": GrvtWSEndpointType.MARKET_DATA, - # ******* Trade Data ******** - "order": GrvtWSEndpointType.TRADE_DATA, - "state": GrvtWSEndpointType.TRADE_DATA, - "cancel": GrvtWSEndpointType.TRADE_DATA, - "position": GrvtWSEndpointType.TRADE_DATA, - "fill": GrvtWSEndpointType.TRADE_DATA, - "transfer": GrvtWSEndpointType.TRADE_DATA, - "deposit": GrvtWSEndpointType.TRADE_DATA, - "withdrawal": GrvtWSEndpointType.TRADE_DATA, -} - - -def is_trading_ws_endpoint(end_point_type: GrvtWSEndpointType) -> bool: - return end_point_type in [ - GrvtWSEndpointType.TRADE_DATA, - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, - ] - - -# "wss://market-data.testnet.grvt.io/ws" -# wss://trades.testnet.grvt.io/ws -# GRVT_ENDPOINTS defines the endpoint paths grouped by endpoint type -GRVT_ENDPOINTS = { - GrvtEndpointType.EDGE: { - "GRAPHQL": "query", - "AUTH": "auth/api_key/login", - }, - GrvtEndpointType.TRADE_DATA: { - "CREATE_ORDER": f"full/{END_POINT_VERSION}/create_order", - "CANCEL_ALL_ORDERS": f"full/{END_POINT_VERSION}/cancel_all_orders", - "CANCEL_ORDER": f"full/{END_POINT_VERSION}/cancel_order", - "GET_OPEN_ORDERS": f"full/{END_POINT_VERSION}/open_orders", - "GET_ACCOUNT_SUMMARY": f"full/{END_POINT_VERSION}/account_summary", - "GET_FUNDING_ACCOUNT_SUMMARY": f"full/{END_POINT_VERSION}/funding_account_summary", - "GET_AGGREGATED_ACCOUNT_SUMMARY": f"full/{END_POINT_VERSION}/aggregated_account_summary", - "GET_ACCOUNT_HISTORY": f"full/{END_POINT_VERSION}/account_history", - "GET_POSITIONS": f"full/{END_POINT_VERSION}/positions", - "GET_ORDER": f"full/{END_POINT_VERSION}/order", - "GET_ORDER_HISTORY": f"full/{END_POINT_VERSION}/order_history", - "GET_FILL_HISTORY": f"full/{END_POINT_VERSION}/fill_history", - "SET_DERISK_MM_RATIO": f"full/{END_POINT_VERSION}/set_derisk_mm_ratio", - "GET_VAULT_MANAGER_INVESTOR_HISTORY": f"full/{END_POINT_VERSION}/vault_manager_investor_history", - "GET_VAULT_REDEMPTION_QUEUE": f"full/{END_POINT_VERSION}/vault_view_redemption_queue", - }, - GrvtEndpointType.MARKET_DATA: { - "GET_ALL_INSTRUMENTS": f"full/{END_POINT_VERSION}/all_instruments", - "GET_INSTRUMENTS": f"full/{END_POINT_VERSION}/instruments", - "GET_INSTRUMENT": f"full/{END_POINT_VERSION}/instrument", - "GET_TICKER": f"full/{END_POINT_VERSION}/ticker", - "GET_MINI_TICKER": f"full/{END_POINT_VERSION}/mini", - "GET_ORDER_BOOK": f"full/{END_POINT_VERSION}/book", - "GET_TRADES": f"full/{END_POINT_VERSION}/trade", - "GET_TRADE_HISTORY": f"full/{END_POINT_VERSION}/trade_history", - "GET_FUNDING": f"full/{END_POINT_VERSION}/funding", - "GET_CANDLESTICK": f"full/{END_POINT_VERSION}/kline", - }, -} - - -def get_grvt_endpoint(environment: GrvtEnv, end_point: str) -> str: - # if end_point == "GET_ALL_INSTRUMENTS": - # return "https://market-data.testnet.grvt.io/full/v1/instruments" - endpoint_domains = get_grvt_endpoint_domains(environment.value) - for endpoints_type, endpoints in GRVT_ENDPOINTS.items(): - if end_point in endpoints: - return f"{endpoint_domains[endpoints_type]}/{endpoints[end_point]}" - return "" - - -def get_all_grvt_endpoints(environment: GrvtEnv) -> dict[str, str]: - endpoint_domains = get_grvt_endpoint_domains(environment.value) - endpoints = {} - for endpoints_type, endpoints_map in GRVT_ENDPOINTS.items(): - for endpoint, path in endpoints_map.items(): - endpoints[endpoint] = f"{endpoint_domains[endpoints_type]}/{path}" - return endpoints - - -CHAIN_IDS = { - GrvtEnv.DEV.value: 327, - GrvtEnv.STAGING.value: 327, - GrvtEnv.TESTNET.value: 326, - GrvtEnv.PROD.value: 325, -} - -######################################################## diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_logging_selector.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_logging_selector.py deleted file mode 100644 index 40ddd72..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_logging_selector.py +++ /dev/null @@ -1,32 +0,0 @@ -import logging -import os -import sys -from datetime import datetime - -LOG_FILE = os.getenv("LOG_FILE", "FALSE").upper() -GRVT_ENV = os.getenv("GRVT_ENV") - -if LOG_FILE == "TRUE": - LOG_TIMESTAMP = datetime.now().strftime("%Y_%m_%d_%H_%M_%S") - fn = sys.argv[0].split("/")[-1] - fn_base = fn.split(".")[0] - if GRVT_ENV: - filename = f"logs/{fn_base}_{GRVT_ENV}_{LOG_TIMESTAMP}.log" - else: - filename = f"logs/{fn_base}_{LOG_TIMESTAMP}.log" - os.makedirs("logs", exist_ok=True) - logging.basicConfig( - filename=filename, - level=os.getenv("LOGGING_LEVEL", "INFO"), - format="%(asctime)s.%(msecs)03d | %(levelname)s | %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - ) - logger = logging.getLogger(__name__) - logger.info(f"Using FILE logger {LOG_FILE=}") -else: - logging.basicConfig( - level=os.getenv("LOGGING_LEVEL", "INFO"), - format="%(asctime)s - %(levelname)s - %(message)s", - ) - logger = logging.getLogger(__name__) - logger.info(f"Using CONSOLE logger {LOG_FILE=}") diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_pro.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_pro.py deleted file mode 100644 index a50f0e8..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_pro.py +++ /dev/null @@ -1,841 +0,0 @@ -# ruff: noqa: D200 -# ruff: noqa: D204 -# ruff: noqa: D205 -# ruff: noqa: D404 -# ruff: noqa: W291 -# ruff: noqa: D400 -# ruff: noqa: E501 - -import asyncio -import json -import logging -from typing import Literal - -import aiohttp - -from .grvt_ccxt_base import GrvtCcxtBase - -# import requests -# from env import ENDPOINTS -from .grvt_ccxt_env import GrvtEnv, get_grvt_endpoint -from .grvt_ccxt_types import ( - Amount, - GrvtInstrumentKind, - GrvtInvalidOrder, - GrvtOrderSide, - GrvtOrderType, - Num, -) -from .grvt_ccxt_utils import ( - EnumEncoder, - GrvtOrder, - get_cookie_with_expiration, - get_cookie_with_expiration_async, - get_grvt_order, - get_order_payload, -) - - -class GrvtCcxtPro(GrvtCcxtBase): - """ - GrvtCcxtPro class to interact with Grvt Rest API and WebSockets in asynchronous mode. - - Args: - env: GrvtCcxtPro (DEV, TESTNET, PROD) - parameters: dict with trading_account_id, private_key, api_key etc - - Examples: - >>> from grvt_api_pro import GrvtCcxtPro - >>> from grvt_env import GrvtEnv - >>> grvt = GrvtCcxtPro(env=GrvtEnv.TESTNET) - >>> await grvt.fetch_markets() - """ - - def __init__( - self, - env: GrvtEnv, - logger: logging.Logger | None = None, - parameters: dict = {}, - order_book_ccxt_format: bool = False, - ): - """Initialize the GrvtCcxt instance.""" - super().__init__(env, logger, parameters, order_book_ccxt_format) - self._clsname: str = type(self).__name__ - self._session = aiohttp.ClientSession(headers={"Content-Type": "application/json"}) - # Force sync call to get cookie here - self._cookie = get_cookie_with_expiration( - get_grvt_endpoint(self.env, "AUTH"), self._api_key - ) - self.update_session_with_cookie() - - def __del__(self): - """Close the aiohttp session when the instance is deleted.""" - self.logger.info(f"{self._clsname} __del__() called") - if self._session: - self.logger.info(f"{self._clsname} closing session") - asyncio.get_running_loop().create_task(self._session.close()) - - def update_session_with_cookie(self) -> None: - if self._cookie: - self._session.cookie_jar.update_cookies({"gravity": self._cookie["gravity"]}) - if self._cookie["X-Grvt-Account-Id"]: - self._session.headers.update( - {"X-Grvt-Account-Id": self._cookie["X-Grvt-Account-Id"]} - ) - self.logger.info( - f"update_session_with_cookie {self._cookie=} {self._session.cookie_jar=}" - f" {self._session.headers=}" - ) - - async def refresh_cookie(self) -> dict | None: - """Refresh the session cookie.""" - if not self.should_refresh_cookie(): - return self._cookie - path: str = get_grvt_endpoint(self.env, "AUTH") - self._cookie = await get_cookie_with_expiration_async(path, self._api_key) - self._path_return_value_map[path] = self._cookie - self.update_session_with_cookie() - return self._cookie - - # PRIVATE API CALLS - async def _auth_and_post(self, path: str, payload: dict) -> dict: - FN = f"{self._clsname} _auth_and_post {path=}" - MAX_LEN_TO_LOG = 1280 - response: dict = {} - if not path: - self.logger.warning(f"{FN} Invalid path {path=} {payload=}") - raise GrvtInvalidOrder(f"{FN} Invalid path {path=} {payload=}") - # Always see if need to referesh cookie before sending a request - await self.refresh_cookie() - payload_json = json.dumps(payload, cls=EnumEncoder) - self.logger.info(f"{FN} {payload=}\n{payload_json=}") - return_text: str = "" - async with self._session.post( - url=path, - data=payload_json, - headers={"Content-Type": "application/json"}, - timeout=5, - ) as return_value: - return_text: str = "" - try: - return_text = await return_value.text() - response = await return_value.json(content_type="application/json") - except Exception as err: - self.logger.warning( - f"{FN} Unable to parse {return_value=} as " - f" json(content_type='application/json'). {err=}" - ) - if not return_value.ok: - self.logger.warning(f"{FN} {payload_json=}\n{return_value=}\n{response=}") - else: - if len(return_text) > MAX_LEN_TO_LOG: - self.logger.debug(f"{FN} OK {return_value=} response={response}") - self.logger.info(f"{FN} OK {return_value=} response=**TOO LONG**") - else: - self.logger.info(f"{FN} OK {return_value=} response={response}") - self._path_return_value_map[path] = response - return response or {} - - async def _create_grvt_order(self, order: GrvtOrder) -> dict: - """ - Send a GrvtOrder object to the exchange. - :param order: The GrvtOrder object. - Return: dictionary representing the order response. - """ - FN = f"{self._clsname} _create_grvt_order cloid:{order.metadata.client_order_id}" - order_payload = get_order_payload( - order, - private_key=self._private_key, - env=self.env, - instruments=self.markets, - ) - path = get_grvt_endpoint(self.env, "CREATE_ORDER") - self.logger.info(f"{FN} {path=} {order_payload=}") - response: dict = await self._auth_and_post(path, payload=order_payload) - if response.get("result") is None: - self.logger.error(f"Error creating order, {response}") - return {} - self.logger.info( - f"{FN} Order created:" - f"{response.get('result', {}).get('metadata', {}).get('client_order_id')}" - ) - return response.get("result", {}) - - def _get_order_with_validations( - self, - symbol: str, - order_type: GrvtOrderType, - side: GrvtOrderSide, - amount: Amount, - price: Num = None, - params: dict = {}, - ) -> GrvtOrder: - self._check_account_auth() - self._check_valid_symbol(symbol) - # Validate order fields - self._check_order_arguments(order_type, side, amount, price) - # create GrvtOrder object - order_duration_secs = params.get("order_duration_secs", 24 * 60 * 60) - return get_grvt_order( - sub_account_id=self.get_trading_account_id(), - symbol=symbol, - order_type=order_type, - side=side, - amount=amount, - limit_price=price, - order_duration_secs=order_duration_secs, - params=params, - ) - - async def create_order( - self, - symbol: str, - order_type: GrvtOrderType, - side: GrvtOrderSide, - amount: Amount, - price: Num = None, - params={}, - ) -> dict: - """Ccxt compliant signature.""" - order = self._get_order_with_validations(symbol, order_type, side, amount, price, params) - return await self._create_grvt_order(order) - - async def create_limit_order( - self, - symbol: str, - side: GrvtOrderSide, - amount: Amount, - price: Num = None, - params={}, - ) -> dict: - return await self.create_order(symbol, "limit", side, amount, price, params) - - async def cancel_all_orders( - self, - params: dict = {}, - ) -> bool: - """ - Ccxt compliant signature BUT lacks symbol - Cancel all orders for a sub-account. - params: dictionary with parameters. Valid keys:
- `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
- `quote` (str): quote currency. Defaults to all.
- """ - self._check_account_auth() - FN = f"{self._clsname} cancel_all_orders" - payload: dict = self._get_payload_cancel_all_orders(params) - path = get_grvt_endpoint(self.env, "CANCEL_ALL_ORDERS") - response: dict = await self._auth_and_post(path, payload=payload) - cancel_ack = response.get("result", {}).get("ack") - - if not cancel_ack: - self.logger.warning(f"{FN} failed to cancel orders: {response=}") - return False - self.logger.info(f"{FN} Cancelled {response=}") - return True - - async def cancel_order( - self, - id: str | None = None, - symbol: str | None = None, - params: dict = {}, - ) -> bool: - """ - Ccxt compliant signature - Cancel specific order for the account.
- Private call requires authorization.
- See [Cancel order](https://api-docs.grvt.io/trading_api/#cancel-order) - for details.
. - - Args: - id (str): exchange assigned order ID
- symbol (str): trading symbol
- params: - * client_order_id (str): client assigned order ID
- * time_to_live_ms (str): lifetime of cancel requiest in millisecs
- Returns: - True if cancel request was acked by exchange. False otherwise.
- """ - FN = f"{self._clsname} cancel_order" - self._check_account_auth() - # Prepare payload - payload: dict = { - "sub_account_id": str(self._trading_account_id), - } - if id: - payload["order_id"] = str(id) - elif "client_order_id" in params: - payload["client_order_id"] = str(params["client_order_id"]) - else: - raise GrvtInvalidOrder(f"{FN} requires either order_id or client_order_id") - if "time_to_live_ms" in params: - payload["time_to_live_ms"] = str(params["time_to_live_ms"]) - - # Send cancel request - path = get_grvt_endpoint(self.env, "CANCEL_ORDER") - self.logger.info( - f"{FN} Send cancel {payload=} for trading_account_id={self._trading_account_id}" - ) - response: dict = await self._auth_and_post(path, payload) - cancel_ack = response.get("result", {}).get("ack") - - if not cancel_ack: - self.logger.warning(f"{FN} failed to cancel order: {response=}") - return False - self.logger.info(f"{FN} Cancelled {response=}") - return True - - async def set_derisk_mm_ratio(self, ratio: str) -> bool: - """ - - Set the Derisk to Maintenance marginb ratio for the account. - Private call requires authorization. - See [Set Derisk M M ratio](https://api-docs.grvt.io/trading_api/#set-derisk-m-m-ratio) - for details. - - Args: - ratio (Amount): The new derisking market making ratio. - - Returns: - True if the request was acknowledged by the exchange. False otherwise. - """ - FN = f"{self._clsname} set_derisk_mm_ratio" - self._check_account_auth() - payload: dict[str, str | dict] = self._get_set_derisk_mm_ratio_payload(str(ratio)) - path = get_grvt_endpoint(self.env, "SET_DERISK_MM_RATIO") - self.logger.info( - f"{FN} Send {payload=} for trading_account_id={self.get_trading_account_id()}" - ) - response: dict = await self._auth_and_post(path, payload) - self.logger.info(f"{FN} Set derisk_mm_ratio {response=}") - return True - - async def fetch_open_orders( - self, - symbol: str | None = None, - since: int | None = None, - limit: int | None = None, - params: dict = {}, - ) -> list[dict]: - """ - Ccxt compliant signature - Fetch open orders for the account.
- Private call requires authorization.
- See [Open orders](https://api-docs.grvt.io/trading_api/#open-orders) - for details.
. - - Args: - symbol: get orders for this symbol only.
- since: ccxt-compliant argument, NOT SUPPORTED.
- limit: ccxt-compliant argument, NOT SUPPORTED.
- params: dictionary with parameters. Valid keys:
- `kind` (str): instrument kind. Valid values are 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch orders - for all base currencies.
- `quote` (str): quote currency. Defaults to all.
- Returns: - a list of dictionaries, each dict represent an order.
- """ - self._check_account_auth() - # Prepare request payload - payload = self._get_payload_fetch_open_orders(symbol, params) - # Post payload and parse the response - path = get_grvt_endpoint(self.env, "GET_OPEN_ORDERS") - response: dict = await self._auth_and_post(path, payload) - open_orders: list = response.get("result", []) - if symbol: - open_orders = [ - o for o in open_orders if o.get("legs") and o["legs"][0].get("instrument") == symbol - ] - return open_orders - - async def fetch_order( - self, - id: str | None = None, - params: dict = {}, - ) -> dict: - """ - Ccxt compliant signature - Private call requires authorization.
- See [Get Order](https://api-docs.grvt.io/trading_api/#get-order) - for details.
. - - Get Order status by either order_id or client_order_id - Args: - id: (str) order_id to fetch.
- symbol: (str) NOT SUPPRTED.
- params: dictionary with parameters. Valid keys:
- `client_order_id` (int): client assigned order ID.
- Returns: - dict with order details or {} if order was NOT found.
- """ - FN = f"{self._clsname} fetch_order" - self._check_account_auth() - payload = { - "sub_account_id": str(self._trading_account_id), - } - if id: - payload["order_id"] = id - elif "client_order_id" in params: - payload["client_order_id"] = str(params["client_order_id"]) - else: - raise GrvtInvalidOrder(f"{FN} requires either order_id or params['client_order_id']") - path = get_grvt_endpoint(self.env, "GET_ORDER") - response: dict = await self._auth_and_post(path, payload) - return response - - async def fetch_order_history(self, params: dict = {}) -> dict: - """ - Ccxt compliant signature, HISTORICAL data.
- Get Order history of orders by kind/base/quote.
- Private call requires authorization.
- See [Order History](https://api-docs.grvt.io/trading_api/#order-history) - for details.
- Args: - params: dictionary with parameters. Valid keys:
- `kind`: (str) - The kind filter to apply. Defaults to all kinds.
- `base`: (str) - The base currency filter. Defaults to all base currencies.
- `quote`: (str) - The quote currency filter. Defaults to all quote currencies.
- `expiration`: (int) The expiration time in nanoseconds. Defaults to all.
- `strike_price`: (str) The strike price to apply. Defaults to all strike prices.
- `limit`: (int) The limit to query for. Defaults to 500; Max 1000.
- `cursor`: (str) The cursor to use for pagination. If nil, return the first page.
- Return: a dictionary with keys: - `total` : total number of account history snapshots.
- `next` : cursor for the next page.
- `result` : a list of dictionaries, each dict represent an order state.
. - """ - self._check_account_auth() - payload = self._get_payload_fetch_order_history(params) - path = get_grvt_endpoint(self.env, "GET_ORDER_HISTORY") - response: dict = await self._auth_and_post(path, payload) - return response - - async def get_account_summary( - self, type: Literal["sub-account", "funding", "aggregated"] = "sub-account" - ) -> dict: - """ - Return: The account summary. - Private call requires authorization.
- See [Account Summary](https://api-docs.grvt.io/trading_api/#account_summary) - for details.
- Returns: dictionary with account data.
. - """ - FN = f"{self._clsname} get_account_summary {type=}" - self._check_account_auth() - payload = {} - if type == "sub-account": - path = get_grvt_endpoint(self.env, "GET_ACCOUNT_SUMMARY") - payload = {"sub_account_id": str(self._trading_account_id)} - elif type == "funding": - path = get_grvt_endpoint(self.env, "GET_FUNDING_ACCOUNT_SUMMARY") - elif type == "aggregated": - path = get_grvt_endpoint(self.env, "GET_AGGREGATED_ACCOUNT_SUMMARY") - else: - raise GrvtInvalidOrder(f"{FN} Invalid account summary type {type}") - - response: dict = await self._auth_and_post(path, payload=payload) - sub_account: dict = response.get("result", {}) - if not sub_account: - self.logger.info(f"{FN} No account summary for {path=} {payload=}") - return sub_account - - async def fetch_balance( - self, type: Literal["sub-account", "funding", "aggregated"] = "sub-account" - ) -> dict: - """ - Ccxt compliant signature - Fetch balances for the account.
- Private call requires authorization.
- See [Account Summary](https://api-docs.grvt.io/trading_api/#sub-account_summary) - for details.
. - - Args: - type: (str) - The type of account to fetch balances for. Defaults to 'sub-account'. - Valid values: 'sub-account', 'funding', 'aggregated'. - - Returns: dictionary with ccxt-compliant balance data https://docs.ccxt.com/#/README?id=account-balance.
. - """ - account_summary: dict = await self.get_account_summary(type) - return self._get_balances_from_account_summary(account_summary) - - async def fetch_account_history(self, params: dict = {}, limit: int = 500) -> dict: - """ - HISTORICAL data.
- Get account history.
- Private call requires authorization.
- See [Account History](https://api-docs.grvt.io/trading_api/#account-history) - for details.
. - - Args: - limit: maximum number of account snapshots per page to fetch.
- params: dictionary with parameters. Valid keys:
- `start_time` (int): fetch orders since this timestamp in nanoseconds.
- `end_time` (int): fetch orders until this timestamp in nanoseconds.
- `cursor` (str): cursor for the pagination. If cursor is present then we ignore - `start_time` and `end_time`.
- Returns: - a dictionary with keys: - `total` : total number of account history snapshots.
- `next` : cursor for the next page.
- `result` : list of account history snapshots.
- """ - self._check_account_auth() - # Prepare request payload - payload = self._get_payload_fetch_account_history(limit, params) - # Post payload and parse the response - path = get_grvt_endpoint(self.env, "GET_ACCOUNT_HISTORY") - response: dict = await self._auth_and_post(path, payload=payload) - return response - - async def fetch_positions(self, symbols: list[str] = [], params={}) -> list[dict]: - """ - Ccxt compliant signature - Fetch positions for the account.
- Private call requires authorization.
- See [Positions](https://api-docs.grvt.io/trading_api/#positions) - for details.
. - - Args: - symbols: list(str) get positions for these symbols only.
- - Returns: list of dictionaries, each dict represent a position.
- """ - self._check_account_auth() - # Prepare request payload - payload = self._get_payload_fetch_positions(symbols, params) - # Post payload and parse the response - path = get_grvt_endpoint(self.env, "GET_POSITIONS") - response: dict = await self._auth_and_post(path, payload) - positions: list = response.get("result", []) - if symbols: - self.logger.info(f"fetch_positions filter positions by {symbols=}") - positions = [p for p in positions if p.get("instrument") in symbols] - return positions - - async def fetch_my_trades( - self, - symbol: str | None = None, - since: int | None = None, - limit: int | None = None, - params: dict = {}, - ) -> dict: - """ - Ccxt compliant signature, HISTORICAL data.
- Fetch past trades for the account.
- Private call requires authorization.
- See [Private Trade History](https://api-docs.grvt.io/trading_api/#private-trade-history) - for details.
. - - Args: - symbol: get trades for this symbol only.
- since: fetch trades since this timestamp in nanoseconds.
- limit: maximum number of trades to fetch.
- params: dictionary with parameters. Valid keys:
- `cursor` (str): cursor for the pagination. - If cursor is present then we ignore other filters.
- `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
- `quote` (str): quote currency. Default: 'USDT'.
- - Returns: - a dictionary with keys: - `total` : total number of account history snapshots.
- `next` : cursor for the next page.
- `result` : a list of dictionaries, each dict represent a trade.
- """ - self._check_account_auth() - # Prepare request payload - payload = self._get_payload_fetch_my_trades(symbol, since, limit, params) - # Post payload and parse the response - path = get_grvt_endpoint(self.env, "GET_FILL_HISTORY") - response: dict = await self._auth_and_post(path, payload=payload) - if symbol: - # filter result by symbol - trades: list = response.get("result", []) - trades = [t for t in trades if t.get("instrument") == symbol] - response["result"] = trades - return response - - # **************** PUBLIC API CALLS - async def load_markets(self) -> dict | None: - self.logger.info("load_markets START") - instruments = await self.fetch_markets( - params={ - "kind": GrvtInstrumentKind.PERPETUAL, - } - ) - if instruments: - self.markets = {i.get("instrument"): i for i in instruments} - self.logger.info(f"load_markets: loaded {len(self.markets)} markets.") - else: - self.logger.warning("load_markets: No markets found.") - return self.markets - - async def fetch_markets( - self, - params: dict = {}, - ) -> list[dict]: - """ - ccxt-compliant signature - Retrieve the list of all instruments of matching kind, base and quote - supported by the exchange. - - Params: dict with keys:
- `is_active` (bool) - defaults to True.
- `limit` (int) - defaiults to 20.
- `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
- `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
- `quote` (str): quote currency. Default: 'USDT'.
- - Returns: list of dictionaries per instrument with keys:
- `instrument`: symbol e.g. 'BTC_USDT_Perp'.
- `instrument_hash`: hashed symbol for order signing e.g. '0x030501'.
- `base`: base currency e.g. 'BTC'.
- `quote`: quote currency e.g. 'USDT'.
- `kind`: kind of instrument 'PERPETUAL'/'FUTURE'.
- 'base_decimals': size multiplier for order signing.
- `tick_size`: price tick size.
- `min_size`: minimum order size.
- """ - # Prepare payload - payload = self._get_payload_fetch_markets(params) - # Make the POST request to get all instruments - path = get_grvt_endpoint(self.env, "GET_INSTRUMENTS") - response: dict = await self._auth_and_post(path, payload=payload) - return response.get("result", []) - - async def fetch_all_markets( - self, - is_active: bool | None = True, - ) -> list[dict]: - """ - Retrieve the list of all instruments supported by the exchange.
- Params:
- `is_active` (bool) - defaults to True.
. - - Returns: list of dictionaries per instrument. See fetch_markets().
- """ - # Prepare payload - payload = {"is_active": is_active} - # Make the POST request to get all instruments - path = get_grvt_endpoint(self.env, "GET_ALL_INSTRUMENTS") - response: dict = await self._auth_and_post(path, payload=payload) - # Extract and return the list of instruments - return response.get("result", []) - - async def fetch_market(self, symbol: str) -> dict: - """ - Retrieve the instrument object for a given symbol. - :param symbol: The symbol of the instrument. - """ - # Make the POST request to get all instruments - path = get_grvt_endpoint(self.env, "GET_INSTRUMENT") - response: dict = await self._auth_and_post(path, payload={"instrument": symbol}) - return response.get("result", []) - - async def fetch_ticker(self, symbol: str, params: dict = {}) -> dict: - """ - ccxt-compliant signature - Retrieve the ticker of a given symbol. - :param symbol: The instrument name. - :return: The ticker dictionary of the instrument. - """ - # {'event_time': '1724252426000000000', 'instrument': 'BTC_USDT_Perp', - # 'mark_price': '59373870996065', 'index_price': '59395287961367', - # 'last_price': '99000000000000', 'last_size': '9917000000', 'mid_price': '59569000', - # 'best_bid_price': '59866000000000', 'best_bid_size': '23705000000', 'best_ask_price': - # '59273700', 'best_ask_size': '21670', 'funding_rate_curr': 2544, 'funding_rate_avg': 0, - # 'interest_rate': 0, 'forward_price': '0', 'buy_volume_u': '401930000000', - # 'sell_volume_u': '1218289000000', 'buy_volume_q': '34637817515500', - # 'sell_volume_q': '687640900', 'high_price': '343545000', 'low_price': '100000', - # 'open_price': '32554000000000', 'open_interest': '8174350000000', - # 'long_short_ratio': 1.0948905} - path = get_grvt_endpoint(self.env, "GET_TICKER") - response: dict = await self._auth_and_post(path, payload={"instrument": symbol}) - return response.get("result", {}) - - async def fetch_mini_ticker(self, symbol: str) -> dict: - """ - Retrieve the mini-ticker of a given symbol. - :param symbol: The instrument name. - :return: The mini-ticker dictionary of the instrument. - """ - # {'event_time': '1724252426000000000', 'instrument': 'BTC_USDT_Perp', - # 'mark_price': '59373870996065', 'index_price': '59395287961367', - # 'last_price': '99000000000000', 'last_size': '9917000000', 'mid_price': '59569000', - # 'best_bid_price': '59866000000000', 'best_bid_size': '23705000000', 'best_ask_price': - # '59273700000000', 'best_ask_size': '21678000000'} - path = get_grvt_endpoint(self.env, "GET_MINI_TICKER") - response: dict = await self._auth_and_post(path, payload={"instrument": symbol}) - return response.get("result", {}) - - async def fetch_order_book(self, symbol: str, limit: int = 10, params={}) -> dict: - """ - ccxt-compliant signature - Retrieve the order book of a given symbol. - :param symbol: The instrument name. - :return: The order book dictionary of the instrument. - """ - # {'event_time': '0', 'instrument': 'BTC_USDT_Perp', - # 'bids': [{'price': '100000000', 'size': '86353000000', 'num_orders': 4},...] - # 'asks': [{'price': '59273700000000', 'size': '21678000000', 'num_orders': 1}, ...] - payload = {"instrument": symbol, "aggregate": 1} - if limit: - payload["depth"] = limit - path = get_grvt_endpoint(self.env, "GET_ORDER_BOOK") - response: dict = await self._auth_and_post(path, payload=payload) - if self.is_order_book_ccxt_format(): - # Convert to ccxt format - return self.convert_grvt_ob_to_ccxt(response.get("result", {})) - return response.get("result", {}) - - async def fetch_recent_trades( - self, - symbol: str, - limit: int | None = None, - ) -> list: - """ - Retrieve the recent trades a given instrument.
- :param instrument: The instrument name. - :return: The order book dictionary of the instrument. - """ - # List of {'event_time': '1724248876870635916', 'instrument': 'ETH_USDT_Perp', - # 'is_taker_buyer': True, 'size': '24000000000', 'price': '2600000000000', - # 'mark_price': '2591055564869', 'index_price': '2592459142472', 'interest_rate': 0, - # 'forward_price': '0', 'trade_id': '729726', 'venue': 'ORDERBOOK'} - payload: dict[str, str | int] = {"instrument": symbol} - if limit: - payload["limit"] = limit - path = get_grvt_endpoint(self.env, "GET_TRADES") - response: dict = await self._auth_and_post(path, payload=payload) - return response.get("result", []) - - async def fetch_trades( - self, - symbol: str, - since: int | None = None, - limit: int = 10, - params: dict = {}, - ) -> dict: - """ - Ccxt-compliant signature, HISTORICAL data.
- Retrieve trade history of a given instrument. - :param symbol: The instrument name. - :return: dict with field 'result' containing a list of trades. - """ - # List of {'event_time': '1724248876870635916', 'instrument': 'ETH_USDT_Perp', - # 'is_taker_buyer': True, 'size': '24000000000', 'price': '2600000000000', - # 'mark_price': '2591055564869', 'index_price': '2592459142472', 'interest_rate': 0, - # 'forward_price': '0', 'trade_id': '729726', 'venue': 'ORDERBOOK'} - payload: dict = self._get_payload_fetch_trades( - symbol, - since=since, - limit=limit, - params=params, - ) - path: str = get_grvt_endpoint(self.env, "GET_TRADE_HISTORY") - response: dict = await self._auth_and_post(path, payload=payload) - return response - - async def fetch_funding_rate_history( - self, - symbol: str, - since: int = 0, - limit: int = 1_000, - params: dict = {}, - ) -> dict: - """ - ccxt-compliant signature, HISTORICAL data.
- Retrieve the funding rates history of a given instrument.
- Args: - symbol (str): The instrument name.
- since (int): fetch trades since this timestamp in nanoseconds.
- limit: int - maximum number of trades to fetch.
- params: dictionary with parameters. Valid keys:
- `cursor` (str): cursor for the pagination. - If cursor is present then we ignore other filters.
- `end_time` (int): end time in nanoseconds.
- Returns: - dict with field 'result' containing list of dictionaries repesenting funding rate - at a point in time with fields:
- `instrument` (str): instrument name.
- 'funding_rate' (float): funding rate.
- 'funding_time' (int): funding time in nanoseconds.
- 'mark_price' (float): mark price.
. - """ - payload: dict[str, str | int] = {"instrument": symbol} - if params.get("cursor"): - payload["cursor"] = params["cursor"] - else: - if since: - payload["start_time"] = str(since) - if params.get("end_time"): - payload["end_time"] = str(params["end_time"]) - if limit: - payload["limit"] = int(limit) - path: str = get_grvt_endpoint(self.env, "GET_FUNDING") - response: dict = await self._auth_and_post(path, payload=payload) - return response - - async def fetch_ohlcv( - self, - symbol: str, - timeframe: str = "1m", - since: int = 0, - limit: int = 10, - params={}, - ) -> dict: - """ - ccxt-compliant signature, HISTORICAL data.
- Retrieve the ohlc history of a given instrument.
- Args: - symbol: The instrument name.
- timeframe: The timeframe of the ohlc. - See `ccxt_interval_to_grvt_candlestick_interval`.
- since: fetch ohlc since this timestamp in nanoseconds.
- limit: maximum number of ohlc to fetch.
- params: dictionary with parameters. Valid keys:
- `cursor` (str): cursor for the pagination. - If cursor is present then we ignore other filters.
- `end_time` (int): end time in nanoseconds.
- `candle_type` (str): candle type. Valid values: 'TRADE', 'MARK', 'INDEX'.
- Returns: - dict with field 'result' containing a list of dictionaries, each dict representing a candlestick with fields:
- `instrument` - instrument name.
- `open_time` - start of interval in nanoseconds.
- `close_time` - end of interval in nanoseconds.
- `open` - opening price.
- `close` - closing price.
- `high` - highest price.
- `low` - lowest price.
- `volume_u` - volume in units.
- `volume_q` - volume in quote(USDT).
- `trades` - number of trades.
. - """ - FN: str = f"{self._clsname} fetch_ohlcv" - payload: dict = self._get_payload_fetch_ohlcv(symbol, timeframe, since, limit, params) - self.logger.info(f"{FN} {payload=}") - path: str = get_grvt_endpoint(self.env, "GET_CANDLESTICK") - response: dict = await self._auth_and_post(path, payload=payload) - return response - - # Vault Management APIs - async def fetch_vault_manager_investor_history(self, only_own_investments: bool = False) -> dict: - payload: dict = self._get_fetch_vault_manager_investor_history_payload( - vault_id=self.get_trading_account_id(), - only_own_investments=only_own_investments, # Default to False to fetch all investments - ) - path: str = get_grvt_endpoint(self.env, "GET_VAULT_MANAGER_INVESTOR_HISTORY") - return await self._auth_and_post(path, payload=payload) - - async def fetch_vault_redemption_queue(self): - payload: dict = self._get_fetch_vault_redemption_queue_payload( - vault_id=self.get_trading_account_id() - ) - path: str = get_grvt_endpoint(self.env, "GET_VAULT_REDEMPTION_QUEUE") - return await self._auth_and_post(path, payload=payload) \ No newline at end of file diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_test_utils.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_test_utils.py deleted file mode 100644 index 981f49f..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_test_utils.py +++ /dev/null @@ -1,75 +0,0 @@ -import logging -from collections.abc import Callable - -from .grvt_ccxt import GrvtCcxt -from .grvt_ccxt_env import get_all_grvt_endpoints -from .grvt_ccxt_pro import GrvtCcxtPro - - -def default_check(return_value: dict) -> str: - if not isinstance(return_value, list | dict): - return "return_value is not a list or dict" - if not return_value: - return "return_value is empty" - return "OK" - - -def validate_return_values(api: GrvtCcxt | GrvtCcxtPro, result_filename: str) -> None: - logging.info("validate_return_values: START") - endpoint_check_map: dict[str, Callable] = { - "GRAPHQL": default_check, - "AUTH": default_check, - "CREATE_ORDER": default_check, - "CANCEL_ALL_ORDERS": default_check, - "CANCEL_ORDER": default_check, - "GET_OPEN_ORDERS": default_check, - "GET_ACCOUNT_SUMMARY": default_check, - "GET_FUNDING_ACCOUNT_SUMMARY": default_check, - "GET_AGGREGATED_ACCOUNT_SUMMARY": default_check, - "GET_ACCOUNT_HISTORY": default_check, - "GET_POSITIONS": default_check, - "GET_ORDER": default_check, - "GET_ORDER_HISTORY": default_check, - "GET_FILL_HISTORY": default_check, - "GET_ALL_INSTRUMENTS": default_check, - "GET_INSTRUMENTS": default_check, - "GET_INSTRUMENT": default_check, - "GET_TICKER": default_check, - "GET_MINI_TICKER": default_check, - "GET_ORDER_BOOK": default_check, - "GET_TRADES": default_check, - "GET_TRADE_HISTORY": default_check, - "GET_FUNDING": default_check, - "GET_CANDLESTICK": default_check, - } - all_endpoints = get_all_grvt_endpoints(api.env) - end_point_status = {} - for short_name, endpoint in all_endpoints.items(): - if not api.was_path_called(endpoint): - logging.info(f"validate_return_values: {short_name=}, {endpoint=}, not called") - end_point_status[short_name] = [endpoint, "not called"] - else: - return_value = api.get_endpoint_return_value(endpoint) - if short_name in endpoint_check_map: - check_function = endpoint_check_map.get(short_name) - if not check_function or not callable(check_function): - logging.error( - f"validate_return_values: {short_name=} " - f"not found in {endpoint_check_map.keys()=}" - ) - continue - check_result = check_function(return_value) - logging.info( - f"validate_return_values: {short_name=}, {endpoint=}, {check_result=}" - ) - end_point_status[short_name] = [endpoint, check_result] - else: - logging.error( - f"validate_return_values: NO {short_name=} in {endpoint_check_map.keys()=}" - ) - end_point_status[short_name] = [endpoint, "no check"] - with open(result_filename, "w") as file_handle: - file_handle.write("NAME, URL, STATUS\n") - for short_name, status in end_point_status.items(): - file_handle.write(f"{short_name}, {status[0]}, {status[1]}\n") - logging.info("validate_return_values: END") diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_types.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_types.py deleted file mode 100644 index 342b0fd..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_types.py +++ /dev/null @@ -1,81 +0,0 @@ -# ruff: noqa: D200 -# ruff: noqa: D204 -# ruff: noqa: D205 -# ruff: noqa: D404 -# ruff: noqa: W291 -# ruff: noqa: D400 -# ruff: noqa: E501 - -from decimal import Decimal -from enum import Enum -from typing import Literal - -Num = None | str | float | int | Decimal -Amount = Decimal | int | float | str -GrvtOrderSide = Literal["buy", "sell"] -GrvtOrderType = Literal["limit", "market"] - -DURATION_SECOND_IN_NSEC = 1_000_000_000 -PRICE_MULTIPLIER = 1_000_000_000 -BTC_ETH_SIZE_MULTIPLIER = 1_000_000_000 - - -class GrvtInvalidOrder(Exception): - pass - - -class CandlestickInterval(Enum): - CI_1_M = "CI_1_M" - CI_3_M = "CI_3_M" - CI_5_M = "CI_5_M" - CI_15_M = "CI_15_M" - CI_30_M = "CI_30_M" - CI_1_H = "CI_1_H" - CI_2_H = "CI_2_H" - CI_4_H = "CI_4_H" - CI_6_H = "CI_6_H" - CI_8_H = "CI_8_H" - CI_12_H = "CI_12_H" - CI_1_D = "CI_1_D" - CI_3_D = "CI_3_D" - CI_5_D = "CI_5_D" - CI_1_W = "CI_1_W" - CI_2_W = "CI_2_W" - CI_3_W = "CI_3_W" - CI_4_W = "CI_4_W" - - -ccxt_interval_to_grvt_candlestick_interval = { - "1m": CandlestickInterval.CI_1_M, - "3m": CandlestickInterval.CI_3_M, - "5m": CandlestickInterval.CI_5_M, - "15m": CandlestickInterval.CI_15_M, - "30m": CandlestickInterval.CI_30_M, - "1h": CandlestickInterval.CI_1_H, - "2h": CandlestickInterval.CI_2_H, - "4h": CandlestickInterval.CI_4_H, - "6h": CandlestickInterval.CI_6_H, - "8h": CandlestickInterval.CI_8_H, - "12h": CandlestickInterval.CI_12_H, - "1d": CandlestickInterval.CI_1_D, - "3d": CandlestickInterval.CI_3_D, - "5d": CandlestickInterval.CI_5_D, - "1w": CandlestickInterval.CI_1_W, - "2w": CandlestickInterval.CI_2_W, - "3w": CandlestickInterval.CI_3_W, - "4w": CandlestickInterval.CI_4_W, -} - - -class CandlestickType(Enum): - TRADE = "TRADE" - MARK = "MARK" - INDEX = "INDEX" - MID = "MID" - - -class GrvtInstrumentKind(Enum): - PERPETUAL = "PERPETUAL" - FUTURE = "FUTURE" - CALL = "CALL" - PUT = "PUT" diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_utils.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_utils.py deleted file mode 100644 index 42d5014..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_utils.py +++ /dev/null @@ -1,544 +0,0 @@ -# ruff: noqa: D200 -# ruff: noqa: D204 -# ruff: noqa: D205 -# ruff: noqa: D404 -# ruff: noqa: W291 -# ruff: noqa: D400 -# ruff: noqa: E501 - -import json -import logging -import random -import time -from dataclasses import dataclass -from datetime import datetime -from decimal import Decimal -from enum import Enum -from http.cookies import SimpleCookie -from typing import Any - -import aiohttp -import requests -from eth_account import Account -from eth_account.messages import encode_typed_data, SignableMessage - -from .grvt_ccxt_env import CHAIN_IDS, GrvtEnv -from .grvt_ccxt_types import ( - BTC_ETH_SIZE_MULTIPLIER, - DURATION_SECOND_IN_NSEC, - Amount, - GrvtOrderSide, - GrvtOrderType, - Num, -) - - -def rand_uint32(): - return random.randint(0, 2**32 - 1) - - -class TimeInForce(Enum): - """ - | | Must Fill All | Can Fill Partial | - | - | - | - | - | Must Fill Immediately | FOK | IOC | - | Can Fill Till Time | AON | GTC |. - - """ - - # GTT - Remains open until it is cancelled, or expired - GOOD_TILL_TIME = "GOOD_TILL_TIME" - # AON - Either fill the whole order or none of it (Block Trades Only) - ALL_OR_NONE = "ALL_OR_NONE" - # IOC - Fill the order as much as possible, when hitting the orderbook. Then cancel it - IMMEDIATE_OR_CANCEL = "IMMEDIATE_OR_CANCEL" - # FOK - Both AoN and IoC. Either fill the full order when hitting the orderbook, or cancel it - FILL_OR_KILL = "FILL_OR_KILL" - - -class SignTimeInForce(Enum): - GOOD_TILL_TIME = 1 - ALL_OR_NONE = 2 - IMMEDIATE_OR_CANCEL = 3 - FILL_OR_KILL = 4 - - -TIME_IN_FORCE_TO_SIGN_TIME_IN_FORCE = { - TimeInForce.GOOD_TILL_TIME: SignTimeInForce.GOOD_TILL_TIME, - TimeInForce.ALL_OR_NONE: SignTimeInForce.ALL_OR_NONE, - TimeInForce.IMMEDIATE_OR_CANCEL: SignTimeInForce.IMMEDIATE_OR_CANCEL, - TimeInForce.FILL_OR_KILL: SignTimeInForce.FILL_OR_KILL, -} - - -def get_EIP712_domain_data(env: GrvtEnv) -> dict[str, str | int]: - # DO NOT MODIFY THESE VALUES ############## - return { - "name": "GRVT Exchange", - "version": "0", - "chainId": CHAIN_IDS[env.value], - } - - -def get_cookie_with_expiration( - path: str, api_key: str | None -) -> dict[str, str | float | None] | None: - """ - Authenticates and retrieves the session cookie, its expiration time and grvt-account-id token. - :return: The session cookie. - """ - FN = f"get_cookie_with_expiration {path=}" - if api_key: - data = {} - try: - data = {"api_key": api_key} - session = requests.Session() - return_value = session.post( - path, - json=data, - headers={"Content-Type": "application/json"}, - timeout=5, - ) - if return_value.ok: - cookie = SimpleCookie() - cookie.load(return_value.headers.get("Set-Cookie", "")) - cookie_value: str = cookie["gravity"].value - cookie_expiry: datetime = datetime.strptime( - cookie["gravity"]["expires"], - "%a, %d %b %Y %H:%M:%S %Z", - ) - grvt_account_id: str = return_value.headers.get("X-Grvt-Account-Id", "") - logging.info( - f"{FN} OK response {cookie_value=} {cookie_expiry=} {grvt_account_id=}" - ) - return { - "gravity": cookie_value, - "expires": cookie_expiry.timestamp(), - "X-Grvt-Account-Id": grvt_account_id, - } - logging.warning(f"{FN} Invalid return_value {data=} {path=} {return_value=}") - return None - except Exception as e: - logging.error(f"{FN} Error getting cookie: {e}") - return None - else: - return None - - -async def get_cookie_with_expiration_async( - path: str, api_key: str | None -) -> dict[str, str | float | None] | None: - """ - Authenticates and retrieves the session cookie, its expiration time and grvt-account-id token. - :return: The session cookie. - """ - FN = f"get_cookie_with_expiration_async {path=}" - if api_key: - data = {} - try: - data = {"api_key": api_key} - logging.info(f"{FN} ask for cookie {path=} {data=}") - async with aiohttp.ClientSession() as session: - async with session.post(url=path, json=data, timeout=5) as return_value: - logging.info(f"{FN} {return_value=}") - if return_value.ok: - cookie = SimpleCookie() - cookie.load(return_value.headers.get("Set-Cookie", "")) - cookie_value: str = cookie["gravity"].value - cookie_expiry: datetime = datetime.strptime( - cookie["gravity"]["expires"], - "%a, %d %b %Y %H:%M:%S %Z", - ) - grvt_account_id: str = return_value.headers.get("X-Grvt-Account-Id", "") - logging.info( - f"{FN} OK response {cookie_value=} {cookie_expiry=} {grvt_account_id=}" - ) - return { - "gravity": cookie_value, - "expires": cookie_expiry.timestamp(), - "X-Grvt-Account-Id": grvt_account_id, - } - except Exception as e: - logging.error(f"{FN} Error getting cookie: {e}") - return None - else: - return None - - -class GrvtKind(Enum): - PERPETUAL = 1 - FUTURE = 2 - CALL = 3 - PUT = 4 - SPOT = 5 - - -class GrvtCurrency(Enum): - USD = 1 - USDC = 2 - USDT = 3 - ETH = 4 - BTC = 5 - - -def hexlify(data: bytes) -> str: - """Convert a byte array to a hex string with a 0x prefix.""" - return f"0x{data.hex()}" - - -class EnumEncoder(json.JSONEncoder): - def default(self, o): - """ - Custom JSON encoder for Enum types. - :param obj: Object to serialize. - :return: Serialized object. - """ - if isinstance(o, Enum): - return o.value - return super().default(o) - - -def get_kuq_from_symbol(symbol: str) -> tuple[str, str, str]: - parts = symbol.split("_") - if len(parts) == 3: - underlying, quote, kind = parts - if kind == "Perp": - kind = "PERPETUAL" - else: - raise ValueError(f"Invalid {symbol=} {kind=}") - elif len(parts) == 4: - underlying, quote, kind, time_str = parts - if kind == "Fut": - kind = "FUTURE" - else: - raise ValueError(f"Invalid {symbol=} {kind=}") - elif len(parts) == 5: - underlying, quote, kind, time_str, strike_price = parts - if kind in {"Call", "Put"}: - kind = kind.upper() - else: - raise ValueError(f"Invalid {symbol=} {kind=}") - else: - raise ValueError(f"Invalid {symbol=}") - return kind, underlying, quote - - -# Custom types -EIP712_ORDER_MESSAGE_TYPE = { - "Order": [ - {"name": "subAccountID", "type": "uint64"}, - {"name": "isMarket", "type": "bool"}, - {"name": "timeInForce", "type": "uint8"}, - {"name": "postOnly", "type": "bool"}, - {"name": "reduceOnly", "type": "bool"}, - {"name": "legs", "type": "OrderLeg[]"}, - {"name": "nonce", "type": "uint32"}, - {"name": "expiration", "type": "int64"}, - ], - "OrderLeg": [ - {"name": "assetID", "type": "uint256"}, - {"name": "contractSize", "type": "uint64"}, - {"name": "limitPrice", "type": "uint64"}, - {"name": "isBuyingContract", "type": "bool"}, - ], -} - - -@dataclass -class GrvtSignature: - # The address (public key) of the wallet signing the payload - signer: str - r: str - s: str - v: int - # Timestamp after which this signature expires, expressed in unix nanoseconds. - # Must be capped at 30 days - expiration: str - """ - Users can randomly generate this value, used as a signature deconflicting key. - ie. You can send the same exact instruction twice with different nonces. - When the same nonce is used, the same payload will generate the same signature. - Our system will consider the payload a duplicate, and ignore it. - """ - nonce: int - - -@dataclass -class OrderMetadata: - """ - Metadata fields are used to support Backend only operations. - Hence, fields in here are never signed, and is never transmitted to the smart contract. - """ - - """ - `client_order_id`: A unique identifier of an active order, specified by the client - This is used to identify the order in the client's system - This value must be unique for all active orders in a subaccount, - otehrwise amendment / cancellation will not work as expected - Gravity UI will generate a random clientOrderID for each order in the range [0, 2^63 - 1] - To prevent any conflicts, client machines should generate a random clientOrderID - in the range [2^63, 2^64 - 1]. - When GRVT Backend receives an order with duplicate `client_order_id`, it will reject the order - with rejectReason set to duplicate `client_order_id`. - """ - client_order_id: str - # [Filled by GRVT Backend] Time at which the order was received by GRVT in unix nanoseconds - create_time: str | None = None - - -@dataclass -class GrvtOrderLeg: - # The instrument to trade in this leg - instrument: str - # The total number of contracts to trade in this leg, expressed in base currency units. - size: Decimal - # Specifies if the order leg is a buy or sell - is_buying_asset: bool - """ - The limit price of the order leg, expressed in `9` decimals. - This is the number of quote currency units to pay/receive for this leg. - This should be `null/0` if the order is a market order - """ - limit_price: Decimal - - -@dataclass -class GrvtOrder: - """ - Order is a typed payload used throughout the GRVT platform to express all orders. - GRVT orders are capable of expressing both single-legged, and multi-legged orders by default. - All fields in the Order payload (except `id`, `metadata`, and `state`) are trustlessly enforced - on our Hyperchain. - This minimizes the amount of trust users have to offer to GRVT. - """ - - # The subaccount initiating the order - sub_account_id: str - # Supported time_in_force : GTT, IOC, FOK:
    - time_in_force: TimeInForce - legs: list[GrvtOrderLeg] - # The signature approving this order - signature: GrvtSignature - # Order Metadata, ignored by the smart contract, and unsigned by the client - metadata: OrderMetadata - # is_market: If the order is a market order - is_market: bool - post_only: bool = False - # If True, Order must reduce the position size, or be cancelled - reduce_only: bool = False - - -def get_signable_message( - order: GrvtOrder, env: GrvtEnv, instruments: dict[str, dict] -) -> bytes | None: - FN = f"get_signable_message {order=}" - size_multiplier = BTC_ETH_SIZE_MULTIPLIER - PRICE_MULTIPLIER = 1_000_000_000 - legs = [] - for leg in order.legs: - instrument = instruments.get(leg.instrument) - if not instrument or not isinstance(instrument, dict): - logging.error(f"{FN}: {leg.instrument=} not found in {instruments=}") - return None - if "base_decimals" not in instrument: - logging.error(f"{FN}: no 'base_decimals' in {instrument=}") - return None - size_multiplier = 10 ** instrument["base_decimals"] - if "instrument_hash" not in instrument: - logging.error(f"{FN}: no 'instrument_hash' in {instrument=}") - return None - legs.append( - { - "assetID": instrument["instrument_hash"], - "contractSize": int(Decimal(leg.size) * Decimal(size_multiplier)), - "limitPrice": int(Decimal(leg.limit_price) * Decimal(PRICE_MULTIPLIER)), - "isBuyingContract": leg.is_buying_asset, - } - ) - message_data = { - "subAccountID": order.sub_account_id, - "isMarket": order.is_market or False, - "timeInForce": TIME_IN_FORCE_TO_SIGN_TIME_IN_FORCE[order.time_in_force].value, - "postOnly": order.post_only or False, - "reduceOnly": order.reduce_only or False, - "legs": legs, - "nonce": order.signature.nonce, - "expiration": order.signature.expiration, - } - domain_data: dict[str, str | int]= get_EIP712_domain_data(env) - logging.info(f"{FN} {domain_data=}\n{EIP712_ORDER_MESSAGE_TYPE=}\n{message_data=}") - return encode_typed_data(domain_data, EIP712_ORDER_MESSAGE_TYPE, message_data) - - -def get_order_payload( - order: GrvtOrder, private_key: str, env: GrvtEnv, instruments: dict[str, dict] -) -> dict: - signable_message = get_signable_message(order, env, instruments) - if signable_message is None: - raise ValueError("Failed to create signable message") - signed_message = Account.sign_message(signable_message, private_key) - order.signature.s = "0x" + signed_message.s.to_bytes(32, byteorder="big").hex() - order.signature.r = "0x" + signed_message.r.to_bytes(32, byteorder="big").hex() - order.signature.v = signed_message.v - order.signature.signer = Account.from_key(private_key).address - - return { - "order": { - "sub_account_id": str(order.sub_account_id), - "is_market": order.is_market, - "time_in_force": order.time_in_force.name, - "post_only": order.post_only, - "reduce_only": order.reduce_only, - "legs": [ - { - "instrument": leg.instrument, - "size": str(leg.size), - "limit_price": str(leg.limit_price), - "is_buying_asset": bool(leg.is_buying_asset), - } - for leg in order.legs - ], - "signature": { - "r": order.signature.r, - "s": order.signature.s, - "v": order.signature.v, - "expiration": order.signature.expiration, - "nonce": order.signature.nonce, - "signer": order.signature.signer, - }, - "metadata": { - "client_order_id": order.metadata.client_order_id, - }, - } - } - - -def get_order_rpc_payload( - order: GrvtOrder, - private_key: str, - env: GrvtEnv, - instruments: dict[str, dict], - version: str = "v1", -) -> dict: - order_payload = get_order_payload(order, private_key, env, instruments) - return { - "jsonrpc": "2.0", - "method": f"{version}/create_order", - "params": order_payload, - } - - -def get_grvt_order( - sub_account_id: str, - symbol: str, - order_type: GrvtOrderType, - side: GrvtOrderSide, - amount: Amount, - limit_price: Num, - order_duration_secs: float = 5 * 60, - params: dict = {}, -) -> GrvtOrder: - """ - Creates an order for a specified symbol with the given limit price and size. - - Args: - symbol . - limit_price (int): The limit price for the order. - size (float): The size of the order. - is_buying_asset(bool) : Buy or Sell. - - Returns: - Order: The created perpetual order. - """ - limit_price = limit_price or 0 - is_buying_asset = side == "buy" - is_market = order_type == "market" - leg = GrvtOrderLeg( - instrument=symbol, - size=round(Decimal(amount), 9), - is_buying_asset=is_buying_asset, - limit_price=round(Decimal(limit_price), 9), - ) - - # create an expiry time - time_in_force = TimeInForce.GOOD_TILL_TIME - if "time_in_force" in params: - time_in_force = TimeInForce[params["time_in_force"]] - post_only: bool = False - if "post_only" in params: - post_only = params["post_only"] - reduce_only: bool = False - if "reduce_only" in params: - reduce_only = params["reduce_only"] - expiry_ns: int = 0 - if order_duration_secs: - expiry_ns = time.time_ns() + int(order_duration_secs * DURATION_SECOND_IN_NSEC) - if "client_order_id" in params: - client_order_id = int(params["client_order_id"]) - else: - client_order_id = rand_uint32() - signature = GrvtSignature( - signer="", - r="", - s="", - v=0, - expiration=str(expiry_ns), - nonce=rand_uint32(), - ) - metadata = OrderMetadata(client_order_id=str(client_order_id)) - return GrvtOrder( - sub_account_id=sub_account_id, - time_in_force=time_in_force, - legs=[leg], - signature=signature, - metadata=metadata, - is_market=is_market, - post_only=post_only, - reduce_only=reduce_only, - ) - -def sign_derisk_mm_ratio_request( - env: GrvtEnv, sub_account_id: int, ratio: str, private_key_hex: str -): - """ - Generate a signature for setting the derisk to maintenance margin ratio. - - :param sub_account_id: The sub-account ID to set the ratio for. - :param ratio: The derisk to maintenance margin ratio as a string (e.g., "2.0"). - :param private_key_hex: The private key in hexadecimal format. - :return: A dictionary containing the signature for the payload. - """ - derisk_ratio_int = int(Decimal(ratio) * 1_000_000) - expiration_ns = int((time.time() + 86400) * 1_000_000_000) - nonce = random.randint(1, 2**32 - 1) - - domain_data = get_EIP712_domain_data(env) - - types = { - "SetDeriskToMaintenanceMarginRatio": [ - {"name": "subAccountID", "type": "uint64"}, - {"name": "deriskToMaintenanceMarginRatio", "type": "uint32"}, - {"name": "nonce", "type": "uint32"}, - {"name": "expiration", "type": "int64"}, - ] - } - - signature_payload = { - "subAccountID": sub_account_id, - "deriskToMaintenanceMarginRatio": derisk_ratio_int, - "nonce": nonce, - "expiration": expiration_ns, - } - - message = encode_typed_data(domain_data, types, signature_payload) - signed = Account.sign_message(message, private_key_hex) - signer = Account.from_key(private_key_hex) - - return { - "signer": signer.address.lower(), - "r": hex(signed.r), - "s": hex(signed.s), - "v": signed.v, - "expiration": str(expiration_ns), - "nonce": nonce, - } \ No newline at end of file diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_ws.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_ws.py deleted file mode 100644 index 132b921..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_ccxt_ws.py +++ /dev/null @@ -1,785 +0,0 @@ -# ruff: noqa: D200 -# ruff: noqa: D204 -# ruff: noqa: D205 -# ruff: noqa: D404 -# ruff: noqa: W291 -# ruff: noqa: D400 -# ruff: noqa: E501 - -import asyncio -import json -import logging -import traceback -from asyncio.events import AbstractEventLoop -from collections.abc import Callable -from decimal import Decimal - -import websockets - -# import requests -# from env import ENDPOINTS -from .grvt_ccxt_env import ( - GRVT_WS_STREAMS, - GrvtEnv, - GrvtWSEndpointType, - get_grvt_ws_endpoint, - is_trading_ws_endpoint, -) -from .grvt_ccxt_pro import GrvtCcxtPro -from .grvt_ccxt_types import ( - GrvtInvalidOrder, - GrvtOrderSide, - GrvtOrderType, - Num, -) -from .grvt_ccxt_utils import get_order_rpc_payload - -WS_READ_TIMEOUT = 5 - - -class GrvtCcxtWS(GrvtCcxtPro): - """ - GrvtCcxtPro class to interact with Grvt Rest API and WebSockets in asynchronous mode. - - Args: - env: GrvtCcxtPro (DEV, TESTNET, PROD) - parameters: dict with trading_account_id, private_key, api_key etc - - Examples: - >>> from grvt_api_pro import GrvtCcxtPro - >>> from grvt_env import GrvtEnv - >>> grvt = GrvtCcxtPro(env=GrvtEnv.TESTNET) - >>> await grvt.fetch_markets() - """ - - def __init__( - self, - env: GrvtEnv, - loop: AbstractEventLoop, - logger: logging.Logger | None = None, - parameters: dict = {}, - ): - """Initialize the GrvtCcxt instance.""" - super().__init__(env, logger, parameters) - self._loop = loop - self._clsname: str = type(self).__name__ - self.api_ws_version = parameters.get("api_ws_version", "v1") - self.force_reconnect_flag: bool = False - self.ws: dict[GrvtWSEndpointType, websockets.WebSocketClientProtocol | None] = {} - self.callbacks: dict[GrvtWSEndpointType, dict[str, dict[str, Callable]]] = {} - self.subscribed_streams: dict[GrvtWSEndpointType, dict] = {} - self.api_url: dict[GrvtWSEndpointType, str] = {} - self._last_message: dict[str, dict] = {} - self._request_id = 0 - self.endpoint_types = [ - GrvtWSEndpointType.MARKET_DATA, - GrvtWSEndpointType.TRADE_DATA, - GrvtWSEndpointType.MARKET_DATA_RPC_FULL, - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, - ] - # Initialize dictionaries for each endpoint type - for grvt_endpoint_type in self.endpoint_types: - self.api_url[grvt_endpoint_type] = get_grvt_ws_endpoint( - self.env.value, grvt_endpoint_type - ) - self.callbacks[grvt_endpoint_type] = {} - self.subscribed_streams[grvt_endpoint_type] = {} - self.ws[grvt_endpoint_type] = None - self._loop.create_task(self._read_messages(grvt_endpoint_type)) - self.logger.info(f"{self._clsname} initialized {self.api_url=}") - self.logger.info(f"{self._clsname} initialized {self.ws=}") - - def __repr__(self) -> str: - return f"{self._clsname} {self.env=} {self.api_ws_version=}" - - async def __aexit__(self): - for grvt_endpoint_type in self.endpoint_types: - await self._close_connection(grvt_endpoint_type) - - def force_reconnect(self) -> None: - self.force_reconnect_flag = True - - async def initialize(self): - """ - Prepares the GrvtCcxtPro instance and connects to WS server. - """ - await self.load_markets() - await self.refresh_cookie() - self._loop.create_task(self.connect_all_channels()) - - def is_connection_open(self, grvt_endpoint_type: GrvtWSEndpointType) -> bool: - return ( - self.ws[grvt_endpoint_type] is not None and self.ws[grvt_endpoint_type].open - ) - - def is_endpoint_connected(self, grvt_endpoint_type: GrvtWSEndpointType) -> bool: - """ - For MARKET_DATA returns True if connection is open. - for TRADE_DATA returns True if one of the following is true: - 1. No cookie - this means this is public connection and we can't connect to TRADE_DATA - 2. Connection to TRADE_DATA is open - """ - if grvt_endpoint_type in [ - GrvtWSEndpointType.MARKET_DATA, - GrvtWSEndpointType.MARKET_DATA_RPC_FULL, - ]: - return self.is_connection_open(grvt_endpoint_type) - if grvt_endpoint_type in [ - GrvtWSEndpointType.TRADE_DATA, - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, - ]: - return bool(not self._cookie or self.is_connection_open(grvt_endpoint_type)) - raise ValueError(f"Unknown endpoint type {grvt_endpoint_type}") - - def are_endpoints_connected( - self, grvt_endpoint_types: list[GrvtWSEndpointType] - ) -> bool: - return all( - self.is_endpoint_connected(endpoint) for endpoint in grvt_endpoint_types - ) - - async def connect_all_channels(self) -> None: - """ - Connects to all channels that are possible to connect. - If cookie is NOT available, it will NOT connect to GrvtWSEndpointType.TRADE_DATA - For trading connection: run this method after cookie is available. - """ - FN = "connect_all_channels" - while True: - try: - for end_point_type in self.endpoint_types: - if ( - not self.is_endpoint_connected(end_point_type) - or self.force_reconnect_flag - ): - await self._reconnect(end_point_type) - all_are_connected = self.are_endpoints_connected(self.endpoint_types) - self.logger.info( - f"{FN} Connection status: {all_are_connected=} {self.force_reconnect_flag=}" - ) - self.force_reconnect_flag = False - except Exception as e: - self.logger.exception(f"{FN} {e=}") - finally: - await asyncio.sleep(5) - - async def connect_channel(self, grvt_endpoint_type: GrvtWSEndpointType) -> bool: - FN = f"{self._clsname} connect_channel {grvt_endpoint_type}" - try: - if self.is_endpoint_connected(grvt_endpoint_type): - self.logger.info(f"{FN} Already connected") - return True - self.subscribed_streams[grvt_endpoint_type] = {} - extra_headers = {} - if self._cookie: - extra_headers = {"Cookie": f"gravity={self._cookie['gravity']}"} - if self._cookie["X-Grvt-Account-Id"]: - extra_headers.update( - {"X-Grvt-Account-Id": self._cookie["X-Grvt-Account-Id"]} - ) - if grvt_endpoint_type in [ - GrvtWSEndpointType.TRADE_DATA, - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, - ]: - if self._cookie: - self.ws[grvt_endpoint_type] = await websockets.connect( - uri=self.api_url[grvt_endpoint_type], - extra_headers=extra_headers, - logger=self.logger, - open_timeout=5, - ) - self.logger.info( - f"{FN} Connected to {self.api_url[grvt_endpoint_type]} {extra_headers=}" - ) - else: - self.logger.info(f"{FN} Waiting for cookie.") - elif grvt_endpoint_type in [ - GrvtWSEndpointType.MARKET_DATA, - GrvtWSEndpointType.MARKET_DATA_RPC_FULL, - ]: - self.ws[grvt_endpoint_type] = await websockets.connect( - uri=self.api_url[grvt_endpoint_type], - extra_headers=extra_headers, - logger=self.logger, - open_timeout=5, - ) - self.logger.info(f"{FN} Connected to {self.api_url[grvt_endpoint_type]} {extra_headers=}") - except ( - websockets.exceptions.ConnectionClosedOK, - websockets.exceptions.ConnectionClosed, - ) as e: - self.logger.info(f"{FN} connection already closed:{e}") - self.ws[grvt_endpoint_type] = None - except Exception as e: - self.logger.warning(f"{FN} error:{e} traceback:{traceback.format_exc()}") - self.ws[grvt_endpoint_type] = None - # return True if connection successful - return self.is_endpoint_connected(grvt_endpoint_type) - - async def _close_connection(self, grvt_endpoint_type: GrvtWSEndpointType): - try: - if self.ws[grvt_endpoint_type]: - self.logger.info(f"{self._clsname} Closing connection...") - await self.ws[grvt_endpoint_type].close() - self.subscribed_streams[grvt_endpoint_type] = {} - self.logger.info(f"{self._clsname} Connection closed") - else: - self.logger.info(f"{self._clsname} No connection to close") - except Exception: - self.logger.exception( - f"{self._clsname} Error when closing connection {traceback.format_exc()}" - ) - - async def _reconnect(self, grvt_endpoint_type: GrvtWSEndpointType): - FN = f"{self._clsname} _reconnect {grvt_endpoint_type=}" - try: - self.logger.info(f"{FN} STARTS") - await self._close_connection(grvt_endpoint_type) - success: bool = await self.connect_channel(grvt_endpoint_type) - if success: - await self._resubscribe(grvt_endpoint_type) - except Exception: - self.logger.exception(f"{FN} failed {traceback.format_exc()}") - - async def _resubscribe(self, grvt_endpoint_type: GrvtWSEndpointType): - if self.is_connection_open(grvt_endpoint_type): - for versioned_stream in self.callbacks[grvt_endpoint_type]: - for selector in self.callbacks[grvt_endpoint_type][versioned_stream]: - self.logger.info( - f"{self._clsname} _resubscribe {grvt_endpoint_type=}" - f" {versioned_stream=}/{selector=}" - ) - await self._subscribe_to_stream( - grvt_endpoint_type, versioned_stream, selector - ) - else: - self.logger.warning(f"{self._clsname} _resubscribe - No connection.") - - # **************** PUBLIC API CALLS - def is_stream_subscribed( - self, grvt_endpoint_type: GrvtWSEndpointType, stream: str - ) -> bool: - versioned_stream = self.get_versioned_stream(stream) - return self.subscribed_streams.get(grvt_endpoint_type, {}).get( - versioned_stream, False - ) - - def _check_susbcribed_stream( - self, grvt_endpoint_type: GrvtWSEndpointType, message: dict - ) -> None: - stream_subscribed: str = "" - if "stream" in message: - stream_subscribed = message["stream"] - elif "result" in message and "stream" in message["result"]: - stream_subscribed = message.get("result", {}).get("stream", "") - if stream_subscribed: - if not self.subscribed_streams[grvt_endpoint_type].get(stream_subscribed): - self.logger.info( - f"{self._clsname} subscribed to stream:{stream_subscribed}" - ) - self.subscribed_streams[grvt_endpoint_type][stream_subscribed] = True - - async def _read_messages(self, grvt_endpoint_type: GrvtWSEndpointType): - FN = f"{self._clsname} _read_messages {grvt_endpoint_type.value}" - while True: - if self.is_connection_open(grvt_endpoint_type): - try: - self.logger.debug(f"{FN} waiting for message") - response = await asyncio.wait_for( - self.ws[grvt_endpoint_type].recv(), timeout=WS_READ_TIMEOUT - ) - message = json.loads(response) - self.logger.debug(f"{FN} received {message=}") - self._check_susbcribed_stream(grvt_endpoint_type, message) - if "feed" in message: - stream_subscribed: str | None = message.get("stream") - selector: str = message.get("selector") - if stream_subscribed is None: - self.logger.warning(f"{FN} missing stream in {message=}") - if selector is None: - self.logger.warning(f"{FN} missing selector in {message=}") - if stream_subscribed and selector: - callback = ( - self.callbacks[grvt_endpoint_type] - .get(stream_subscribed, {}) - .get(selector, None) - ) - if callback: - await callback(message) - stream: str = self.get_non_versioned_stream( - stream_subscribed - ) - self._last_message[stream] = message - else: - self.logger.warning( - f"{FN} No callback for {stream_subscribed=}/{selector=}" - ) - elif "jsonrpc" in message: - """ - {'jsonrpc': '', 'result': {'result': - {'order_id': '0x00', 'sub_account_id': '8751933338735530', - 'is_market': False, 'time_in_force': 'GOOD_TILL_TIME', 'post_only': False, - 'reduce_only': False, 'legs': [{'instrument': 'BTC_USDT_Perp', 'size': '0.001', - 'limit_price': '50000.0', 'is_buying_asset': True}], - 'signature': {'signer': '0x2989e3783e2ae05f9a1538dd411a22a4cd9554ad', - 'r': '0xa566702c1e5557ab96e8d5197b6871456765a80556bba46c9d4928bd573ca66c', - 's': '0x6f6e0be6dca125643fce884ca28c0ae341b201efe49e10a9626859517b4a09af', - 'v': 28, 'expiration': '1729005262433997000', 'nonce': 3898454329}, - 'metadata': {'client_order_id': '123', 'create_time': '1728918862633971628'}, - 'state': {'status': 'OPEN', 'reject_reason': 'UNSPECIFIED', - 'book_size': ['0.001'], 'traded_size': ['0.0'], 'update_time': '1728918862633971628'}}}, - 'id': 2} - """ - self.logger.debug(f"{FN} jsonrpc result:{message.get('result')}") - else: - self.logger.info(f"{FN} Non-actionable message:{message}") - except ( - websockets.exceptions.ConnectionClosedError, - websockets.exceptions.ConnectionClosedOK, - ): - self.logger.exception( - f"{FN} connection closed {traceback.format_exc()}" - ) - await self._reconnect(grvt_endpoint_type) - except asyncio.TimeoutError: # noqa: UP041 - self.logger.debug(f"{FN} Timeout {WS_READ_TIMEOUT} secs") - pass - except Exception: - self.logger.exception( - f"{FN} connection failed {traceback.format_exc()}" - ) - await asyncio.sleep(1) - else: - self.logger.info(f"{FN} connection not open") - await asyncio.sleep(2) - - async def _send(self, end_point_type: GrvtWSEndpointType, message: str): - try: - if self.ws[end_point_type] and self.ws[end_point_type].open: - self.logger.info( - f"{self._clsname} _send() {end_point_type=}" - f" url:{self.api_url[end_point_type]} {message=}" - ) - await self.ws[end_point_type].send(message) - except websockets.exceptions.ConnectionClosedError as e: - self.logger.info(f"{self._clsname} _send() Restarted connection {e}") - await self._reconnect(end_point_type) - if self.ws[end_point_type]: - self.logger.info( - f"{self._clsname} _send() RESEND on RECONNECT {end_point_type=}" - f" url:{self.api_url[end_point_type]} {message=}" - ) - await self.ws[end_point_type].send(message) - except Exception: - self.logger.exception(f"{self._clsname} send failed {traceback.format_exc()}") - await self._reconnect(end_point_type) - - def _construct_selector(self, stream: str, params: dict) -> str: - feed: str = "" - # ******** Market Data ******** - if stream.endswith(("mini.s", "mini.d", "ticker.s", "ticker.d")): - feed = f"{params.get('instrument', '')}@{params.get('rate', '500')}" - if stream.endswith("book.s"): - feed = ( - f"{params.get('instrument', '')}@{params.get('rate', '500')}-" - f"{params.get('depth', '10')}" - ) - if stream.endswith("book.d"): - feed = f"{params.get('instrument', '')}@{params.get('rate', '500')}" - if stream.endswith("trade"): - feed = f"{params.get('instrument', '')}@{params.get('limit', '50')}" - if stream.endswith("candle"): - feed = ( - f"{params.get('instrument', '')}@{params.get('interval', 'CI_1_M')}-" - f"{params.get('type', 'TRADE')}" - ) - # ******** Trade Data ******** - if stream.endswith(("order", "state", "position", "fill")): - if not params: - feed = f"{self._trading_account_id}" - elif params.get("instrument"): - feed = f"{self._trading_account_id}-{params.get('instrument', '')}" - else: - feed = ( - f"{self._trading_account_id}-{params.get('kind', '')}-" - f"{params.get('base', '')}-{params.get('quote', '')}" - ) - # Deposit, Transfer, Withdrawal - if stream.endswith(("deposit", "transfer", "withdrawal")): - feed = "" - # f"{params.get('sub_account_id', '')}-{params.get('main_account_id', '')}" - - return feed - - async def subscribe( - self, - stream: str, - callback: Callable, - ws_end_point_type: GrvtWSEndpointType | None = None, - params: dict = {}, - ) -> None: - """ - Subscribe to a stream with optional parameters. - Call the callback function when a message is received. - callback function should have the following signature: - (dict) -> None. - """ - FN = f"{self._clsname} subscribe {stream=}" - if not ws_end_point_type: # use default endpoint type - ws_end_point_type = GRVT_WS_STREAMS.get(stream) - if not ws_end_point_type: - self.logger.error(f"{FN} unknown GrvtWSEndpointType for {stream=}") - return - is_trade_data = is_trading_ws_endpoint(ws_end_point_type) - if is_trade_data and not self._trading_account_id: - self.logger.error( - f"{FN} {stream=} is a trading data connection. Requires trading_account_id." - ) - return - # create selector string and register callback - selector: str = self._construct_selector(stream, params) - versioned_stream: str = self.get_versioned_stream(stream) - if versioned_stream not in self.callbacks[ws_end_point_type]: - self.callbacks[ws_end_point_type][versioned_stream] = {} - self.callbacks[ws_end_point_type][versioned_stream][selector] = callback - self.logger.info( - f"{FN} {params=} {ws_end_point_type=}/{versioned_stream=}/{selector=} callback:{callback}" - ) - # check if connection is open and subscribe - if self.is_connection_open(ws_end_point_type): - await self._subscribe_to_stream(ws_end_point_type, versioned_stream, selector) - else: - self.logger.info(f"{FN} Connection not open. Will subscribe on connect.") - - async def re_subscribe_stream( - self, - stream: str, - callback: Callable, - ws_end_point_type: GrvtWSEndpointType | None = None, - params: dict = {}, - ) -> None: - """ This method should be called in a separate task - - otherwise it will block the event loop for 5 seconds. - Unsubscribe from a specific stream and subscribe again with optional parameters. - Call the callback function when a message is received. - callback function should have the following signature: - (dict) -> None. - """ - FN = f"{self._clsname} re_subscribe {stream=}" - if not ws_end_point_type: # use default endpoint type - ws_end_point_type = GRVT_WS_STREAMS.get(stream) - if not ws_end_point_type: - self.logger.error(f"{FN} unknown GrvtWSEndpointType for {stream=}") - return - if not self.is_connection_open(ws_end_point_type): - self.logger.info(f"{FN} {ws_end_point_type=} not open. Try again after connect.") - return - is_trade_data = is_trading_ws_endpoint(ws_end_point_type) - if is_trade_data and not self._trading_account_id: - self.logger.error( - f"{FN} {stream=} is a trading data connection. Requires trading_account_id." - ) - return - # create selector string and register callback - selector: str = self._construct_selector(stream, params) - versioned_stream: str = self.get_versioned_stream(stream) - if versioned_stream not in self.callbacks[ws_end_point_type]: - self.callbacks[ws_end_point_type][versioned_stream] = {} - self.callbacks[ws_end_point_type][versioned_stream][selector] = callback - # self.logger.info( - # f"{FN} {params=} {ws_end_point_type=}/{versioned_stream=}/{selector=} callback:{callback}" - # ) - await self._unsubscribe_to_stream(ws_end_point_type, versioned_stream, selector) - await asyncio.sleep(5) # wait for unsubscribe to complete - await self._subscribe_to_stream(ws_end_point_type, versioned_stream, selector) - - - def get_versioned_stream(self, stream: str) -> str: - return ( - stream if self.api_ws_version == "v0" else f"{self.api_ws_version}.{stream}" - ) - - def get_non_versioned_stream(self, versioned_stream: str) -> str: - if self.api_ws_version == "v0": - return versioned_stream - return versioned_stream.split(".")[1] - - async def _subscribe_to_stream( - self, - ws_end_point_type: GrvtWSEndpointType, - versioned_stream: str, - selector: str, - ) -> None: - FN = ( - f"{self._clsname} _subscribe_to_stream {ws_end_point_type=}" - f" {versioned_stream=} {selector=}" - ) - self._request_id += 1 - if ws_end_point_type in [ - GrvtWSEndpointType.TRADE_DATA, - GrvtWSEndpointType.MARKET_DATA, - ]: # Legacy subscription - subscribe_json = json.dumps( - { - "request_id": self._request_id, - "stream": versioned_stream, - "feed": [selector], - "method": "subscribe", - "is_full": True, - } - ) - self.logger.info(f"{FN} {versioned_stream=} {subscribe_json=}") - else: # RPC WS format - self._request_id += 1 - subscribe_json = json.dumps( - { - "jsonrpc": "2.0", - "method": "subscribe", - "params": { - "stream": versioned_stream, - "selectors": [selector], - }, - "id": self._request_id, - } - ) - self.logger.info(f"{FN} {versioned_stream=} {subscribe_json=}") - await self._send(ws_end_point_type, subscribe_json) - stream: str = self.get_non_versioned_stream(versioned_stream) - if stream not in self._last_message: - self._last_message[stream] = {} - - async def _unsubscribe_to_stream( - self, - ws_end_point_type: GrvtWSEndpointType, - versioned_stream: str, - selector: str, - ) -> None: - FN = ( - f"{self._clsname} _unsubscribe_to_stream {ws_end_point_type=}" - f" {versioned_stream=} {selector=}" - ) - self._request_id += 1 - if ws_end_point_type in [ - GrvtWSEndpointType.TRADE_DATA, - GrvtWSEndpointType.MARKET_DATA, - ]: # Legacy subscription - subscribe_json = json.dumps( - { - "request_id": self._request_id, - "stream": versioned_stream, - "feed": [selector], - "method": "unsubscribe", - "is_full": True, - } - ) - self.logger.info(f"{FN} {versioned_stream=} {subscribe_json=}") - else: # RPC WS format - self._request_id += 1 - subscribe_json = json.dumps( - { - "jsonrpc": "2.0", - "method": "unsubscribe", - "params": { - "stream": versioned_stream, - "selectors": [selector], - }, - "id": self._request_id, - } - ) - self.logger.info(f"{FN} {versioned_stream=} {subscribe_json=}") - await self._send(ws_end_point_type, subscribe_json) - - def jsonrpc_wrap_payload( - self, payload: dict, method: str, version: str = "v1" - ) -> dict: - """ - Wrap the payload in JSON-RPC format. - """ - self._request_id += 1 - return { - "jsonrpc": "2.0", - "method": f"{version}/{method}", - "params": payload, - "id": self._request_id, - } - - async def send_rpc_message( - self, end_point_type: GrvtWSEndpointType, message: dict - ) -> None: - """ - Send a message to the server. - """ - await self._send(end_point_type, json.dumps(message)) - self.logger.info(f"{self._clsname} send_rpc_message {end_point_type=} {message=}") - - async def rpc_create_order( - self, - symbol: str, - order_type: GrvtOrderType, - side: GrvtOrderSide, - amount: float | Decimal | str | int, - price: Num = None, - params={}, - ) -> dict: - """ - Create an order. - """ - FN = f"{self._clsname} rpc_create_order" - if not self.is_endpoint_connected(GrvtWSEndpointType.TRADE_DATA_RPC_FULL): - raise GrvtInvalidOrder("Trade data connection not available.") - order = self._get_order_with_validations( - symbol, order_type, side, amount, price, params - ) - self.logger.info(f"{FN} {order=}") - payload = get_order_rpc_payload(order, self._private_key, self.env, self.markets) - self._request_id += 1 - payload["id"] = self._request_id - self.logger.info(f"{FN} {payload=}") - await self.send_rpc_message(GrvtWSEndpointType.TRADE_DATA_RPC_FULL, payload) - return payload - - async def rpc_create_limit_order( - self, - symbol: str, - side: GrvtOrderSide, - amount: float | Decimal | str | int, - price: Num, - params={}, - ) -> dict: - return await self.rpc_create_order(symbol, "limit", side, amount, price, params) - - async def rpc_cancel_all_orders( - self, - params: dict = {}, - ) -> dict: - """ - Ccxt compliant signature BUT lacks symbol - Cancel all orders for a sub-account. - params: dictionary with parameters. Valid keys:
    - `kind` (str): instrument kind. Valid values: 'PERPETUAL'.
    - `base` (str): base currency. If missing/empty then fetch - orders for all base currencies.
    - `quote` (str): quote currency. Defaults to all.
    - """ - self._check_account_auth() - # FN = f"{self._clsname} rpc_cancel_all_orders" - payload: dict = self._get_payload_cancel_all_orders(params) - jsonrpc_payload: dict = self.jsonrpc_wrap_payload(payload, method="cancel_all_orders") - await self.send_rpc_message( - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, jsonrpc_payload - ) - return jsonrpc_payload - - async def rpc_cancel_order( - self, - id: str | None = None, - symbol: str | None = None, - params: dict = {}, - ) -> dict: - """ - Ccxt compliant signature - Cancel specific order for the account by sending JsonRpc call on WebSocket.
    - Private call requires authorization.
    - See [Cancel order](https://api-docs.grvt.io/trading_api/#cancel-order) - for details.
    . - - Args: - id (str): exchange assigned order ID
    - symbol (str): trading symbol
    - params: - * client_order_id (str): client assigned order ID
    - * time_to_live_ms (str): lifetime of cancel requiest in millisecs
    - Returns: - payload used to cancel order.
    - """ - FN = f"{self._clsname} rpc_cancel_order" - if not self.is_endpoint_connected(GrvtWSEndpointType.TRADE_DATA_RPC_FULL): - raise GrvtInvalidOrder("Trade data connection not available.") - self._check_account_auth() - # Prepare payload - payload: dict = { - "sub_account_id": str(self._trading_account_id), - } - if id: - payload["order_id"] = str(id) - elif "client_order_id" in params: - payload["client_order_id"] = str(params["client_order_id"]) - else: - raise GrvtInvalidOrder(f"{FN} requires either order_id or client_order_id") - if "time_to_live_ms" in params: - payload["time_to_live_ms"] = str(params["time_to_live_ms"]) - # Send cancel requiest - jsonrpc_payload = self.jsonrpc_wrap_payload(payload, method="cancel_order") - await self.send_rpc_message( - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, jsonrpc_payload - ) - return jsonrpc_payload - - async def rpc_fetch_open_orders( - self, - params: dict = {}, - ) -> dict: - """ - Fetch open orders for the account.
    - Private call requires authorization.
    - See [Open orders](https://api-docs.grvt.io/trading_api/#open-orders) - for details.
    . - Fetches open orders for the account.
    - Sends JsonRpc call on WebSocket.
    - Args: - params: dictionary with parameters. Valid keys:
    - `kind` (str): instrument kind. Valid values are 'PERPETUAL'.
    - `base` (str): base currency. If missing/empty then fetch orders - for all base currencies.
    - `quote` (str): quote currency. Defaults to all.
    - Returns: - payload used to fetch open orders.

    - """ - self._check_account_auth() - # Prepare request payload - payload: dict = self._get_payload_fetch_open_orders(symbol=None, params=params) - jsonrpc_payload: dict = self.jsonrpc_wrap_payload(payload, method="open_orders") - await self.send_rpc_message( - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, jsonrpc_payload - ) - return jsonrpc_payload - - async def rpc_fetch_order( - self, - id: str | None = None, - symbol: str | None = None, - params: dict = {}, - ) -> dict: - """ - Ccxt compliant signature.
    - Private call requires authorization.
    - See [Get Order](https://api-docs.grvt.io/trading_api/#get-order) - for details.
    . - Get Order status by either order_id or client_order_id.
    - Sends JsonRpc call on WebSocket.
    - Args: - id: (str) order_id to fetch.
    - symbol: (str) NOT SUPPRTED.
    - params: dictionary with parameters. Valid keys:
    - `client_order_id` (int): client assigned order ID.
    - Returns: - payload used to fetch order.
    - """ - FN = f"{self._clsname} rpc_fetch_order" - self._check_account_auth() - payload = { - "sub_account_id": str(self._trading_account_id), - } - if id: - payload["order_id"] = id - elif "client_order_id" in params: - payload["client_order_id"] = str(params["client_order_id"]) - else: - raise GrvtInvalidOrder( - f"{FN} requires either order_id or params['client_order_id']" - ) - jsonrpc_payload = self.jsonrpc_wrap_payload(payload, method="order") - await self.send_rpc_message( - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, jsonrpc_payload - ) - return jsonrpc_payload diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_fixed_types.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_fixed_types.py deleted file mode 100644 index 9700e96..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_fixed_types.py +++ /dev/null @@ -1,25 +0,0 @@ -from dataclasses import dataclass - -from .grvt_raw_types import Signature, TransferType - - -@dataclass -class Transfer: - # The account to transfer from - from_account_id: str - # The subaccount to transfer from (0 if transferring from main account) - from_sub_account_id: str - # The account to deposit into - to_account_id: str - # The subaccount to transfer to (0 if transferring to main account) - to_sub_account_id: str - # The token currency to transfer - currency: str - # The number of tokens to transfer - num_tokens: str - # The signature of the transfer - signature: Signature - # The type of transfer - transfer_type: TransferType - # The metadata of the transfer - transfer_metadata: str diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_async.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_async.py deleted file mode 100644 index a3dd798..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_async.py +++ /dev/null @@ -1,365 +0,0 @@ -from enum import Enum - -from dacite import Config, from_dict - -from . import grvt_raw_types as types -from .grvt_raw_base import GrvtApiConfig, GrvtError, GrvtRawAsyncBase - -# mypy: disable-error-code="no-any-return" - - -class GrvtRawAsync(GrvtRawAsyncBase): - def __init__(self, config: GrvtApiConfig): - super().__init__(config) - self.md_rpc = self.env.market_data.rpc_endpoint - self.td_rpc = self.env.trade_data.rpc_endpoint - - async def get_instrument_v1( - self, req: types.ApiGetInstrumentRequest - ) -> types.ApiGetInstrumentResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/instrument", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiGetInstrumentResponse, resp, Config(cast=[Enum])) - - async def get_all_instruments_v1( - self, req: types.ApiGetAllInstrumentsRequest - ) -> types.ApiGetAllInstrumentsResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/all_instruments", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiGetAllInstrumentsResponse, resp, Config(cast=[Enum])) - - async def get_filtered_instruments_v1( - self, req: types.ApiGetFilteredInstrumentsRequest - ) -> types.ApiGetFilteredInstrumentsResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/instruments", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiGetFilteredInstrumentsResponse, resp, Config(cast=[Enum]) - ) - - async def get_currency_v1( - self, req: types.ApiGetCurrencyRequest - ) -> types.ApiGetCurrencyResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/currency", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiGetCurrencyResponse, resp, Config(cast=[Enum])) - - async def mini_ticker_v1( - self, req: types.ApiMiniTickerRequest - ) -> types.ApiMiniTickerResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/mini", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiMiniTickerResponse, resp, Config(cast=[Enum])) - - async def ticker_v1( - self, req: types.ApiTickerRequest - ) -> types.ApiTickerResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/ticker", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTickerResponse, resp, Config(cast=[Enum])) - - async def orderbook_levels_v1( - self, req: types.ApiOrderbookLevelsRequest - ) -> types.ApiOrderbookLevelsResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/book", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiOrderbookLevelsResponse, resp, Config(cast=[Enum])) - - async def trade_v1( - self, req: types.ApiTradeRequest - ) -> types.ApiTradeResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/trade", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTradeResponse, resp, Config(cast=[Enum])) - - async def trade_history_v1( - self, req: types.ApiTradeHistoryRequest - ) -> types.ApiTradeHistoryResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/trade_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTradeHistoryResponse, resp, Config(cast=[Enum])) - - async def candlestick_v1( - self, req: types.ApiCandlestickRequest - ) -> types.ApiCandlestickResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/kline", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiCandlestickResponse, resp, Config(cast=[Enum])) - - async def funding_rate_v1( - self, req: types.ApiFundingRateRequest - ) -> types.ApiFundingRateResponse | GrvtError: - resp = await self._post(False, self.md_rpc + "/full/v1/funding", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiFundingRateResponse, resp, Config(cast=[Enum])) - - async def create_order_v1( - self, req: types.ApiCreateOrderRequest - ) -> types.ApiCreateOrderResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/create_order", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiCreateOrderResponse, resp, Config(cast=[Enum])) - - async def cancel_order_v1( - self, req: types.ApiCancelOrderRequest - ) -> types.AckResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/cancel_order", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - async def cancel_all_orders_v1( - self, req: types.ApiCancelAllOrdersRequest - ) -> types.AckResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/cancel_all_orders", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - async def get_order_v1( - self, req: types.ApiGetOrderRequest - ) -> types.ApiGetOrderResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/order", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiGetOrderResponse, resp, Config(cast=[Enum])) - - async def open_orders_v1( - self, req: types.ApiOpenOrdersRequest - ) -> types.ApiOpenOrdersResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/open_orders", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiOpenOrdersResponse, resp, Config(cast=[Enum])) - - async def order_history_v1( - self, req: types.ApiOrderHistoryRequest - ) -> types.ApiOrderHistoryResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/order_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiOrderHistoryResponse, resp, Config(cast=[Enum])) - - async def cancel_on_disconnect_v1( - self, req: types.ApiCancelOnDisconnectRequest - ) -> types.AckResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/cancel_on_disconnect", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - async def fill_history_v1( - self, req: types.ApiFillHistoryRequest - ) -> types.ApiFillHistoryResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/fill_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiFillHistoryResponse, resp, Config(cast=[Enum])) - - async def positions_v1( - self, req: types.ApiPositionsRequest - ) -> types.ApiPositionsResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/positions", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiPositionsResponse, resp, Config(cast=[Enum])) - - async def funding_payment_history_v1( - self, req: types.ApiFundingPaymentHistoryRequest - ) -> types.ApiFundingPaymentHistoryResponse | GrvtError: - resp = await self._post( - True, self.td_rpc + "/full/v1/funding_payment_history", req - ) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiFundingPaymentHistoryResponse, resp, Config(cast=[Enum]) - ) - - async def deposit_history_v1( - self, req: types.ApiDepositHistoryRequest - ) -> types.ApiDepositHistoryResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/deposit_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiDepositHistoryResponse, resp, Config(cast=[Enum])) - - async def transfer_v1( - self, req: types.ApiTransferRequest - ) -> types.ApiTransferResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/transfer", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTransferResponse, resp, Config(cast=[Enum])) - - async def transfer_history_v1( - self, req: types.ApiTransferHistoryRequest - ) -> types.ApiTransferHistoryResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/transfer_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTransferHistoryResponse, resp, Config(cast=[Enum])) - - async def withdrawal_v1( - self, req: types.ApiWithdrawalRequest - ) -> types.AckResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/withdrawal", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - async def withdrawal_history_v1( - self, req: types.ApiWithdrawalHistoryRequest - ) -> types.ApiWithdrawalHistoryResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/withdrawal_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiWithdrawalHistoryResponse, resp, Config(cast=[Enum])) - - async def sub_account_summary_v1( - self, req: types.ApiSubAccountSummaryRequest - ) -> types.ApiSubAccountSummaryResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/account_summary", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiSubAccountSummaryResponse, resp, Config(cast=[Enum])) - - async def sub_account_history_v1( - self, req: types.ApiSubAccountHistoryRequest - ) -> types.ApiSubAccountHistoryResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/account_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiSubAccountHistoryResponse, resp, Config(cast=[Enum])) - - async def aggregated_account_summary_v1( - self, req: types.EmptyRequest - ) -> types.ApiAggregatedAccountSummaryResponse | GrvtError: - resp = await self._post( - True, self.td_rpc + "/full/v1/aggregated_account_summary", req - ) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiAggregatedAccountSummaryResponse, resp, Config(cast=[Enum]) - ) - - async def funding_account_summary_v1( - self, req: types.EmptyRequest - ) -> types.ApiFundingAccountSummaryResponse | GrvtError: - resp = await self._post( - True, self.td_rpc + "/full/v1/funding_account_summary", req - ) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiFundingAccountSummaryResponse, resp, Config(cast=[Enum]) - ) - - async def set_derisk_mm_ratio_v1( - self, req: types.ApiSetDeriskToMaintenanceMarginRatioRequest - ) -> types.ApiSetDeriskToMaintenanceMarginRatioResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/set_derisk_mm_ratio", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiSetDeriskToMaintenanceMarginRatioResponse, resp, Config(cast=[Enum]) - ) - - async def get_all_initial_leverage_v1( - self, req: types.ApiGetAllInitialLeverageRequest - ) -> types.ApiGetAllInitialLeverageResponse | GrvtError: - resp = await self._post( - True, self.td_rpc + "/full/v1/get_all_initial_leverage", req - ) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiGetAllInitialLeverageResponse, resp, Config(cast=[Enum]) - ) - - async def set_initial_leverage_v1( - self, req: types.ApiSetInitialLeverageRequest - ) -> types.ApiSetInitialLeverageResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/set_initial_leverage", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiSetInitialLeverageResponse, resp, Config(cast=[Enum])) - - async def vault_burn_tokens_v1( - self, req: types.ApiVaultBurnTokensRequest - ) -> types.AckResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/vault_burn_tokens", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - async def vault_invest_v1( - self, req: types.ApiVaultInvestRequest - ) -> types.AckResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/vault_invest", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - async def vault_investor_summary_v1( - self, req: types.ApiVaultInvestorSummaryRequest - ) -> types.ApiVaultInvestorSummaryResponse | GrvtError: - resp = await self._post( - True, self.td_rpc + "/full/v1/vault_investor_summary", req - ) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiVaultInvestorSummaryResponse, resp, Config(cast=[Enum])) - - async def vault_redeem_v1( - self, req: types.ApiVaultRedeemRequest - ) -> types.AckResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/vault_redeem", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - async def vault_redeem_cancel_v1( - self, req: types.ApiVaultRedeemCancelRequest - ) -> types.AckResponse | GrvtError: - resp = await self._post(True, self.td_rpc + "/full/v1/vault_redeem_cancel", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - async def vault_redemption_queue_v1( - self, req: types.ApiVaultViewRedemptionQueueRequest - ) -> types.ApiVaultViewRedemptionQueueResponse | GrvtError: - resp = await self._post( - True, self.td_rpc + "/full/v1/vault_view_redemption_queue", req - ) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiVaultViewRedemptionQueueResponse, resp, Config(cast=[Enum]) - ) - - async def query_vault_manager_investor_history_v1( - self, req: types.ApiQueryVaultManagerInvestorHistoryRequest - ) -> types.ApiQueryVaultManagerInvestorHistoryResponse | GrvtError: - resp = await self._post( - True, self.td_rpc + "/full/v1/vault_manager_investor_history", req - ) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiQueryVaultManagerInvestorHistoryResponse, resp, Config(cast=[Enum]) - ) diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_base.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_base.py deleted file mode 100644 index b5b5d1f..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_base.py +++ /dev/null @@ -1,267 +0,0 @@ -import dataclasses -import json -import logging -import time -from dataclasses import dataclass -from datetime import datetime -from enum import Enum -from http.cookies import SimpleCookie -from typing import Any - -import aiohttp -import requests # type: ignore -from eth_account import Account - -from .grvt_raw_env import GrvtEnv, GrvtEnvConfig, get_env_config - - -@dataclass -class GrvtApiConfig: - env: GrvtEnv - trading_account_id: str | None - private_key: str | None - api_key: str | None - logger: logging.Logger | None - - -@dataclass -class GrvtError: - code: int - message: str - status: int - - -@dataclass -class GrvtCookie: - gravity: str - expires: datetime - grvt_account_id: str | None = None - - -class GrvtRawBase: - """ - GrvtRawBase is base class for Grvt Rest API classes. - - This should not be used directly, but rather through a derivative API class. - """ - - def __init__(self, config: GrvtApiConfig): - self.config = config - self.env: GrvtEnvConfig = get_env_config(config.env) - self.logger: logging.Logger = config.logger or logging.getLogger(__name__) - self._cookie: GrvtCookie | None = None - if self.config.private_key is not None: - self.account: Account = Account.from_key(self.config.private_key) - - """ - Cookie handling - """ - - def _should_refresh_cookie(self) -> bool: - if not self.config.api_key: - raise ValueError("Attempting to use Authenticated API without API key set") - time_till_expiration = None - if self._cookie and self._cookie.expires: - time_till_expiration = self._cookie.expires.timestamp() - time.time() - is_cookie_fresh = time_till_expiration is not None and time_till_expiration > 5 - if not is_cookie_fresh: - self.logger.info( - f"cookie should be refreshed now={time.time()}" - f" {time_till_expiration=} secs" - ) - return not is_cookie_fresh - - -class GrvtRawSyncBase(GrvtRawBase): - def __init__(self, config: GrvtApiConfig): - super().__init__(config) - # Sync API session - self._session: requests.Session = requests.Session() - self._session.headers.update({"Content-Type": "application/json"}) - - """ - Cookie handling - """ - - def _refresh_cookie(self) -> None: - if not self._should_refresh_cookie(): - return None - # Get cookie - self._cookie = self._get_cookie( - self.env.edge.rpc_endpoint + "/auth/api_key/login", str(self.config.api_key) - ) - self.logger.info(f"refresh_cookie cookie={self._cookie}") - # Update cookie in session - if self._cookie: - self._session.cookies.update({"gravity": self._cookie.gravity}) - if self._cookie.grvt_account_id: - self._session.headers.update( - {"X-Grvt-Account-Id": self._cookie.grvt_account_id} - ) - return None - - def _get_cookie(self, path: str, api_key: str) -> GrvtCookie | None: - FN = f"_get_cookie {path=}" - try: - return_value = self._session.post( - path, - json={"api_key": api_key}, - headers={"Content-Type": "application/json"}, - timeout=5, - ) - self.logger.info(f"{FN} {return_value=}") - if return_value.ok: - cookie = SimpleCookie() - cookie_header = return_value.headers.get("Set-Cookie") - grvt_cookie = return_value.cookies.get("gravity") - self.logger.info( - f"{FN} OK {return_value.headers=} \n " - f"{return_value.cookies=}\n{grvt_cookie=}\n{cookie_header=}" - ) - cookie.load(cookie_header) - cookie_value = cookie["gravity"].value - cookie_expiry = datetime.strptime( - cookie["gravity"]["expires"], - "%a, %d %b %Y %H:%M:%S %Z", - ) - grvt_account_id: str | None = return_value.headers.get( - "X-Grvt-Account-Id" - ) - return GrvtCookie( - gravity=cookie_value, - expires=cookie_expiry, - grvt_account_id=grvt_account_id, - ) - return None - except Exception as e: - self.logger.error(f"{FN} Error getting cookie: {e}") - return None - - """ - Post handling - """ - - def _post(self, is_auth: bool, path: str, req: Any) -> Any: - FN = f"_post {path=}" - # Always see if need to referesh cookie before sending an authenticated request - if is_auth: - self._refresh_cookie() - - req_json = json.dumps(req, cls=DataclassJSONEncoder) - resp_json: Any = {} - - self.logger.debug(f"{FN} {req_json=}") - resp: requests.Response = self._session.post(path, data=req_json, timeout=5) - try: - resp_json = resp.json() - if not resp.ok: - self.logger.warning(f"{FN} Error {resp_json=}") - else: - self.logger.debug(f"{FN} OK {resp_json=}") - except Exception as err: - self.logger.error(f"{FN} Unable to parse {resp.text=} as json:{err=}") - return resp_json - - -class GrvtRawAsyncBase(GrvtRawBase): - def __init__(self, config: GrvtApiConfig): - super().__init__(config) - # Async API session - self._session: aiohttp.ClientSession = aiohttp.ClientSession( - headers={"Content-Type": "application/json"} - ) - - """ - Cookie handling - """ - - async def _refresh_cookie(self) -> None: - if not self._should_refresh_cookie(): - return None - - # Get cookie - self._cookie = await self._get_cookie( - self.env.edge.rpc_endpoint + "/auth/api_key/login", str(self.config.api_key) - ) - self.logger.info(f"refresh_cookie cookie={self._cookie}") - - # Update cookie in session - if self._cookie: - self._session.cookie_jar.update_cookies({"gravity": self._cookie.gravity}) - if self._cookie.grvt_account_id: - self._session.headers.update( - {"X-Grvt-Account-Id": self._cookie.grvt_account_id} - ) - return None - - async def _get_cookie(self, path: str, api_key: str) -> GrvtCookie | None: - FN = f"_get_cookie {path=}" - try: - data = {"api_key": api_key} - self.logger.info(f"{FN} ask for cookie {path=} {data=}") - async with aiohttp.ClientSession() as session: - async with session.post(url=path, json=data, timeout=5) as return_value: - self.logger.info(f"{FN} {return_value=}") - if return_value.ok: - cookie = SimpleCookie() - cookie_header = return_value.headers.get("Set-Cookie") - grvt_cookie = return_value.cookies.get("gravity") - self.logger.info( - f"{FN} OK {return_value.headers=} \n " - f"{return_value.cookies=}\n{grvt_cookie=}\n{cookie_header=}" - ) - cookie.load(cookie_header) - cookie_value = cookie["gravity"].value - cookie_expiry = datetime.strptime( - cookie["gravity"]["expires"], - "%a, %d %b %Y %H:%M:%S %Z", - ) - grvt_account_id: str | None = return_value.headers.get( - "X-Grvt-Account-Id" - ) - return GrvtCookie( - gravity=cookie_value, - expires=cookie_expiry, - grvt_account_id=grvt_account_id, - ) - return None - except Exception as e: - self.logger.error(f"{FN} Error getting cookie: {e}") - return None - - """ - Post handling - """ - - async def _post(self, is_auth: bool, path: str, req: Any) -> Any: - FN = f"_post {path=}" - # Always see if need to referesh cookie before sending an authenticated request - if is_auth: - await self._refresh_cookie() - - req_json = json.dumps(req, cls=DataclassJSONEncoder) - resp_json: Any = {} - - self.logger.debug(f"{FN} {req_json=}") - resp: aiohttp.ClientResponse = await self._session.post( - path, data=req_json, timeout=5 - ) - try: - resp_text = await resp.text() - resp_json = json.loads(resp_text) - if not resp.ok: - self.logger.warning(f"{FN} Error {resp_text=}") - else: - self.logger.debug(f"{FN} OK {resp_text=}") - except Exception as err: - self.logger.error(f"{FN} Unable to parse {resp_text=} as json:{err=}") - return resp_json - - -class DataclassJSONEncoder(json.JSONEncoder): - def default(self, o: Any) -> Any: - if dataclasses.is_dataclass(o): - return dataclasses.asdict(o) # type: ignore - if isinstance(o, Enum): - return o.value - return super().default(o) diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_env.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_env.py deleted file mode 100644 index 1c3d5d8..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_env.py +++ /dev/null @@ -1,77 +0,0 @@ -from dataclasses import dataclass -from enum import Enum - - -class GrvtEnv(Enum): - DEV = "dev" - STAGING = "staging" - TESTNET = "testnet" - PROD = "prod" - - -@dataclass -class GrvtEndpointConfig: - rpc_endpoint: str - ws_endpoint: str | None - - -@dataclass -class GrvtEnvConfig: - edge: GrvtEndpointConfig - trade_data: GrvtEndpointConfig - market_data: GrvtEndpointConfig - chain_id: int - - -def get_env_config(environment: GrvtEnv) -> GrvtEnvConfig: - match environment: - case GrvtEnv.PROD: - return GrvtEnvConfig( - edge=GrvtEndpointConfig( - rpc_endpoint="https://edge.grvt.io", - ws_endpoint=None, - ), - trade_data=GrvtEndpointConfig( - rpc_endpoint="https://trades.grvt.io", - ws_endpoint="wss://trades.grvt.io/ws", - ), - market_data=GrvtEndpointConfig( - rpc_endpoint="https://market-data.grvt.io", - ws_endpoint="wss://market-data.grvt.io/ws", - ), - chain_id=325, - ) - case GrvtEnv.TESTNET: - return GrvtEnvConfig( - edge=GrvtEndpointConfig( - rpc_endpoint=f"https://edge.{environment.value}.grvt.io", - ws_endpoint=None, - ), - trade_data=GrvtEndpointConfig( - rpc_endpoint=f"https://trades.{environment.value}.grvt.io", - ws_endpoint=f"wss://trades.{environment.value}.grvt.io/ws", - ), - market_data=GrvtEndpointConfig( - rpc_endpoint=f"https://market-data.{environment.value}.grvt.io", - ws_endpoint=f"wss://market-data.{environment.value}.grvt.io/ws", - ), - chain_id=326, - ) - case GrvtEnv.DEV | GrvtEnv.STAGING: - return GrvtEnvConfig( - edge=GrvtEndpointConfig( - rpc_endpoint=f"https://edge.{environment.value}.gravitymarkets.io", - ws_endpoint=None, - ), - trade_data=GrvtEndpointConfig( - rpc_endpoint=f"https://trades.{environment.value}.gravitymarkets.io", - ws_endpoint=f"wss://trades.{environment.value}.gravitymarkets.io/ws", - ), - market_data=GrvtEndpointConfig( - rpc_endpoint=f"https://market-data.{environment.value}.gravitymarkets.io", - ws_endpoint=f"wss://market-data.{environment.value}.gravitymarkets.io/ws", - ), - chain_id=327 if environment == GrvtEnv.DEV else 328, - ) - case _: - raise ValueError(f"Unknown environment={environment}") diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_signing.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_signing.py deleted file mode 100644 index 1000bd3..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_signing.py +++ /dev/null @@ -1,248 +0,0 @@ -from enum import Enum -from decimal import Decimal -from typing import Any, Optional - -from eth_account import Account -from eth_account.messages import encode_typed_data - -from .grvt_ccxt_utils import GrvtCurrency -from .grvt_raw_base import GrvtApiConfig, GrvtEnv -from .grvt_raw_types import Instrument, Order, Withdrawal, TimeInForce -from .grvt_fixed_types import Transfer - -######################### -# INSTRUMENT CONVERSION # -######################### - - -PRICE_MULTIPLIER = 1_000_000_000 - - -class SignTimeInForce(Enum): - GOOD_TILL_TIME = 1 - ALL_OR_NONE = 2 - IMMEDIATE_OR_CANCEL = 3 - FILL_OR_KILL = 4 - - -TIME_IN_FORCE_TO_SIGN_TIME_IN_FORCE = { - TimeInForce.GOOD_TILL_TIME: SignTimeInForce.GOOD_TILL_TIME, - TimeInForce.ALL_OR_NONE: SignTimeInForce.ALL_OR_NONE, - TimeInForce.IMMEDIATE_OR_CANCEL: SignTimeInForce.IMMEDIATE_OR_CANCEL, - TimeInForce.FILL_OR_KILL: SignTimeInForce.FILL_OR_KILL, -} - - -##################### -# EIP-712 chain IDs # -##################### -CHAIN_IDS = { - GrvtEnv.DEV: 327, - GrvtEnv.STAGING: 327, - GrvtEnv.TESTNET: 326, - GrvtEnv.PROD: 325, -} - - -def get_EIP712_domain_data(env: GrvtEnv, chainId: int | None) -> dict[str, str | int]: - return { - "name": "GRVT Exchange", - "version": "0", - "chainId": chainId or CHAIN_IDS[env], - } - - -##################### -# Sign Order # -##################### - -EIP712_ORDER_MESSAGE_TYPE = { - "Order": [ - {"name": "subAccountID", "type": "uint64"}, - {"name": "isMarket", "type": "bool"}, - {"name": "timeInForce", "type": "uint8"}, - {"name": "postOnly", "type": "bool"}, - {"name": "reduceOnly", "type": "bool"}, - {"name": "legs", "type": "OrderLeg[]"}, - {"name": "nonce", "type": "uint32"}, - {"name": "expiration", "type": "int64"}, - ], - "OrderLeg": [ - {"name": "assetID", "type": "uint256"}, - {"name": "contractSize", "type": "uint64"}, - {"name": "limitPrice", "type": "uint64"}, - {"name": "isBuyingContract", "type": "bool"}, - ], -} - - -def sign_order( - order: Order, - config: GrvtApiConfig, - account: Account, - instruments: dict[str, Instrument], -) -> Order: - if config.private_key is None: - raise ValueError("Private key is not set") - - message_data = build_EIP712_order_message_data(order, instruments) - - domain_data = get_EIP712_domain_data(config.env, CHAIN_IDS[config.env]) - signable_message = encode_typed_data( - domain_data, EIP712_ORDER_MESSAGE_TYPE, message_data - ) - signed_message = account.sign_message(signable_message) - - order.signature.s = "0x" + signed_message.s.to_bytes(32, byteorder="big").hex() - order.signature.r = "0x" + signed_message.r.to_bytes(32, byteorder="big").hex() - order.signature.v = signed_message.v - order.signature.signer = str(account.address) - - return order - - -def build_EIP712_order_message_data( - order: Order, instruments: dict[str, Instrument] -) -> dict[str, Any]: - legs = [] - for leg in order.legs: - instrument = instruments[leg.instrument] - size_multiplier = 10**instrument.base_decimals - - # use Decimal() instead of float() to avoid precision loss - # int(float("1.013") * 1e9) = 1012999999 - # int(Decimal("1.013") * Decimal(1e9) = 1013000000 - size_int = int(Decimal(leg.size) * Decimal(size_multiplier)) - price_int = int(Decimal(leg.limit_price) * Decimal(PRICE_MULTIPLIER)) - legs.append( - { - "assetID": instrument.instrument_hash, - "contractSize": size_int, - "limitPrice": price_int, - "isBuyingContract": leg.is_buying_asset, - } - ) - return { - "subAccountID": order.sub_account_id, - "isMarket": order.is_market or False, - "timeInForce": TIME_IN_FORCE_TO_SIGN_TIME_IN_FORCE[order.time_in_force].value, - "postOnly": order.post_only or False, - "reduceOnly": order.reduce_only or False, - "legs": legs, - "nonce": order.signature.nonce, - "expiration": order.signature.expiration, - } - - -##################### -# Sign Transfer # -##################### - -EIP712_TRANSFER_MESSAGE_TYPE = { - "Transfer": [ - {"name": "fromAccount", "type": "address"}, - {"name": "fromSubAccount", "type": "uint64"}, - {"name": "toAccount", "type": "address"}, - {"name": "toSubAccount", "type": "uint64"}, - {"name": "tokenCurrency", "type": "uint8"}, - {"name": "numTokens", "type": "uint64"}, - {"name": "nonce", "type": "uint32"}, - {"name": "expiration", "type": "int64"}, - ], -} - - -def build_EIP712_transfer_message_data(transfer: Transfer, currencyId: int): - return { - "fromAccount": transfer.from_account_id, - "fromSubAccount": transfer.from_sub_account_id, - "toAccount": transfer.to_account_id, - "toSubAccount": transfer.to_sub_account_id, - "tokenCurrency": currencyId, - "numTokens": int( - Decimal(transfer.num_tokens) * Decimal(1e6) - ), # USDT has 6 decimals - "nonce": transfer.signature.nonce, - "expiration": transfer.signature.expiration, - } - - -def sign_transfer( - transfer: Transfer, - config: GrvtApiConfig, - account: Account, - chainId: int | None = None, - currencyId: int = 3, # currencyId of USDT; refer to Get Currency API -) -> Transfer: - if config.private_key is None: - raise ValueError("Private key is not set") - - domain = get_EIP712_domain_data(config.env, chainId) - - message_data = build_EIP712_transfer_message_data(transfer, currencyId) - signable_message = encode_typed_data( - domain, EIP712_TRANSFER_MESSAGE_TYPE, message_data - ) - signed_message = account.sign_message(signable_message) - - transfer.signature.r = "0x" + signed_message.r.to_bytes(32, byteorder="big").hex() - transfer.signature.s = "0x" + signed_message.s.to_bytes(32, byteorder="big").hex() - transfer.signature.v = signed_message.v - transfer.signature.signer = str(account.address) - - return transfer - - -##################### -# Sign Withdrawal # -##################### - -EIP712_WITHDRAWAL_MESSAGE_TYPE = { - "Withdrawal": [ - {"name": "fromAccount", "type": "address"}, - {"name": "toEthAddress", "type": "address"}, - {"name": "tokenCurrency", "type": "uint8"}, - {"name": "numTokens", "type": "uint64"}, - {"name": "nonce", "type": "uint32"}, - {"name": "expiration", "type": "int64"}, - ], -} - - -def build_EIP712_withdrawal_message_data(withdrawal: Withdrawal, currencyId: int): - return { - "fromAccount": withdrawal.from_account_id, - "toEthAddress": withdrawal.to_eth_address, - "tokenCurrency": currencyId, - "numTokens": int( - Decimal(withdrawal.num_tokens) * Decimal(1e6) - ), # USDT has 6 decimals - "nonce": withdrawal.signature.nonce, - "expiration": withdrawal.signature.expiration, - } - - -def sign_withdrawal( - withdrawal: Withdrawal, - config: GrvtApiConfig, - account: Account, - chainId: int | None = None, - currencyId: int = 3, # currencyId of USDT; refer to Get Currency API -) -> Withdrawal: - if config.private_key is None: - raise ValueError("Private key is not set") - - domain = get_EIP712_domain_data(config.env, chainId) - - message_data = build_EIP712_withdrawal_message_data(withdrawal, currencyId) - signable_message = encode_typed_data( - domain, EIP712_WITHDRAWAL_MESSAGE_TYPE, message_data - ) - signed_message = account.sign_message(signable_message) - - withdrawal.signature.r = "0x" + signed_message.r.to_bytes(32, byteorder="big").hex() - withdrawal.signature.s = "0x" + signed_message.s.to_bytes(32, byteorder="big").hex() - withdrawal.signature.v = signed_message.v - withdrawal.signature.signer = str(account.address) - - return withdrawal diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_sync.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_sync.py deleted file mode 100644 index 451ebdb..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_sync.py +++ /dev/null @@ -1,351 +0,0 @@ -from enum import Enum - -from dacite import Config, from_dict - -from . import grvt_raw_types as types -from .grvt_raw_base import GrvtApiConfig, GrvtError, GrvtRawSyncBase - -# mypy: disable-error-code="no-any-return" - - -class GrvtRawSync(GrvtRawSyncBase): - def __init__(self, config: GrvtApiConfig): - super().__init__(config) - self.md_rpc = self.env.market_data.rpc_endpoint - self.td_rpc = self.env.trade_data.rpc_endpoint - - def get_instrument_v1( - self, req: types.ApiGetInstrumentRequest - ) -> types.ApiGetInstrumentResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/instrument", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiGetInstrumentResponse, resp, Config(cast=[Enum])) - - def get_all_instruments_v1( - self, req: types.ApiGetAllInstrumentsRequest - ) -> types.ApiGetAllInstrumentsResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/all_instruments", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiGetAllInstrumentsResponse, resp, Config(cast=[Enum])) - - def get_filtered_instruments_v1( - self, req: types.ApiGetFilteredInstrumentsRequest - ) -> types.ApiGetFilteredInstrumentsResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/instruments", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiGetFilteredInstrumentsResponse, resp, Config(cast=[Enum]) - ) - - def get_currency_v1( - self, req: types.ApiGetCurrencyRequest - ) -> types.ApiGetCurrencyResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/currency", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiGetCurrencyResponse, resp, Config(cast=[Enum])) - - def mini_ticker_v1( - self, req: types.ApiMiniTickerRequest - ) -> types.ApiMiniTickerResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/mini", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiMiniTickerResponse, resp, Config(cast=[Enum])) - - def ticker_v1( - self, req: types.ApiTickerRequest - ) -> types.ApiTickerResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/ticker", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTickerResponse, resp, Config(cast=[Enum])) - - def orderbook_levels_v1( - self, req: types.ApiOrderbookLevelsRequest - ) -> types.ApiOrderbookLevelsResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/book", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiOrderbookLevelsResponse, resp, Config(cast=[Enum])) - - def trade_v1(self, req: types.ApiTradeRequest) -> types.ApiTradeResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/trade", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTradeResponse, resp, Config(cast=[Enum])) - - def trade_history_v1( - self, req: types.ApiTradeHistoryRequest - ) -> types.ApiTradeHistoryResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/trade_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTradeHistoryResponse, resp, Config(cast=[Enum])) - - def candlestick_v1( - self, req: types.ApiCandlestickRequest - ) -> types.ApiCandlestickResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/kline", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiCandlestickResponse, resp, Config(cast=[Enum])) - - def funding_rate_v1( - self, req: types.ApiFundingRateRequest - ) -> types.ApiFundingRateResponse | GrvtError: - resp = self._post(False, self.md_rpc + "/full/v1/funding", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiFundingRateResponse, resp, Config(cast=[Enum])) - - def create_order_v1( - self, req: types.ApiCreateOrderRequest - ) -> types.ApiCreateOrderResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/create_order", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiCreateOrderResponse, resp, Config(cast=[Enum])) - - def cancel_order_v1( - self, req: types.ApiCancelOrderRequest - ) -> types.AckResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/cancel_order", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - def cancel_all_orders_v1( - self, req: types.ApiCancelAllOrdersRequest - ) -> types.AckResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/cancel_all_orders", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - def get_order_v1( - self, req: types.ApiGetOrderRequest - ) -> types.ApiGetOrderResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/order", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiGetOrderResponse, resp, Config(cast=[Enum])) - - def open_orders_v1( - self, req: types.ApiOpenOrdersRequest - ) -> types.ApiOpenOrdersResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/open_orders", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiOpenOrdersResponse, resp, Config(cast=[Enum])) - - def order_history_v1( - self, req: types.ApiOrderHistoryRequest - ) -> types.ApiOrderHistoryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/order_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiOrderHistoryResponse, resp, Config(cast=[Enum])) - - def cancel_on_disconnect_v1( - self, req: types.ApiCancelOnDisconnectRequest - ) -> types.AckResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/cancel_on_disconnect", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - def fill_history_v1( - self, req: types.ApiFillHistoryRequest - ) -> types.ApiFillHistoryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/fill_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiFillHistoryResponse, resp, Config(cast=[Enum])) - - def positions_v1( - self, req: types.ApiPositionsRequest - ) -> types.ApiPositionsResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/positions", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiPositionsResponse, resp, Config(cast=[Enum])) - - def funding_payment_history_v1( - self, req: types.ApiFundingPaymentHistoryRequest - ) -> types.ApiFundingPaymentHistoryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/funding_payment_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiFundingPaymentHistoryResponse, resp, Config(cast=[Enum]) - ) - - def deposit_history_v1( - self, req: types.ApiDepositHistoryRequest - ) -> types.ApiDepositHistoryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/deposit_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiDepositHistoryResponse, resp, Config(cast=[Enum])) - - def transfer_v1( - self, req: types.ApiTransferRequest - ) -> types.ApiTransferResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/transfer", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTransferResponse, resp, Config(cast=[Enum])) - - def transfer_history_v1( - self, req: types.ApiTransferHistoryRequest - ) -> types.ApiTransferHistoryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/transfer_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiTransferHistoryResponse, resp, Config(cast=[Enum])) - - def withdrawal_v1( - self, req: types.ApiWithdrawalRequest - ) -> types.AckResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/withdrawal", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - def withdrawal_history_v1( - self, req: types.ApiWithdrawalHistoryRequest - ) -> types.ApiWithdrawalHistoryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/withdrawal_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiWithdrawalHistoryResponse, resp, Config(cast=[Enum])) - - def sub_account_summary_v1( - self, req: types.ApiSubAccountSummaryRequest - ) -> types.ApiSubAccountSummaryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/account_summary", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiSubAccountSummaryResponse, resp, Config(cast=[Enum])) - - def sub_account_history_v1( - self, req: types.ApiSubAccountHistoryRequest - ) -> types.ApiSubAccountHistoryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/account_history", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiSubAccountHistoryResponse, resp, Config(cast=[Enum])) - - def aggregated_account_summary_v1( - self, req: types.EmptyRequest - ) -> types.ApiAggregatedAccountSummaryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/aggregated_account_summary", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiAggregatedAccountSummaryResponse, resp, Config(cast=[Enum]) - ) - - def funding_account_summary_v1( - self, req: types.EmptyRequest - ) -> types.ApiFundingAccountSummaryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/funding_account_summary", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiFundingAccountSummaryResponse, resp, Config(cast=[Enum]) - ) - - def set_derisk_mm_ratio_v1( - self, req: types.ApiSetDeriskToMaintenanceMarginRatioRequest - ) -> types.ApiSetDeriskToMaintenanceMarginRatioResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/set_derisk_mm_ratio", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiSetDeriskToMaintenanceMarginRatioResponse, resp, Config(cast=[Enum]) - ) - - def get_all_initial_leverage_v1( - self, req: types.ApiGetAllInitialLeverageRequest - ) -> types.ApiGetAllInitialLeverageResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/get_all_initial_leverage", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiGetAllInitialLeverageResponse, resp, Config(cast=[Enum]) - ) - - def set_initial_leverage_v1( - self, req: types.ApiSetInitialLeverageRequest - ) -> types.ApiSetInitialLeverageResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/set_initial_leverage", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiSetInitialLeverageResponse, resp, Config(cast=[Enum])) - - def vault_burn_tokens_v1( - self, req: types.ApiVaultBurnTokensRequest - ) -> types.AckResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/vault_burn_tokens", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - def vault_invest_v1( - self, req: types.ApiVaultInvestRequest - ) -> types.AckResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/vault_invest", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - def vault_investor_summary_v1( - self, req: types.ApiVaultInvestorSummaryRequest - ) -> types.ApiVaultInvestorSummaryResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/vault_investor_summary", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.ApiVaultInvestorSummaryResponse, resp, Config(cast=[Enum])) - - def vault_redeem_v1( - self, req: types.ApiVaultRedeemRequest - ) -> types.AckResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/vault_redeem", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - def vault_redeem_cancel_v1( - self, req: types.ApiVaultRedeemCancelRequest - ) -> types.AckResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/vault_redeem_cancel", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict(types.AckResponse, resp, Config(cast=[Enum])) - - def vault_redemption_queue_v1( - self, req: types.ApiVaultViewRedemptionQueueRequest - ) -> types.ApiVaultViewRedemptionQueueResponse | GrvtError: - resp = self._post(True, self.td_rpc + "/full/v1/vault_view_redemption_queue", req) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiVaultViewRedemptionQueueResponse, resp, Config(cast=[Enum]) - ) - - def query_vault_manager_investor_history_v1( - self, req: types.ApiQueryVaultManagerInvestorHistoryRequest - ) -> types.ApiQueryVaultManagerInvestorHistoryResponse | GrvtError: - resp = self._post( - True, self.td_rpc + "/full/v1/vault_manager_investor_history", req - ) - if resp.get("code"): - return GrvtError(**resp) - return from_dict( - types.ApiQueryVaultManagerInvestorHistoryResponse, resp, Config(cast=[Enum]) - ) diff --git a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_types.py b/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_types.py deleted file mode 100644 index d803543..0000000 --- a/docs/grvt/grvt-pysdk-main/src/pysdk/grvt_raw_types.py +++ /dev/null @@ -1,2697 +0,0 @@ -# ruff: noqa: D200 -# ruff: noqa: D204 -# ruff: noqa: D205 -# ruff: noqa: D404 -# ruff: noqa: W291 -# ruff: noqa: D400 -# ruff: noqa: E501 -from dataclasses import dataclass -from enum import Enum -from typing import Any - - -class BrokerTag(Enum): - UNSPECIFIED = "UNSPECIFIED" - # CoinRoutes - COIN_ROUTES = "COIN_ROUTES" - # Alertatron - ALERTATRON = "ALERTATRON" - # Origami - ORIGAMI = "ORIGAMI" - - -class CancelStatus(Enum): - # Cancellation has expired because corresponding order had not arrived within the defined time-to-live window. - EXPIRED = "EXPIRED" - # This cancellation request was dropped because its TTL window overlaps with another cancellation request for the same order. - DROPPED_DUPLICATE = "DROPPED_DUPLICATE" - - -class CandlestickInterval(Enum): - # 1 minute - CI_1_M = "CI_1_M" - # 3 minutes - CI_3_M = "CI_3_M" - # 5 minutes - CI_5_M = "CI_5_M" - # 15 minutes - CI_15_M = "CI_15_M" - # 30 minutes - CI_30_M = "CI_30_M" - # 1 hour - CI_1_H = "CI_1_H" - # 2 hour - CI_2_H = "CI_2_H" - # 4 hour - CI_4_H = "CI_4_H" - # 6 hour - CI_6_H = "CI_6_H" - # 8 hour - CI_8_H = "CI_8_H" - # 12 hour - CI_12_H = "CI_12_H" - # 1 day - CI_1_D = "CI_1_D" - # 3 days - CI_3_D = "CI_3_D" - # 5 days - CI_5_D = "CI_5_D" - # 1 week - CI_1_W = "CI_1_W" - # 2 weeks - CI_2_W = "CI_2_W" - # 3 weeks - CI_3_W = "CI_3_W" - # 4 weeks - CI_4_W = "CI_4_W" - - -class CandlestickType(Enum): - # Tracks traded prices - TRADE = "TRADE" - # Tracks mark prices - MARK = "MARK" - # Tracks index prices - INDEX = "INDEX" - # Tracks book mid prices - MID = "MID" - - -class InstrumentSettlementPeriod(Enum): - # Instrument settles through perpetual funding cycles - PERPETUAL = "PERPETUAL" - # Instrument settles at an expiry date, marked as a daily instrument - DAILY = "DAILY" - # Instrument settles at an expiry date, marked as a weekly instrument - WEEKLY = "WEEKLY" - # Instrument settles at an expiry date, marked as a monthly instrument - MONTHLY = "MONTHLY" - # Instrument settles at an expiry date, marked as a quarterly instrument - QUARTERLY = "QUARTERLY" - - -class Kind(Enum): - # the perpetual asset kind - PERPETUAL = "PERPETUAL" - # the future asset kind - FUTURE = "FUTURE" - # the call option asset kind - CALL = "CALL" - # the put option asset kind - PUT = "PUT" - - -class MarginType(Enum): - # Simple Cross Margin Mode: all assets have a predictable margin impact, the whole subaccount shares a single margin - SIMPLE_CROSS_MARGIN = "SIMPLE_CROSS_MARGIN" - # Portfolio Cross Margin Mode: asset margin impact is analysed on portfolio level, the whole subaccount shares a single margin - PORTFOLIO_CROSS_MARGIN = "PORTFOLIO_CROSS_MARGIN" - - -class OrderRejectReason(Enum): - # order is not cancelled or rejected - UNSPECIFIED = "UNSPECIFIED" - # client called a Cancel API - CLIENT_CANCEL = "CLIENT_CANCEL" - # client called a Bulk Cancel API - CLIENT_BULK_CANCEL = "CLIENT_BULK_CANCEL" - # client called a Session Cancel API, or set the WebSocket connection to 'cancelOrdersOnTerminate' - CLIENT_SESSION_END = "CLIENT_SESSION_END" - # the market order was cancelled after no/partial fill. Lower precedence than other TimeInForce cancel reasons - MARKET_CANCEL = "MARKET_CANCEL" - # the IOC order was cancelled after no/partial fill - IOC_CANCEL = "IOC_CANCEL" - # the AON order was cancelled as it could not be fully matched - AON_CANCEL = "AON_CANCEL" - # the FOK order was cancelled as it could not be fully matched - FOK_CANCEL = "FOK_CANCEL" - # the order was cancelled as it has expired - EXPIRED = "EXPIRED" - # the post-only order could not be posted into the orderbook - FAIL_POST_ONLY = "FAIL_POST_ONLY" - # the reduce-only order would have caused position size to increase - FAIL_REDUCE_ONLY = "FAIL_REDUCE_ONLY" - # the order was cancelled due to market maker protection trigger - MM_PROTECTION = "MM_PROTECTION" - # the order was cancelled due to self-trade protection trigger - SELF_TRADE_PROTECTION = "SELF_TRADE_PROTECTION" - # the order matched with another order from the same sub account - SELF_MATCHED_SUBACCOUNT = "SELF_MATCHED_SUBACCOUNT" - # an active order on your sub account shares the same clientOrderId - OVERLAPPING_CLIENT_ORDER_ID = "OVERLAPPING_CLIENT_ORDER_ID" - # the order will bring the sub account below initial margin requirement - BELOW_MARGIN = "BELOW_MARGIN" - # the sub account is liquidated (and all open orders are cancelled by Gravity) - LIQUIDATION = "LIQUIDATION" - # instrument is invalid or not found on Gravity - INSTRUMENT_INVALID = "INSTRUMENT_INVALID" - # instrument is no longer tradable on Gravity. (typically due to a market halt, or instrument expiry) - INSTRUMENT_DEACTIVATED = "INSTRUMENT_DEACTIVATED" - # system failover resulting in loss of order state - SYSTEM_FAILOVER = "SYSTEM_FAILOVER" - # the credentials used (userSession/apiKeySession/walletSignature) is not authorised to perform the action - UNAUTHORISED = "UNAUTHORISED" - # the session key used to sign the order expired - SESSION_KEY_EXPIRED = "SESSION_KEY_EXPIRED" - # the subaccount does not exist - SUB_ACCOUNT_NOT_FOUND = "SUB_ACCOUNT_NOT_FOUND" - # the signature used to sign the order has no trade permission - NO_TRADE_PERMISSION = "NO_TRADE_PERMISSION" - # the order payload does not contain a supported TimeInForce value - UNSUPPORTED_TIME_IN_FORCE = "UNSUPPORTED_TIME_IN_FORCE" - # the order has multiple legs, but multiple legs are not supported by this venue - MULTI_LEGGED_ORDER = "MULTI_LEGGED_ORDER" - # the order would have caused the subaccount to exceed the max position size - EXCEED_MAX_POSITION_SIZE = "EXCEED_MAX_POSITION_SIZE" - # the signature supplied is more than 30 days in the future - EXCEED_MAX_SIGNATURE_EXPIRATION = "EXCEED_MAX_SIGNATURE_EXPIRATION" - # the market order has a limit price set - MARKET_ORDER_WITH_LIMIT_PRICE = "MARKET_ORDER_WITH_LIMIT_PRICE" - # client cancel on disconnect triggered - CLIENT_CANCEL_ON_DISCONNECT_TRIGGERED = "CLIENT_CANCEL_ON_DISCONNECT_TRIGGERED" - # the OCO counter part order was triggered - OCO_COUNTER_PART_TRIGGERED = "OCO_COUNTER_PART_TRIGGERED" - # the remaining order size was cancelled because it exceeded current position size - REDUCE_ONLY_LIMIT = "REDUCE_ONLY_LIMIT" - # the order was replaced by a client replace request - CLIENT_REPLACE = "CLIENT_REPLACE" - # the derisk order must be an IOC order - DERISK_MUST_BE_IOC = "DERISK_MUST_BE_IOC" - # the derisk order must be a reduce-only order - DERISK_MUST_BE_REDUCE_ONLY = "DERISK_MUST_BE_REDUCE_ONLY" - # derisk is not supported - DERISK_NOT_SUPPORTED = "DERISK_NOT_SUPPORTED" - # the order type is invalid - INVALID_ORDER_TYPE = "INVALID_ORDER_TYPE" - # the currency is not defined - CURRENCY_NOT_DEFINED = "CURRENCY_NOT_DEFINED" - - -class OrderStatus(Enum): - # Order has been sent to the matching engine and is pending a transition to open/filled/rejected. - PENDING = "PENDING" - # Order is actively matching on the matching engine, could be unfilled or partially filled. - OPEN = "OPEN" - # Order is fully filled and hence closed. Taker Orders can transition directly from pending to filled, without going through open. - FILLED = "FILLED" - # Order is rejected by matching engine since if fails a particular check (See OrderRejectReason). Once an order is open, it cannot be rejected. - REJECTED = "REJECTED" - # Order is cancelled by the user using one of the supported APIs (See OrderRejectReason). Before an order is open, it cannot be cancelled. - CANCELLED = "CANCELLED" - - -class TimeInForce(Enum): - """ - | | Must Fill All | Can Fill Partial | - | - | - | - | - | Must Fill Immediately | FOK | IOC | - | Can Fill Till Time | AON | GTC | - - """ - - # GTT - Remains open until it is cancelled, or expired - GOOD_TILL_TIME = "GOOD_TILL_TIME" - # AON - Either fill the whole order or none of it (Block Trades Only) - ALL_OR_NONE = "ALL_OR_NONE" - # IOC - Fill the order as much as possible, when hitting the orderbook. Then cancel it - IMMEDIATE_OR_CANCEL = "IMMEDIATE_OR_CANCEL" - # FOK - Both AoN and IoC. Either fill the full order when hitting the orderbook, or cancel it - FILL_OR_KILL = "FILL_OR_KILL" - # RPI - A GTT + PostOnly maker order, that can only be taken by non-algorithmic UI users. - RETAIL_PRICE_IMPROVEMENT = "RETAIL_PRICE_IMPROVEMENT" - - -class TransferType(Enum): - # Default transfer that has nothing to do with bridging - UNSPECIFIED = "UNSPECIFIED" - # Standard transfer that has nothing to do with bridging - STANDARD = "STANDARD" - # Fast Arb Deposit Metadata type - FAST_ARB_DEPOSIT = "FAST_ARB_DEPOSIT" - # Fast Arb Withdrawal Metadata type - FAST_ARB_WITHDRAWAL = "FAST_ARB_WITHDRAWAL" - # Transfer type for non native bridging deposit - NON_NATIVE_BRIDGE_DEPOSIT = "NON_NATIVE_BRIDGE_DEPOSIT" - # Transfer type for non native bridging withdrawal - NON_NATIVE_BRIDGE_WITHDRAWAL = "NON_NATIVE_BRIDGE_WITHDRAWAL" - - -class TriggerBy(Enum): - """ - Defines the price type that activates a Take Profit (TP) or Stop Loss (SL) order. - - Trigger orders are executed when the selected price type reaches the specified trigger price.Different price types ensure flexibility in executing strategies based on market conditions. - - - """ - - # no trigger condition - UNSPECIFIED = "UNSPECIFIED" - # INDEX - Order is activated when the index price reaches the trigger price - INDEX = "INDEX" - # LAST - Order is activated when the last trade price reaches the trigger price - LAST = "LAST" - # MID - Order is activated when the mid price reaches the trigger price - MID = "MID" - # MARK - Order is activated when the mark price reaches the trigger price - MARK = "MARK" - - -class TriggerType(Enum): - """ - Defines the type of trigger order used in trading, such as Take Profit or Stop Loss. - - Trigger orders allow execution based on pre-defined price conditions rather than immediate market conditions. - - - """ - - # Not a trigger order. The order executes normally without any trigger conditions. - UNSPECIFIED = "UNSPECIFIED" - # Take Profit Order - Executes when the price reaches a specified level to secure profits. - TAKE_PROFIT = "TAKE_PROFIT" - # Stop Loss Order - Executes when the price reaches a specified level to limit losses. - STOP_LOSS = "STOP_LOSS" - - -class VaultInvestorAction(Enum): - UNSPECIFIED = "UNSPECIFIED" - VAULT_INVEST = "VAULT_INVEST" - VAULT_BURN_LP_TOKEN = "VAULT_BURN_LP_TOKEN" - VAULT_REDEEM = "VAULT_REDEEM" - - -class VaultRedemptionReqAgeCategory(Enum): - """ - Denotes the age category of a given redemption request. - - - """ - - # This request is at least as old as the minimum redemption period, and is eligible for automated redemption. - NORMAL = "NORMAL" - # This request is nearing the maxmimum redemption period and will be factored into pre-order check margin requirements. - URGENT = "URGENT" - # This request has exceeded the maximum redemption period and will be considered for forced redemptions. - OVERDUE = "OVERDUE" - # This request has yet to exceed the minimum redemption period, and is not yet eligible for automated redemption. - PRE_MIN = "PRE_MIN" - - -class Venue(Enum): - # the trade is cleared on the orderbook venue - ORDERBOOK = "ORDERBOOK" - # the trade is cleared on the RFQ venue - RFQ = "RFQ" - - -@dataclass -class ApiPositionsRequest: - # The sub account ID to request for - sub_account_id: str - # The kind filter to apply. If nil, this defaults to all kinds. Otherwise, only entries matching the filter will be returned - kind: list[Kind] | None = None - # The base filter to apply. If nil, this defaults to all bases. Otherwise, only entries matching the filter will be returned - base: list[str] | None = None - # The quote filter to apply. If nil, this defaults to all quotes. Otherwise, only entries matching the filter will be returned - quote: list[str] | None = None - - -@dataclass -class Positions: - # Time at which the event was emitted in unix nanoseconds - event_time: str - # The sub account ID that participated in the trade - sub_account_id: str - # The instrument being represented - instrument: str - # The size of the position, expressed in base asset decimal units. Negative for short positions - size: str - # The notional value of the position, negative for short assets, expressed in quote asset decimal units - notional: str - """ - The entry price of the position, expressed in `9` decimals - Whenever increasing the size of a position, the entry price is updated to the new average entry price - `new_entry_price = (old_entry_price * old_size + trade_price * trade_size) / (old_size + trade_size)` - """ - entry_price: str - """ - The exit price of the position, expressed in `9` decimals - Whenever decreasing the size of a position, the exit price is updated to the new average exit price - `new_exit_price = (old_exit_price * old_exit_trade_size + trade_price * trade_size) / (old_exit_trade_size + trade_size)` - """ - exit_price: str - # The mark price of the position, expressed in `9` decimals - mark_price: str - """ - The unrealized PnL of the position, expressed in quote asset decimal units - `unrealized_pnl = (mark_price - entry_price) * size` - """ - unrealized_pnl: str - """ - The realized PnL of the position, expressed in quote asset decimal units - `realized_pnl = (exit_price - entry_price) * exit_trade_size` - """ - realized_pnl: str - """ - The total PnL of the position, expressed in quote asset decimal units - `total_pnl = realized_pnl + unrealized_pnl` - """ - total_pnl: str - """ - The ROI of the position, expressed as a percentage - `roi = (total_pnl / (entry_price * abs(size))) * 100^` - """ - roi: str - # The index price of the quote currency. (reported in `USD`) - quote_index_price: str - # The estimated liquidation price - est_liquidation_price: str - # The current leverage value for this position - leverage: str - - -@dataclass -class ApiPositionsResponse: - # The positions matching the request filter - result: list[Positions] - - -@dataclass -class ApiFillHistoryRequest: - """ - Query for all historical fills made by a single account. A single order can be matched multiple times, hence there is no real way to uniquely identify a trade. - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The sub account ID to request for - sub_account_id: str - # The kind filter to apply. If nil, this defaults to all kinds. Otherwise, only entries matching the filter will be returned - kind: list[Kind] | None = None - # The base filter to apply. If nil, this defaults to all bases. Otherwise, only entries matching the filter will be returned - base: list[str] | None = None - # The quote filter to apply. If nil, this defaults to all quotes. Otherwise, only entries matching the filter will be returned - quote: list[str] | None = None - # The start time to apply in unix nanoseconds. If nil, this defaults to all start times. Otherwise, only entries matching the filter will be returned - start_time: str | None = None - # The end time to apply in unix nanoseconds. If nil, this defaults to all end times. Otherwise, only entries matching the filter will be returned - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the query from - cursor: str | None = None - - -@dataclass -class Fill: - # Time at which the event was emitted in unix nanoseconds - event_time: str - # The sub account ID that participated in the trade - sub_account_id: str - # The instrument being represented - instrument: str - # The side that the subaccount took on the trade - is_buyer: bool - # The role that the subaccount took on the trade - is_taker: bool - # The number of assets being traded, expressed in base asset decimal units - size: str - # The traded price, expressed in `9` decimals - price: str - # The mark price of the instrument at point of trade, expressed in `9` decimals - mark_price: str - # The index price of the instrument at point of trade, expressed in `9` decimals - index_price: str - # The interest rate of the underlying at point of trade, expressed in centibeeps (1/100th of a basis point) - interest_rate: str - # [Options] The forward price of the option at point of trade, expressed in `9` decimals - forward_price: str - # The realized PnL of the trade, expressed in quote asset decimal units (0 if increasing position size) - realized_pnl: str - # The fees paid on the trade, expressed in quote asset decimal unit (negative if maker rebate applied) - fee: str - # The fee rate paid on the trade - fee_rate: str - """ - A trade identifier, globally unique, and monotonically increasing (not by `1`). - All trades sharing a single taker execution share the same first component (before `-`), and `event_time`. - `trade_id` is guaranteed to be consistent across MarketData `Trade` and Trading `Fill`. - """ - trade_id: str - # An order identifier - order_id: str - # The venue where the trade occurred - venue: Venue - """ - A unique identifier for the active order within a subaccount, specified by the client - This is used to identify the order in the client's system - This field can be used for order amendment/cancellation, but has no bearing on the smart contract layer - This field will not be propagated to the smart contract, and should not be signed by the client - This value must be unique for all active orders in a subaccount, or amendment/cancellation will not work as expected - Gravity UI will generate a random clientOrderID for each order in the range [0, 2^63 - 1] - To prevent any conflicts, client machines should generate a random clientOrderID in the range [2^63, 2^64 - 1] - - When GRVT Backend receives an order with an overlapping clientOrderID, we will reject the order with rejectReason set to overlappingClientOrderId - """ - client_order_id: str - # The address (public key) of the wallet signing the payload - signer: str - # If the trade is a RPI trade - is_rpi: bool - # Specifies the broker who brokered the order - broker: BrokerTag | None = None - - -@dataclass -class ApiFillHistoryResponse: - # The private trades matching the request asset - result: list[Fill] - # The cursor to indicate when to start the query from - next: str - - -@dataclass -class ApiFundingPaymentHistoryRequest: - """ - Query for all historical funding payments made by a single account. - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The sub account ID to request for - sub_account_id: str - # The perpetual instrument to filter for - instrument: str | None = None - # The start time to apply in unix nanoseconds. If nil, this defaults to all start times. Otherwise, only entries matching the filter will be returned - start_time: str | None = None - # The end time to apply in unix nanoseconds. If nil, this defaults to all end times. Otherwise, only entries matching the filter will be returned - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the query from - cursor: str | None = None - - -@dataclass -class FundingPayment: - # Time at which the event was emitted in unix nanoseconds - event_time: str - # The sub account ID that made the funding payment - sub_account_id: str - # The perpetual instrument being funded - instrument: str - # The currency of the funding payment - currency: str - # The amount of the funding payment. Positive if paid, negative if received - amount: str - """ - The transaction ID of the funding payment. - Funding payments can be triggered by a trade, transfer, or liquidation. - The `tx_id` will match the corresponding `trade_id` or `tx_id`. - """ - tx_id: str - - -@dataclass -class ApiFundingPaymentHistoryResponse: - # The funding payments matching the request asset - result: list[FundingPayment] - # The cursor to indicate when to start the query from - next: str - - -@dataclass -class ApiSubAccountSummaryRequest: - # The subaccount ID to filter by - sub_account_id: str - - -@dataclass -class SpotBalance: - # The currency you hold a spot balance in - currency: str - # This currency's balance in this trading account. - balance: str - # The index price of this currency. (reported in `USD`) - index_price: str - - -@dataclass -class SubAccount: - # Time at which the event was emitted in unix nanoseconds - event_time: str - # The sub account ID this entry refers to - sub_account_id: str - # The type of margin algorithm this subaccount uses - margin_type: MarginType - """ - The settlement, margin, and reporting currency of this account. - This subaccount can only open positions quoted in this currency - - In the future, when users select a Multi-Currency Margin Type, this will be USD - All other assets are converted to this currency for the purpose of calculating margin - """ - settle_currency: str - """ - The total unrealized PnL of all positions owned by this subaccount, denominated in quote currency decimal units. - `unrealized_pnl = sum(position.unrealized_pnl * position.quote_index_price) / settle_index_price` - """ - unrealized_pnl: str - """ - The notional value of your account if all positions are closed, excluding trading fees (reported in `settle_currency`). - `total_equity = sum(spot_balance.balance * spot_balance.index_price) / settle_index_price + unrealized_pnl` - """ - total_equity: str - """ - The `total_equity` required to open positions in the account (reported in `settle_currency`). - Computation is different depending on account's `margin_type` - """ - initial_margin: str - """ - The `total_equity` required to avoid liquidation of positions in the account (reported in `settle_currency`). - Computation is different depending on account's `margin_type` - """ - maintenance_margin: str - """ - The notional value available to transfer out of the trading account into the funding account (reported in `settle_currency`). - `available_balance = total_equity - initial_margin - min(unrealized_pnl, 0)` - """ - available_balance: str - # The list of spot assets owned by this sub account, and their balances - spot_balances: list[SpotBalance] - # The list of positions owned by this sub account - positions: list[Positions] - # The index price of the settle currency. (reported in `USD`) - settle_index_price: str - # The derisk margin of this sub account - derisk_margin: str - # The derisk margin to maintenance margin ratio of this sub account - derisk_to_maintenance_margin_ratio: str - # Whether this sub account is a vault - is_vault: bool | None = None - # Total amount of IM (reported in `settle_currency`) deducted from the vault due to redemptions nearing the end of their redemption period - vault_im_additions: str | None = None - - -@dataclass -class ApiSubAccountSummaryResponse: - # The sub account matching the request sub account - result: SubAccount - - -@dataclass -class ApiSubAccountHistoryRequest: - """ - The request to get the history of a sub account - SubAccount Summary values are snapshotted once every hour - No snapshots are taken if the sub account has no activity in the hourly window - History is preserved only for the last 30 days - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The sub account ID to request for - sub_account_id: str - # Start time of sub account history in unix nanoseconds - start_time: str | None = None - # End time of sub account history in unix nanoseconds - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the next query from - cursor: str | None = None - - -@dataclass -class ApiSubAccountHistoryResponse: - # The sub account history matching the request sub account - result: list[SubAccount] - # The cursor to indicate when to start the next query from - next: str - - -@dataclass -class AggregatedAccountSummary: - # The main account ID of the account to which the summary belongs - main_account_id: str - # Total equity of the main (+ sub) account, denominated in USD - total_equity: str - # The list of spot assets owned by this main (+ sub) account, and their balances - spot_balances: list[SpotBalance] - - -@dataclass -class ApiAggregatedAccountSummaryResponse: - # The aggregated account summary - result: AggregatedAccountSummary - - -@dataclass -class FundingAccountSummary: - # The main account ID of the account to which the summary belongs - main_account_id: str - # Total equity of the main account, denominated in USD - total_equity: str - # The list of spot assets owned by this main account, and their balances - spot_balances: list[SpotBalance] - - -@dataclass -class ClientTier: - tier: int - futures_taker_fee: int - futures_maker_fee: int - options_taker_fee: int - options_maker_fee: int - - -@dataclass -class ApiFundingAccountSummaryResponse: - # The funding account summary - result: FundingAccountSummary - # Client fee tier at the time of query - tier: ClientTier - - -@dataclass -class ApiSetInitialLeverageRequest: - # The sub account ID to set the leverage for - sub_account_id: str - # The instrument to set the leverage for - instrument: str - # The leverage to set for the sub account - leverage: str - - -@dataclass -class ApiSetInitialLeverageResponse: - # Whether the leverage was set successfully - success: bool - - -@dataclass -class ApiGetAllInitialLeverageRequest: - # The sub account ID to get the leverage for - sub_account_id: str - - -@dataclass -class InitialLeverageResult: - # The instrument to get the leverage for - instrument: str - # The initial leverage of the sub account - leverage: str - # The min leverage this sub account can set - min_leverage: str - # The max leverage this sub account can set - max_leverage: str - - -@dataclass -class ApiGetAllInitialLeverageResponse: - # The initial leverage of the sub account - results: list[InitialLeverageResult] - - -@dataclass -class Signature: - # The address (public key) of the wallet signing the payload - signer: str - # Signature R - r: str - # Signature S - s: str - # Signature V - v: int - # Timestamp after which this signature expires, expressed in unix nanoseconds. Must be capped at 30 days - expiration: str - """ - Users can randomly generate this value, used as a signature deconflicting key. - ie. You can send the same exact instruction twice with different nonces. - When the same nonce is used, the same payload will generate the same signature. - Our system will consider the payload a duplicate, and ignore it. - """ - nonce: int - - -@dataclass -class ApiSetDeriskToMaintenanceMarginRatioRequest: - # The sub account ID to set the leverage for - sub_account_id: str - # The derisk margin to maintenance margin ratio of this sub account - ratio: str - # The signature of this operation - signature: Signature - - -@dataclass -class ApiSetDeriskToMaintenanceMarginRatioResponse: - # Whether the derisk margin to maintenance margin ratio was set successfully - success: bool - - -@dataclass -class JSONRPCRequest: - """ - All Websocket JSON RPC Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to. - If a `request_id` is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error). - When subscribing to the same primary selector again, the previous secondary selector will be replaced. See `Overview` page for more details. - """ - - # The JSON RPC version to use for the request - jsonrpc: str - # The method to use for the request (eg: `subscribe` / `unsubscribe` / `v1/instrument` ) - method: str - # The parameters for the request - params: Any - """ - Optional Field which is used to match the response by the client. - If not passed, this field will not be returned - """ - id: int | None = None - - -@dataclass -class Error: - # The error code for the request - code: int - # The error message for the request - message: str - - -@dataclass -class JSONRPCResponse: - """ - All Websocket JSON RPC Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request. - If a `request_id` is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response. - """ - - # The JSON RPC version to use for the request - jsonrpc: str - # The method used in the request for this response (eg: `subscribe` / `unsubscribe` / `v1/instrument` ) - method: str - # The result for the request - result: Any | None = None - # The error for the request - error: Error | None = None - """ - Optional Field which is used to match the response by the client. - If not passed, this field will not be returned - """ - id: int | None = None - - -@dataclass -class WSSubscribeParams: - """ - All V1 Websocket Subscription Requests are housed in this wrapper. You may specify a stream and a list of feeds to subscribe to. - When subscribing to the same primary selector again, the previous secondary selector will be replaced. See `Overview` page for more details. - Sequence numbers can be either gateway-specific or global: - - **Gateway Unique Sequence Number**: Increments by one per stream, resets to 0 on gateway restart. - - **Global Unique Sequence Number**: A cluster-wide unique number assigned to each cluster payload, does not reset on gateway restarts, and can be used to track and identify message order across streams using `sequence_number` and `prev_sequence_number` in the feed response. - Set `useGlobalSequenceNumber = true` if you need a persistent, unique identifier across all streams or ordering across multiple feeds. - """ - - # The channel to subscribe to (eg: ticker.s / ticker.d) - stream: str - # The list of feeds to subscribe to - selectors: list[str] - # Whether to use the global sequence number for the stream - use_global_sequence_number: bool | None = None - - -@dataclass -class WSSubscribeResult: - """ - To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
    • All snapshot payloads will have a sequence number of `0`. All delta payloads will have a sequence number of `1+`. So its easy to distinguish between snapshots, and deltas
    • Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
    • First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
    • Sequence numbers should always monotonically increase by `1`. If it decreases, or increases by more than `1`. Please reconnect
    • Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
    - When subscribing to the same primary selector again, the previous secondary selector will be replaced. See `Overview` page for more details. - """ - - # The channel to subscribe to (eg: ticker.s / ticker.d) - stream: str - # The list of feeds subscribed to - subs: list[str] - # The list of feeds unsubscribed from - unsubs: list[str] - # The number of snapshot payloads to expect for each subscribed feed. Returned in same order as `subs` - num_snapshots: list[int] - # The first sequence number to expect for each subscribed feed. Returned in same order as `subs` - first_sequence_number: list[str] - # The sequence number of the most recent message in the stream. Next received sequence number must be larger than this one. Returned in same order as `subs` - latest_sequence_number: list[str] - - -@dataclass -class WSUnsubscribeParams: - # The channel to unsubscribe from (eg: ticker.s / ticker.d) - stream: str - # The list of feeds to unsubscribe from - selectors: list[str] - # Whether to use the global sequence number for the stream - use_global_sequence_number: bool | None = None - - -@dataclass -class WSUnsubscribeResult: - # The channel to subscribe to (eg: ticker.s / ticker.d) - stream: str - # The list of feeds unsubscribed from - unsubs: list[str] - - -@dataclass -class WSSubscribeRequestV1Legacy: - """ - All V1 Websocket Requests are housed in this wrapper. You may specify a stream, and a list of feeds to subscribe to. - If a `request_id` is supplied in this JSON RPC request, it will be propagated back to any relevant JSON RPC responses (including error). - When subscribing to the same primary selector again, the previous secondary selector will be replaced. See `Overview` page for more details. - """ - - # The channel to subscribe to (eg: ticker.s / ticker.d) - stream: str - # The list of feeds to subscribe to - feed: list[str] - # The method to use for the request (eg: subscribe / unsubscribe) - method: str - """ - Optional Field which is used to match the response by the client. - If not passed, this field will not be returned - """ - request_id: int | None = None - # Whether the request is for full data or lite data - is_full: bool | None = None - - -@dataclass -class WSSubscribeResponseV1Legacy: - """ - All V1 Websocket Responses are housed in this wrapper. It returns a confirmation of the JSON RPC subscribe request. - If a `request_id` is supplied in the JSON RPC request, it will be propagated back in this JSON RPC response. - To ensure you always know if you have missed any payloads, GRVT servers apply the following heuristics to sequence numbers:
    • All snapshot payloads will have a sequence number of `0`. All delta payloads will have a sequence number of `1+`. So its easy to distinguish between snapshots, and deltas
    • Num snapshots returned in Response (per stream): You can ensure that you received the right number of snapshots
    • First sequence number returned in Response (per stream): You can ensure that you received the first stream, without gaps from snapshots
    • Sequence numbers should always monotonically increase by `1`. If it decreases, or increases by more than `1`. Please reconnect
    • Duplicate sequence numbers are possible due to network retries. If you receive a duplicate, please ignore it, or idempotently re-update it.
    - When subscribing to the same primary selector again, the previous secondary selector will be replaced. See `Overview` page for more details. - """ - - # The channel to subscribe to (eg: ticker.s / ticker.d) - stream: str - # The list of feeds subscribed to - subs: list[str] - # The list of feeds unsubscribed from - unsubs: list[str] - # The number of snapshot payloads to expect for each subscribed feed. Returned in same order as `subs` - num_snapshots: list[int] - # The first sequence number to expect for each subscribed feed. Returned in same order as `subs` - first_sequence_number: list[str] - # The sequence number of the most recent message in the stream. Next received sequence number must be larger than this one. Returned in same order as `subs` - latest_sequence_number: list[str] - """ - Optional Field which is used to match the response by the client. - If not passed, this field will not be returned - """ - request_id: int | None = None - - -@dataclass -class WSOrderbookLevelsFeedSelectorV1: - """ - Subscribes to aggregated orderbook updates for a single instrument. The `book.s` channel offers simpler integration. To experience higher publishing rates, please use the `book.d` channel. - Unlike the `book.d` channel which publishes an initial snapshot, then only streams deltas after, the `book.s` channel publishes full snapshots at each feed. - - The Delta feed will work as follows:
    • On subscription, the server will send a full snapshot of all levels of the Orderbook.
    • After the snapshot, the server will only send levels that have changed in value.
    - - Subscription Pattern:
    • Delta - `instrument@rate`
    • Snapshot - `instrument@rate-depth`
    - - Field Semantics:
    • [DeltaOnly] If a level is not updated, level not published
    • If a level is updated, {size: '123'}
    • If a level is set to zero, {size: '0'}
    • Incoming levels will be published as soon as price moves
    • Outgoing levels will be published with `size = 0`
    - """ - - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - """ - The minimal rate at which we publish feeds (in milliseconds) - Delta (50, 100, 500, 1000) - Snapshot (500, 1000) - """ - rate: int - """ - Depth of the order book to be retrieved - Delta(0 - `unlimited`) - Snapshot(10, 50, 100, 500) - """ - depth: int | None = None - - -@dataclass -class OrderbookLevel: - # The price of the level, expressed in `9` decimals - price: str - # The number of assets offered, expressed in base asset decimal units - size: str - # The number of open orders at this level - num_orders: int - - -@dataclass -class OrderbookLevels: - # Time at which the event was emitted in unix nanoseconds - event_time: str - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # The list of best bids up till query depth - bids: list[OrderbookLevel] - # The list of best asks up till query depth - asks: list[OrderbookLevel] - - -@dataclass -class WSOrderbookLevelsFeedDataV1: - # Stream name - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # An orderbook levels object matching the request filter - feed: OrderbookLevels - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSMiniTickerFeedSelectorV1: - """ - Subscribes to a mini ticker feed for a single instrument. The `mini.s` channel offers simpler integration. To experience higher publishing rates, please use the `mini.d` channel. - Unlike the `mini.d` channel which publishes an initial snapshot, then only streams deltas after, the `mini.s` channel publishes full snapshots at each feed. - - The Delta feed will work as follows:
    • On subscription, the server will send a full snapshot of the mini ticker.
    • After the snapshot, the server will only send deltas of the mini ticker.
    • The server will send a delta if any of the fields in the mini ticker have changed.
    - - Field Semantics:
    • [DeltaOnly] If a field is not updated, {}
    • If a field is updated, {field: '123'}
    • If a field is set to zero, {field: '0'}
    • If a field is set to null, {field: ''}
    - """ - - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - """ - The minimal rate at which we publish feeds (in milliseconds) - Delta (0 - `raw`, 50, 100, 200, 500, 1000, 5000) - Snapshot (200, 500, 1000, 5000) - """ - rate: int - - -@dataclass -class MiniTicker: - # Time at which the event was emitted in unix nanoseconds - event_time: str | None = None - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str | None = None - # The mark price of the instrument, expressed in `9` decimals - mark_price: str | None = None - # The index price of the instrument, expressed in `9` decimals - index_price: str | None = None - # The last traded price of the instrument (also close price), expressed in `9` decimals - last_price: str | None = None - # The number of assets traded in the last trade, expressed in base asset decimal units - last_size: str | None = None - # The mid price of the instrument, expressed in `9` decimals - mid_price: str | None = None - # The best bid price of the instrument, expressed in `9` decimals - best_bid_price: str | None = None - # The number of assets offered on the best bid price of the instrument, expressed in base asset decimal units - best_bid_size: str | None = None - # The best ask price of the instrument, expressed in `9` decimals - best_ask_price: str | None = None - # The number of assets offered on the best ask price of the instrument, expressed in base asset decimal units - best_ask_size: str | None = None - - -@dataclass -class WSMiniTickerFeedDataV1: - # Stream name - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # A mini ticker matching the request filter - feed: MiniTicker - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSTickerFeedSelectorV1: - """ - Subscribes to a ticker feed for a single instrument. The `ticker.s` channel offers simpler integration. To experience higher publishing rates, please use the `ticker.d` channel. - Unlike the `ticker.d` channel which publishes an initial snapshot, then only streams deltas after, the `ticker.s` channel publishes full snapshots at each feed. - - The Delta feed will work as follows:
    • On subscription, the server will send a full snapshot of the ticker.
    • After the snapshot, the server will only send deltas of the ticker.
    • The server will send a delta if any of the fields in the ticker have changed.
    - - Field Semantics:
    • [DeltaOnly] If a field is not updated, {}
    • If a field is updated, {field: '123'}
    • If a field is set to zero, {field: '0'}
    • If a field is set to null, {field: ''}
    - """ - - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - """ - The minimal rate at which we publish feeds (in milliseconds) - Delta (100, 200, 500, 1000, 5000) - Snapshot (500, 1000, 5000) - """ - rate: int - - -@dataclass -class Ticker: - """ - Derived data such as the below, will not be included by default: - - 24 hour volume (`buyVolume + sellVolume`) - - 24 hour taker buy/sell ratio (`buyVolume / sellVolume`) - - 24 hour average trade price (`volumeQ / volumeU`) - - 24 hour average trade volume (`volume / trades`) - - 24 hour percentage change (`24hStatChange / 24hStat`) - - 48 hour statistics (`2 * 24hStat - 24hStatChange`) - - To query for an extended ticker payload, leverage the `greeks` and the `derived` flags. - Ticker extensions are currently under design to offer you more convenience. - These flags are only supported on the `Ticker Snapshot` WS endpoint, and on the `Ticker` API endpoint. - - """ - - # Time at which the event was emitted in unix nanoseconds - event_time: str | None = None - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str | None = None - # The mark price of the instrument, expressed in `9` decimals - mark_price: str | None = None - # The index price of the instrument, expressed in `9` decimals - index_price: str | None = None - # The last traded price of the instrument (also close price), expressed in `9` decimals - last_price: str | None = None - # The number of assets traded in the last trade, expressed in base asset decimal units - last_size: str | None = None - # The mid price of the instrument, expressed in `9` decimals - mid_price: str | None = None - # The best bid price of the instrument, expressed in `9` decimals - best_bid_price: str | None = None - # The number of assets offered on the best bid price of the instrument, expressed in base asset decimal units - best_bid_size: str | None = None - # The best ask price of the instrument, expressed in `9` decimals - best_ask_price: str | None = None - # The number of assets offered on the best ask price of the instrument, expressed in base asset decimal units - best_ask_size: str | None = None - # The current funding rate of the instrument, expressed in percentage points - funding_rate_8h_curr: str | None = None - # The average funding rate of the instrument (over last 8h), expressed in percentage points - funding_rate_8h_avg: str | None = None - # The interest rate of the underlying, expressed in centibeeps (1/100th of a basis point) - interest_rate: str | None = None - # [Options] The forward price of the option, expressed in `9` decimals - forward_price: str | None = None - # The 24 hour taker buy volume of the instrument, expressed in base asset decimal units - buy_volume_24h_b: str | None = None - # The 24 hour taker sell volume of the instrument, expressed in base asset decimal units - sell_volume_24h_b: str | None = None - # The 24 hour taker buy volume of the instrument, expressed in quote asset decimal units - buy_volume_24h_q: str | None = None - # The 24 hour taker sell volume of the instrument, expressed in quote asset decimal units - sell_volume_24h_q: str | None = None - # The 24 hour highest traded price of the instrument, expressed in `9` decimals - high_price: str | None = None - # The 24 hour lowest traded price of the instrument, expressed in `9` decimals - low_price: str | None = None - # The 24 hour first traded price of the instrument, expressed in `9` decimals - open_price: str | None = None - # The open interest in the instrument, expressed in base asset decimal units - open_interest: str | None = None - # The ratio of accounts that are net long vs net short on this instrument - long_short_ratio: str | None = None - - -@dataclass -class WSTickerFeedDataV1: - # Stream name - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # A ticker matching the request filter - feed: Ticker - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSTradeFeedSelectorV1: - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # The limit to query for. Valid values are (50, 200, 500, 1000). Default is 50 - limit: int - - -@dataclass -class Trade: - # Time at which the event was emitted in unix nanoseconds - event_time: str - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # If taker was the buyer on the trade - is_taker_buyer: bool - # The number of assets being traded, expressed in base asset decimal units - size: str - # The traded price, expressed in `9` decimals - price: str - # The mark price of the instrument at point of trade, expressed in `9` decimals - mark_price: str - # The index price of the instrument at point of trade, expressed in `9` decimals - index_price: str - # The interest rate of the underlying at point of trade, expressed in centibeeps (1/100th of a basis point) - interest_rate: str - # [Options] The forward price of the option at point of trade, expressed in `9` decimals - forward_price: str - """ - A trade identifier, globally unique, and monotonically increasing (not by `1`). - All trades sharing a single taker execution share the same first component (before `-`), and `event_time`. - `trade_id` is guaranteed to be consistent across MarketData `Trade` and Trading `Fill`. - """ - trade_id: str - # The venue where the trade occurred - venue: Venue - # If the trade is a RPI trade - is_rpi: bool - - -@dataclass -class WSTradeFeedDataV1: - # Stream name - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # A public trade matching the request filter - feed: Trade - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSCandlestickFeedSelectorV1: - """ - Subscribes to a stream of Kline/Candlestick updates for an instrument. A Kline is uniquely identified by its open time. - A new Kline is published every interval (if it exists). Upon subscription, the server will send the 5 most recent Kline for the requested interval. - """ - - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # The interval of each candlestick - interval: CandlestickInterval - # The type of candlestick data to retrieve - type: CandlestickType - - -@dataclass -class Candlestick: - # Open time of kline bar in unix nanoseconds - open_time: str - # Close time of kline bar in unix nanosecond - close_time: str - # The open price, expressed in underlying currency resolution units - open: str - # The close price, expressed in underlying currency resolution units - close: str - # The high price, expressed in underlying currency resolution units - high: str - # The low price, expressed in underlying currency resolution units - low: str - # The underlying volume transacted, expressed in base asset decimal units - volume_b: str - # The quote volume transacted, expressed in quote asset decimal units - volume_q: str - # The number of trades transacted - trades: int - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - - -@dataclass -class WSCandlestickFeedDataV1: - # Stream name - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # A candlestick entry matching the request filters - feed: Candlestick - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSUnsubscribeAllParams: - pass - - -@dataclass -class StreamReference: - # The channel to subscribe to (eg: ticker.s / ticker.d) - stream: str - # The list of selectors for the stream - selectors: list[str] - - -@dataclass -class WSUnsubscribeAllResult: - # The list of stream references unsubscribed from - stream_reference: list[StreamReference] - - -@dataclass -class WSListStreamsParams: - pass - - -@dataclass -class WSListStreamsResult: - # The list of stream references the connection is connected to - stream_reference: list[StreamReference] - - -@dataclass -class ApiOrderbookLevelsRequest: - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # Depth of the order book to be retrieved (10, 50, 100, 500) - depth: int - - -@dataclass -class ApiOrderbookLevelsResponse: - # The orderbook levels objects matching the request asset - result: OrderbookLevels - - -@dataclass -class ApiMiniTickerRequest: - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - - -@dataclass -class ApiMiniTickerResponse: - # The mini ticker matching the request asset - result: MiniTicker - - -@dataclass -class ApiTickerRequest: - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - - -@dataclass -class ApiTickerResponse: - # The mini ticker matching the request asset - result: Ticker - - -@dataclass -class ApiTradeRequest: - """ - Retrieves up to 1000 of the most recent trades in any given instrument. Do not use this to poll for data -- a websocket subscription is much more performant, and useful. - This endpoint offers public trading data, use the Trading APIs instead to query for your personalized trade tape. - """ - - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # The limit to query for. Defaults to 500; Max 1000 - limit: int - - -@dataclass -class ApiTradeResponse: - # The public trades matching the request asset - result: list[Trade] - - -@dataclass -class ApiTradeHistoryRequest: - """ - Perform historical lookup of public trades in any given instrument. - This endpoint offers public trading data, use the Trading APIs instead to query for your personalized trade tape. - Only data from the last three months will be retained. - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # The start time to apply in nanoseconds. If nil, this defaults to all start times. Otherwise, only entries matching the filter will be returned - start_time: str | None = None - # The end time to apply in nanoseconds. If nil, this defaults to all end times. Otherwise, only entries matching the filter will be returned - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the query from - cursor: str | None = None - - -@dataclass -class ApiTradeHistoryResponse: - # The public trades matching the request asset - result: list[Trade] - # The cursor to indicate when to start the next query from - next: str | None = None - - -@dataclass -class ApiGetInstrumentRequest: - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - - -@dataclass -class Instrument: - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # The asset ID used for instrument signing. - instrument_hash: str - # The base currency - base: str - # The quote currency - quote: str - # The kind of instrument - kind: Kind - # Venues that this instrument can be traded at - venues: list[Venue] - # The settlement period of the instrument - settlement_period: InstrumentSettlementPeriod - # The smallest denomination of the base asset supported by GRVT (+3 represents 0.001, -3 represents 1000, 0 represents 1) - base_decimals: int - # The smallest denomination of the quote asset supported by GRVT (+3 represents 0.001, -3 represents 1000, 0 represents 1) - quote_decimals: int - # The size of a single tick, expressed in price decimal units - tick_size: str - # The minimum contract size, expressed in base asset decimal units - min_size: str - # Creation time in unix nanoseconds - create_time: str - # The maximum position size, expressed in base asset decimal units - max_position_size: str - - -@dataclass -class ApiGetInstrumentResponse: - # The instrument matching the request asset - result: Instrument - - -@dataclass -class ApiGetFilteredInstrumentsRequest: - # The kind filter to apply. If nil, this defaults to all kinds. Otherwise, only entries matching the filter will be returned - kind: list[Kind] | None = None - # The base filter to apply. If nil, this defaults to all bases. Otherwise, only entries matching the filter will be returned - base: list[str] | None = None - # The quote filter to apply. If nil, this defaults to all quotes. Otherwise, only entries matching the filter will be returned - quote: list[str] | None = None - # Request for active instruments only - is_active: bool | None = None - # The limit to query for. Defaults to 500; Max 100000 - limit: int | None = None - - -@dataclass -class ApiGetFilteredInstrumentsResponse: - # The instruments matching the request filter - result: list[Instrument] - - -@dataclass -class ApiGetCurrencyRequest: - pass - - -@dataclass -class CurrencyDetail: - # The integer value of the currency - id: int - # The name of the currency - symbol: str - # The balance decimals of the currency - balance_decimals: int - # The quantity multiplier of the currency - quantity_multiplier: str - - -@dataclass -class ApiGetCurrencyResponse: - # The list of currencies - result: list[CurrencyDetail] - - -@dataclass -class ApiCandlestickRequest: - """ - Kline/Candlestick bars for an instrument. Klines are uniquely identified by their instrument, type, interval, and open time. - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # The interval of each candlestick - interval: CandlestickInterval - # The type of candlestick data to retrieve - type: CandlestickType - # Start time of kline data in unix nanoseconds - start_time: str | None = None - # End time of kline data in unix nanoseconds - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the query from - cursor: str | None = None - - -@dataclass -class ApiCandlestickResponse: - # The candlestick result set for given interval - result: list[Candlestick] - # The cursor to indicate when to start the next query from - next: str | None = None - - -@dataclass -class ApiFundingRateRequest: - """ - Lookup the historical funding rate of a perpetual future. - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # Start time of funding rate in unix nanoseconds - start_time: str | None = None - # End time of funding rate in unix nanoseconds - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the query from - cursor: str | None = None - - -@dataclass -class FundingRate: - # The readable instrument name:
    • Perpetual: `ETH_USDT_Perp`
    • Future: `BTC_USDT_Fut_20Oct23`
    • Call: `ETH_USDT_Call_20Oct23_2800`
    • Put: `ETH_USDT_Put_20Oct23_2800`
    - instrument: str - # The funding rate of the instrument, expressed in percentage points - funding_rate: str - # The funding timestamp of the funding rate, expressed in unix nanoseconds - funding_time: str - # The mark price of the instrument at funding timestamp, expressed in `9` decimals - mark_price: str - # The 8h average funding rate of the instrument, expressed in percentage points - funding_rate_8_h_avg: str - - -@dataclass -class ApiFundingRateResponse: - # The funding rate result set for given interval - result: list[FundingRate] - # The cursor to indicate when to start the next query from - next: str | None = None - - -@dataclass -class ApiGetAllInstrumentsRequest: - # Fetch only active instruments - is_active: bool | None = None - - -@dataclass -class ApiGetAllInstrumentsResponse: - # List of instruments - result: list[Instrument] - - -@dataclass -class ApiQueryVaultManagerInvestorHistoryRequest: - # The unique identifier of the vault to filter by - vault_id: str - # Whether to only return investments made by the manager - only_own_investments: bool - - -@dataclass -class ApiVaultInvestorHistory: - # Time at which the event was emitted in unix nanoseconds - event_time: str - # The off chain account id of the investor, only visible to the manager - off_chain_account_id: str - # The unique identifier of the vault. - vault_id: str - # The type of transaction that occurred. List of types: vaultInvest, vaultBurnLpToken, vaultRedeem - type: VaultInvestorAction - # The price of the vault LP tokens at the time of the event. - price: str - # The amount of Vault LP tokens invested or redeemed. - size: str - # The realized PnL of the vault. - realized_pnl: str - # The performance fee of the vault. - performance_fee: str - - -@dataclass -class ApiQueryVaultManagerInvestorHistoryResponse: - # The list of vault investor history belong to the manager - result: list[ApiVaultInvestorHistory] - - -@dataclass -class OrderLeg: - # The instrument to trade in this leg - instrument: str - # The total number of assets to trade in this leg, expressed in base asset decimal units. - size: str - # Specifies if the order leg is a buy or sell - is_buying_asset: bool - """ - The limit price of the order leg, expressed in `9` decimals. - This is the number of quote currency units to pay/receive for this leg. - This should be `null/0` if the order is a market order - """ - limit_price: str | None = None - - -@dataclass -class TPSLOrderMetadata: - """ - Contains metadata for Take Profit (TP) and Stop Loss (SL) trigger orders. - - ### Fields: - - **triggerBy**: Defines the price type that activates the order (e.g., index price). - - **triggerPrice**: The price at which the order is triggered, expressed in `9` decimal precision. - - - """ - - # Defines the price type that activates a Take Profit (TP) or Stop Loss (SL) order - trigger_by: TriggerBy - # The Trigger Price of the order, expressed in `9` decimals. - trigger_price: str - # If True, the order will close the position when the trigger price is reached - close_position: bool - - -@dataclass -class TriggerOrderMetadata: - """ - Contains metadata related to trigger orders, such as Take Profit (TP) or Stop Loss (SL). - - Trigger orders are used to automatically execute an order when a predefined price condition is met, allowing traders to implement risk management strategies. - - - """ - - # Type of the trigger order. eg: Take Profit, Stop Loss, etc - trigger_type: TriggerType - """ - Contains metadata for Take Profit (TP) and Stop Loss (SL) trigger orders. - - - """ - tpsl: TPSLOrderMetadata - - -@dataclass -class OrderMetadata: - """ - Metadata fields are used to support Backend only operations. These operations are not trustless by nature. - Hence, fields in here are never signed, and is never transmitted to the smart contract. - """ - - """ - A unique identifier for the active order within a subaccount, specified by the client - This is used to identify the order in the client's system - This field can be used for order amendment/cancellation, but has no bearing on the smart contract layer - This field will not be propagated to the smart contract, and should not be signed by the client - This value must be unique for all active orders in a subaccount, or amendment/cancellation will not work as expected - Gravity UI will generate a random clientOrderID for each order in the range [0, 2^63 - 1] - To prevent any conflicts, client machines should generate a random clientOrderID in the range [2^63, 2^64 - 1] - - When GRVT Backend receives an order with an overlapping clientOrderID, we will reject the order with rejectReason set to overlappingClientOrderId - """ - client_order_id: str - # [Filled by GRVT Backend] Time at which the order was received by GRVT in unix nanoseconds - create_time: str | None = None - # Trigger fields are used to support any type of trigger order such as TP/SL - trigger: TriggerOrderMetadata | None = None - # Specifies the broker who brokered the order - broker: BrokerTag | None = None - - -@dataclass -class OrderState: - # The status of the order - status: OrderStatus - # The reason for rejection or cancellation - reject_reason: OrderRejectReason - # The number of assets available for orderbook/RFQ matching. Sorted in same order as Order.Legs - book_size: list[str] - # The total number of assets traded. Sorted in same order as Order.Legs - traded_size: list[str] - # Time at which the order was updated by GRVT, expressed in unix nanoseconds - update_time: str - # The average fill price of the order. Sorted in same order as Order.Legs - avg_fill_price: list[str] - - -@dataclass -class Order: - """ - Order is a typed payload used throughout the GRVT platform to express all orderbook, RFQ, and liquidation orders. - GRVT orders are capable of expressing both single-legged, and multi-legged orders by default. - This increases the learning curve slightly but reduces overall integration load, since the order payload is used across all GRVT trading venues. - Given GRVT's trustless settlement model, the Order payload also carries the signature, required to trade the order on our ZKSync Hyperchain. - - All fields in the Order payload (except `id`, `metadata`, and `state`) are trustlessly enforced on our Hyperchain. - This minimizes the amount of trust users have to offer to GRVT - """ - - # The subaccount initiating the order - sub_account_id: str - """ - Four supported types of orders: GTT, IOC, AON, FOK:
      -
    • PARTIAL EXECUTION = GTT / IOC - allows partial size execution on each leg
    • -
    • FULL EXECUTION = AON / FOK - only allows full size execution on all legs
    • -
    • TAKER ONLY = IOC / FOK - only allows taker orders
    • -
    • MAKER OR TAKER = GTT / AON - allows maker or taker orders
    • -
    Exchange only supports (GTT, IOC, FOK) - RFQ Maker only supports (GTT, AON), RFQ Taker only supports (FOK) - """ - time_in_force: TimeInForce - """ - The legs present in this order - The legs must be sorted by Asset.Instrument/Underlying/Quote/Expiration/StrikePrice - """ - legs: list[OrderLeg] - # The signature approving this order - signature: Signature - # Order Metadata, ignored by the smart contract, and unsigned by the client - metadata: OrderMetadata - # [Filled by GRVT Backend] A unique 128-bit identifier for the order, deterministically generated within the GRVT backend - order_id: str | None = None - """ - If the order is a market order - Market Orders do not have a limit price, and are always executed according to the maker order price. - Market Orders must always be taker orders - """ - is_market: bool | None = None - """ - If True, Order must be a maker order. It has to fill the orderbook instead of match it. - If False, Order can be either a maker or taker order. In this case, order creation is currently subject to a speedbump of 25ms to ensure orders are matched against updated orderbook quotes. - - | | Must Fill All | Can Fill Partial | - | - | - | - | - | Must Be Taker | FOK + False | IOC + False | - | Can Be Either | AON + False | GTC + False | - | Must Be Maker | AON + True | GTC + True | - - """ - post_only: bool | None = None - # If True, Order must reduce the position size, or be cancelled - reduce_only: bool | None = None - # [Filled by GRVT Backend] The current state of the order, ignored by the smart contract, and unsigned by the client - state: OrderState | None = None - - -@dataclass -class ApiCreateOrderRequest: - # The order to create - order: Order - - -@dataclass -class ApiCreateOrderResponse: - # The created order - result: Order - - -@dataclass -class ApiCancelOrderRequest: - # The subaccount ID cancelling the order - sub_account_id: str - # Cancel the order with this `order_id` - order_id: str | None = None - # Cancel the order with this `client_order_id` - client_order_id: str | None = None - """ - Specifies the time-to-live (in milliseconds) for this cancellation. - During this period, any order creation with a matching `client_order_id` will be cancelled and not be added to the GRVT matching engine. - This mechanism helps mitigate time-of-flight issues where cancellations might arrive before the corresponding orders. - Hence, cancellation by `order_id` ignores this field as the exchange can only assign `order_id`s to already-processed order creations. - The duration cannot be negative, is rounded down to the nearest 100ms (e.g., `'670'` -> `'600'`, `'30'` -> `'0'`) and capped at 5 seconds (i.e., `'5000'`). - Value of `'0'` or omission results in the default time-to-live value being applied. - If the caller requests multiple successive cancellations for a given order, such that the time-to-live windows overlap, only the first request will be considered. - - """ - time_to_live_ms: str | None = None - - -@dataclass -class ApiCancelAllOrdersRequest: - # The subaccount ID cancelling all orders - sub_account_id: str - # The kind filter to apply. If nil, this defaults to all kinds. Otherwise, only entries matching the filter will be cancelled - kind: list[Kind] | None = None - # The base filter to apply. If nil, this defaults to all bases. Otherwise, only entries matching the filter will be cancelled - base: list[str] | None = None - # The quote filter to apply. If nil, this defaults to all quotes. Otherwise, only entries matching the filter will be cancelled - quote: list[str] | None = None - - -@dataclass -class ApiOpenOrdersRequest: - # The subaccount ID to filter by - sub_account_id: str - # The kind filter to apply. If nil, this defaults to all kinds. Otherwise, only entries matching the filter will be returned - kind: list[Kind] | None = None - # The base filter to apply. If nil, this defaults to all bases. Otherwise, only entries matching the filter will be returned - base: list[str] | None = None - # The quote filter to apply. If nil, this defaults to all quotes. Otherwise, only entries matching the filter will be returned - quote: list[str] | None = None - - -@dataclass -class ApiOpenOrdersResponse: - # The Open Orders matching the request filter - result: list[Order] - - -@dataclass -class ApiOrderHistoryRequest: - """ - Retrieves the order history for the account. - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The subaccount ID to filter by - sub_account_id: str - # The kind filter to apply. If nil, this defaults to all kinds. Otherwise, only entries matching the filter will be returned - kind: list[Kind] | None = None - # The base filter to apply. If nil, this defaults to all bases. Otherwise, only entries matching the filter will be returned - base: list[str] | None = None - # The quote filter to apply. If nil, this defaults to all quotes. Otherwise, only entries matching the filter will be returned - quote: list[str] | None = None - # The start time to apply in nanoseconds. If nil, this defaults to all start times. Otherwise, only entries matching the filter will be returned - start_time: str | None = None - # The end time to apply in nanoseconds. If nil, this defaults to all end times. Otherwise, only entries matching the filter will be returned - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the query from - cursor: str | None = None - - -@dataclass -class ApiOrderHistoryResponse: - # The Open Orders matching the request filter - result: list[Order] - # The cursor to indicate when to start the query from - next: str - - -@dataclass -class EmptyRequest: - pass - - -@dataclass -class Ack: - # Gravity has acknowledged that the request has been successfully received and it will process it in the backend - ack: bool - - -@dataclass -class AckResponse: - # The Ack Object - result: Ack - - -@dataclass -class ApiGetOrderRequest: - # The subaccount ID to filter by - sub_account_id: str - # Filter for `order_id` - order_id: str | None = None - # Filter for `client_order_id` - client_order_id: str | None = None - - -@dataclass -class ApiGetOrderResponse: - # The order object for the requested filter - result: Order - - -@dataclass -class ApiCancelOnDisconnectRequest: - """ - Auto-Cancel All Open Orders when the countdown time hits zero. - - Market Maker inputs a countdown time parameter in milliseconds (e.g. 120000 for 120s) rounded down to the smallest second follows the following logic: - - Market Maker initially entered a value between 0 -> 1000, which is rounded to 0: will result in termination of their COD - - Market Maker initially entered a value between 1001 -> 300_000, which is rounded to the nearest second: will result in refresh of their COD - - Market Maker initially entered a value bigger than 300_000, which will result in error (upper bound) - Market Maker will send a heartbeat message by calling the endpoint at specific intervals (ex. every 30 seconds) to the server to refresh the count down. - - If the server does not receive a heartbeat message within the countdown time, it will cancel all open orders for the specified Sub Account ID. - """ - - # The subaccount ID cancelling the orders for - sub_account_id: str - """ - Countdown time in milliseconds (ex. 120000 for 120s). - - 0 to disable the timer. - - Does not accept negative values. - - Minimum acceptable value is 1,000. - - Maximum acceptable value is 300,000 - """ - countdown_time: str | None = None - - -@dataclass -class WSOrderFeedSelectorV1: - """ - Subscribes to a feed of order updates pertaining to orders made by your account. - Each Order can be uniquely identified by its `order_id` or `client_order_id`. - To subscribe to all orders, specify an empty `instrument` (eg. `2345123`). - Otherwise, specify the `instrument` to only receive orders for that instrument (eg. `2345123-BTC_USDT_Perp`). - """ - - # The subaccount ID to filter by - sub_account_id: str - # The instrument filter to apply. - instrument: str | None = None - - -@dataclass -class WSOrderFeedDataV1: - # Stream name - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # The order object being created or updated - feed: Order - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSOrderStateFeedSelectorV1: - """ - Subscribes to a feed of order updates pertaining to orders made by your account. - Unlike the Order Stream, this only streams state updates, drastically improving throughput, and latency. - Each Order can be uniquely identified by its `order_id` or `client_order_id`. - To subscribe to all orders, specify an empty `instrument` (eg. `2345123`). - Otherwise, specify the `instrument` to only receive orders for that instrument (eg. `2345123-BTC_USDT_Perp`). - """ - - # The subaccount ID to filter by - sub_account_id: str - # The instrument filter to apply. - instrument: str | None = None - - -@dataclass -class OrderStateFeed: - # A unique 128-bit identifier for the order, deterministically generated within the GRVT backend - order_id: str - # A unique identifier for the active order within a subaccount, specified by the client - client_order_id: str - # The order state object being created or updated - order_state: OrderState - - -@dataclass -class WSOrderStateFeedDataV1: - # Stream name - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # The Order State Feed - feed: OrderStateFeed - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSPositionsFeedSelectorV1: - """ - Subscribes to a feed of position updates. - Updates get published when a trade is executed, and when leverage configurations are changed for instruments with ongoing positions. - To subscribe to all positions, specify an empty `instrument` (eg. `2345123`). - Otherwise, specify the `instrument` to only receive positions for that instrument (eg. `2345123-BTC_USDT_Perp`). - """ - - # The subaccount ID to filter by - sub_account_id: str - # The instrument filter to apply. - instrument: str | None = None - - -@dataclass -class WSPositionsFeedDataV1: - # Stream name - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # A Position being created or updated matching the request filter - feed: Positions - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSFillFeedSelectorV1: - """ - Subscribes to a feed of private trade updates. This happens when a trade is executed. - To subscribe to all private trades, specify an empty `instrument` (eg. `2345123`). - Otherwise, specify the `instrument` to only receive private trades for that instrument (eg. `2345123-BTC_USDT_Perp`). - """ - - # The sub account ID to request for - sub_account_id: str - # The instrument filter to apply. - instrument: str | None = None - - -@dataclass -class WSFillFeedDataV1: - # The websocket channel to which the response is sent - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # A private trade matching the request filter - feed: Fill - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSTransferFeedSelectorV1: - """ - Subscribes to a feed of transfers. This will execute when there is any transfer to or from the selected account. - To subscribe to a main account, specify the account ID (eg. `0x9fe3758b67ce7a2875ee4b452f01a5282d84ed8a`). - To subscribe to a sub account, specify the main account and the sub account dash separated (eg. `0x9fe3758b67ce7a2875ee4b452f01a5282d84ed8a-1920109784202388`). - """ - - # The main account ID to request for - main_account_id: str - # The sub account ID to request for - sub_account_id: str | None = None - - -@dataclass -class TransferHistory: - # The transaction ID of the transfer - tx_id: str - # The account to transfer from - from_account_id: str - # The subaccount to transfer from (0 if transferring from main account) - from_sub_account_id: str - # The account to deposit into - to_account_id: str - # The subaccount to transfer to (0 if transferring to main account) - to_sub_account_id: str - # The token currency to transfer - currency: str - # The number of tokens to transfer - num_tokens: str - # The signature of the transfer - signature: Signature - # The timestamp of the transfer in unix nanoseconds - event_time: str - # The type of transfer - transfer_type: TransferType - # The metadata of the transfer - transfer_metadata: str - - -@dataclass -class WSTransferFeedDataV1: - # The websocket channel to which the response is sent - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # The transfer history matching the requested filters - feed: TransferHistory - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSDepositFeedSelectorV1: - """ - Subscribes to a feed of deposits. This will execute when there is any deposit to selected account. - To subscribe to a main account, specify the account ID (eg. `0x9fe3758b67ce7a2875ee4b452f01a5282d84ed8a`). - """ - - # The main account ID to request for - main_account_id: str - - -@dataclass -class Deposit: - # The hash of the bridgemint event producing the deposit - tx_hash: str - # The account to deposit into - to_account_id: str - # The token currency to deposit - currency: str - # The number of tokens to deposit - num_tokens: str - - -@dataclass -class WSDepositFeedDataV1: - # The websocket channel to which the response is sent - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # The Deposit object - feed: Deposit - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSWithdrawalFeedSelectorV1: - """ - Subscribes to a feed of withdrawals. This will execute when there is any withdrawal from the selected account. - To subscribe to a main account, specify the account ID (eg. `0x9fe3758b67ce7a2875ee4b452f01a5282d84ed8a`). - """ - - # The main account ID to request for - main_account_id: str - - -@dataclass -class Withdrawal: - # The subaccount to withdraw from - from_account_id: str - # The ethereum address to withdraw to - to_eth_address: str - # The token currency to withdraw - currency: str - # The number of tokens to withdraw - num_tokens: str - # The signature of the withdrawal - signature: Signature - - -@dataclass -class WSWithdrawalFeedDataV1: - # The websocket channel to which the response is sent - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # The Withdrawal object - feed: Withdrawal - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class CancelStatusFeed: - # The subaccount ID that requested the cancellation - sub_account_id: str - # A unique identifier for the active order within a subaccount, specified by the client - client_order_id: str - # A unique 128-bit identifier for the order, deterministically generated within the GRVT backend - order_id: str - # The user-provided reason for cancelling the order - reason: OrderRejectReason - # Status of the cancellation attempt - cancel_status: CancelStatus - # [Filled by GRVT Backend] Time at which the cancellation status was updated by GRVT in unix nanoseconds - update_time: str | None = None - - -@dataclass -class WSCancelFeedDataV1: - # Stream name - stream: str - # Primary selector - selector: str - """ - A sequence number used to determine message order within a stream. - - If `useGlobalSequenceNumber` is **false**, this returns the gateway sequence number, which increments by one locally within each stream and resets on gateway restarts. - - If `useGlobalSequenceNumber` is **true**, this returns the global sequence number, which uniquely identifies messages across the cluster. - - A single cluster payload can be multiplexed into multiple stream payloads. - - To distinguish each stream payload, a `dedupCounter` is included. - - The returned sequence number is computed as: `cluster_sequence_number * 10^5 + dedupCounter`. - """ - sequence_number: str - # Data relating to the status of the cancellation attempt - feed: CancelStatusFeed - # The previous sequence number that determines the message order - prev_sequence_number: str - - -@dataclass -class WSCancelFeedSelectorV1: - """ - Subscribes to a feed of time-to-live expiry events for order cancellations requested by a given subaccount. - **This stream presently only provides expiry updates for cancel-order requests set with a valid TTL value**. - Successful order cancellations will reflect as updates published to the [order-state stream](https://api-docs.grvt.io/trading_streams/#order-state). - _A future release will expand the functionality of this stream to provide more general status updates on order cancellation requests._ - Each Order can be uniquely identified by its `client_order_id`. - - """ - - # The subaccount ID to filter by - sub_account_id: str - - -@dataclass -class ApiWithdrawalRequest: - """ - Leverage this API to initialize a withdrawal from GRVT's Hyperchain onto Ethereum. - Do take note that the bridging process does take time. The GRVT UI will help you keep track of bridging progress, and notify you once its complete. - - If not withdrawing the entirety of your balance, there is a minimum withdrawal amount. Currently that amount is ~25 USDT. - Withdrawal fees also apply to cover the cost of the Ethereum transaction. - Note that your funds will always remain in self-custory throughout the withdrawal process. At no stage does GRVT gain control over your funds. - """ - - # The main account to withdraw from - from_account_id: str - # The Ethereum wallet to withdraw into - to_eth_address: str - # The token currency to withdraw - currency: str - # The number of tokens to withdraw, quoted in tokenCurrency decimal units - num_tokens: str - # The signature of the withdrawal - signature: Signature - - -@dataclass -class ApiTransferRequest: - """ - This API allows you to transfer funds in multiple different ways
      -
    • Between SubAccounts within your Main Account
    • -
    • Between your MainAccount and your SubAccounts
    • -
    • To other MainAccounts that you have previously allowlisted
    • -
    Fast Withdrawal Funding Address - For fast withdrawals, funds must be sent to the designated funding account address. Please ensure you use the correct address based on the environment: - Production Environment Address: - [To be updated, not ready yet] - This address should be specified as the to_account_id in your API requests for transferring funds using the transfer API. Ensure accurate input to avoid loss of funds or use the UI. - - """ - - # The main account to transfer from - from_account_id: str - # The subaccount to transfer from (0 if transferring from main account) - from_sub_account_id: str - # The main account to deposit into - to_account_id: str - # The subaccount to transfer to (0 if transferring to main account) - to_sub_account_id: str - # The token currency to transfer - currency: str - # The number of tokens to transfer, quoted in tokenCurrency decimal units - num_tokens: str - # The signature of the transfer - signature: Signature - # The type of transfer - transfer_type: TransferType - # The metadata of the transfer - transfer_metadata: str - - -@dataclass -class ApiTransferAck: - # Gravity has acknowledged that the transfer has been successfully processed. If true, a `tx_id` will be returned. If false, an error will be returned. - ack: bool - # The transaction ID of the transfer. This is only returned if the transfer is successful. - tx_id: str - - -@dataclass -class ApiTransferResponse: - # The Transfer response object - result: ApiTransferAck - - -@dataclass -class ApiDepositHistoryRequest: - """ - The request to get the historical deposits of an account - The history is returned in reverse chronological order - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The token currency to query for, if nil or empty, return all deposits. Otherwise, only entries matching the filter will be returned - currency: list[str] - # The start time to query for in unix nanoseconds - start_time: str | None = None - # The end time to query for in unix nanoseconds - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the next query from - cursor: str | None = None - # Main account ID being queried. By default, applies the requestor's main account ID. - main_account_id: str | None = None - - -@dataclass -class DepositHistory: - # The L1 txHash of the deposit - l_1_hash: str - # The L2 txHash of the deposit - l_2_hash: str - # The account to deposit into - to_account_id: str - # The token currency to deposit - currency: str - # The number of tokens to deposit - num_tokens: str - # The timestamp when the deposit was initiated on L1 in unix nanoseconds - initiated_time: str - # The timestamp when the deposit was confirmed on L2 in unix nanoseconds - confirmed_time: str - # The address of the sender - from_address: str - - -@dataclass -class ApiDepositHistoryResponse: - # The deposit history matching the request account - result: list[DepositHistory] - # The cursor to indicate when to start the next query from - next: str | None = None - - -@dataclass -class ApiTransferHistoryRequest: - """ - The request to get the historical transfers of an account - The history is returned in reverse chronological order - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The token currency to query for, if nil or empty, return all transfers. Otherwise, only entries matching the filter will be returned - currency: list[str] - # The start time to query for in unix nanoseconds - start_time: str | None = None - # The end time to query for in unix nanoseconds - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the next query from - cursor: str | None = None - # The transaction ID to query for - tx_id: str | None = None - # Main account ID being queried. By default, applies the requestor's main account ID. - main_account_id: str | None = None - - -@dataclass -class ApiTransferHistoryResponse: - # The transfer history matching the request account - result: list[TransferHistory] - # The cursor to indicate when to start the next query from - next: str | None = None - - -@dataclass -class ApiWithdrawalHistoryRequest: - """ - The request to get the historical withdrawals of an account - The history is returned in reverse chronological order - - Pagination works as follows:
    • We perform a reverse chronological lookup, starting from `end_time`. If `end_time` is not set, we start from the most recent data.
    • The lookup is limited to `limit` records. If more data is requested, the response will contain a `next` cursor for you to query the next page.
    • If a `cursor` is provided, it will be used to fetch results from that point onwards.
    • Pagination will continue until the `start_time` is reached. If `start_time` is not set, pagination will continue as far back as our data retention policy allows.
    - """ - - # The token currency to query for, if nil or empty, return all withdrawals. Otherwise, only entries matching the filter will be returned - currency: list[str] - # The start time to query for in unix nanoseconds - start_time: str | None = None - # The end time to query for in unix nanoseconds - end_time: str | None = None - # The limit to query for. Defaults to 500; Max 1000 - limit: int | None = None - # The cursor to indicate when to start the next query from - cursor: str | None = None - # Main account ID being queried. By default, applies the requestor's main account ID. - main_account_id: str | None = None - - -@dataclass -class WithdrawalHistory: - # The transaction ID of the withdrawal - tx_id: str - # The subaccount to withdraw from - from_account_id: str - # The ethereum address to withdraw to - to_eth_address: str - # The token currency to withdraw - currency: str - # The number of tokens to withdraw - num_tokens: str - # The signature of the withdrawal - signature: Signature - # The timestamp of the withdrawal in unix nanoseconds - event_time: str - - -@dataclass -class ApiWithdrawalHistoryResponse: - # The withdrawals history matching the request account - result: list[WithdrawalHistory] - # The cursor to indicate when to start the next query from - next: str | None = None - - -@dataclass -class ApiVaultInvestRequest: - """ - Request payload for investing in a vault. - - This API allows a client to invest a specified amount of tokens in a particular vault. - """ - - # The address of the main account initiating the investment. - main_account_id: str - # The unique identifier of the vault to invest in. - vault_id: str - # The currency used for the investment. This should be the vault's quote currency. - currency: str - # The investment sum, in terms of the token currency specified (i.e., `numTokens` of '1000' with `tokenCurrency` of 'USDT' denotes investment of 1,000 USDT). - num_tokens: str - """ - The digital signature from the investing account. - This signature must be generated by the main account ID and is used to verify the authenticity of the request. - The signature must comply with AccountPermExternalTransfer permission. - """ - signature: Signature - - -@dataclass -class ApiVaultRedeemRequest: - """ - Request payload for redeeming from a vault. - - This API allows a client to redeem a specified amount of tokens from a particular vault. - """ - - # The address of the main account initiating the redemption. - main_account_id: str - # The unique identifier of the vault to redeem from. - vault_id: str - # The currency used for the redemption. This should be the vault's quote currency. - currency: str - # The number of shares to redeem. - num_tokens: str - """ - The digital signature from the investing account. - This signature must be generated by the main account ID and is used to verify the authenticity of the request. - The signature must comply with AccountPermExternalTransfer permission. - """ - signature: Signature - - -@dataclass -class ApiVaultRedeemCancelRequest: - """ - Request payload for canceling a vault redemption. - - This API allows a client to cancel a previously initiated redemption from a vault. - """ - - # The address of the main account initiating the cancellation. - main_account_id: str - # The unique identifier of the vault to cancel the redemption from. - vault_id: str - - -@dataclass -class ApiVaultViewRedemptionQueueRequest: - """ - Request payload for a vault manager to view the redemption queue for their vault. - - Fetches the redemption queue for a vault, ordered by descending priority. - - Urgent redemption requests, defined as having been pending >90% of the manager-defined maximum redemption period, have top priority (following insertion order). - - Non-urgent redemption requests are otherwise prioritized by insertion order, unless they are >5x the size of the smallest redemption request. - - E.g., If FIFO ordering (all non-urgent) is 1k -> 50k -> 100k -> 20k -> 10k -> 25k, then priority ordering is 1k -> 10k -> 50k -> 20k -> 100k -> 25k. - - Only displays redemption requests that are eligible for automated redemption, i.e., have been pending for the manager-defined minimum redemption period. - """ - - # The address of the vault manager making the request. - main_account_id: str - # The unique identifier of the vault to fetch the redemption queue for. - vault_id: str - - -@dataclass -class VaultRedemptionRequest: - # [Filled by GRVT Backend] Time at which the redemption request was received by GRVT in unix nanoseconds - request_time: str - # The number of shares to redeem - num_lp_tokens: str - # [Filled by GRVT Backend] Time in unix nanoseconds, beyond which the request will be force-redeemed. - max_redemption_period_timestamp: str - # Age category of this redemption request. - age_category: VaultRedemptionReqAgeCategory - # `true` if this request belongs to the vault manager, omitted otherwise. - is_manager: bool | None = None - - -@dataclass -class ApiVaultViewRedemptionQueueResponse: - """ - Response payload for a vault manager to view the redemption queue for their vault, ordered by descending priority. - - Excludes requests that have not yet aged past the minmimum redemption period. - - Also includes counters for total redemption sizes pending as well as urgent (refer to API integration guide for more detail on redemption request classifications). - - - """ - - # Outstanding vault redemption requests, ordered by descending priority. Excludes requests that have not yet aged past the minmimum redemption period. - redemption_queue: list[VaultRedemptionRequest] - # Number of shares eligible for automated redemption (held in queue for at least the minimum redemption period). - pending_redemption_token_count: str - # Number of shares nearing the maximum redemption period (>= 90% of maximum redemption period). - urgent_redemption_token_count: str - # Amount available for automated redemption request servicing (in USD). - auto_redeemable_balance: str - # Current share price (in USD). - share_price: str - - -@dataclass -class ApiVaultInvestorSummaryRequest: - """ - Request payload for fetching the summary of a vault investor. - - This API allows a client to retrieve the summary of investments in a specific vault. - """ - - # The address of the main account initiating the request. - main_account_id: str - # The unique identifier of the vault to fetch the summary for. - vault_id: str - - -@dataclass -class VaultRedemption: - """ - Vault redemption information. - - This struct contains information about a pending redemption from a vault. - """ - - # The number of LP Tokens requested for redemption. - num_lp_tokens: str - # The valuation (in USD) of the redemption request. - request_valuation: str - # [Filled by GRVT Backend] Time at which the redemption request was received by GRVT in unix nanoseconds - request_time: str - # [Filled by GRVT Backend] Time in unix nanoseconds, beyond which the request will be force-redeemed. - max_redemption_period_timestamp: str - - -@dataclass -class VaultInvestorSummary: - """ - Vault investor summary information. - - This struct contains the summary of investments in a vault. - """ - - # The unique identifier of the vault sub account. - sub_account_id: str - # The number of Vault LP tokens held by the investor. - num_lp_tokens: str - # The average entry price (in USD) of the vault LP tokens. - avg_entry_price: str - # The current price (in USD) of the vault LP tokens. - current_price: str - # The current valuation (in USD) of all held vault LP tokens. - total_equity: str - # The all-time realized PnL (in USD) that the investor has received from the vault. - all_time_realized_pnl: str - # The singleton pending redemption (omitted if none). - pending_redemption: VaultRedemption | None = None - - -@dataclass -class ApiVaultInvestorSummaryResponse: - """ - Response payload for the summary of a vault investor. - - This API provides the summary of investments in a specific vault. - """ - - # The summary of investments in the vault. - vault_investor_summary: list[VaultInvestorSummary] - - -@dataclass -class ApiVaultBurnTokensRequest: - """ - Request payload for burning tokens in a vault. - - This API allows a client to burn a specified amount of tokens in a particular vault. - """ - - # The address of the main account initiating the burn. - main_account_id: str - # The unique identifier of the vault to burn tokens from. - vault_id: str - # The currency used for the burn. This should be the vault's quote currency. - currency: str - # The number of tokens to burn. - num_tokens: str - """ - The digital signature from the investing account. - This signature must be generated by the main account ID and is used to verify the authenticity of the request. - The signature must comply with AccountPermExternalTransfer permission. - """ - signature: Signature diff --git a/docs/grvt/grvt-pysdk-main/tests/__init__.py b/docs/grvt/grvt-pysdk-main/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/__init__.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt.py deleted file mode 100644 index 174b809..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt.py +++ /dev/null @@ -1,316 +0,0 @@ - -import os -import time -import traceback -from datetime import datetime -from decimal import Decimal - -from pysdk.grvt_ccxt import GrvtCcxt -from pysdk.grvt_ccxt_env import GrvtEnv -from pysdk.grvt_ccxt_logging_selector import logger -from pysdk.grvt_ccxt_test_utils import validate_return_values -from pysdk.grvt_ccxt_types import DURATION_SECOND_IN_NSEC, GrvtOrderSide -from pysdk.grvt_ccxt_utils import rand_uint32 - - -def get_open_orders(api: GrvtCcxt) -> list[dict]: - open_orders: list[dict] = api.fetch_open_orders( - symbol="BTC_USDT_Perp", - params={"kind": "PERPETUAL"}, - ) - logger.info(f"open_orders: {open_orders=}") - return open_orders - - -def fetch_order_history(api: GrvtCcxt) -> dict: - order_history: dict = api.fetch_order_history( - params={"kind": "PERPETUAL", "limit": 3}, - ) - logger.info(f"order_history: {order_history=}") - return order_history - -def fetch_funding_history(api: GrvtCcxt) -> dict: - start_date: datetime = datetime.strptime("2025-05-01T00:00:00Z", "%Y-%m-%dT%H:%M:%SZ") - funding_history: dict = api.fetch_funding_rate_history( - symbol="BTC_USDT_Perp", - since=int(start_date.timestamp() * DURATION_SECOND_IN_NSEC), # Convert to nanoseconds - limit=500, - ) - results: list = funding_history.get("result", []) - if results: - logger.info(f"funding_history: START={results[0]}") - logger.info(f"funding_history: END={results[-1]}") - else: - logger.info(f"funding_history: No results found in {funding_history=}") - return funding_history - - -def cancel_orders(api: GrvtCcxt, open_orders: list) -> int: - FN = "cancel_orders" - order_count = 0 - for order_dict in open_orders: - client_order_id = order_dict["metadata"].get("client_order_id") - if client_order_id: - # Cancel - logger.info(f"{FN} cancel order by id:{order_dict['order_id']}") - success = api.cancel_order( - id=order_dict["order_id"], params={"time_to_live_ms": "1000"} - ) - order_count += int(success) - else: - logger.warning(f"{FN} client_order_id not found in {order_dict=}") - return order_count - -def show_derisk_mm_ratios(api: GrvtCcxt, keyword: str) -> None: - """Show the current derisking market making ratios.""" - FN = "show_derisk_mm_ratios" - acc_summary = api.get_account_summary(type="sub-account") - maintenance_margin = acc_summary.get("maintenance_margin") - derisk_margin = acc_summary.get("derisk_margin") - derisk_ratio = acc_summary.get("derisk_to_maintenance_margin_ratio") - logger.info(f"{FN} {keyword} {maintenance_margin=}") - logger.info(f"{FN} {keyword} {derisk_margin=}") - logger.info(f"{FN} {keyword} {derisk_ratio=}") - logger.info(f"sub-account summary:\n{acc_summary}") - -def set_derisk_mm_ratio(api: GrvtCcxt, ratio: str = "1.4") -> None: - """Set the derisking market making ratio.""" - FN = f"set_derisk_mm_ratio {ratio=}" - logger.info(f"{FN} START") - show_derisk_mm_ratios(api, "BEFORE") - api.set_derisk_mm_ratio(ratio) - show_derisk_mm_ratios(api, "AFTER") - - -def cancel_all_orders(api: GrvtCcxt) -> bool: - FN = "cancel_all_orders" - logger.info(f"{FN} START") - cancel_response = api.cancel_all_orders() - logger.info(f"{FN} {cancel_response=}") - return cancel_response - - -def print_instruments(api: GrvtCcxt): - logger.info("print_instruments: START") - if not api.markets: - return - for market in list(api.markets.values())[:3]: - logger.info(f"{market=}") - instrument = market["instrument"] - logger.info(f"fetch_market: {instrument=}, {api.fetch_market(instrument)}") - logger.info(f"fetch_mini_ticker: {instrument=}, {api.fetch_mini_ticker(instrument)}") - logger.info(f"fetch_ticker: {instrument=}, {api.fetch_ticker(instrument)}") - logger.info(f"fetch_order_book {instrument=}, {api.fetch_order_book(instrument, limit=10)}") - logger.info( - f"fetch_recent_trades {instrument=}, {api.fetch_recent_trades(instrument, limit=5)}" - ) - logger.info(f"fetch_trades {instrument=}, {api.fetch_trades(instrument, limit=5)}") - logger.info( - f"fetch_funding_rate_history {instrument=}, " - f"{api.fetch_funding_rate_history(instrument, limit=5)}" - ) - for type in ["TRADE", "MARK", "INDEX", "MID"]: - ohlc = api.fetch_ohlcv( - instrument, timeframe="5m", limit=5, params={"candle_type": type} - ) - logger.info(f"fetch_ohlcv {type} {instrument=}, {ohlc}") - - -def send_order(api: GrvtCcxt, side: GrvtOrderSide, client_order_id: int) -> dict: - price = 94_000 if side == "buy" else 95_000 - send_order_response: dict = api.create_order( - symbol="BTC_USDT_Perp", - order_type="limit", - side=side, - amount=0.01, - price=price, - params={"client_order_id": client_order_id}, - ) - logger.info(f"send order: {send_order_response=} {client_order_id=}") - return send_order_response - - -def send_mkt_order( - api: GrvtCcxt, symbol: str, side: GrvtOrderSide, amount: Decimal, client_order_id: int -) -> dict: - send_order_response: dict = api.create_order( - symbol=symbol, - order_type="market", - side=side, - amount=amount, - params={"client_order_id": client_order_id}, - ) - logger.info(f"send mkt order: {send_order_response=} {client_order_id=}") - return send_order_response - - -# Test scenarios, called by the __main__ test routine -def send_fetch_order(api: GrvtCcxt): - client_order_id = rand_uint32() - _ = send_order(api, side="buy", client_order_id=client_order_id) - time.sleep(0.1) - order_status = api.fetch_order( - id=None, - params={"client_order_id": client_order_id}, - ) - logger.info(f"result of fetch_order: {order_status=}") - - -def check_cancel_check_orders(api: GrvtCcxt): - logger.info("check_cancel_check_orders: START") - open_orders = get_open_orders(api) - if open_orders: - cancel_orders(api, open_orders) - get_open_orders(api) - - -def fetch_my_trades(api: GrvtCcxt): - logger.info("fetch_my_trades: START") - my_trades = api.fetch_my_trades( - symbol="BTC_USDT_Perp", - limit=10, - params={}, - ) - logger.info(f"my_trades: num trades:{len(my_trades)}") - logger.info(f"my_trades: {my_trades=}") - - -def cancel_send_order(api: GrvtCcxt): - FN = "cancel_send_order" - logger.info(f"{FN}: START") - client_order_id: int = rand_uint32() - logger.info(f"{FN} cancel order by {client_order_id=}") - result = api.cancel_order( - params={"client_order_id": client_order_id, "time_to_live_ms": "1000"} - ) - logger.info(f"{FN} cancel_order: {result=}") - order_response = send_mkt_order( - api, - symbol="BTC_USDT_Perp", - side="sell", - amount=Decimal("0.01"), - client_order_id=client_order_id, - ) - if order_response: - time.sleep(0.1) - # Get status - logger.info(f"{FN} fetch_order by {client_order_id=}") - order_status = api.fetch_order(params={"client_order_id": client_order_id}) - logger.info(f"{FN} {order_status=}") - else: - logger.warning(f"{FN}: order_response is None") - - -def send_fetch_mkt_order(api: GrvtCcxt): - FN = "send_fetch_mkt_order" - logger.info(f"{FN}: START") - client_order_id: int = rand_uint32() - order_response = send_mkt_order( - api, - symbol="BTC_USDT_Perp", - side="sell", - amount=Decimal("0.01"), - client_order_id=client_order_id, - ) - if order_response: - time.sleep(0.1) - # Get status - logger.info(f"{FN} fetch_order by {client_order_id=}") - order_status = api.fetch_order(params={"client_order_id": client_order_id}) - logger.info(f"{FN} {order_status=}") - else: - logger.warning(f"{FN}: order_response is None") - - -def print_markets(api: GrvtCcxt): - logger.info("print_markets: START") - if api.markets: - logger.info(f"MARKETS:{len(api.markets)}") - for market in api.markets.values(): - logger.info(f"MARKET:{market}") - - -def fetch_all_markets(api: GrvtCcxt): - logger.info("fetch_all_markets: START") - instruments = api.fetch_all_markets() - logger.info(f"fetch_all_markets: num instruments={len(instruments)}") - - -def print_account_summary(api: GrvtCcxt): - try: - logger.info(f"sub-account summary:\n{api.get_account_summary(type='sub-account')}") - logger.info(f"funding-account summary:\n{api.get_account_summary(type='funding')}") - logger.info(f"aggregated-account summary:\n{api.get_account_summary(type='aggregated')}") - logger.info(f"fetch_balance:\n{api.fetch_balance()}") - except Exception as e: - logger.error(f"account summary failed: {e}") - - -def print_account_history(api: GrvtCcxt): - try: - hist = api.fetch_account_history(params={}) - logger.info(f"account history:\n{hist}") - except Exception as e: - logger.error(f"account history failed: {e}") - - -def print_positions(api: GrvtCcxt): - try: - logger.info(f"positions:\n{api.fetch_positions(symbols=['BTC_USDT_Perp'])}") - except Exception as e: - logger.error(f"positions failed: {e}") - - -def print_description(api: GrvtCcxt): - try: - logger.info(f"print_description: {api.describe()}") - except Exception as e: - logger.error(f"print_description failed: {e}") - - -def test_grvt_ccxt(): - params = { - "api_key": os.getenv("GRVT_API_KEY"), - "trading_account_id": os.getenv("GRVT_TRADING_ACCOUNT_ID"), - "private_key": os.getenv("GRVT_PRIVATE_KEY"), - } - env = GrvtEnv(os.getenv("GRVT_ENV", "testnet")) - test_api = GrvtCcxt(env, logger, parameters=params, order_book_ccxt_format=True) - function_list = [ - print_description, - # -------- MARKET related - fetch_all_markets, - print_markets, - print_instruments, - print_account_summary, - print_account_history, - # print_positions, - # -------- TRADE related - # fetch_my_trades, - fetch_order_history, - fetch_funding_history, - # # -------- order related - send_fetch_order, - fetch_my_trades, - print_positions, - check_cancel_check_orders, - cancel_send_order, - send_fetch_mkt_order, - get_open_orders, - send_fetch_order, - get_open_orders, - cancel_all_orders, - get_open_orders, - # Derisk MM ratio - set_derisk_mm_ratio, - ] - for f in function_list: - try: - f(test_api) - except Exception as e: - logger.error(f"Error in {f.__name__}: {e} {traceback.format_exc()}") - validate_return_values(test_api, "test_results_sync.csv") - - -if __name__ == "__main__": - test_grvt_ccxt() diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_pro.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_pro.py deleted file mode 100644 index 3c38fec..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_pro.py +++ /dev/null @@ -1,300 +0,0 @@ -import asyncio -import os -import traceback -from datetime import datetime -from decimal import Decimal - -from pysdk.grvt_ccxt_env import GrvtEnv -from pysdk.grvt_ccxt_logging_selector import logger -from pysdk.grvt_ccxt_pro import GrvtCcxtPro -from pysdk.grvt_ccxt_test_utils import validate_return_values -from pysdk.grvt_ccxt_types import DURATION_SECOND_IN_NSEC, GrvtOrderSide -from pysdk.grvt_ccxt_utils import rand_uint32 - - -# Utility functions , not called directly by the __main__ test routine -async def get_open_orders(api: GrvtCcxtPro) -> list[dict]: - open_orders = await api.fetch_open_orders( - - symbol="BTC_USDT_Perp", - params={"kind": "PERPETUAL"}, - ) - logger.info(f"open_orders: {open_orders=}") - return open_orders - - -async def fetch_order_history(api: GrvtCcxtPro) -> dict: - order_history: dict = await api.fetch_order_history( - params={"kind": "PERPETUAL", "limit": 3}, - ) - logger.info(f"order_history: {order_history=}") - return order_history - -async def fetch_funding_history(api: GrvtCcxtPro) -> dict: - start_date: datetime = datetime.strptime("2025-05-01T00:00:00Z", "%Y-%m-%dT%H:%M:%SZ") - funding_history: dict = await api.fetch_funding_rate_history( - symbol="BTC_USDT_Perp", - since=int(start_date.timestamp() * DURATION_SECOND_IN_NSEC), # Convert to nanoseconds - limit=500, - ) - results: list = funding_history.get("result", []) - if results: - logger.info(f"funding_history: START={results[0]}") - logger.info(f"funding_history: END={results[-1]}") - else: - logger.info(f"funding_history: No results found in {funding_history=}") - return funding_history - - -async def cancel_orders(api: GrvtCcxtPro, open_orders: list) -> int: - FN = "cancel_orders" - logger.info(f"{FN} START") - order_count: int = 0 - for order_dict in open_orders: - client_order_id = order_dict["metadata"].get("client_order_id") - if client_order_id: - # Cancel - logger.info(f"{FN} cancel order by id:{order_dict['order_id']}") - await api.cancel_order(id=order_dict["order_id"]) - order_count += 1 - else: - logger.warning(f"{FN} client_order_id not found in {order_dict=}") - return order_count - -async def show_derisk_mm_ratios(api: GrvtCcxtPro, keyword: str) -> None: - """Show the current derisking market making ratios.""" - FN = "show_derisk_mm_ratios" - acc_summary = await api.get_account_summary(type="sub-account") - maintenance_margin = acc_summary.get("maintenance_margin") - derisk_margin = acc_summary.get("derisk_margin") - derisk_ratio = acc_summary.get("derisk_to_maintenance_margin_ratio") - logger.info(f"{FN} {keyword} {maintenance_margin=}") - logger.info(f"{FN} {keyword} {derisk_margin=}") - logger.info(f"{FN} {keyword} {derisk_ratio=}") - logger.info(f"sub-account summary:\n{acc_summary}") - -async def set_derisk_mm_ratio(api: GrvtCcxtPro, ratio: str = "1.5") -> None: - """Set the derisking market making ratio.""" - FN = f"set_derisk_mm_ratio {ratio=}" - logger.info(f"{FN} START") - await show_derisk_mm_ratios(api, "BEFORE") - await api.set_derisk_mm_ratio(ratio) - await show_derisk_mm_ratios(api, "AFTER") - -async def cancel_all_orders(api: GrvtCcxtPro) -> bool: - FN = "cancel_all_orders" - logger.info(f"{FN} START") - cancel_response = await api.cancel_all_orders() - logger.info(f"{FN} {cancel_response=}") - return cancel_response - - -async def print_instruments(api: GrvtCcxtPro): - logger.info("print_instruments: START") - if not api.markets: - return - for market in list(api.markets.values())[:3]: - logger.info(f"{market=}") - instrument = market["instrument"] - logger.info(f"fetch_mini_ticker: {instrument=}, {await api.fetch_mini_ticker(instrument)}") - logger.info(f"fetch_ticker: {instrument=}, {await api.fetch_ticker(instrument)}") - logger.info( - f"fetch_order_book {instrument=}, {await api.fetch_order_book(instrument, limit=10)}" - ) - logger.info( - f"fetch_recent_trades {instrument=}, " - f"{await api.fetch_recent_trades(instrument, limit=7)}" - ) - logger.info(f"fetch_trades {instrument=}, {await api.fetch_trades(instrument, limit=5)}") - logger.info( - f"fetch_funding_rate_history {instrument=}, " - f"{await api.fetch_funding_rate_history(instrument, limit=5)}" - ) - for type in ["TRADE", "MARK", "INDEX", "MID"]: - ohlc = await api.fetch_ohlcv( - instrument, timeframe="1m", limit=5, params={"candle_type": type} - ) - logger.info(f"fetch_ohlcv {type} {instrument=}, {ohlc}") - - -async def send_order(api: GrvtCcxtPro, side: GrvtOrderSide, client_order_id: int) -> dict: - price = 64_000 if side == "buy" else 65_000 - send_order_response = await api.create_order( - symbol="BTC_USDT_Perp", - order_type="limit", - side=side, - amount=0.01, - price=price, - params={"client_order_id": client_order_id}, - ) - logger.info(f"send order: {send_order_response=} {client_order_id=}") - return send_order_response - - -# Test scenarios, called by the __main__ test routine -async def send_fetch_order(api: GrvtCcxtPro): - client_order_id = rand_uint32() - _ = await send_order(api, side="buy", client_order_id=client_order_id) - order_status = await api.fetch_order( - id=None, - params={"client_order_id": client_order_id}, - ) - logger.info(f"result of fetch_order: {order_status=}") - - -async def send_mkt_order( - api: GrvtCcxtPro, symbol: str, side: GrvtOrderSide, amount: Decimal, client_order_id: int -) -> dict: - send_order_response = await api.create_order( - symbol=symbol, - order_type="market", - side=side, - amount=amount, - params={"client_order_id": client_order_id}, - ) - logger.info(f"send mkt order: {send_order_response=} {client_order_id=}") - return send_order_response - - -async def check_cancel_check_orders(api: GrvtCcxtPro): - logger.info("check_cancel_check_orders: START") - open_orders = await get_open_orders(api) - if open_orders: - await cancel_orders(api, open_orders) - await get_open_orders(api) - - -async def fetch_my_trades(api: GrvtCcxtPro): - logger.info("fetch_my_trades: START") - my_trades = await api.fetch_my_trades( - symbol="BTC_USDT_Perp", - limit=10, - params={}, - ) - logger.info(f"my_trades: num trades:{len(my_trades)}") - logger.info(f"my_trades: {my_trades=}") - - -async def cancel_send_order(api: GrvtCcxtPro): - FN = "cancel_send_order" - logger.info(f"{FN}: START") - client_order_id: int = rand_uint32() - logger.info(f"{FN} cancel order by {client_order_id=}") - result = await api.cancel_order( - params={"client_order_id": client_order_id, "time_to_live_ms": "1000"} - ) - logger.info(f"{FN} cancel_order: {result=}") - order_response = await send_mkt_order( - api, - symbol="BTC_USDT_Perp", - side="sell", - amount=Decimal("0.01"), - client_order_id=client_order_id, - ) - if order_response: - # Get status - logger.info(f"{FN} fetch_order by {client_order_id=}") - order_status = await api.fetch_order(params={"client_order_id": client_order_id}) - logger.info(f"{FN} {order_status=}") - - -async def print_markets(api: GrvtCcxtPro): - logger.info("print_markets: START") - if api.markets: - logger.info(f"MARKETS:{len(api.markets)}") - for market in api.markets.values(): - logger.info(f"MARKET:{market}") - - -async def fetch_all_markets(api: GrvtCcxtPro): - logger.info("fetch_all_markets: START") - instruments = await api.fetch_all_markets() - logger.info(f"fetch_all_markets: num instruments={len(instruments)}") - - -async def print_account_summary(api: GrvtCcxtPro): - try: - logger.info("print_account_summary: START") - logger.info(f"sub-account summary:\n{await api.get_account_summary(type='sub-account')}") - logger.info(f"funding-account summary:\n{await api.get_account_summary(type='funding')}") - logger.info( - f"aggregated-account summary:\n{await api.get_account_summary(type='aggregated')}" - ) - logger.info(f"fetch_balance:\n{await api.fetch_balance()}") - except Exception as e: - logger.error(f"account summary failed: {e}") - - -async def print_account_history(api: GrvtCcxtPro): - try: - hist = await api.fetch_account_history(params={}) - logger.info(f"account history:\n{hist}") - except Exception as e: - logger.error(f"account history failed: {e}") - - -async def print_positions(api: GrvtCcxtPro): - try: - logger.info(f"positions:\n{await api.fetch_positions(symbols=['BTC_USDT_Perp'])}") - except Exception as e: - logger.error(f"positions failed: {e}") - - -async def print_description(api: GrvtCcxtPro): - try: - logger.info(f"print_description: {api.describe()}") - except Exception as e: - logger.error(f"print_description failed: {e}") - - -async def grvt_ccxt_pro(): - params = { - "api_key": os.getenv("GRVT_API_KEY"), - "trading_account_id": os.getenv("GRVT_TRADING_ACCOUNT_ID"), - "private_key": os.getenv("GRVT_PRIVATE_KEY"), - } - env = GrvtEnv(os.getenv("GRVT_ENV", "testnet")) - test_api = GrvtCcxtPro(env, logger, parameters=params, order_book_ccxt_format=True) - await test_api.load_markets() - await asyncio.sleep(2) - function_list = [ - print_description, - # -------- MARKET related - fetch_all_markets, - print_markets, - print_instruments, - print_account_summary, - print_account_history, - print_positions, - # Order / Trade history - fetch_my_trades, - fetch_order_history, - fetch_funding_history, - # Trade related - send_fetch_order, - check_cancel_check_orders, - fetch_my_trades, - fetch_order_history, - print_positions, - cancel_send_order, - get_open_orders, - send_fetch_order, - get_open_orders, - cancel_all_orders, - get_open_orders, - set_derisk_mm_ratio, - ] - for f in function_list: - try: - await f(test_api) - except Exception as e: - logger.error(f"Error in {f.__name__}: {e} {traceback.format_exc()}") - validate_return_values(test_api, "test_results.csv") - - -def test_grvt_ccxt_pro() -> None: - asyncio.run(grvt_ccxt_pro()) - - -if __name__ == "__main__": - test_grvt_ccxt_pro() diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_vault.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_vault.py deleted file mode 100644 index 14299cf..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_vault.py +++ /dev/null @@ -1,52 +0,0 @@ -import os -import traceback - -from pysdk.grvt_ccxt import GrvtCcxt -from pysdk.grvt_ccxt_env import GrvtEnv -from pysdk.grvt_ccxt_logging_selector import logger - - -def call_vault_manager_investor_history(api: GrvtCcxt): - FN = "call_vault_manager_investor_history" - logger.info(f"{FN}: START") - try: - history = api.fetch_vault_manager_investor_history() - # Expect dict with result key and list of dicts with history items - # [{'event_time': '1752057360756255849', 'off_chain_account_id': 'ACC:2s**fW', - # 'vault_id': '2002239639', 'type': 'VAULT_REDEEM', 'price': '0.998912', 'size': '1900.0', - # 'realized_pnl': '-0.077452', 'performance_fee': '0.0'}, ...] - logger.info(f"{FN}: {history=}") - except Exception as e: - logger.error(f"{FN} failed: {e}") - - -def call_vault_redemption_queue(api: GrvtCcxt): - FN = "call_vault_redemption_queue" - logger.info(f"{FN}: START") - try: - redemption_queue = api.fetch_vault_redemption_queue() - logger.info(f"{FN}: {redemption_queue=}") - except Exception as e: - logger.error(f"{FN} failed: {e}") - - -def test_grvt_ccxt_vault(): - params = { - "api_key": os.getenv("GRVT_API_KEY"), - "trading_account_id": os.getenv("GRVT_TRADING_ACCOUNT_ID"), - "private_key": os.getenv("GRVT_PRIVATE_KEY"), - } - env = GrvtEnv(os.getenv("GRVT_ENV", "testnet")) - test_api = GrvtCcxt(env, logger, parameters=params, order_book_ccxt_format=True) - function_list = [ - call_vault_manager_investor_history, - call_vault_redemption_queue, - ] - for f in function_list: - try: - f(test_api) - except Exception as e: - logger.error(f"Error in {f.__name__}: {e} {traceback.format_exc()}") - -if __name__ == "__main__": - test_grvt_ccxt_vault() diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_vault_pro.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_vault_pro.py deleted file mode 100644 index f2e1075..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_vault_pro.py +++ /dev/null @@ -1,60 +0,0 @@ -import asyncio -import os -import traceback - -from pysdk.grvt_ccxt_env import GrvtEnv -from pysdk.grvt_ccxt_logging_selector import logger -from pysdk.grvt_ccxt_pro import GrvtCcxtPro - - -async def call_vault_manager_investor_history(api: GrvtCcxtPro): - FN = "call_vault_manager_investor_history" - logger.info(f"{FN}: START") - try: - history = await api.fetch_vault_manager_investor_history() - # Expect dict with result key and list of dicts with history items - # [{'event_time': '1752057360756255849', 'off_chain_account_id': 'ACC:2s**fW', - # 'vault_id': '2002239639', 'type': 'VAULT_REDEEM', 'price': '0.998912', 'size': '1900.0', - # 'realized_pnl': '-0.077452', 'performance_fee': '0.0'}, ...] - logger.info(f"{FN}: {history=}") - except Exception as e: - logger.error(f"{FN} failed: {e}") - - -async def call_vault_redemption_queue(api: GrvtCcxtPro): - FN = "call_vault_redemption_queue" - logger.info(f"{FN}: START") - try: - redemption_queue = await api.fetch_vault_redemption_queue() - logger.info(f"{FN}: {redemption_queue=}") - except Exception as e: - logger.error(f"{FN} failed: {e}") - - -async def grvt_ccxt_vault_pro(): - params = { - "api_key": os.getenv("GRVT_API_KEY"), - "trading_account_id": os.getenv("GRVT_TRADING_ACCOUNT_ID"), - "private_key": os.getenv("GRVT_PRIVATE_KEY"), - } - env = GrvtEnv(os.getenv("GRVT_ENV", "testnet")) - test_api = GrvtCcxtPro(env, logger, parameters=params, order_book_ccxt_format=True) - await test_api.load_markets() - await asyncio.sleep(2) - function_list = [ - call_vault_manager_investor_history, - call_vault_redemption_queue, - ] - for f in function_list: - try: - await f(test_api) - except Exception as e: - logger.error(f"Error in {f.__name__}: {e} {traceback.format_exc()}") - - -def test_grvt_ccxt_vault_pro() -> None: - asyncio.run(grvt_ccxt_vault_pro()) - - -if __name__ == "__main__": - test_grvt_ccxt_vault_pro() diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_ws.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_ws.py deleted file mode 100644 index a64b7d8..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_ccxt_ws.py +++ /dev/null @@ -1,297 +0,0 @@ -import asyncio -import os -import signal -import sys -import traceback - -from pysdk.grvt_ccxt_env import GrvtEnv, GrvtWSEndpointType -from pysdk.grvt_ccxt_logging_selector import logger -from pysdk.grvt_ccxt_types import GrvtOrderSide -from pysdk.grvt_ccxt_utils import rand_uint32 -from pysdk.grvt_ccxt_ws import GrvtCcxtWS - - -# Utility functions , not called directly by the __main__ test routine -async def callback_general(message: dict) -> None: - message.get("params", {}).get("channel") - logger.info(f"callback_general(): message:{message}") - - -async def grvt_ws_subscribe(api: GrvtCcxtWS, args_list: dict) -> None: - """Subscribes to Websocket channels/feeds in args list.""" - for stream, (callback, ws_endpoint_type, params) in args_list.items(): - logger.info(f"Subscribing to {stream} {params=}") - await api.subscribe( - stream=stream, - callback=callback, - ws_end_point_type=ws_endpoint_type, - params=params, - ) - await asyncio.sleep(0) - - -async def subscribe(loop) -> GrvtCcxtWS: - """Subscribe to Websocket channels and feeds.""" - params = { - "api_key": os.getenv("GRVT_API_KEY"), - "trading_account_id": os.getenv("GRVT_TRADING_ACCOUNT_ID"), - "api_ws_version": os.getenv("GRVT_WS_STREAM_VERSION", "v1"), - } - if os.getenv("GRVT_PRIVATE_KEY"): - params["private_key"] = os.getenv("GRVT_PRIVATE_KEY") - env = GrvtEnv(os.getenv("GRVT_ENV", "testnet")) - - test_api = GrvtCcxtWS(env, loop, logger, parameters=params) - await test_api.initialize() - pub_args_dict = { - # ********* Market Data ********* - "mini.s": ( - callback_general, - None, # use deafult endpoint - {"instrument": "BTC_USDT_Perp"}, - ), - "mini.d": ( - callback_general, - GrvtWSEndpointType.MARKET_DATA_RPC_FULL, - {"instrument": "BTC_USDT_Perp", "rate": 0}, - ), - "ticker.s": ( - callback_general, - None, # use deafult endpoint - {"instrument": "BTC_USDT_Perp"}, - ), - "ticker.d": ( - callback_general, - GrvtWSEndpointType.MARKET_DATA_RPC_FULL, - {"instrument": "BTC_USDT_Perp"}, - ), - "book.s": ( - callback_general, - GrvtWSEndpointType.MARKET_DATA_RPC_FULL, - {"instrument": "BTC_USDT_Perp"}, - ), - "book.d": ( - callback_general, - GrvtWSEndpointType.MARKET_DATA_RPC_FULL, - {"instrument": "BTC_USDT_Perp"}, - ), - "trade": ( - callback_general, - GrvtWSEndpointType.MARKET_DATA_RPC_FULL, - {"instrument": "BTC_USDT_Perp"}, - ), - "candle": ( - callback_general, - GrvtWSEndpointType.MARKET_DATA_RPC_FULL, - { - "instrument": "BTC_USDT_Perp", - "interval": "CI_1_M", - "type": "TRADE", - }, - ), - } - prv_args_dict = { - # ********* Trade Data ********* - "position": ( - callback_general, - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, - {}, - ), - "order": ( - callback_general, - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, - { - "instrument": "BTC_USDT_Perp", - }, - ), - "cancel": ( - callback_general, - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, - {}, - ), - "state": ( - callback_general, - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, - { - "instrument": "BTC_USDT_Perp", - }, - ), - "fill": ( - callback_general, - GrvtWSEndpointType.TRADE_DATA_RPC_FULL, - { - "instrument": "BTC_USDT_Perp", - }, - ), - "deposit": (callback_general, GrvtWSEndpointType.TRADE_DATA, {}), - "transfer": (callback_general, GrvtWSEndpointType.TRADE_DATA, {}), - "withdrawal": (callback_general, GrvtWSEndpointType.TRADE_DATA, {}), - } - try: - if "private_key" in params: - await grvt_ws_subscribe(test_api, {**pub_args_dict, **prv_args_dict}) - else: # not private_key , subscribe to public feeds only - await grvt_ws_subscribe(test_api, pub_args_dict) - except Exception as e: - logger.error(f"Error in grvt_ws_subscribe: {e} {traceback.format_exc()}") - return test_api - - -async def rpc_create_order( - test_api: GrvtCcxtWS, side: GrvtOrderSide, price: str, client_order_id: str = "" -) -> str: - if test_api and test_api._private_key: - # Send order - if not client_order_id: - client_order_id = str(rand_uint32()) - payload = await test_api.rpc_create_order( - symbol="BTC_USDT_Perp", - order_type="limit", - side=side, - amount=0.001, - price=price, - params={ - "client_order_id": client_order_id, - # "time_in_force": "IMMEDIATE_OR_CANCEL", - "time_in_force": "GOOD_TILL_TIME", - }, - ) - logger.info(f"rpc_create_order: {payload=}") - return client_order_id - return "" - - -async def rpc_create_mkt_order( - test_api: GrvtCcxtWS, symbol: str, side: GrvtOrderSide, client_order_id: str = "" -) -> str: - FN = "rpc_create_mkt_order" - if test_api and test_api._private_key: - # Send order - if not client_order_id: - client_order_id = str(rand_uint32()) - payload = await test_api.rpc_create_order( - symbol=symbol, - order_type="market", - side=side, - amount=0.001, - params={ - "client_order_id": client_order_id, - "time_in_force": "GOOD_TILL_TIME", - }, - ) - logger.info(f"{FN}: {payload=}") - return client_order_id - return "" - - -async def rpc_fetch_order(test_api: GrvtCcxtWS, client_order_id: str) -> None: - if test_api and test_api._private_key: - # Send order - payload = await test_api.rpc_fetch_order( - params={ - "client_order_id": client_order_id, - }, - ) - logger.info(f"rpc_fetch_order: {payload=}") - - -async def rpc_fetch_open_orders(test_api: GrvtCcxtWS) -> None: - if test_api and test_api._private_key: - # Send order - payload: dict = await test_api.rpc_fetch_open_orders() - logger.info(f"rpc_fetch_open_orders: {payload=}") - - -async def rpc_cancel_order( - test_api: GrvtCcxtWS, client_order_id: str, time_to_live_ms: str = "" -) -> None: - if test_api and test_api._private_key: - # Send order - params: dict = {"client_order_id": client_order_id} - if time_to_live_ms: - params["time_to_live_ms"] = time_to_live_ms - payload = await test_api.rpc_cancel_order(params=params) - logger.info(f"rpc_cancel_order: {payload=}") - - -async def rpc_cancel_all_orders(test_api: GrvtCcxtWS) -> None: - if test_api and test_api._private_key: - # Send order - payload: dict = await test_api.rpc_cancel_all_orders() - logger.info(f"rpc_cancel_all_orders: {payload=}") - - -async def cancel_send_rpc_order(test_api: GrvtCcxtWS) -> None: - FN = "cancel_send_rpc_order" - """Cancels order then sends an order to be canceled.""" - if test_api and test_api._private_key: - cloid = str(rand_uint32()) - logger.info(f"{FN} {cloid=}") - await rpc_cancel_order(test_api, cloid, time_to_live_ms="0") - await asyncio.sleep(1) - await rpc_cancel_order(test_api, cloid, time_to_live_ms="5000") - await asyncio.sleep(0.01) - await rpc_create_mkt_order( - test_api, symbol="BTC_USDT_Perp", side="buy", client_order_id=cloid - ) - await asyncio.sleep(0.01) - await rpc_fetch_order(test_api, cloid) - - -async def send_check_cancel_rpc_order(test_api: GrvtCcxtWS) -> None: - if test_api and test_api._private_key: - # Send order - cloid = await rpc_create_order(test_api, side="buy", price="60000") - if cloid: - await rpc_fetch_open_orders(test_api) - await rpc_fetch_order(test_api, cloid) - await asyncio.sleep(5) - await rpc_cancel_order(test_api, cloid) - cloid = await rpc_create_order(test_api, side="sell", price="70000") - if cloid: - await rpc_fetch_open_orders(test_api) - await rpc_fetch_order(test_api, cloid) - await asyncio.sleep(5) - await rpc_cancel_all_orders(test_api) - - -async def send_rpc_messages(test_api: GrvtCcxtWS) -> None: - """Sends test RPC messages for send/fetch/cancel orders.""" - await send_check_cancel_rpc_order(test_api) - await cancel_send_rpc_order(test_api) - - -async def shutdown(loop, test_api: GrvtCcxtWS) -> None: - """Clean up resources and stop the bot gracefully.""" - import time - logger.info("Shutting down gracefully...") - if test_api: - for stream, message in test_api._last_message.items(): - logger.info(f"Last message: {stream=} {message=}") - logger.info("Delete GrvtCcxtWS...") - del test_api # Close the websocket connection and session - time.sleep(3) # Allow time for cleanup - await asyncio.sleep(5) # Allow time for cleanup - logger.info("Cancelling all tasks...") - tasks = [t for t in asyncio.all_tasks(loop) if t is not asyncio.current_task(loop)] - _ = [task.cancel() for task in tasks] - logger.info(f"Cancelling {len(tasks)=}") - await asyncio.gather(*tasks, return_exceptions=True) - logger.info("Shutdown complete.") - sys.exit(0) - - -if __name__ == "__main__": - loop = asyncio.get_event_loop() - test_api = loop.run_until_complete(subscribe(loop)) - if not test_api: - logger.error("Failed to subscribe to Websocket channels.") - sys.exit(1) - for sig in (signal.SIGINT, signal.SIGTERM): - loop.add_signal_handler( - sig, lambda: asyncio.create_task(shutdown(loop, test_api)) - ) - loop.run_until_complete(asyncio.sleep(5)) - loop.run_until_complete(send_rpc_messages(test_api)) - loop.run_forever() - loop.close() diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_async.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_async.py deleted file mode 100644 index 574d4d3..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_async.py +++ /dev/null @@ -1,137 +0,0 @@ -import asyncio - -from pysdk import grvt_raw_types -from pysdk.grvt_raw_async import GrvtRawAsync -from pysdk.grvt_raw_base import GrvtError - -from .test_raw_utils import ( - get_config, - get_test_order, - get_test_transfer, - get_test_withdrawal, -) - - -async def get_all_instruments() -> None: - api = GrvtRawAsync(config=get_config()) - resp = await api.get_all_instruments_v1( - grvt_raw_types.ApiGetAllInstrumentsRequest(is_active=True) - ) - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected results to be non-null") - if len(resp.result) == 0: - raise ValueError("Expected results to be non-empty") - - -async def open_orders() -> None: - api = GrvtRawAsync(config=get_config()) - - # Skip test if trading account id is not set - if api.config.trading_account_id is None or api.config.api_key is None: - return None # Skip test if configs are not set - - resp = await api.open_orders_v1( - grvt_raw_types.ApiOpenOrdersRequest( - sub_account_id=str(api.config.trading_account_id), - kind=[grvt_raw_types.Kind.PERPETUAL], - base=["BTC", "ETH"], - quote=["USDT"], - ) - ) - if isinstance(resp, GrvtError): - api.logger.error(f"Received error: {resp}") - return None - if resp.result is None: - raise ValueError("Expected orders to be non-null") - if len(resp.result) == 0: - api.logger.info("Expected orders to be non-empty") - - -async def create_order_with_signing() -> None: - api = GrvtRawAsync(config=get_config()) - - inst_resp = await api.get_all_instruments_v1( - grvt_raw_types.ApiGetAllInstrumentsRequest(is_active=True) - ) - if isinstance(inst_resp, GrvtError): - raise ValueError(f"Received error: {inst_resp}") - - order = get_test_order(api, {inst.instrument: inst for inst in inst_resp.result}) - if order is None: - return None # Skip test if configs are not set - resp = await api.create_order_v1(grvt_raw_types.ApiCreateOrderRequest(order=order)) - - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected order to be non-null") - - -async def transfer_with_signing_async() -> None: - api = GrvtRawAsync(config=get_config()) - transfer = get_test_transfer(api) - - if transfer is None: - return None # Skip test if configs are not set - - resp = await api.transfer_v1( - grvt_raw_types.ApiTransferRequest( - transfer.from_account_id, - transfer.from_sub_account_id, - transfer.to_account_id, - transfer.to_sub_account_id, - transfer.currency, - transfer.num_tokens, - transfer.signature, - ) - ) - - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected transfer response to be non-null") - - -async def withdrawal_with_signing_async() -> None: - api = GrvtRawAsync(config=get_config()) - withdrawal = get_test_withdrawal(api) - - if withdrawal is None: - return None # Skip test if configs are not set - - resp = await api.withdrawal_v1( - grvt_raw_types.ApiWithdrawalRequest( - withdrawal.from_account_id, - withdrawal.to_eth_address, - withdrawal.currency, - withdrawal.num_tokens, - withdrawal.signature, - ) - ) - - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected withdrawal response to be non-null") - - -def test_get_all_instruments() -> None: - asyncio.run(get_all_instruments()) - - -def test_open_orders() -> None: - asyncio.run(open_orders()) - - -def test_create_order_with_signing() -> None: - asyncio.run(create_order_with_signing()) - - -def test_transfer_with_signing_async() -> None: - asyncio.run(transfer_with_signing_async()) - - -def test_withdrawal_with_signing_async() -> None: - asyncio.run(withdrawal_with_signing_async()) diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_signing.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_signing.py deleted file mode 100644 index 6482a41..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_signing.py +++ /dev/null @@ -1,400 +0,0 @@ -import logging -import traceback -from pprint import pprint - -from eth_account import Account - -from pysdk.grvt_fixed_types import Transfer -from pysdk.grvt_raw_base import GrvtApiConfig -from pysdk.grvt_raw_env import GrvtEnv -from pysdk.grvt_raw_signing import sign_order, sign_transfer -from pysdk.grvt_raw_types import ( - Instrument, - InstrumentSettlementPeriod, - Kind, - Order, - OrderLeg, - OrderMetadata, - Signature, - TimeInForce, - TransferType, -) - -# Setup logger -logging.basicConfig() -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) - - -def test_sign_order_table(): - private_key = "f7934647276a6e1fa0af3f4467b4b8ddaf45d25a7368fa1a295eef49a446819d" - sub_account_id = "8289849667772468" - expiry = 1730800479321350000 - nonce = 828700936 - - test_cases = [ - { - "name": "test decimal precision 1, 3 decimals", - "order": Order( - metadata=OrderMetadata( - client_order_id="1", create_time="1730800479321350000" - ), - sub_account_id=sub_account_id, - time_in_force=TimeInForce.GOOD_TILL_TIME, - post_only=False, - is_market=False, - reduce_only=False, - legs=[ - OrderLeg( - instrument="BTC_USDT_Perp", - size="1.013", - limit_price="68900.5", - is_buying_asset=False, - ) - ], - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - ), - "want_r": "0xb00512d986a718b15136a8ba23de1c1ec84bbdb9958629cbbe4909bae620bb04", - "want_s": "0x79f706de61c68cc14d7734594b5d8689df2b2a7b25951f9a3f61d799f4327ffc", - "want_v": 28, - "want_error": None, - }, - { - "name": "test decimal precision 2, 9 decimals", - "order": Order( - metadata=OrderMetadata( - client_order_id="1", create_time="1730800479321350000" - ), - sub_account_id=sub_account_id, - time_in_force=TimeInForce.GOOD_TILL_TIME, - post_only=False, - is_market=False, - reduce_only=False, - legs=[ - OrderLeg( - instrument="BTC_USDT_Perp", - size="1.123123123", - limit_price="68900.777123479", - is_buying_asset=False, - ) - ], - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - ), - "want_r": "0x365ec79d299c8bcd5f2acff89faf741a90ca02a4b8a6b1b1a5d4f3d16130f9f0", - "want_s": "0x465129bca7855f008ea5bc22fe3ee630e4a8e3b9b99c1745631deef29957048a", - "want_v": 28, - "want_error": None, - }, - { - "name": "test decimal precision 3, round down", - "order": Order( - metadata=OrderMetadata( - client_order_id="1", create_time="1730800479321350000" - ), - sub_account_id=sub_account_id, - time_in_force=TimeInForce.GOOD_TILL_TIME, - post_only=False, - is_market=False, - reduce_only=False, - legs=[ - OrderLeg( - instrument="BTC_USDT_Perp", - size="1.1231231234", - limit_price="68900.7771234794", - is_buying_asset=False, - ) - ], - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - ), - "want_r": "0x365ec79d299c8bcd5f2acff89faf741a90ca02a4b8a6b1b1a5d4f3d16130f9f0", - "want_s": "0x465129bca7855f008ea5bc22fe3ee630e4a8e3b9b99c1745631deef29957048a", - "want_v": 28, - "want_error": None, - }, - { - "name": "test decimal precision 4, round down", - "order": Order( - metadata=OrderMetadata( - client_order_id="1", create_time="1730800479321350000" - ), - sub_account_id=sub_account_id, - time_in_force=TimeInForce.GOOD_TILL_TIME, - post_only=False, - is_market=False, - reduce_only=False, - legs=[ - OrderLeg( - instrument="BTC_USDT_Perp", - size="1.1231231239", - limit_price="68900.7771234799", - is_buying_asset=False, - ) - ], - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - ), - "want_r": "0x365ec79d299c8bcd5f2acff89faf741a90ca02a4b8a6b1b1a5d4f3d16130f9f0", - "want_s": "0x465129bca7855f008ea5bc22fe3ee630e4a8e3b9b99c1745631deef29957048a", - "want_v": 28, - "want_error": None, - }, - # { - # "name": "no private key", - # "order": Order(), - # "want_error": ValueError("Private key is not set") - # }, - # { - # "name": "decimal precision test", - # "order": Order( - # sub_account_id="123", - # time_in_force=TimeInForce.GOOD_TILL_TIME, - # legs=[ - # OrderLeg( - # instrument="BTC_USDT_Perp", - # size="1.013", - # limit_price="64170.7", - # is_buying_asset=True - # ) - # ], - # signature=Signature( - # expiration=expiry, - # nonce=nonce - # ) - # ), - # "want_error": None - # } - ] - - account = Account.from_key(private_key) - - instruments = { - "BTC_USDT_Perp": Instrument( - instrument="BTC_USDT_Perp", - instrument_hash="0x030501", - base="BTC", - quote="USDT", - kind=Kind.PERPETUAL, - venues=[], - settlement_period=InstrumentSettlementPeriod.DAILY, - tick_size="0.00000001", - min_size="0.00000001", - create_time="123", - base_decimals=9, - quote_decimals=9, - max_position_size="1000000", - ) - } - - for tc in test_cases: - config = GrvtApiConfig( - env=GrvtEnv.TESTNET, - private_key=private_key, - trading_account_id=sub_account_id, - api_key="not-needed", - logger=logger, - ) - - signed_order = sign_order(tc["order"], config, account, instruments) - pprint(signed_order) - - # Verify signature fields are populated - assert signed_order.signature.signer == str(account.address) - - # Compare r, s, v values with expected values - if "want_r" in tc: - assert ( - signed_order.signature.r == tc["want_r"] - ), f"Test '{tc['name']}' failed: r value mismatch" - if "want_s" in tc: - assert ( - signed_order.signature.s == tc["want_s"] - ), f"Test '{tc['name']}' failed: s value mismatch" - if "want_v" in tc: - assert ( - signed_order.signature.v == tc["want_v"] - ), f"Test '{tc['name']}' failed: v value mismatch" - - -def test_sign_transfer_table(): - chainId = 1 - private_key = "f7934647276a6e1fa0af3f4467b4b8ddaf45d25a7368fa1a295eef49a446819d" - main_account_id = "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1" - sub_account_id = "8289849667772468" - expiry = "1730800479321350000" - nonce = 828700936 - - test_cases = [ - { - "name": "Transfer $1 from main account to sub account", - "transfer": Transfer( - from_account_id=main_account_id, - from_sub_account_id="0", - to_account_id=main_account_id, - to_sub_account_id=sub_account_id, - currency="USDT", - num_tokens="1", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "want_r": "0x21c7d7a8e225cb146c80dc79bbe818f915536817f1343e974cfdbe2bfc952cf1", - "want_s": "0x6de83999555f6236e5a56c86876defe00b4776c428ab5a4d7f997d290baaea10", - "want_v": 28, - "want_error": None, - }, - { - "name": "Transfer $1.5 from main account to sub account", - "transfer": Transfer( - from_account_id=main_account_id, - from_sub_account_id="0", - to_account_id=main_account_id, - to_sub_account_id=sub_account_id, - currency="USDT", - num_tokens="1.5", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "want_r": "0xe0a9c66d8d11c3a9ae3624e150cbbdf85d542722cac5255cad4e50af5ac1ddcb", - "want_s": "0x06769e5284352ead5735b8b11f9e9510d024bbb889a828889db4cb04132b52aa", - "want_v": 28, - "want_error": None, - }, - { - "name": "Transfer $1 from sub account to main account", - "transfer": Transfer( - from_account_id=main_account_id, - from_sub_account_id=sub_account_id, - to_account_id=main_account_id, - to_sub_account_id="0", - currency="USDT", - num_tokens="1", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "want_r": "0xc1214ee17dbc14f183297b9dd3f93120b16e633691817ee26045451bc629101c", - "want_s": "0x2de27d226a3d3188742629ab222d430d7989d6ea3e6a86bc259606e371123df3", - "want_v": 27, - "want_error": None, - }, - { - "name": "Transfer $1.5 from sub account to main account", - "transfer": Transfer( - from_account_id=main_account_id, - from_sub_account_id=sub_account_id, - to_account_id=main_account_id, - to_sub_account_id="0", - currency="USDT", - num_tokens="1.5", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "want_r": "0xb9b80dfd4b0d53e64b6dd1067d7d936c79a8c3966175bcefb2021cc71d08116f", - "want_s": "0x3cbe955c9f56e41f70c658e02df07873e77d347aa5c422943b87fdfd94293ae6", - "want_v": 27, - "want_error": None, - }, - { - "name": "Transfer $1 external", - "transfer": Transfer( - from_account_id="0x922a4874196806460fc63b5bcbff45f94c87f76f", - from_sub_account_id="0", - to_account_id="0x6a3434fce60ff567f60d80fb98f2f981e9b081fd", - to_sub_account_id="0", - currency="USDT", - num_tokens="1", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "want_r": "0x185ad129ca0de3584fcd91f6df0c25d8065411041db117c50dabd057249a1a43", - "want_s": "0x58b1979c1f8c65970578bc2756f17a0b5c7352c27007811800dcd8966351647d", - "want_v": 28, - "want_error": None, - }, - { - "name": "Transfer $1.5 external revert", - "transfer": Transfer( - from_account_id="0x6a3434fce60ff567f60d80fb98f2f981e9b081fd", - from_sub_account_id="0", - to_account_id="0x922a4874196806460fc63b5bcbff45f94c87f76f", - to_sub_account_id="0", - currency="USDT", - num_tokens="1.5", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "want_r": "0xbbdd4726fef5cddb6eeb5fac07ed95702673293133d66481777a6a3ee82adc12", - "want_s": "0x0ad3592ea3ebf428b260c56723386383253481bc188d9aeb87d9b21b85069821", - "want_v": 28, - "want_error": None, - }, - ] - - account = Account.from_key(private_key) - config = GrvtApiConfig( - env=GrvtEnv.TESTNET, - private_key=private_key, - trading_account_id=sub_account_id, - api_key="not-needed", - logger=logger, - ) - - for tc in test_cases: - signed = sign_transfer(tc["transfer"], config, account, chainId) - pprint(signed) - - # Verify signature fields are populated - assert signed.signature.signer == str(account.address) - - # Compare r, s, v values with expected values - if "want_r" in tc: - assert ( - signed.signature.r == tc["want_r"] - ), f"Test '{tc['name']}' failed: r value mismatch" - if "want_s" in tc: - assert ( - signed.signature.s == tc["want_s"] - ), f"Test '{tc['name']}' failed: s value mismatch" - if "want_v" in tc: - assert ( - signed.signature.v == tc["want_v"] - ), f"Test '{tc['name']}' failed: v value mismatch" - - -def main(): - functions = [ - test_sign_order_table, - test_sign_transfer_table, - ] - for f in functions: - try: - f() - except Exception as e: - logger.error(f"Error in {f.__name__}: {e} {traceback.format_exc()}") - - -if __name__ == "__main__": - main() diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_signing_intermediate_steps.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_signing_intermediate_steps.py deleted file mode 100644 index d25f300..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_signing_intermediate_steps.py +++ /dev/null @@ -1,837 +0,0 @@ -import json -import logging -import traceback - -from eth_account import Account -from eth_account.messages import encode_typed_data - -from pysdk.grvt_fixed_types import Transfer -from pysdk.grvt_raw_base import GrvtApiConfig -from pysdk.grvt_raw_env import GrvtEnv -from pysdk.grvt_raw_signing import ( - EIP712_ORDER_MESSAGE_TYPE, - EIP712_TRANSFER_MESSAGE_TYPE, - build_EIP712_order_message_data, - build_EIP712_transfer_message_data, - get_EIP712_domain_data, - sign_order, -) -from pysdk.grvt_raw_types import ( - Instrument, - InstrumentSettlementPeriod, - Kind, - Order, - OrderLeg, - OrderMetadata, - Signature, - TimeInForce, - TransferType, -) - -# Setup logger -logging.basicConfig() -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) - - -def test_sign_order_table(): - # Generated using https://key.tokenpocket.pro/#/?network=ETH - # NOTE: `0x` hexadecimal prefix removed - public_key = "ee2060eECaC18beC7F8F670D751801294911E445" - private_key = "c0663ca94684aead40c41a1cb3a94b68a24296e87245be3a186e882a29a15ee0" - - sub_account_id = "8289849667772468" - expiry = 1730800479321350000 - nonce = 828700936 - - test_cases = [ - { - "name": "test decimal precision 1, 3 decimals", - "order": Order( - metadata=OrderMetadata( - client_order_id="1", create_time="1730800479321350000" - ), - sub_account_id=sub_account_id, - time_in_force=TimeInForce.GOOD_TILL_TIME, - post_only=False, - is_market=False, - reduce_only=False, - legs=[ - OrderLeg( - instrument="BTC_USDT_Perp", - size="1.013", - limit_price="68900.5", - is_buying_asset=False, - ) - ], - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - ), - "expected_message_data_json": """ -{ - "subAccountID": "8289849667772468", - "isMarket": false, - "timeInForce": 1, - "postOnly": false, - "reduceOnly": false, - "legs": [ - { - "assetID": "0x030501", - "contractSize": 1013000000, - "limitPrice": 68900500000000, - "isBuyingContract": false - } - ], - "nonce": 828700936, - "expiration": 1730800479321350000 -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 326 -}""", - # Per EIP-191: https://eips.ethereum.org/EIPS/eip-191 - "expected_signable_message": """ -{ - "version": "01", - "header": "1254f97f8495f704630a238cbcd898a4b8ab20d77bb93e17049d3445f4f81f16", - "body": "41650c08ab6e720f899307d7c2b4381a10c1301888375cec2dfefd6a583859eb" -}""", - # EIP-712 signable message format: https://eips.ethereum.org/EIPS/eip-712 - # Pre-image of the signed message's message hash - # encode(domainSeparator : 𝔹²⁵⁶, message : 𝕊) = "\x19"‖ version ‖ domainSeparator ‖ hashStruct(message) - "digest_input": "0x19011254f97f8495f704630a238cbcd898a4b8ab20d77bb93e17049d3445f4f81f1641650c08ab6e720f899307d7c2b4381a10c1301888375cec2dfefd6a583859eb", - "expected_signed_message": """ -{ - "message_hash": "03cb7ca7b353969ab2c00ff92fd472f81f59a84d28fa1aa39128176f21062982", - "r": 14615867946748605809126568669694142791729730263440553623296112010401671344650, - "s": 41758084966111141828834491248882149351523023670747687501271185591898818786045, - "v": 28, - "signature": "205049c0db6e38fd88e4e46be81db7bc354520d52ec6268d210fa35b86c4f20a5c523d0ff8e6f12542fdcf34a6e6e2c547986b7c8fa53f86a5e656d9ab44b2fd1c" -}""", - }, - { - "name": "test decimal precision 2, 9 decimals", - "order": Order( - metadata=OrderMetadata( - client_order_id="1", create_time="1730800479321350000" - ), - sub_account_id=sub_account_id, - time_in_force=TimeInForce.GOOD_TILL_TIME, - post_only=False, - is_market=False, - reduce_only=False, - legs=[ - OrderLeg( - instrument="BTC_USDT_Perp", - size="1.123123123", - limit_price="68900.777123479", - is_buying_asset=False, - ) - ], - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - ), - "expected_message_data_json": """ -{ - "subAccountID": "8289849667772468", - "isMarket": false, - "timeInForce": 1, - "postOnly": false, - "reduceOnly": false, - "legs": [ - { - "assetID": "0x030501", - "contractSize": 1123123123, - "limitPrice": 68900777123479, - "isBuyingContract": false - } - ], - "nonce": 828700936, - "expiration": 1730800479321350000 -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 326 -}""", - "expected_signable_message": """ -{ - "version": "01", - "header": "1254f97f8495f704630a238cbcd898a4b8ab20d77bb93e17049d3445f4f81f16", - "body": "e85ffec169d4ebd4b8057e5fbd31ed31d4511b2f2299bbce0adab6beb5fe2814" -}""", - "digest_input": "0x19011254f97f8495f704630a238cbcd898a4b8ab20d77bb93e17049d3445f4f81f16e85ffec169d4ebd4b8057e5fbd31ed31d4511b2f2299bbce0adab6beb5fe2814", - "expected_signed_message": """ -{ - "message_hash": "2d0a437f7d64523386974c2a729d69604f8e2a7f0684b7de923845d8b175ab69", - "r": 30067953785684815030293507105225786115862149795459199007947867478230986262090, - "s": 23299979093064779986156565292425191814752388247725004533191995996670719399433, - "v": 28, - "signature": "4279dbd734584fb07b016bce7d9f029e7f7f80e378dc65cddc06aa6b0c9e064a33835221a0fbcb700de3068169b45572a27756bff479f2887e8c89139e6f96091c" -}""", - }, - { - "name": "test decimal precision 3, round down", - "order": Order( - metadata=OrderMetadata( - client_order_id="1", create_time="1730800479321350000" - ), - sub_account_id=sub_account_id, - time_in_force=TimeInForce.GOOD_TILL_TIME, - post_only=False, - is_market=False, - reduce_only=False, - legs=[ - OrderLeg( - instrument="BTC_USDT_Perp", - size="1.1231231234", - limit_price="68900.7771234794", - is_buying_asset=False, - ) - ], - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - ), - "expected_message_data_json": """ -{ - "subAccountID": "8289849667772468", - "isMarket": false, - "timeInForce": 1, - "postOnly": false, - "reduceOnly": false, - "legs": [ - { - "assetID": "0x030501", - "contractSize": 1123123123, - "limitPrice": 68900777123479, - "isBuyingContract": false - } - ], - "nonce": 828700936, - "expiration": 1730800479321350000 -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 326 -}""", - "expected_signable_message": """ -{ - "version": "01", - "header": "1254f97f8495f704630a238cbcd898a4b8ab20d77bb93e17049d3445f4f81f16", - "body": "e85ffec169d4ebd4b8057e5fbd31ed31d4511b2f2299bbce0adab6beb5fe2814" -}""", - "digest_input": "0x19011254f97f8495f704630a238cbcd898a4b8ab20d77bb93e17049d3445f4f81f16e85ffec169d4ebd4b8057e5fbd31ed31d4511b2f2299bbce0adab6beb5fe2814", - "expected_signed_message": """ -{ - "message_hash": "2d0a437f7d64523386974c2a729d69604f8e2a7f0684b7de923845d8b175ab69", - "r": 30067953785684815030293507105225786115862149795459199007947867478230986262090, - "s": 23299979093064779986156565292425191814752388247725004533191995996670719399433, - "v": 28, - "signature": "4279dbd734584fb07b016bce7d9f029e7f7f80e378dc65cddc06aa6b0c9e064a33835221a0fbcb700de3068169b45572a27756bff479f2887e8c89139e6f96091c" -}""", - }, - { - "name": "test decimal precision 4, round down", - "order": Order( - metadata=OrderMetadata( - client_order_id="1", create_time="1730800479321350000" - ), - sub_account_id=sub_account_id, - time_in_force=TimeInForce.GOOD_TILL_TIME, - post_only=False, - is_market=False, - reduce_only=False, - legs=[ - OrderLeg( - instrument="BTC_USDT_Perp", - size="1.1231231239", - limit_price="68900.7771234799", - is_buying_asset=False, - ) - ], - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - ), - "expected_message_data_json": """ -{ - "subAccountID": "8289849667772468", - "isMarket": false, - "timeInForce": 1, - "postOnly": false, - "reduceOnly": false, - "legs": [ - { - "assetID": "0x030501", - "contractSize": 1123123123, - "limitPrice": 68900777123479, - "isBuyingContract": false - } - ], - "nonce": 828700936, - "expiration": 1730800479321350000 -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 326 -}""", - "expected_signable_message": """ -{ - "version": "01", - "header": "1254f97f8495f704630a238cbcd898a4b8ab20d77bb93e17049d3445f4f81f16", - "body": "e85ffec169d4ebd4b8057e5fbd31ed31d4511b2f2299bbce0adab6beb5fe2814" -}""", - "digest_input": "0x19011254f97f8495f704630a238cbcd898a4b8ab20d77bb93e17049d3445f4f81f16e85ffec169d4ebd4b8057e5fbd31ed31d4511b2f2299bbce0adab6beb5fe2814", - "expected_signed_message": """ -{ - "message_hash": "2d0a437f7d64523386974c2a729d69604f8e2a7f0684b7de923845d8b175ab69", - "r": 30067953785684815030293507105225786115862149795459199007947867478230986262090, - "s": 23299979093064779986156565292425191814752388247725004533191995996670719399433, - "v": 28, - "signature": "4279dbd734584fb07b016bce7d9f029e7f7f80e378dc65cddc06aa6b0c9e064a33835221a0fbcb700de3068169b45572a27756bff479f2887e8c89139e6f96091c" -}""", - }, - ] - - account = Account.from_key(private_key) - - instruments = { - "BTC_USDT_Perp": Instrument( - instrument="BTC_USDT_Perp", - instrument_hash="0x030501", - base="BTC", - quote="USDT", - kind=Kind.PERPETUAL, - venues=[], - settlement_period=InstrumentSettlementPeriod.DAILY, - tick_size="0.00000001", - min_size="0.00000001", - create_time="123", - base_decimals=9, - quote_decimals=9, - max_position_size="1000000", - ) - } - - for tc in test_cases: - config = GrvtApiConfig( - env=GrvtEnv.TESTNET, - private_key=private_key, - trading_account_id=sub_account_id, - api_key="not-needed", - logger=logger, - ) - - # Get intermediate values - message_data = build_EIP712_order_message_data(tc["order"], instruments) - domain_data = get_EIP712_domain_data(config.env, 326) - signable_message = encode_typed_data( - domain_data, EIP712_ORDER_MESSAGE_TYPE, message_data - ) - signed_message = account.sign_message(signable_message) - signed_order = sign_order(tc["order"], config, account, instruments) - - # Convert to comparable strings - message_data_json = json.dumps(message_data, indent=2) - domain_data_json = json.dumps(domain_data, indent=2) - signable_message_json = json.dumps( - { - "version": signable_message.version.hex(), - "header": signable_message.header.hex(), - "body": signable_message.body.hex(), - }, - indent=2, - ) - signed_message_json = json.dumps( - { - "message_hash": signed_message.message_hash.hex(), - "r": signed_message.r, - "s": signed_message.s, - "v": signed_message.v, - "signature": signed_message.signature.hex(), - }, - indent=2, - ) - # EIP-712 signable message format: https://eips.ethereum.org/EIPS/eip-712 - signed_message_hash_preimage = ( - "0x19" - + signable_message.version.hex() - + signable_message.header.hex() - + signable_message.body.hex() - ) - - # Strip whitespace for comparison - assert ( - message_data_json.strip() == tc["expected_message_data_json"].strip() - ), f""" -Test '{tc['name']}' failed: message_data mismatch. -Wanted: -{tc['expected_message_data_json'].strip()} -Got: -{message_data_json.strip()} -""" - assert ( - domain_data_json.strip() == tc["expected_domain_data_json"].strip() - ), f""" -Test '{tc['name']}' failed: domain_data mismatch. -Wanted: -{tc['expected_domain_data_json'].strip()} -Got: -{domain_data_json.strip()} -""" - assert ( - signable_message_json.strip() == tc["expected_signable_message"].strip() - ), f""" -Test '{tc['name']}' failed: signable_message mismatch. -Wanted: -{tc['expected_signable_message'].strip()} -Got: -{signable_message_json.strip()} -""" - assert ( - signed_message_hash_preimage.strip() == tc["digest_input"].strip() - ), f""" -Test '{tc['name']}' failed: digest_input mismatch. -Wanted: -{tc["digest_input"].strip() -} -Got: -{signed_message_hash_preimage.strip()} -""" - assert ( - signed_message_json.strip() == tc["expected_signed_message"].strip() - ), f""" -Test '{tc['name']}' failed: signed_message mismatch. -Wanted: -{tc['expected_signed_message'].strip()} -Got: -{signed_message_json.strip()} -""" - assert ( - signed_order.signature.signer == str(account.address) == "0x" + public_key - ), f"""Test '{tc['name']}' failed: signer mismatch.""" - - -def test_sign_transfer_table(): - chainId = 1 - private_key = "f7934647276a6e1fa0af3f4467b4b8ddaf45d25a7368fa1a295eef49a446819d" - main_account_id = "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1" - sub_account_id = "8289849667772468" - expiry = "1730800479321350000" - nonce = 828700936 - - test_cases = [ - { - "name": "Transfer $1 from main account to sub account", - "transfer": Transfer( - from_account_id=main_account_id, - from_sub_account_id="0", - to_account_id=main_account_id, - to_sub_account_id=sub_account_id, - currency="USDT", - num_tokens="1", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "expected_message_data_json": """ -{ - "fromAccount": "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1", - "fromSubAccount": "0", - "toAccount": "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1", - "toSubAccount": "8289849667772468", - "tokenCurrency": 3, - "numTokens": 1000000, - "nonce": 828700936, - "expiration": "1730800479321350000" -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 1 -}""", - # Per EIP-191: https://eips.ethereum.org/EIPS/eip-191 - "expected_signable_message": """ -{ - "version": "01", - "header": "950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6", - "body": "8dfbfc161ca14b60b318aec118c0f77137ab6d5c0d6f4aa283a75995ec842a9f" -}""", - # EIP-712 signable message format: https://eips.ethereum.org/EIPS/eip-712 - # Pre-image of the signed message's message hash - # encode(domainSeparator : 𝔹²⁵⁶, message : 𝕊) = "\x19"‖ version ‖ domainSeparator ‖ hashStruct(message) - "digest_input": "0x1901950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f68dfbfc161ca14b60b318aec118c0f77137ab6d5c0d6f4aa283a75995ec842a9f", - "expected_signed_message": """ -{ - "message_hash": "f237c6e8ceaf8f75c35537c26a5810f5029fe3fa0179d636cfa75dba0eeaecda", - "r": 15279414997690414521303216846501751476684522786442627331685751803272563600625, - "s": 49712406548009011982925909577001640710775887931482920893646195243522061953552, - "v": 28, - "signature": "21c7d7a8e225cb146c80dc79bbe818f915536817f1343e974cfdbe2bfc952cf16de83999555f6236e5a56c86876defe00b4776c428ab5a4d7f997d290baaea101c" -}""", - }, - { - "name": "Transfer $1.5 from main account to sub account", - "transfer": Transfer( - from_account_id=main_account_id, - from_sub_account_id="0", - to_account_id=main_account_id, - to_sub_account_id=sub_account_id, - currency="USDT", - num_tokens="1.5", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "expected_message_data_json": """ -{ - "fromAccount": "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1", - "fromSubAccount": "0", - "toAccount": "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1", - "toSubAccount": "8289849667772468", - "tokenCurrency": 3, - "numTokens": 1500000, - "nonce": 828700936, - "expiration": "1730800479321350000" -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 1 -}""", - "expected_signable_message": """ -{ - "version": "01", - "header": "950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6", - "body": "efc25031927cbee99a4b8c408d427168218312cb5fcbc2ef0644a25c411e9cd6" -}""", - "digest_input": "0x1901950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6efc25031927cbee99a4b8c408d427168218312cb5fcbc2ef0644a25c411e9cd6", - "expected_signed_message": """ -{ - "message_hash": "e9a82979035693538d20cbd16a231379d68b2484f065a64b5ac962a0ef45ed2c", - "r": 101618044735866410136029494650850506089543609286068143785089360195209387957707, - "s": 2923457745704967739422721965786309607758766142290846761836065357300251710122, - "v": 28, - "signature": "e0a9c66d8d11c3a9ae3624e150cbbdf85d542722cac5255cad4e50af5ac1ddcb06769e5284352ead5735b8b11f9e9510d024bbb889a828889db4cb04132b52aa1c" -}""", - }, - { - "name": "Transfer $1 from sub account to main account", - "transfer": Transfer( - from_account_id=main_account_id, - from_sub_account_id=sub_account_id, - to_account_id=main_account_id, - to_sub_account_id="0", - currency="USDT", - num_tokens="1", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "expected_message_data_json": """ -{ - "fromAccount": "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1", - "fromSubAccount": "8289849667772468", - "toAccount": "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1", - "toSubAccount": "0", - "tokenCurrency": 3, - "numTokens": 1000000, - "nonce": 828700936, - "expiration": "1730800479321350000" -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 1 -}""", - "expected_signable_message": """ -{ - "version": "01", - "header": "950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6", - "body": "325bbcdd0af37fd856ab19d5a34f04c98b4b9125fd924a41d149290d85cf5d1a" -}""", - "digest_input": "0x1901950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6325bbcdd0af37fd856ab19d5a34f04c98b4b9125fd924a41d149290d85cf5d1a", - "expected_signed_message": """ -{ - "message_hash": "05a4682aaaffda9347f7f577623dc86be873d75680250d94f30e27fb450b0597", - "r": 87355230145152558239319417798390737905701563801639010151017443441731256782876, - "s": 20754249269006714296744776682911604802815023385414018875577784419437276970483, - "v": 27, - "signature": "c1214ee17dbc14f183297b9dd3f93120b16e633691817ee26045451bc629101c2de27d226a3d3188742629ab222d430d7989d6ea3e6a86bc259606e371123df31b" -}""", - }, - { - "name": "Transfer $1.5 from sub account to main account", - "transfer": Transfer( - from_account_id=main_account_id, - from_sub_account_id=sub_account_id, - to_account_id=main_account_id, - to_sub_account_id="0", - currency="USDT", - num_tokens="1.5", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "expected_message_data_json": """ -{ - "fromAccount": "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1", - "fromSubAccount": "8289849667772468", - "toAccount": "0x0c1f4c8ee7acd9ea19b91bbb343cbaf6efd58ce1", - "toSubAccount": "0", - "tokenCurrency": 3, - "numTokens": 1500000, - "nonce": 828700936, - "expiration": "1730800479321350000" -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 1 -}""", - "expected_signable_message": """ -{ - "version": "01", - "header": "950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6", - "body": "d20efa4f5ca3d7cd996d0a7be827a788fdea40ad9dc3f7d64f909ec3df2f0f1c" -}""", - "digest_input": "0x1901950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6d20efa4f5ca3d7cd996d0a7be827a788fdea40ad9dc3f7d64f909ec3df2f0f1c", - "expected_signed_message": """ -{ - "message_hash": "57de810bfd4c46796b923242eba5fba199c69ec6159fd7f0bae13d20e6b2e32f", - "r": 84003073399296424218543069615592899281416934630850361306323613156742252728687, - "s": 27475502714605040799395938380083883707063662756512201821577577919846841662182, - "v": 27, - "signature": "b9b80dfd4b0d53e64b6dd1067d7d936c79a8c3966175bcefb2021cc71d08116f3cbe955c9f56e41f70c658e02df07873e77d347aa5c422943b87fdfd94293ae61b" -}""", - }, - { - "name": "Transfer $1 external", - "transfer": Transfer( - from_account_id="0x922a4874196806460fc63b5bcbff45f94c87f76f", - from_sub_account_id="0", - to_account_id="0x6a3434fce60ff567f60d80fb98f2f981e9b081fd", - to_sub_account_id="0", - currency="USDT", - num_tokens="1", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "expected_message_data_json": """ -{ - "fromAccount": "0x922a4874196806460fc63b5bcbff45f94c87f76f", - "fromSubAccount": "0", - "toAccount": "0x6a3434fce60ff567f60d80fb98f2f981e9b081fd", - "toSubAccount": "0", - "tokenCurrency": 3, - "numTokens": 1000000, - "nonce": 828700936, - "expiration": "1730800479321350000" -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 1 -}""", - "expected_signable_message": """ -{ - "version": "01", - "header": "950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6", - "body": "c92edbd85a6756bbc1d472694218135800c5c34cecd62dfecf8b79696fb30a5a" -}""", - "digest_input": "0x1901950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6c92edbd85a6756bbc1d472694218135800c5c34cecd62dfecf8b79696fb30a5a", - "expected_signed_message": """ -{ - "message_hash": "aa540bb37dc69583724239e2ee089f9863760b1f5dd3707f63254f5f9045a36b", - "r": 11015968193451536627767691276906473050663313657726362297424610772811255519811, - "s": 40117308978565698603770991327546519074883337154968913527997965101318785819773, - "v": 28, - "signature": "185ad129ca0de3584fcd91f6df0c25d8065411041db117c50dabd057249a1a4358b1979c1f8c65970578bc2756f17a0b5c7352c27007811800dcd8966351647d1c" -}""", - }, - { - "name": "Transfer $1.5 external revert", - "transfer": Transfer( - from_account_id="0x6a3434fce60ff567f60d80fb98f2f981e9b081fd", - from_sub_account_id="0", - to_account_id="0x922a4874196806460fc63b5bcbff45f94c87f76f", - to_sub_account_id="0", - currency="USDT", - num_tokens="1.5", - signature=Signature( - signer="", r="", s="", v=0, expiration=expiry, nonce=nonce - ), - transfer_type=TransferType.STANDARD, - transfer_metadata="", - ), - "expected_message_data_json": """ -{ - "fromAccount": "0x6a3434fce60ff567f60d80fb98f2f981e9b081fd", - "fromSubAccount": "0", - "toAccount": "0x922a4874196806460fc63b5bcbff45f94c87f76f", - "toSubAccount": "0", - "tokenCurrency": 3, - "numTokens": 1500000, - "nonce": 828700936, - "expiration": "1730800479321350000" -}""", - "expected_domain_data_json": """ -{ - "name": "GRVT Exchange", - "version": "0", - "chainId": 1 -}""", - "expected_signable_message": """ -{ - "version": "01", - "header": "950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f6", - "body": "5660d6d82b43a7bd01c7bee9379478b27e2c7774d9e9aebd69ea163c523f8730" -}""", - "digest_input": "0x1901950ca409f14e4f89a10e63790c40b5dc9c5fab89944e8c98112dece5b08415f65660d6d82b43a7bd01c7bee9379478b27e2c7774d9e9aebd69ea163c523f8730", - "expected_signed_message": """ -{ - "message_hash": "2a02bf2a7772d74f176d75f987e984dd253837aba1faed4b0a65ba5a3038ce06", - "r": 84973466961705873082056285677608514305288271637256010073726199940890275535890, - "s": 4896548729346283309439956649162331116008267310844279523516289648065258100769, - "v": 28, - "signature": "bbdd4726fef5cddb6eeb5fac07ed95702673293133d66481777a6a3ee82adc120ad3592ea3ebf428b260c56723386383253481bc188d9aeb87d9b21b850698211c" -}""", - }, - ] - - account = Account.from_key(private_key) - config = GrvtApiConfig( - env=GrvtEnv.TESTNET, - private_key=private_key, - trading_account_id=sub_account_id, - api_key="not-needed", - logger=logger, - ) - - for tc in test_cases: - message_data = build_EIP712_transfer_message_data( - tc["transfer"], 3 # assume all test cases are USDT transfers - ) - domain_data = get_EIP712_domain_data(config.env, chainId) - signable_message = encode_typed_data( - domain_data, EIP712_TRANSFER_MESSAGE_TYPE, message_data - ) - signed_message = account.sign_message(signable_message) - - # Convert to comparable strings - message_data_json = json.dumps(message_data, indent=2) - domain_data_json = json.dumps(domain_data, indent=2) - signable_message_json = json.dumps( - { - "version": signable_message.version.hex(), - "header": signable_message.header.hex(), - "body": signable_message.body.hex(), - }, - indent=2, - ) - signed_message_json = json.dumps( - { - "message_hash": signed_message.message_hash.hex(), - "r": signed_message.r, - "s": signed_message.s, - "v": signed_message.v, - "signature": signed_message.signature.hex(), - }, - indent=2, - ) - # EIP-712 signable message format: https://eips.ethereum.org/EIPS/eip-712 - signed_message_hash_preimage = ( - "0x19" - + signable_message.version.hex() - + signable_message.header.hex() - + signable_message.body.hex() - ) - - # Strip whitespace for comparison - assert ( - message_data_json.strip() == tc["expected_message_data_json"].strip() - ), f""" -Test '{tc['name']}' failed: message_data mismatch. -Wanted: -{tc['expected_message_data_json'].strip()} -Got: -{message_data_json.strip()} -""" - assert ( - domain_data_json.strip() == tc["expected_domain_data_json"].strip() - ), f""" -Test '{tc['name']}' failed: domain_data mismatch. -Wanted: -{tc['expected_domain_data_json'].strip()} -Got: -{domain_data_json.strip()} -""" - assert ( - signable_message_json.strip() == tc["expected_signable_message"].strip() - ), f""" -Test '{tc['name']}' failed: signable_message mismatch. -Wanted: -{tc['expected_signable_message'].strip()} -Got: -{signable_message_json.strip()} -""" - assert ( - signed_message_hash_preimage.strip() == tc["digest_input"].strip() - ), f""" -Test '{tc['name']}' failed: digest_input mismatch. -Wanted: -{tc["digest_input"].strip() -} -Got: -{signed_message_hash_preimage.strip()} -""" - assert ( - signed_message_json.strip() == tc["expected_signed_message"].strip() - ), f""" -Test '{tc['name']}' failed: signed_message mismatch. -Wanted: -{tc['expected_signed_message'].strip()} -Got: -{signed_message_json.strip()} -""" - - -def main(): - functions = [ - test_sign_transfer_table, - ] - for f in functions: - try: - f() - except Exception as e: - logger.error(f"Error in {f.__name__}: {e} {traceback.format_exc()}") - - -if __name__ == "__main__": - main() diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_sync.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_sync.py deleted file mode 100644 index 2c8d640..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_grvt_raw_sync.py +++ /dev/null @@ -1,141 +0,0 @@ -from pysdk import grvt_raw_types -from pysdk.grvt_raw_base import GrvtError -from pysdk.grvt_raw_sync import GrvtRawSync - -from .test_raw_utils import ( - get_config, - get_test_order, - get_test_tpsl_order, - get_test_transfer, - get_test_withdrawal, -) - - -def test_get_all_instruments() -> None: - api = GrvtRawSync(config=get_config()) - resp = api.get_all_instruments_v1( - grvt_raw_types.ApiGetAllInstrumentsRequest(is_active=True) - ) - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected results to be non-null") - if len(resp.result) == 0: - raise ValueError("Expected results to be non-empty") - - -def test_open_orders() -> None: - api = GrvtRawSync(config=get_config()) - - # Skip test if trading account id is not set - if api.config.trading_account_id is None or api.config.api_key is None: - return None # Skip test if configs are not set - - resp = api.open_orders_v1( - grvt_raw_types.ApiOpenOrdersRequest( - # sub_account_id=233, Uncomment to test error path with invalid sub account id - sub_account_id=str(api.config.trading_account_id), - kind=[grvt_raw_types.Kind.PERPETUAL], - base=["BTC", "ETH"], - quote=["USDT"], - ) - ) - if isinstance(resp, GrvtError): - api.logger.error(f"Received error: {resp}") - return None - if resp.result is None: - raise ValueError("Expected orders to be non-null") - if len(resp.result) == 0: - api.logger.info("Expected orders to be non-empty") - - -def test_create_order_with_signing() -> None: - api = GrvtRawSync(config=get_config()) - - inst_resp = api.get_all_instruments_v1( - grvt_raw_types.ApiGetAllInstrumentsRequest(is_active=True) - ) - if isinstance(inst_resp, GrvtError): - raise ValueError(f"Received error: {inst_resp}") - - order = get_test_order(api, {inst.instrument: inst for inst in inst_resp.result}) - if order is None: - return None # Skip test if configs are not set - resp = api.create_order_v1(grvt_raw_types.ApiCreateOrderRequest(order=order)) - - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected order to be non-null") - - -def test_create_tpsl_order_with_signing() -> None: - api = GrvtRawSync(config=get_config()) - - inst_resp = api.get_all_instruments_v1( - grvt_raw_types.ApiGetAllInstrumentsRequest(is_active=True) - ) - if isinstance(inst_resp, GrvtError): - raise ValueError(f"Received error: {inst_resp}") - - order = get_test_tpsl_order( - api, {inst.instrument: inst for inst in inst_resp.result} - ) - if order is None: - return None # Skip test if configs are not set - resp = api.create_order_v1(grvt_raw_types.ApiCreateOrderRequest(order=order)) - - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected order to be non-null") - - -def test_transfer_with_signing() -> None: - api = GrvtRawSync(config=get_config()) - transfer = get_test_transfer(api) - - if transfer is None: - return None # Skip test if configs are not set - - resp = api.transfer_v1( - grvt_raw_types.ApiTransferRequest( - transfer.from_account_id, - transfer.from_sub_account_id, - transfer.to_account_id, - transfer.to_sub_account_id, - transfer.currency, - transfer.num_tokens, - transfer.signature, - grvt_raw_types.TransferType.STANDARD, - "", - ) - ) - - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected transfer response to be non-null") - - -def test_withdrawal_with_signing() -> None: - api = GrvtRawSync(config=get_config()) - withdrawal = get_test_withdrawal(api) - - if withdrawal is None: - return None # Skip test if configs are not set - - resp = api.withdrawal_v1( - grvt_raw_types.ApiWithdrawalRequest( - withdrawal.from_account_id, - withdrawal.to_eth_address, - withdrawal.currency, - withdrawal.num_tokens, - withdrawal.signature, - ) - ) - - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected withdrawal response to be non-null") diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_raw_utils.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_raw_utils.py deleted file mode 100644 index 1087485..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_raw_utils.py +++ /dev/null @@ -1,158 +0,0 @@ -import logging -import os -import random -import time - -from pysdk import grvt_fixed_types, grvt_raw_types -from pysdk.grvt_raw_base import GrvtApiConfig, GrvtError -from pysdk.grvt_raw_env import GrvtEnv -from pysdk.grvt_raw_signing import sign_order, sign_transfer, sign_withdrawal -from pysdk.grvt_raw_sync import GrvtRawSync - - -def get_config() -> GrvtApiConfig: - logging.basicConfig() - logger = logging.getLogger() - logger.setLevel(logging.DEBUG) - conf = GrvtApiConfig( - env=GrvtEnv(os.getenv("GRVT_ENV", "testnet")), - trading_account_id=os.getenv("GRVT_SUB_ACCOUNT_ID"), - private_key=os.getenv("GRVT_PRIVATE_KEY"), - api_key=os.getenv("GRVT_API_KEY"), - logger=logger, - ) - logger.debug(conf) - return conf - - -def get_main_account_id(api: GrvtRawSync) -> str: - resp = api.funding_account_summary_v1(grvt_raw_types.EmptyRequest()) - if isinstance(resp, GrvtError): - raise ValueError(f"Received error: {resp}") - if resp.result is None: - raise ValueError("Expected funding_account_summary_v1 response to be non-null") - return resp.result.main_account_id - - -def get_test_order( - api: GrvtRawSync, instruments: dict[str, grvt_raw_types.Instrument] -) -> grvt_raw_types.Order | None: - # Skip test if configs are not set - if ( - api.config.trading_account_id is None - or api.config.private_key is None - or api.config.api_key is None - ): - return None - - order = grvt_raw_types.Order( - sub_account_id=str(api.config.trading_account_id), - time_in_force=grvt_raw_types.TimeInForce.GOOD_TILL_TIME, - legs=[ - grvt_raw_types.OrderLeg( - instrument="BTC_USDT_Perp", - size="1.2", # 1.2 BTC - limit_price="64170.7", # 80,000 USDT - is_buying_asset=True, - ) - ], - signature=grvt_raw_types.Signature( - signer="", # Populated by sign_order - r="", # Populated by sign_order - s="", # Populated by sign_order - v=0, # Populated by sign_order - expiration=str( - time.time_ns() + 20 * 24 * 60 * 60 * 1_000_000_000 - ), # 20 days - nonce=random.randint(0, 2**32 - 1), - ), - metadata=grvt_raw_types.OrderMetadata( - client_order_id=str(random.randint(0, 2**32 - 1)), - ), - ) - return sign_order(order, api.config, api.account, instruments) - - -def get_test_tpsl_order( - api: GrvtRawSync, instruments: dict[str, grvt_raw_types.Instrument] -) -> grvt_raw_types.Order | None: - order = get_test_order(api, instruments) - if order: - order.metadata.trigger = grvt_raw_types.TriggerOrderMetadata( - trigger_type=grvt_raw_types.TriggerType.TAKE_PROFIT, - tpsl=grvt_raw_types.TPSLOrderMetadata( - trigger_by=grvt_raw_types.TriggerBy.LAST, - trigger_price="64000", - ), - ) - return order - - -def get_test_transfer(api: GrvtRawSync) -> grvt_fixed_types.Transfer | None: - # Skip test if configs are not set - if ( - api.config.trading_account_id is None - or api.config.private_key is None - or api.config.api_key is None - ): - return None - - funding_account_address = get_main_account_id(api) - - return sign_transfer( - grvt_fixed_types.Transfer( - from_account_id=funding_account_address, - from_sub_account_id="0", - to_account_id=funding_account_address, - to_sub_account_id=str(api.config.trading_account_id), - currency="USDT", - num_tokens="1", - signature=grvt_raw_types.Signature( - signer="", - r="", - s="", - v=0, - expiration=str( - time.time_ns() + 20 * 24 * 60 * 60 * 1_000_000_000 - ), # 20 days - nonce=random.randint(0, 2**32 - 1), - ), - transfer_type=grvt_fixed_types.TransferType.STANDARD, - transfer_metadata="", - ), - api.config, - api.account, - ) - - -def get_test_withdrawal(api: GrvtRawSync) -> grvt_raw_types.Withdrawal | None: - # Skip test if configs are not set - if ( - api.config.trading_account_id is None - or api.config.private_key is None - or api.config.api_key is None - ): - return None - - funding_account_address = get_main_account_id(api) - - return sign_withdrawal( - grvt_raw_types.Withdrawal( - from_account_id=funding_account_address, - to_eth_address="0xed3FF6F4E84a64556e8F7d149dC3533f0c7D9c49", # Just a test address - currency="USDT", - num_tokens="1", - signature=grvt_raw_types.Signature( - signer="", - r="", - s="", - v=0, - expiration=str( - time.time_ns() + 20 * 24 * 60 * 60 * 1_000_000_000 - ), # 20 days - nonce=random.randint(0, 2**32 - 1), - ), - ), - api.config, - api.account, - ) diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_transfer.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_transfer.py deleted file mode 100644 index 35980ac..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_transfer.py +++ /dev/null @@ -1,4 +0,0 @@ -from .test_grvt_raw_sync import test_transfer_with_signing - -if __name__ == "__main__": - test_transfer_with_signing() diff --git a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_withdrawal.py b/docs/grvt/grvt-pysdk-main/tests/pysdk/test_withdrawal.py deleted file mode 100644 index faa002f..0000000 --- a/docs/grvt/grvt-pysdk-main/tests/pysdk/test_withdrawal.py +++ /dev/null @@ -1,4 +0,0 @@ -from .test_grvt_raw_sync import test_withdrawal_with_signing - -if __name__ == "__main__": - test_withdrawal_with_signing() diff --git a/docs/grvt/grvt-pysdk-main/uv.lock b/docs/grvt/grvt-pysdk-main/uv.lock deleted file mode 100644 index e340bf1..0000000 --- a/docs/grvt/grvt-pysdk-main/uv.lock +++ /dev/null @@ -1,1961 +0,0 @@ -version = 1 -requires-python = ">=3.10" - -[[package]] -name = "aiohappyeyeballs" -version = "2.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/08/07/508f9ebba367fc3370162e53a3cfd12f5652ad79f0e0bfdf9f9847c6f159/aiohappyeyeballs-2.4.6.tar.gz", hash = "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0", size = 21726 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/4c/03fb05f56551828ec67ceb3665e5dc51638042d204983a03b0a1541475b6/aiohappyeyeballs-2.4.6-py3-none-any.whl", hash = "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1", size = 14543 }, -] - -[[package]] -name = "aiohttp" -version = "3.11.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/37/4b/952d49c73084fb790cb5c6ead50848c8e96b4980ad806cf4d2ad341eaa03/aiohttp-3.11.12.tar.gz", hash = "sha256:7603ca26d75b1b86160ce1bbe2787a0b706e592af5b2504e12caa88a217767b0", size = 7673175 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/42/3880e133590820aa7bc6d068eb7d8e0ad9fdce9b4663f92b821d3f6b5601/aiohttp-3.11.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f", size = 708721 }, - { url = "https://files.pythonhosted.org/packages/d8/8c/04869803bed108b25afad75f94c651b287851843caacbec6677d8f2d572b/aiohttp-3.11.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854", size = 468596 }, - { url = "https://files.pythonhosted.org/packages/4f/f4/9074011f0d1335b161c953fb32545b6667cf24465e1932b9767874995c7e/aiohttp-3.11.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:584096938a001378484aa4ee54e05dc79c7b9dd933e271c744a97b3b6f644957", size = 455758 }, - { url = "https://files.pythonhosted.org/packages/fd/68/06298c57ef8f534065930b805e6dbd83613f0534447922782fb9920fce28/aiohttp-3.11.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:392432a2dde22b86f70dd4a0e9671a349446c93965f261dbaecfaf28813e5c42", size = 1584797 }, - { url = "https://files.pythonhosted.org/packages/bd/1e/cee6b51fcb3b1c4185a7dc62b3113bc136fae07f39386c88c90b7f79f199/aiohttp-3.11.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88d385b8e7f3a870146bf5ea31786ef7463e99eb59e31db56e2315535d811f55", size = 1632535 }, - { url = "https://files.pythonhosted.org/packages/71/1f/42424462b7a09da362e1711090db9f8d68a37a33f0aab51307335517c599/aiohttp-3.11.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b10a47e5390c4b30a0d58ee12581003be52eedd506862ab7f97da7a66805befb", size = 1668484 }, - { url = "https://files.pythonhosted.org/packages/f6/79/0e25542bbe3c2bfd7a12c7a49c7bce73b09a836f65079e4b77bc2bafc89e/aiohttp-3.11.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b5263dcede17b6b0c41ef0c3ccce847d82a7da98709e75cf7efde3e9e3b5cae", size = 1589708 }, - { url = "https://files.pythonhosted.org/packages/d1/13/93ae26b75e23f7d3a613872e472fae836ca100dc5bde5936ebc93ada8890/aiohttp-3.11.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50c5c7b8aa5443304c55c262c5693b108c35a3b61ef961f1e782dd52a2f559c7", size = 1544752 }, - { url = "https://files.pythonhosted.org/packages/cf/5e/48847fad1b014ef92ef18ea1339a3b58eb81d3bc717b94c3627f5d2a42c5/aiohttp-3.11.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1c031a7572f62f66f1257db37ddab4cb98bfaf9b9434a3b4840bf3560f5e788", size = 1529417 }, - { url = "https://files.pythonhosted.org/packages/ae/56/fbd4ea019303f4877f0e0b8c9de92e9db24338e7545570d3f275f3c74c53/aiohttp-3.11.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:7e44eba534381dd2687be50cbd5f2daded21575242ecfdaf86bbeecbc38dae8e", size = 1557808 }, - { url = "https://files.pythonhosted.org/packages/f1/43/112189cf6b3c482ecdd6819b420eaa0c2033426f28d741bb7f19db5dd2bb/aiohttp-3.11.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:145a73850926018ec1681e734cedcf2716d6a8697d90da11284043b745c286d5", size = 1536765 }, - { url = "https://files.pythonhosted.org/packages/30/12/59986547de8306e06c7b30e547ccda02d29636e152366caba2dd8627bfe1/aiohttp-3.11.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2c311e2f63e42c1bf86361d11e2c4a59f25d9e7aabdbdf53dc38b885c5435cdb", size = 1607621 }, - { url = "https://files.pythonhosted.org/packages/aa/9b/af3b323b20df3318ed20d701d8242e523d59c842ca93f23134b05c9d5054/aiohttp-3.11.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ea756b5a7bac046d202a9a3889b9a92219f885481d78cd318db85b15cc0b7bcf", size = 1628977 }, - { url = "https://files.pythonhosted.org/packages/36/62/adf5a331a7bda475cc326dde393fa2bc5849060b1b37ac3d1bee1953f2cd/aiohttp-3.11.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:526c900397f3bbc2db9cb360ce9c35134c908961cdd0ac25b1ae6ffcaa2507ff", size = 1564455 }, - { url = "https://files.pythonhosted.org/packages/90/c4/4a24291f22f111a854dfdb54dc94d4e0a5229ccbb7bc7f0bed972aa50410/aiohttp-3.11.12-cp310-cp310-win32.whl", hash = "sha256:b8d3bb96c147b39c02d3db086899679f31958c5d81c494ef0fc9ef5bb1359b3d", size = 416768 }, - { url = "https://files.pythonhosted.org/packages/51/69/5221c8006acb7bb10d9e8e2238fb216571bddc2e00a8d95bcfbe2f579c57/aiohttp-3.11.12-cp310-cp310-win_amd64.whl", hash = "sha256:7fe3d65279bfbee8de0fb4f8c17fc4e893eed2dba21b2f680e930cc2b09075c5", size = 442170 }, - { url = "https://files.pythonhosted.org/packages/9c/38/35311e70196b6a63cfa033a7f741f800aa8a93f57442991cbe51da2394e7/aiohttp-3.11.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:87a2e00bf17da098d90d4145375f1d985a81605267e7f9377ff94e55c5d769eb", size = 708797 }, - { url = "https://files.pythonhosted.org/packages/44/3e/46c656e68cbfc4f3fc7cb5d2ba4da6e91607fe83428208028156688f6201/aiohttp-3.11.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b34508f1cd928ce915ed09682d11307ba4b37d0708d1f28e5774c07a7674cac9", size = 468669 }, - { url = "https://files.pythonhosted.org/packages/a0/d6/2088fb4fd1e3ac2bfb24bc172223babaa7cdbb2784d33c75ec09e66f62f8/aiohttp-3.11.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:936d8a4f0f7081327014742cd51d320296b56aa6d324461a13724ab05f4b2933", size = 455739 }, - { url = "https://files.pythonhosted.org/packages/e7/dc/c443a6954a56f4a58b5efbfdf23cc6f3f0235e3424faf5a0c56264d5c7bb/aiohttp-3.11.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de1378f72def7dfb5dbd73d86c19eda0ea7b0a6873910cc37d57e80f10d64e1", size = 1685858 }, - { url = "https://files.pythonhosted.org/packages/25/67/2d5b3aaade1d5d01c3b109aa76e3aa9630531252cda10aa02fb99b0b11a1/aiohttp-3.11.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9d45dbb3aaec05cf01525ee1a7ac72de46a8c425cb75c003acd29f76b1ffe94", size = 1743829 }, - { url = "https://files.pythonhosted.org/packages/90/9b/9728fe9a3e1b8521198455d027b0b4035522be18f504b24c5d38d59e7278/aiohttp-3.11.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:930ffa1925393381e1e0a9b82137fa7b34c92a019b521cf9f41263976666a0d6", size = 1785587 }, - { url = "https://files.pythonhosted.org/packages/ce/cf/28fbb43d4ebc1b4458374a3c7b6db3b556a90e358e9bbcfe6d9339c1e2b6/aiohttp-3.11.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8340def6737118f5429a5df4e88f440746b791f8f1c4ce4ad8a595f42c980bd5", size = 1675319 }, - { url = "https://files.pythonhosted.org/packages/e5/d2/006c459c11218cabaa7bca401f965c9cc828efbdea7e1615d4644eaf23f7/aiohttp-3.11.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4016e383f91f2814e48ed61e6bda7d24c4d7f2402c75dd28f7e1027ae44ea204", size = 1619982 }, - { url = "https://files.pythonhosted.org/packages/9d/83/ca425891ebd37bee5d837110f7fddc4d808a7c6c126a7d1b5c3ad72fc6ba/aiohttp-3.11.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3c0600bcc1adfaaac321422d615939ef300df81e165f6522ad096b73439c0f58", size = 1654176 }, - { url = "https://files.pythonhosted.org/packages/25/df/047b1ce88514a1b4915d252513640184b63624e7914e41d846668b8edbda/aiohttp-3.11.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:0450ada317a65383b7cce9576096150fdb97396dcfe559109b403c7242faffef", size = 1660198 }, - { url = "https://files.pythonhosted.org/packages/d3/cc/6ecb8e343f0902528620b9dbd567028a936d5489bebd7dbb0dd0914f4fdb/aiohttp-3.11.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:850ff6155371fd802a280f8d369d4e15d69434651b844bde566ce97ee2277420", size = 1650186 }, - { url = "https://files.pythonhosted.org/packages/f8/f8/453df6dd69256ca8c06c53fc8803c9056e2b0b16509b070f9a3b4bdefd6c/aiohttp-3.11.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8fd12d0f989c6099e7b0f30dc6e0d1e05499f3337461f0b2b0dadea6c64b89df", size = 1733063 }, - { url = "https://files.pythonhosted.org/packages/55/f8/540160787ff3000391de0e5d0d1d33be4c7972f933c21991e2ea105b2d5e/aiohttp-3.11.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:76719dd521c20a58a6c256d058547b3a9595d1d885b830013366e27011ffe804", size = 1755306 }, - { url = "https://files.pythonhosted.org/packages/30/7d/49f3bfdfefd741576157f8f91caa9ff61a6f3d620ca6339268327518221b/aiohttp-3.11.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:97fe431f2ed646a3b56142fc81d238abcbaff08548d6912acb0b19a0cadc146b", size = 1692909 }, - { url = "https://files.pythonhosted.org/packages/40/9c/8ce00afd6f6112ce9a2309dc490fea376ae824708b94b7b5ea9cba979d1d/aiohttp-3.11.12-cp311-cp311-win32.whl", hash = "sha256:e10c440d142fa8b32cfdb194caf60ceeceb3e49807072e0dc3a8887ea80e8c16", size = 416584 }, - { url = "https://files.pythonhosted.org/packages/35/97/4d3c5f562f15830de472eb10a7a222655d750839943e0e6d915ef7e26114/aiohttp-3.11.12-cp311-cp311-win_amd64.whl", hash = "sha256:246067ba0cf5560cf42e775069c5d80a8989d14a7ded21af529a4e10e3e0f0e6", size = 442674 }, - { url = "https://files.pythonhosted.org/packages/4d/d0/94346961acb476569fca9a644cc6f9a02f97ef75961a6b8d2b35279b8d1f/aiohttp-3.11.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e392804a38353900c3fd8b7cacbea5132888f7129f8e241915e90b85f00e3250", size = 704837 }, - { url = "https://files.pythonhosted.org/packages/a9/af/05c503f1cc8f97621f199ef4b8db65fb88b8bc74a26ab2adb74789507ad3/aiohttp-3.11.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8fa1510b96c08aaad49303ab11f8803787c99222288f310a62f493faf883ede1", size = 464218 }, - { url = "https://files.pythonhosted.org/packages/f2/48/b9949eb645b9bd699153a2ec48751b985e352ab3fed9d98c8115de305508/aiohttp-3.11.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dc065a4285307607df3f3686363e7f8bdd0d8ab35f12226362a847731516e42c", size = 456166 }, - { url = "https://files.pythonhosted.org/packages/14/fb/980981807baecb6f54bdd38beb1bd271d9a3a786e19a978871584d026dcf/aiohttp-3.11.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddb31f8474695cd61fc9455c644fc1606c164b93bff2490390d90464b4655df", size = 1682528 }, - { url = "https://files.pythonhosted.org/packages/90/cb/77b1445e0a716914e6197b0698b7a3640590da6c692437920c586764d05b/aiohttp-3.11.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9dec0000d2d8621d8015c293e24589d46fa218637d820894cb7356c77eca3259", size = 1737154 }, - { url = "https://files.pythonhosted.org/packages/ff/24/d6fb1f4cede9ccbe98e4def6f3ed1e1efcb658871bbf29f4863ec646bf38/aiohttp-3.11.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3552fe98e90fdf5918c04769f338a87fa4f00f3b28830ea9b78b1bdc6140e0d", size = 1793435 }, - { url = "https://files.pythonhosted.org/packages/17/e2/9f744cee0861af673dc271a3351f59ebd5415928e20080ab85be25641471/aiohttp-3.11.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dfe7f984f28a8ae94ff3a7953cd9678550dbd2a1f9bda5dd9c5ae627744c78e", size = 1692010 }, - { url = "https://files.pythonhosted.org/packages/90/c4/4a1235c1df544223eb57ba553ce03bc706bdd065e53918767f7fa1ff99e0/aiohttp-3.11.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a481a574af914b6e84624412666cbfbe531a05667ca197804ecc19c97b8ab1b0", size = 1619481 }, - { url = "https://files.pythonhosted.org/packages/60/70/cf12d402a94a33abda86dd136eb749b14c8eb9fec1e16adc310e25b20033/aiohttp-3.11.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1987770fb4887560363b0e1a9b75aa303e447433c41284d3af2840a2f226d6e0", size = 1641578 }, - { url = "https://files.pythonhosted.org/packages/1b/25/7211973fda1f5e833fcfd98ccb7f9ce4fbfc0074e3e70c0157a751d00db8/aiohttp-3.11.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a4ac6a0f0f6402854adca4e3259a623f5c82ec3f0c049374133bcb243132baf9", size = 1684463 }, - { url = "https://files.pythonhosted.org/packages/93/60/b5905b4d0693f6018b26afa9f2221fefc0dcbd3773fe2dff1a20fb5727f1/aiohttp-3.11.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c96a43822f1f9f69cc5c3706af33239489a6294be486a0447fb71380070d4d5f", size = 1646691 }, - { url = "https://files.pythonhosted.org/packages/b4/fc/ba1b14d6fdcd38df0b7c04640794b3683e949ea10937c8a58c14d697e93f/aiohttp-3.11.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a5e69046f83c0d3cb8f0d5bd9b8838271b1bc898e01562a04398e160953e8eb9", size = 1702269 }, - { url = "https://files.pythonhosted.org/packages/5e/39/18c13c6f658b2ba9cc1e0c6fb2d02f98fd653ad2addcdf938193d51a9c53/aiohttp-3.11.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:68d54234c8d76d8ef74744f9f9fc6324f1508129e23da8883771cdbb5818cbef", size = 1734782 }, - { url = "https://files.pythonhosted.org/packages/9f/d2/ccc190023020e342419b265861877cd8ffb75bec37b7ddd8521dd2c6deb8/aiohttp-3.11.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9fd9dcf9c91affe71654ef77426f5cf8489305e1c66ed4816f5a21874b094b9", size = 1694740 }, - { url = "https://files.pythonhosted.org/packages/3f/54/186805bcada64ea90ea909311ffedcd74369bfc6e880d39d2473314daa36/aiohttp-3.11.12-cp312-cp312-win32.whl", hash = "sha256:0ed49efcd0dc1611378beadbd97beb5d9ca8fe48579fc04a6ed0844072261b6a", size = 411530 }, - { url = "https://files.pythonhosted.org/packages/3d/63/5eca549d34d141bcd9de50d4e59b913f3641559460c739d5e215693cb54a/aiohttp-3.11.12-cp312-cp312-win_amd64.whl", hash = "sha256:54775858c7f2f214476773ce785a19ee81d1294a6bedc5cc17225355aab74802", size = 437860 }, - { url = "https://files.pythonhosted.org/packages/c3/9b/cea185d4b543ae08ee478373e16653722c19fcda10d2d0646f300ce10791/aiohttp-3.11.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:413ad794dccb19453e2b97c2375f2ca3cdf34dc50d18cc2693bd5aed7d16f4b9", size = 698148 }, - { url = "https://files.pythonhosted.org/packages/91/5c/80d47fe7749fde584d1404a68ade29bcd7e58db8fa11fa38e8d90d77e447/aiohttp-3.11.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a93d28ed4b4b39e6f46fd240896c29b686b75e39cc6992692e3922ff6982b4c", size = 460831 }, - { url = "https://files.pythonhosted.org/packages/8e/f9/de568f8a8ca6b061d157c50272620c53168d6e3eeddae78dbb0f7db981eb/aiohttp-3.11.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d589264dbba3b16e8951b6f145d1e6b883094075283dafcab4cdd564a9e353a0", size = 453122 }, - { url = "https://files.pythonhosted.org/packages/8b/fd/b775970a047543bbc1d0f66725ba72acef788028fce215dc959fd15a8200/aiohttp-3.11.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5148ca8955affdfeb864aca158ecae11030e952b25b3ae15d4e2b5ba299bad2", size = 1665336 }, - { url = "https://files.pythonhosted.org/packages/82/9b/aff01d4f9716245a1b2965f02044e4474fadd2bcfe63cf249ca788541886/aiohttp-3.11.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:525410e0790aab036492eeea913858989c4cb070ff373ec3bc322d700bdf47c1", size = 1718111 }, - { url = "https://files.pythonhosted.org/packages/e0/a9/166fd2d8b2cc64f08104aa614fad30eee506b563154081bf88ce729bc665/aiohttp-3.11.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bd8695be2c80b665ae3f05cb584093a1e59c35ecb7d794d1edd96e8cc9201d7", size = 1775293 }, - { url = "https://files.pythonhosted.org/packages/13/c5/0d3c89bd9e36288f10dc246f42518ce8e1c333f27636ac78df091c86bb4a/aiohttp-3.11.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0203433121484b32646a5f5ea93ae86f3d9559d7243f07e8c0eab5ff8e3f70e", size = 1677338 }, - { url = "https://files.pythonhosted.org/packages/72/b2/017db2833ef537be284f64ead78725984db8a39276c1a9a07c5c7526e238/aiohttp-3.11.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40cd36749a1035c34ba8d8aaf221b91ca3d111532e5ccb5fa8c3703ab1b967ed", size = 1603365 }, - { url = "https://files.pythonhosted.org/packages/fc/72/b66c96a106ec7e791e29988c222141dd1219d7793ffb01e72245399e08d2/aiohttp-3.11.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a7442662afebbf7b4c6d28cb7aab9e9ce3a5df055fc4116cc7228192ad6cb484", size = 1618464 }, - { url = "https://files.pythonhosted.org/packages/3f/50/e68a40f267b46a603bab569d48d57f23508801614e05b3369898c5b2910a/aiohttp-3.11.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8a2fb742ef378284a50766e985804bd6adb5adb5aa781100b09befdbfa757b65", size = 1657827 }, - { url = "https://files.pythonhosted.org/packages/c5/1d/aafbcdb1773d0ba7c20793ebeedfaba1f3f7462f6fc251f24983ed738aa7/aiohttp-3.11.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2cee3b117a8d13ab98b38d5b6bdcd040cfb4181068d05ce0c474ec9db5f3c5bb", size = 1616700 }, - { url = "https://files.pythonhosted.org/packages/b0/5e/6cd9724a2932f36e2a6b742436a36d64784322cfb3406ca773f903bb9a70/aiohttp-3.11.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f6a19bcab7fbd8f8649d6595624856635159a6527861b9cdc3447af288a00c00", size = 1685643 }, - { url = "https://files.pythonhosted.org/packages/8b/38/ea6c91d5c767fd45a18151675a07c710ca018b30aa876a9f35b32fa59761/aiohttp-3.11.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e4cecdb52aaa9994fbed6b81d4568427b6002f0a91c322697a4bfcc2b2363f5a", size = 1715487 }, - { url = "https://files.pythonhosted.org/packages/8e/24/e9edbcb7d1d93c02e055490348df6f955d675e85a028c33babdcaeda0853/aiohttp-3.11.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:30f546358dfa0953db92ba620101fefc81574f87b2346556b90b5f3ef16e55ce", size = 1672948 }, - { url = "https://files.pythonhosted.org/packages/25/be/0b1fb737268e003198f25c3a68c2135e76e4754bf399a879b27bd508a003/aiohttp-3.11.12-cp313-cp313-win32.whl", hash = "sha256:ce1bb21fc7d753b5f8a5d5a4bae99566386b15e716ebdb410154c16c91494d7f", size = 410396 }, - { url = "https://files.pythonhosted.org/packages/68/fd/677def96a75057b0a26446b62f8fbb084435b20a7d270c99539c26573bfd/aiohttp-3.11.12-cp313-cp313-win_amd64.whl", hash = "sha256:f7914ab70d2ee8ab91c13e5402122edbc77821c66d2758abb53aabe87f013287", size = 436234 }, -] - -[[package]] -name = "aiosignal" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, -] - -[[package]] -name = "attrs" -version = "25.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152 }, -] - -[[package]] -name = "backports-tarfile" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", size = 86406 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181 }, -] - -[[package]] -name = "backports-weakref" -version = "1.0.post1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/ab/cf35cf43a4a6215e3255cf2e49c77d5ba1e9c733af2aa3ec1ca9c4d02592/backports.weakref-1.0.post1.tar.gz", hash = "sha256:bc4170a29915f8b22c9e7c4939701859650f2eb84184aee80da329ac0b9825c2", size = 10574 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/ec/f598b633c3d5ffe267aaada57d961c94fdfa183c5c3ebda2b6d151943db6/backports.weakref-1.0.post1-py2.py3-none-any.whl", hash = "sha256:81bc9b51c0abc58edc76aefbbc68c62a787918ffe943a37947e162c3f8e19e82", size = 5237 }, -] - -[[package]] -name = "bandit" -version = "1.8.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, - { name = "pyyaml" }, - { name = "rich" }, - { name = "stevedore" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9b/e2/c229cdb4eefc124e5b77ac2557eb0a3cb5b9fc89bc465dd2b8dc1033dbb8/bandit-1.8.2.tar.gz", hash = "sha256:e00ad5a6bc676c0954669fe13818024d66b70e42cf5adb971480cf3b671e835f", size = 4228832 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/c1/991a7a1404626558cc7db0cc34243e13e5e336eba053bf6979e9fd6006f7/bandit-1.8.2-py3-none-any.whl", hash = "sha256:df6146ad73dd30e8cbda4e29689ddda48364e36ff655dbfc86998401fcf1721f", size = 127049 }, -] - -[[package]] -name = "bitarray" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/62/dcfac53d22ef7e904ed10a8e710a36391d2d6753c34c869b51bfc5e4ad54/bitarray-3.0.0.tar.gz", hash = "sha256:a2083dc20f0d828a7cdf7a16b20dae56aab0f43dc4f347a3b3039f6577992b03", size = 126627 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/f7/2cd02557fa9f177d54b51e6d668696266bdc1af978b5c27179449cbf5870/bitarray-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5ddbf71a97ad1d6252e6e93d2d703b624d0a5b77c153b12f9ea87d83e1250e0c", size = 172224 }, - { url = "https://files.pythonhosted.org/packages/49/0a/0362089c127f2639041171803f6bf193a9e1deba72df637ebd36cb510f46/bitarray-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0e7f24a0b01e6e6a0191c50b06ca8edfdec1988d9d2b264d669d2487f4f4680", size = 123359 }, - { url = "https://files.pythonhosted.org/packages/c7/ab/a0982708b5ad92d6ec40833846ac954b57b16d9f90551a9da59e4bce79e1/bitarray-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:150b7b29c36d9f1a24779aea723fdfc73d1c1c161dc0ea14990da27d4e947092", size = 121267 }, - { url = "https://files.pythonhosted.org/packages/10/23/134ad08b9e7be3b80575fd4a50c33c79b3b360794dfc2716b6a18bf4dd60/bitarray-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8330912be6cb8e2fbfe8eb69f82dee139d605730cadf8d50882103af9ac83bb4", size = 278114 }, - { url = "https://files.pythonhosted.org/packages/c1/a1/df7d0b415207de7c6210403865a5d8a9c920209d542f552a09a02749038a/bitarray-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e56ba8be5f17dee0ffa6d6ce85251e062ded2faa3cbd2558659c671e6c3bf96d", size = 292725 }, - { url = "https://files.pythonhosted.org/packages/ec/06/03a636ac237c1860e63f037ccff35f0fec45188c94e55d9df526ee80adc3/bitarray-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffd94b4803811c738e504a4b499fb2f848b2f7412d71e6b517508217c1d7929d", size = 294722 }, - { url = "https://files.pythonhosted.org/packages/17/33/c2a7cb6f0030ea94408c84c4f80f4065b54b2bf1d4080e36fcd0b4c587a2/bitarray-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0255bd05ec7165e512c115423a5255a3f301417973d20a80fc5bfc3f3640bcb", size = 278304 }, - { url = "https://files.pythonhosted.org/packages/2c/a3/a06f76dd55d5337ff55585059058761c148da6d1e9e2bc0469d881ba5eb8/bitarray-3.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe606e728842389943a939258809dc5db2de831b1d2e0118515059e87f7bbc1a", size = 268807 }, - { url = "https://files.pythonhosted.org/packages/29/48/e8157c422542c308d6a0f5b213b21fef5779c80c00e673e2e4d7b3854d60/bitarray-3.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e89ea59a3ed86a6eb150d016ed28b1bedf892802d0ed32b5659d3199440f3ced", size = 272791 }, - { url = "https://files.pythonhosted.org/packages/ad/53/219d82592b150b580fbc479a718a7c31086627ed4599c9930408f43b6de4/bitarray-3.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cf0cc2e91dd38122dec2e6541efa99aafb0a62e118179218181eff720b4b8153", size = 264821 }, - { url = "https://files.pythonhosted.org/packages/95/08/c47b24fbb34a305531d8d0d7c15f5ab9788478384583a2614b07c2449cf8/bitarray-3.0.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:2d9fe3ee51afeb909b68f97e14c6539ace3f4faa99b21012e610bbe7315c388d", size = 287871 }, - { url = "https://files.pythonhosted.org/packages/77/31/5cdf3dcf407e8fcc5ca07a06f45aaf6b0adb15f38fe6fddd03d5d1fbaf9f/bitarray-3.0.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:37be5482b9df3105bad00fdf7dc65244e449b130867c3879c9db1db7d72e508b", size = 299459 }, - { url = "https://files.pythonhosted.org/packages/b5/26/15b3630dc9bed79fc0e4a5dc92f4b1d30a872ff92f20a8b7acbb7a484bfd/bitarray-3.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0027b8f3bb2bba914c79115e96a59b9924aafa1a578223a7c4f0a7242d349842", size = 271131 }, - { url = "https://files.pythonhosted.org/packages/45/4b/1c8ba97a015d9cf44b54d4488a0005c2e9fb33ff1df38fdcf68d1cb76785/bitarray-3.0.0-cp310-cp310-win32.whl", hash = "sha256:628f93e9c2c23930bd1cfe21c634d6c84ec30f45f23e69aefe1fcd262186d7bb", size = 114230 }, - { url = "https://files.pythonhosted.org/packages/84/54/d883073137d5c245555f66c48f9518c855704b4c619aa92ddd74d6eb2c98/bitarray-3.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:0b655c3110e315219e266b2732609fddb0857bc69593de29f3c2ba74b7d3f51a", size = 121439 }, - { url = "https://files.pythonhosted.org/packages/61/41/321edc0fbf7e8c88552d5ff9ee07777d58e2078f2706c6478bc6651b1945/bitarray-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:44c3e78b60070389b824d5a654afa1c893df723153c81904088d4922c3cfb6ac", size = 172452 }, - { url = "https://files.pythonhosted.org/packages/48/92/4c312d6d55ac30dae96749830c9f5007a914efcb591ee0828914078eec9f/bitarray-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:545d36332de81e4742a845a80df89530ff193213a50b4cbef937ed5a44c0e5e5", size = 123502 }, - { url = "https://files.pythonhosted.org/packages/75/2c/9f3ed70ffac8e6d2b0880e132d9e5024e4ef9404a24220deca8dbd702f15/bitarray-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a9eb510cde3fa78c2e302bece510bf5ed494ec40e6b082dec753d6e22d5d1b1", size = 121363 }, - { url = "https://files.pythonhosted.org/packages/48/e0/8ec59416aaa7ca1461a0268c0fe2fbdc8d574ac41e307980f555b773d5f6/bitarray-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e3727ab63dfb6bde00b281934e2212bb7529ea3006c0031a556a84d2268bea5", size = 285792 }, - { url = "https://files.pythonhosted.org/packages/b9/8a/fb9d76ecb44a79f02188240278574376e851d0ca81437f433c9e6481d2e5/bitarray-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2055206ed653bee0b56628f6a4d248d53e5660228d355bbec0014bdfa27050ae", size = 300848 }, - { url = "https://files.pythonhosted.org/packages/63/c5/067b688553b23e99d61ecf930abf1ad5cb5f80c2ebe6f0e2fe8ecab00b3f/bitarray-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:147542299f458bdb177f798726e5f7d39ab8491de4182c3c6d9885ed275a3c2b", size = 303027 }, - { url = "https://files.pythonhosted.org/packages/dc/46/25ebc667907736b2c5c84f4bd8260d9bece8b69719a33db5c3f3dcb281a5/bitarray-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f761184b93092077c7f6b7dad7bd4e671c1620404a76620da7872ceb576a94", size = 286125 }, - { url = "https://files.pythonhosted.org/packages/16/dd/f9a1d84965a992ff42cae5b61536e68fc944f3e31a349b690347d98fc5e0/bitarray-3.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e008b7b4ce6c7f7a54b250c45c28d4243cc2a3bbfd5298fa7dac92afda229842", size = 277111 }, - { url = "https://files.pythonhosted.org/packages/16/5b/44f298586a09beb62ec553f9efa06c8a5356d2e230e4080c72cb2800a48f/bitarray-3.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dfea514e665af278b2e1d4deb542de1cd4f77413bee83dd15ae16175976ea8d5", size = 280941 }, - { url = "https://files.pythonhosted.org/packages/28/7c/c6e157332227862727959057ba2987e6710985992b196a81f61995f21e19/bitarray-3.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:66d6134b7bb737b88f1d16478ad0927c571387f6054f4afa5557825a4c1b78e2", size = 272817 }, - { url = "https://files.pythonhosted.org/packages/b7/5d/9f7aaaaf85b5247b4a69b93af60ac7dcfff5545bf544a35517618c4244a0/bitarray-3.0.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3cd565253889940b4ec4768d24f101d9fe111cad4606fdb203ea16f9797cf9ed", size = 295830 }, - { url = "https://files.pythonhosted.org/packages/14/1b/86dd50edd2e0612b092fe4caec3001a24298c9acab5e89a503f002ed3bef/bitarray-3.0.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4800c91a14656789d2e67d9513359e23e8a534c8ee1482bb9b517a4cfc845200", size = 307592 }, - { url = "https://files.pythonhosted.org/packages/d6/8f/45a1f1bcce5fd88d2f0bb2e1ebe8bbb55247edcb8e7a8ef06e4437e2b5e3/bitarray-3.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c2945e0390d1329c585c584c6b6d78be017d9c6a1288f9c92006fe907f69cc28", size = 278971 }, - { url = "https://files.pythonhosted.org/packages/43/2d/948c5718fe901aa58c98cef52b8898a6bea865bea7528cff6c2bc703f9f3/bitarray-3.0.0-cp311-cp311-win32.whl", hash = "sha256:c23286abba0cb509733c6ce8f4013cd951672c332b2e184dbefbd7331cd234c8", size = 114242 }, - { url = "https://files.pythonhosted.org/packages/8c/75/e921ada57bb0bcece5eb515927c031f0bc828f702b8f213639358d9df396/bitarray-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:ca79f02a98cbda1472449d440592a2fe2ad96fe55515a0447fa8864a38017cf8", size = 121524 }, - { url = "https://files.pythonhosted.org/packages/4e/2e/2e4beb2b714dc83a9e90ac0e4bacb1a191c71125734f72962ee2a20b9cfb/bitarray-3.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:184972c96e1c7e691be60c3792ca1a51dd22b7f25d96ebea502fe3c9b554f25d", size = 172152 }, - { url = "https://files.pythonhosted.org/packages/e0/1f/9ec96408c060ffc3df5ba64d2b520fd0484cb3393a96691df8f660a43b17/bitarray-3.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:787db8da5e9e29be712f7a6bce153c7bc8697ccc2c38633e347bb9c82475d5c9", size = 123319 }, - { url = "https://files.pythonhosted.org/packages/80/9f/4dd05086308bfcc84ad88c663460a8ad9f5f638f9f96eb5fa08381054db6/bitarray-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2da91ab3633c66999c2a352f0ca9ae064f553e5fc0eca231d28e7e305b83e942", size = 121242 }, - { url = "https://files.pythonhosted.org/packages/55/bb/8865b7380e9d20445bc775079f24f2279a8c0d9ee11d57c49b118d39beaf/bitarray-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7edb83089acbf2c86c8002b96599071931dc4ea5e1513e08306f6f7df879a48b", size = 287463 }, - { url = "https://files.pythonhosted.org/packages/db/8b/779119ee438090a80cbfaa49f96e783651183ab4c25b9760fe360aa7cb31/bitarray-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996d1b83eb904589f40974538223eaed1ab0f62be8a5105c280b9bd849e685c4", size = 301599 }, - { url = "https://files.pythonhosted.org/packages/41/25/78f7ba7fa8ab428767dfb722fc1ea9aac4a9813e348023d8047d8fd32253/bitarray-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4817d73d995bd2b977d9cde6050be8d407791cf1f84c8047fa0bea88c1b815bc", size = 304837 }, - { url = "https://files.pythonhosted.org/packages/f7/8d/30a448d3157b4239e635c92fc3b3789a5b87784875ca2776f65bd543d136/bitarray-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d47bc4ff9b0e1624d613563c6fa7b80aebe7863c56c3df5ab238bb7134e8755", size = 288588 }, - { url = "https://files.pythonhosted.org/packages/86/e0/c1f1b595682244f55119d55f280b5a996bcd462b702ec220d976a7566d27/bitarray-3.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aca0a9cd376beaccd9f504961de83e776dd209c2de5a4c78dc87a78edf61839b", size = 279002 }, - { url = "https://files.pythonhosted.org/packages/5c/4d/a17626923ad2c9d20ed1625fc5b27a8dfe2d1a3e877083e9422455ec302d/bitarray-3.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:572a61fba7e3a710a8324771322fba8488d134034d349dcd036a7aef74723a80", size = 281898 }, - { url = "https://files.pythonhosted.org/packages/50/d8/5c410580a510e669d9a28bf17675e58843236c55c60fc6dc8f8747808757/bitarray-3.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a817ad70c1aff217530576b4f037dd9b539eb2926603354fcac605d824082ad1", size = 274622 }, - { url = "https://files.pythonhosted.org/packages/e7/21/de2e8eda85c5f6a05bda75a00c22c94aee71ef09db0d5cbf22446de74312/bitarray-3.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:2ac67b658fa5426503e9581a3fb44a26a3b346c1abd17105735f07db572195b3", size = 296930 }, - { url = "https://files.pythonhosted.org/packages/13/7b/7cfad12d77db2932fb745fa281693b0031c3dfd7f2ecf5803be688cc3798/bitarray-3.0.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:12f19ede03e685c5c588ab5ed63167999295ffab5e1126c5fe97d12c0718c18f", size = 309836 }, - { url = "https://files.pythonhosted.org/packages/53/e1/5120fbb8438a0d718e063f70168a2975e03f00ce6b86e74b8eec079cb492/bitarray-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcef31b062f756ba7eebcd7890c5d5de84b9d64ee877325257bcc9782288564a", size = 281535 }, - { url = "https://files.pythonhosted.org/packages/73/75/8acebbbb4f85dcca73b8e91dde5d3e1e3e2317b36fae4f5b133c60720834/bitarray-3.0.0-cp312-cp312-win32.whl", hash = "sha256:656db7bdf1d81ec3b57b3cad7ec7276765964bcfd0eb81c5d1331f385298169c", size = 114423 }, - { url = "https://files.pythonhosted.org/packages/ca/56/dadae4d4351b337de6e0269001fb40f3ebe9f72222190456713d2c1be53d/bitarray-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f785af6b7cb07a9b1e5db0dea9ef9e3e8bb3d74874a0a61303eab9c16acc1999", size = 121680 }, - { url = "https://files.pythonhosted.org/packages/4f/30/07d7be4624981537d32b261dc48a16b03757cc9d88f66012d93acaf11663/bitarray-3.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7cb885c043000924554fe2124d13084c8fdae03aec52c4086915cd4cb87fe8be", size = 172147 }, - { url = "https://files.pythonhosted.org/packages/f0/e9/be1fa2828bad9cb32e1309e6dbd05adcc41679297d9e96bbb372be928e38/bitarray-3.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7814c9924a0b30ecd401f02f082d8697fc5a5be3f8d407efa6e34531ff3c306a", size = 123319 }, - { url = "https://files.pythonhosted.org/packages/22/28/33601d276a6eb76e40fe8a61c61f59cc9ff6d9ecf0b676235c02689475b8/bitarray-3.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bcf524a087b143ba736aebbb054bb399d49e77cf7c04ed24c728e411adc82bfa", size = 121236 }, - { url = "https://files.pythonhosted.org/packages/85/d3/f36b213ffae8f9c8e4c6f12a91e18c06570a04f42d5a1bda4303380f2639/bitarray-3.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1d5abf1d6d910599ac16afdd9a0ed3e24f3b46af57f3070cf2792f236f36e0b", size = 287395 }, - { url = "https://files.pythonhosted.org/packages/b7/1a/2da3b00d876883b05ffd3be9b1311858b48d4a26579f8647860e271c5385/bitarray-3.0.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9929051feeaf8d948cc0b1c9ce57748079a941a1a15c89f6014edf18adaade84", size = 301501 }, - { url = "https://files.pythonhosted.org/packages/88/b9/c1b5af8d1c918f1ee98748f7f7270f932f531c2259dd578c0edcf16ec73e/bitarray-3.0.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96cf0898f8060b2d3ae491762ae871b071212ded97ff9e1e3a5229e9fefe544c", size = 304804 }, - { url = "https://files.pythonhosted.org/packages/92/24/81a10862856419638c0db13e04de7cbf19938353517a67e4848c691f0b7c/bitarray-3.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab37da66a8736ad5a75a58034180e92c41e864da0152b84e71fcc253a2f69cd4", size = 288507 }, - { url = "https://files.pythonhosted.org/packages/da/70/a093af92ef7b207a59087e3b5819e03767fbdda9dd56aada3a4ee25a1fbd/bitarray-3.0.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beeb79e476d19b91fd6a3439853e4e5ba1b3b475920fa40d62bde719c8af786f", size = 278905 }, - { url = "https://files.pythonhosted.org/packages/fb/40/0925c6079c4b282b16eb9085f82df0cdf1f787fb4c67fd4baca3e37acf7f/bitarray-3.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f75fc0198c955d840b836059bd43e0993edbf119923029ca60c4fc017cefa54a", size = 281909 }, - { url = "https://files.pythonhosted.org/packages/61/4b/e11754a5d34cb997250d8019b1fe555d4c06fe2d2a68b0bf7c5580537046/bitarray-3.0.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f12cc7c7638074918cdcc7491aff897df921b092ffd877227892d2686e98f876", size = 274711 }, - { url = "https://files.pythonhosted.org/packages/5b/78/39513f75423959ee2d82a82e10296b6a7bc7d880b16d714980a6752ef33b/bitarray-3.0.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dbe1084935b942fab206e609fa1ed3f46ad1f2612fb4833e177e9b2a5e006c96", size = 297038 }, - { url = "https://files.pythonhosted.org/packages/af/a2/5cb81f8773a479de7c06cc1ada36d5cc5a8ebcd8715013e1c4e01a76e84a/bitarray-3.0.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ac06dd72ee1e1b6e312504d06f75220b5894af1fb58f0c20643698f5122aea76", size = 309814 }, - { url = "https://files.pythonhosted.org/packages/03/3e/795b57c6f6eea61c47d0716e1d60219218028b1f260f7328802eac684964/bitarray-3.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00f9a88c56e373009ac3c73c55205cfbd9683fbd247e2f9a64bae3da78795252", size = 281564 }, - { url = "https://files.pythonhosted.org/packages/f6/31/5914002ae4dd0e0079f8bccfd0647119cff364280d106108a19bd2511933/bitarray-3.0.0-cp313-cp313-win32.whl", hash = "sha256:9c6e52005e91803eb4e08c0a08a481fb55ddce97f926bae1f6fa61b3396b5b61", size = 114404 }, - { url = "https://files.pythonhosted.org/packages/76/0a/184f85a1739db841ae8fbb1d9ec028240d5a351e36abec9cd020de889dab/bitarray-3.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:cb98d5b6eac4b2cf2a5a69f60a9c499844b8bea207059e9fc45c752436e6bb49", size = 121672 }, - { url = "https://files.pythonhosted.org/packages/01/6b/405d04ed3d0e46dcc52b9f9ca98b342de5930ed87adcacb86afc830e188b/bitarray-3.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fef4e3b3f2084b4dae3e5316b44cda72587dcc81f68b4eb2dbda1b8d15261b61", size = 119755 }, - { url = "https://files.pythonhosted.org/packages/90/d8/cdfd2d41a836479db66c1d33f2615c37529458427586c8d585fec4c39c5c/bitarray-3.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e9eee03f187cef1e54a4545124109ee0afc84398628b4b32ebb4852b4a66393", size = 124105 }, - { url = "https://files.pythonhosted.org/packages/12/5d/4214bb7103fa9601332b49fc2fcef73005750581aabe7e13163ad66013cc/bitarray-3.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cb5702dd667f4bb10fed056ffdc4ddaae8193a52cd74cb2cdb54e71f4ef2dd1", size = 124669 }, - { url = "https://files.pythonhosted.org/packages/fc/9b/ecfe49cf03047c8415d71ee931352b11b747525cbff9bc5db9c3592d21da/bitarray-3.0.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:666e44b0458bb2894b64264a29f2cc7b5b2cbcc4c5e9cedfe1fdbde37a8e329a", size = 126520 }, - { url = "https://files.pythonhosted.org/packages/e7/79/190bcac2a23fb5f726d0305b372f73e0bf496a43da0ace4e285e9927fcdb/bitarray-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c756a92cf1c1abf01e56a4cc40cb89f0ff9147f2a0be5b557ec436a23ff464d8", size = 122035 }, -] - -[[package]] -name = "certifi" -version = "2025.1.31" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, -] - -[[package]] -name = "cffi" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024 }, - { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188 }, - { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571 }, - { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687 }, - { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211 }, - { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325 }, - { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784 }, - { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564 }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/58/5580c1716040bc89206c77d8f74418caf82ce519aae06450393ca73475d1/charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", size = 198013 }, - { url = "https://files.pythonhosted.org/packages/d0/11/00341177ae71c6f5159a08168bcb98c6e6d196d372c94511f9f6c9afe0c6/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", size = 141285 }, - { url = "https://files.pythonhosted.org/packages/01/09/11d684ea5819e5a8f5100fb0b38cf8d02b514746607934134d31233e02c8/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", size = 151449 }, - { url = "https://files.pythonhosted.org/packages/08/06/9f5a12939db324d905dc1f70591ae7d7898d030d7662f0d426e2286f68c9/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", size = 143892 }, - { url = "https://files.pythonhosted.org/packages/93/62/5e89cdfe04584cb7f4d36003ffa2936681b03ecc0754f8e969c2becb7e24/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", size = 146123 }, - { url = "https://files.pythonhosted.org/packages/a9/ac/ab729a15c516da2ab70a05f8722ecfccc3f04ed7a18e45c75bbbaa347d61/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", size = 147943 }, - { url = "https://files.pythonhosted.org/packages/03/d2/3f392f23f042615689456e9a274640c1d2e5dd1d52de36ab8f7955f8f050/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", size = 142063 }, - { url = "https://files.pythonhosted.org/packages/f2/e3/e20aae5e1039a2cd9b08d9205f52142329f887f8cf70da3650326670bddf/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", size = 150578 }, - { url = "https://files.pythonhosted.org/packages/8d/af/779ad72a4da0aed925e1139d458adc486e61076d7ecdcc09e610ea8678db/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", size = 153629 }, - { url = "https://files.pythonhosted.org/packages/c2/b6/7aa450b278e7aa92cf7732140bfd8be21f5f29d5bf334ae987c945276639/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", size = 150778 }, - { url = "https://files.pythonhosted.org/packages/39/f4/d9f4f712d0951dcbfd42920d3db81b00dd23b6ab520419626f4023334056/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", size = 146453 }, - { url = "https://files.pythonhosted.org/packages/49/2b/999d0314e4ee0cff3cb83e6bc9aeddd397eeed693edb4facb901eb8fbb69/charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", size = 95479 }, - { url = "https://files.pythonhosted.org/packages/2d/ce/3cbed41cff67e455a386fb5e5dd8906cdda2ed92fbc6297921f2e4419309/charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", size = 102790 }, - { url = "https://files.pythonhosted.org/packages/72/80/41ef5d5a7935d2d3a773e3eaebf0a9350542f2cab4eac59a7a4741fbbbbe/charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", size = 194995 }, - { url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471 }, - { url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831 }, - { url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335 }, - { url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862 }, - { url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673 }, - { url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211 }, - { url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039 }, - { url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939 }, - { url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075 }, - { url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340 }, - { url = "https://files.pythonhosted.org/packages/b5/b6/9674a4b7d4d99a0d2df9b215da766ee682718f88055751e1e5e753c82db0/charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", size = 95205 }, - { url = "https://files.pythonhosted.org/packages/1e/ab/45b180e175de4402dcf7547e4fb617283bae54ce35c27930a6f35b6bef15/charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", size = 102441 }, - { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, - { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, - { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, - { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, - { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, - { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, - { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, - { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, - { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, - { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, - { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, - { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, - { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, - { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, - { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, - { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, - { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, - { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, - { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, - { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, - { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, - { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, - { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, - { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, - { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, - { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, - { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, -] - -[[package]] -name = "ckzg" -version = "2.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/80/4b6219a65634915efc4694fa606f38d4b893dcdc1e50b9bcf69b38ec82b0/ckzg-2.0.1.tar.gz", hash = "sha256:62c5adc381637affa7e1df465c57750b356a761b8a3164c3106589b02532b9c9", size = 1113747 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/3b/6c9e4a1b84bd4a8cab3277754a05816707d4fb873e7c2ee56a793fdb76dc/ckzg-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b7f9ba6d215f8981c5545f952aac84875bd564a63da02fb22a3d1321662ecdc0", size = 114745 }, - { url = "https://files.pythonhosted.org/packages/b5/19/9f8b9c35a00040ddbb9c33a4b9c03e4f3e18987fd098ab45b3c4ce67eb44/ckzg-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8fdec3ff96399acba9baeef9e1b0b5258c08f73245780e6c69f7b73def5e8d0a", size = 98693 }, - { url = "https://files.pythonhosted.org/packages/c8/88/706c97167ebf4a5acfcb32766bf55760db10d110757ca4776e80fe3a9063/ckzg-2.0.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1644369af9900a9f109d417d6760693edf134118f3100d0c68f56667de775b80", size = 174085 }, - { url = "https://files.pythonhosted.org/packages/02/85/ed6d01f8b54aba83d029208a5bca395401263d24e55ed33ce7d42b68cb1c/ckzg-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0a2146f122d489ac7e67ae0c0743f8d0db1718e6aeed8f05717340594fe07dd", size = 160084 }, - { url = "https://files.pythonhosted.org/packages/e7/73/2883fc3a2e63a9b1b69b3abfba6fa6af00b02777f0f5c580840723316570/ckzg-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:979841be50f2782b447762db38e9bc927ae251f6ca86c54a26561a52068ee779", size = 168864 }, - { url = "https://files.pythonhosted.org/packages/55/b4/e377569c018c90f0028f2e73c8791e776ac526ecf09a35e0a1ab4d7a74b0/ckzg-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4516d86647ee4e8ea9470f4adf68fbebb6dc1bdedff7d9592c2504fe53145908", size = 170524 }, - { url = "https://files.pythonhosted.org/packages/cd/56/145b81f4650e7ca4eba58c24ca8bbdfbdc4cf5427c61895cbc0cd2eb17e4/ckzg-2.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:91866fc58a29b4829201efd9ffadfac3ffeca6359254a54a360ff6a189c34bf5", size = 185023 }, - { url = "https://files.pythonhosted.org/packages/d7/39/663dcd97cf4dac9baa59f3143187349c7dbd43628640a34cf1e04b97d8e0/ckzg-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed35508dac059b2c0a7994383bc7a92eaf35d0b9ce790016819e2619e0f4b8a9", size = 179076 }, - { url = "https://files.pythonhosted.org/packages/fe/05/c250fc209f30a4dea8eb92a12d720391a3bd657b55a5b6ab7ba16c56e092/ckzg-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:449c4fe38017351eca362106420eeb2d28d50b7e54aa8668b3af29a8ab780132", size = 98229 }, - { url = "https://files.pythonhosted.org/packages/56/eb/00e5978a32facf9203e2069d7905f8a5c262cafd6795adf9933531e7427f/ckzg-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:260608a22e2f2cadcd31f4495832d45d6460438c38faba9761b92df885a99d88", size = 114743 }, - { url = "https://files.pythonhosted.org/packages/b7/99/65015b5c6447293a3321112cb33d303ae07a5000302fa08c976819fcad64/ckzg-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e1015f99c50215098751b07d7e459ba9a2790d3692ca81552eed29996128e90d", size = 98687 }, - { url = "https://files.pythonhosted.org/packages/92/ec/5d324b490b30e581888d8f7243c3259aad6a25913653ea6d8d673c84ec0d/ckzg-2.0.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dd350d97554c161dc5b8c7b32c2dc8e659632c374f60e2669fb3c9b5b294827", size = 174848 }, - { url = "https://files.pythonhosted.org/packages/71/50/40a6c567c15eb65c73cbc45c1ed9341a0f1ea77bf489078f56e40e0e4836/ckzg-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eec7724fa8dc4ae95757efe4a87e7b2d4b880cb348c72ce7355fc0c4f64bc298", size = 160846 }, - { url = "https://files.pythonhosted.org/packages/03/c9/044fbe6083fc0e8477b9545b193b82bf349a03f4b561f87870f0b2280f36/ckzg-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3fa0f4398fa67fb71f0a2b34a652cc89e6e0e6af1340b0dc771db1a5f3e089c", size = 169632 }, - { url = "https://files.pythonhosted.org/packages/ae/f5/54e736a969813c72c745c2f0c2906e973d63f89744d947c4e3429c81761d/ckzg-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f865a0297aabeeb638187a46f7df445763360417b9df4dea60560d512c2cda09", size = 171214 }, - { url = "https://files.pythonhosted.org/packages/f4/2f/0896c133021479c5fb57ffbddd584774bdebd7d8c966be732380aa1d62ac/ckzg-2.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b6ec738350771dbf5974fb70cc8bbb20a4df784af770f7e655922adc08a2171", size = 185708 }, - { url = "https://files.pythonhosted.org/packages/02/a8/513876410e9634f10ef933f6aae6e71afd3e0786817773c9d40908b6abd4/ckzg-2.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9b4b669fc77edeb16adc182efc32b3737b36f741a2e33a170d40619e8b171a94", size = 179787 }, - { url = "https://files.pythonhosted.org/packages/c4/b6/5fe04bdbcf881bf23626ff82145e0c077ee3bdb35c86d177bf37fa57832e/ckzg-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:decb97f4a17c7338b2130dcc4b045df4cc0e7785ece872c764b554c7c73a99ff", size = 98228 }, - { url = "https://files.pythonhosted.org/packages/6c/87/dcc62fc2f6651127b6306a37db492998c291ad1a09a6a0d18895882fec51/ckzg-2.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:285cf3121b8a8c5609c5b706314f68d2ba2784ab02c5bb7487c6ae1714ecb27f", size = 114776 }, - { url = "https://files.pythonhosted.org/packages/fd/99/2d3aa09ebf692c26e03d17b9e7426a34fd71fe4d9b2ff1acf482736cc8da/ckzg-2.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f927bc41c2551b0ef0056a649a7ebed29d9665680a10795f4cee5002c69ddb7", size = 98711 }, - { url = "https://files.pythonhosted.org/packages/50/b3/44a533895aa4257d0dcb2818f7dd9b1321664784cac2d381022ed8c40113/ckzg-2.0.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fd9fb690c88919f30c9f3ab7cc46a7ecd734d5ff4c9ccea383c119b9b7cc4da", size = 175026 }, - { url = "https://files.pythonhosted.org/packages/54/a2/c594861665851f91ae81ec29cf90e38999de042aa95604737d4b779a8609/ckzg-2.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fabc3bd41b306d1c7025d561c3281a007c2aca8ceaf998582dc3894904d9c73e", size = 161039 }, - { url = "https://files.pythonhosted.org/packages/59/a0/96bb77fb8bf4cd4d51d8bd1d67d59d13f51fa2477b11b915ab6465aa92ce/ckzg-2.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eb50c53efdb9c34f762bd0c8006cf79bc92a9daf47aa6b541e496988484124f", size = 169889 }, - { url = "https://files.pythonhosted.org/packages/68/c4/77d54a7e5f85d833e9664935f6278fbea7de30f4fde213d121f7fdbc27a0/ckzg-2.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7960cc62f959403293fb53a3c2404778369ae7cefc6d7f202e5e00567cf98c4b", size = 171378 }, - { url = "https://files.pythonhosted.org/packages/02/54/6520ab37c06680910f8ff99afdc473c945c37ab1016662288d98a028d775/ckzg-2.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d721bcd492294c70eca39da0b0a433c29b6a571dbac2f7084bab06334904af06", size = 185969 }, - { url = "https://files.pythonhosted.org/packages/d6/fa/16c3a4fd8353a3a9f95728f4141b2800b08e588522f7b5644c91308f6fe1/ckzg-2.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dde2391d025b5033ef0eeacf62b11ecfe446aea25682b5f547a907766ad0a8cb", size = 180093 }, - { url = "https://files.pythonhosted.org/packages/d5/ae/91d36445c247a8832bbb7a71bd75293c4c006731d03a2ccaa13e5506ac8a/ckzg-2.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fab8859d9420f6f7df4e094ee3639bc49d18c8dab0df81bee825e2363dd67a09", size = 98280 }, - { url = "https://files.pythonhosted.org/packages/79/92/4910b9131eb637c6f72e655c1535b9a9c72a5fb2bdf52742f50066cb9e6b/ckzg-2.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9747d92883199d4f8f3a3d7018134745fddcf692dfe67115434e4b32609ea785", size = 114793 }, - { url = "https://files.pythonhosted.org/packages/09/95/cb52623cbc4573b2e65bd924524f479e6a8611002c4634dfd6e9d490b403/ckzg-2.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b2cf58fb9e165da97f0ffe9f4a6efb73992645fac8e0fa223a6cc7ec486a434a", size = 98715 }, - { url = "https://files.pythonhosted.org/packages/27/05/3f246149a728b5d829dd8e0b75379fd6bce0d420de4042b8ca692083f96d/ckzg-2.0.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d25d006899d76bb8c9d3e8b27981dd6b66a78f9826e33c1bf981af6577a69a19", size = 175008 }, - { url = "https://files.pythonhosted.org/packages/5f/76/df568b24de6bdbb99fe2c48519744d01f1b9e152fa791ed84b43a2752e78/ckzg-2.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a04bf0b32f04f5ea5e4b8518e292d3321bc05596fde95f9c3b4f504e5e4bc780", size = 161009 }, - { url = "https://files.pythonhosted.org/packages/7f/b5/8bbde8acb339a018c0456fb9af714fcca86ed9bf96114ece9556415afbac/ckzg-2.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0cf3dccd72376bff10e1833641cc9d642f34f60ca63972626d9dfcfdc8e77f", size = 169873 }, - { url = "https://files.pythonhosted.org/packages/5f/8f/9b9492f807acbfe791c4c447bbeb96e19160fda272328a9dc6700a2fcb08/ckzg-2.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:770809c7e93087470cc524724419b0f85590edb033c7c73ba94aef70b36ca18b", size = 171438 }, - { url = "https://files.pythonhosted.org/packages/f1/58/47d4ed23e338dbe1b06cca99e55ae49c3a539d88576c5893e8b589bf3ac6/ckzg-2.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e31b59b8124148d5e21f7e41b35532d7af98260c44a77c3917958adece84296d", size = 186020 }, - { url = "https://files.pythonhosted.org/packages/a5/f0/dc6f961b325d186af1a469e7119a0f48cdc36240f2aca6e10a5e5f91b8b8/ckzg-2.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:174f0c356df644d6e349ce03b7284d83dbec859e11ca5d1b1b3bace8b8fbc65d", size = 180132 }, - { url = "https://files.pythonhosted.org/packages/72/ca/44676731ca52e6d2289f7e9c74d836f59dc986e9b4182ddd2c7d0b14d88f/ckzg-2.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:30e375cd45142e56b5dbfdec05ce4deb2368d7f7dedfc7408ba37d5639af05ff", size = 98284 }, - { url = "https://files.pythonhosted.org/packages/d0/e7/9530e51d23d2ef3840aa8c18c3e7844a1c1465f0226befaef14b4270a9fa/ckzg-2.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:a12e96f20dce35e5222f898a5c8355054ef7c5ee038eeb97dbb694640b57577b", size = 112463 }, - { url = "https://files.pythonhosted.org/packages/c5/31/463330808421319784a41667c8141a1912ed71abb6b55192186142502aaf/ckzg-2.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:4e0ebc55253addaa24dd2cd871bbe3b8f57855f32b5f74e70bf2cb76b6f7da54", size = 95936 }, - { url = "https://files.pythonhosted.org/packages/fe/6e/84dc599aefcd4533298349bd468e3f56790b1dbd086ebd624184e0d8c6fb/ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f917a7bf363a3735db30559e1ed63cf1ccf414234433ba687fa72c007abd756", size = 125768 }, - { url = "https://files.pythonhosted.org/packages/51/2d/bdc7dd9d902bceb523d77e90f9d62a4692999dc8715a5795fb2817b1737f/ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f08c984286853271d4adae219e9ba87275a15047dbaa262ab8dd6c01be97b0", size = 102410 }, - { url = "https://files.pythonhosted.org/packages/f1/f8/c2a06ad4daf189057652ed2ec6ebb1cb29190f57bf67fd4f4309d5614947/ckzg-2.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fa1ea4888417e1f109fd5e57965788fb7f53b674329b937a65604a3c1ca1d03", size = 110686 }, - { url = "https://files.pythonhosted.org/packages/99/a9/ce3d5fd9df58da092c90ddc7b214fd313b54d5bc325770c488c8864ad17a/ckzg-2.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0b249914aeaf05cabc71c5c3797e3d6c126cb2c64192b7eb6755ef6aa5ab2f11", size = 98327 }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, -] - -[[package]] -name = "coverage" -version = "7.6.12" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0c/d6/2b53ab3ee99f2262e6f0b8369a43f6d66658eab45510331c0b3d5c8c4272/coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2", size = 805941 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/67/81dc41ec8f548c365d04a29f1afd492d3176b372c33e47fa2a45a01dc13a/coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8", size = 208345 }, - { url = "https://files.pythonhosted.org/packages/33/43/17f71676016c8829bde69e24c852fef6bd9ed39f774a245d9ec98f689fa0/coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879", size = 208775 }, - { url = "https://files.pythonhosted.org/packages/86/25/c6ff0775f8960e8c0840845b723eed978d22a3cd9babd2b996e4a7c502c6/coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe", size = 237925 }, - { url = "https://files.pythonhosted.org/packages/b0/3d/5f5bd37046243cb9d15fff2c69e498c2f4fe4f9b42a96018d4579ed3506f/coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674", size = 235835 }, - { url = "https://files.pythonhosted.org/packages/b5/f1/9e6b75531fe33490b910d251b0bf709142e73a40e4e38a3899e6986fe088/coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb", size = 236966 }, - { url = "https://files.pythonhosted.org/packages/4f/bc/aef5a98f9133851bd1aacf130e754063719345d2fb776a117d5a8d516971/coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c", size = 236080 }, - { url = "https://files.pythonhosted.org/packages/eb/d0/56b4ab77f9b12aea4d4c11dc11cdcaa7c29130b837eb610639cf3400c9c3/coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c", size = 234393 }, - { url = "https://files.pythonhosted.org/packages/0d/77/28ef95c5d23fe3dd191a0b7d89c82fea2c2d904aef9315daf7c890e96557/coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e", size = 235536 }, - { url = "https://files.pythonhosted.org/packages/29/62/18791d3632ee3ff3f95bc8599115707d05229c72db9539f208bb878a3d88/coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425", size = 211063 }, - { url = "https://files.pythonhosted.org/packages/fc/57/b3878006cedfd573c963e5c751b8587154eb10a61cc0f47a84f85c88a355/coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa", size = 211955 }, - { url = "https://files.pythonhosted.org/packages/64/2d/da78abbfff98468c91fd63a73cccdfa0e99051676ded8dd36123e3a2d4d5/coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015", size = 208464 }, - { url = "https://files.pythonhosted.org/packages/31/f2/c269f46c470bdabe83a69e860c80a82e5e76840e9f4bbd7f38f8cebbee2f/coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45", size = 208893 }, - { url = "https://files.pythonhosted.org/packages/47/63/5682bf14d2ce20819998a49c0deadb81e608a59eed64d6bc2191bc8046b9/coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702", size = 241545 }, - { url = "https://files.pythonhosted.org/packages/6a/b6/6b6631f1172d437e11067e1c2edfdb7238b65dff965a12bce3b6d1bf2be2/coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0", size = 239230 }, - { url = "https://files.pythonhosted.org/packages/c7/01/9cd06cbb1be53e837e16f1b4309f6357e2dfcbdab0dd7cd3b1a50589e4e1/coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f", size = 241013 }, - { url = "https://files.pythonhosted.org/packages/4b/26/56afefc03c30871326e3d99709a70d327ac1f33da383cba108c79bd71563/coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f", size = 239750 }, - { url = "https://files.pythonhosted.org/packages/dd/ea/88a1ff951ed288f56aa561558ebe380107cf9132facd0b50bced63ba7238/coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d", size = 238462 }, - { url = "https://files.pythonhosted.org/packages/6e/d4/1d9404566f553728889409eff82151d515fbb46dc92cbd13b5337fa0de8c/coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba", size = 239307 }, - { url = "https://files.pythonhosted.org/packages/12/c1/e453d3b794cde1e232ee8ac1d194fde8e2ba329c18bbf1b93f6f5eef606b/coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f", size = 211117 }, - { url = "https://files.pythonhosted.org/packages/d5/db/829185120c1686fa297294f8fcd23e0422f71070bf85ef1cc1a72ecb2930/coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558", size = 212019 }, - { url = "https://files.pythonhosted.org/packages/e2/7f/4af2ed1d06ce6bee7eafc03b2ef748b14132b0bdae04388e451e4b2c529b/coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad", size = 208645 }, - { url = "https://files.pythonhosted.org/packages/dc/60/d19df912989117caa95123524d26fc973f56dc14aecdec5ccd7d0084e131/coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3", size = 208898 }, - { url = "https://files.pythonhosted.org/packages/bd/10/fecabcf438ba676f706bf90186ccf6ff9f6158cc494286965c76e58742fa/coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574", size = 242987 }, - { url = "https://files.pythonhosted.org/packages/4c/53/4e208440389e8ea936f5f2b0762dcd4cb03281a7722def8e2bf9dc9c3d68/coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985", size = 239881 }, - { url = "https://files.pythonhosted.org/packages/c4/47/2ba744af8d2f0caa1f17e7746147e34dfc5f811fb65fc153153722d58835/coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750", size = 242142 }, - { url = "https://files.pythonhosted.org/packages/e9/90/df726af8ee74d92ee7e3bf113bf101ea4315d71508952bd21abc3fae471e/coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea", size = 241437 }, - { url = "https://files.pythonhosted.org/packages/f6/af/995263fd04ae5f9cf12521150295bf03b6ba940d0aea97953bb4a6db3e2b/coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3", size = 239724 }, - { url = "https://files.pythonhosted.org/packages/1c/8e/5bb04f0318805e190984c6ce106b4c3968a9562a400180e549855d8211bd/coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a", size = 241329 }, - { url = "https://files.pythonhosted.org/packages/9e/9d/fa04d9e6c3f6459f4e0b231925277cfc33d72dfab7fa19c312c03e59da99/coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95", size = 211289 }, - { url = "https://files.pythonhosted.org/packages/53/40/53c7ffe3c0c3fff4d708bc99e65f3d78c129110d6629736faf2dbd60ad57/coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288", size = 212079 }, - { url = "https://files.pythonhosted.org/packages/76/89/1adf3e634753c0de3dad2f02aac1e73dba58bc5a3a914ac94a25b2ef418f/coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1", size = 208673 }, - { url = "https://files.pythonhosted.org/packages/ce/64/92a4e239d64d798535c5b45baac6b891c205a8a2e7c9cc8590ad386693dc/coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd", size = 208945 }, - { url = "https://files.pythonhosted.org/packages/b4/d0/4596a3ef3bca20a94539c9b1e10fd250225d1dec57ea78b0867a1cf9742e/coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9", size = 242484 }, - { url = "https://files.pythonhosted.org/packages/1c/ef/6fd0d344695af6718a38d0861408af48a709327335486a7ad7e85936dc6e/coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e", size = 239525 }, - { url = "https://files.pythonhosted.org/packages/0c/4b/373be2be7dd42f2bcd6964059fd8fa307d265a29d2b9bcf1d044bcc156ed/coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4", size = 241545 }, - { url = "https://files.pythonhosted.org/packages/a6/7d/0e83cc2673a7790650851ee92f72a343827ecaaea07960587c8f442b5cd3/coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6", size = 241179 }, - { url = "https://files.pythonhosted.org/packages/ff/8c/566ea92ce2bb7627b0900124e24a99f9244b6c8c92d09ff9f7633eb7c3c8/coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3", size = 239288 }, - { url = "https://files.pythonhosted.org/packages/7d/e4/869a138e50b622f796782d642c15fb5f25a5870c6d0059a663667a201638/coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc", size = 241032 }, - { url = "https://files.pythonhosted.org/packages/ae/28/a52ff5d62a9f9e9fe9c4f17759b98632edd3a3489fce70154c7d66054dd3/coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3", size = 211315 }, - { url = "https://files.pythonhosted.org/packages/bc/17/ab849b7429a639f9722fa5628364c28d675c7ff37ebc3268fe9840dda13c/coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef", size = 212099 }, - { url = "https://files.pythonhosted.org/packages/d2/1c/b9965bf23e171d98505eb5eb4fb4d05c44efd256f2e0f19ad1ba8c3f54b0/coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e", size = 209511 }, - { url = "https://files.pythonhosted.org/packages/57/b3/119c201d3b692d5e17784fee876a9a78e1b3051327de2709392962877ca8/coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703", size = 209729 }, - { url = "https://files.pythonhosted.org/packages/52/4e/a7feb5a56b266304bc59f872ea07b728e14d5a64f1ad3a2cc01a3259c965/coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0", size = 253988 }, - { url = "https://files.pythonhosted.org/packages/65/19/069fec4d6908d0dae98126aa7ad08ce5130a6decc8509da7740d36e8e8d2/coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924", size = 249697 }, - { url = "https://files.pythonhosted.org/packages/1c/da/5b19f09ba39df7c55f77820736bf17bbe2416bbf5216a3100ac019e15839/coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b", size = 252033 }, - { url = "https://files.pythonhosted.org/packages/1e/89/4c2750df7f80a7872267f7c5fe497c69d45f688f7b3afe1297e52e33f791/coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d", size = 251535 }, - { url = "https://files.pythonhosted.org/packages/78/3b/6d3ae3c1cc05f1b0460c51e6f6dcf567598cbd7c6121e5ad06643974703c/coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827", size = 249192 }, - { url = "https://files.pythonhosted.org/packages/6e/8e/c14a79f535ce41af7d436bbad0d3d90c43d9e38ec409b4770c894031422e/coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9", size = 250627 }, - { url = "https://files.pythonhosted.org/packages/cb/79/b7cee656cfb17a7f2c1b9c3cee03dd5d8000ca299ad4038ba64b61a9b044/coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3", size = 212033 }, - { url = "https://files.pythonhosted.org/packages/b6/c3/f7aaa3813f1fa9a4228175a7bd368199659d392897e184435a3b66408dd3/coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f", size = 213240 }, - { url = "https://files.pythonhosted.org/packages/7a/7f/05818c62c7afe75df11e0233bd670948d68b36cdbf2a339a095bc02624a8/coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf", size = 200558 }, - { url = "https://files.pythonhosted.org/packages/fb/b2/f655700e1024dec98b10ebaafd0cedbc25e40e4abe62a3c8e2ceef4f8f0a/coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953", size = 200552 }, -] - -[package.optional-dependencies] -toml = [ - { name = "tomli", marker = "python_full_version <= '3.11'" }, -] - -[[package]] -name = "cryptography" -version = "44.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/67/545c79fe50f7af51dbad56d16b23fe33f63ee6a5d956b3cb68ea110cbe64/cryptography-44.0.1.tar.gz", hash = "sha256:f51f5705ab27898afda1aaa430f34ad90dc117421057782022edf0600bec5f14", size = 710819 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/b9/4d1fa8d73ae6ec350012f89c3abfbff19fc95fe5420cf972e12a8d182986/cryptography-44.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7c7e2d71d908dc0f8d2027e1604102140d84b155e658c20e8ad1304317691f", size = 3943865 }, - { url = "https://files.pythonhosted.org/packages/6e/57/371a9f3f3a4500807b5fcd29fec77f418ba27ffc629d88597d0d1049696e/cryptography-44.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887143b9ff6bad2b7570da75a7fe8bbf5f65276365ac259a5d2d5147a73775f2", size = 4162562 }, - { url = "https://files.pythonhosted.org/packages/c5/1d/5b77815e7d9cf1e3166988647f336f87d5634a5ccecec2ffbe08ef8dd481/cryptography-44.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:322eb03ecc62784536bc173f1483e76747aafeb69c8728df48537eb431cd1911", size = 3951923 }, - { url = "https://files.pythonhosted.org/packages/28/01/604508cd34a4024467cd4105887cf27da128cba3edd435b54e2395064bfb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:21377472ca4ada2906bc313168c9dc7b1d7ca417b63c1c3011d0c74b7de9ae69", size = 3685194 }, - { url = "https://files.pythonhosted.org/packages/c6/3d/d3c55d4f1d24580a236a6753902ef6d8aafd04da942a1ee9efb9dc8fd0cb/cryptography-44.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:df978682c1504fc93b3209de21aeabf2375cb1571d4e61907b3e7a2540e83026", size = 4187790 }, - { url = "https://files.pythonhosted.org/packages/ea/a6/44d63950c8588bfa8594fd234d3d46e93c3841b8e84a066649c566afb972/cryptography-44.0.1-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:eb3889330f2a4a148abead555399ec9a32b13b7c8ba969b72d8e500eb7ef84cd", size = 3951343 }, - { url = "https://files.pythonhosted.org/packages/c1/17/f5282661b57301204cbf188254c1a0267dbd8b18f76337f0a7ce1038888c/cryptography-44.0.1-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8e6a85a93d0642bd774460a86513c5d9d80b5c002ca9693e63f6e540f1815ed0", size = 4187127 }, - { url = "https://files.pythonhosted.org/packages/f3/68/abbae29ed4f9d96596687f3ceea8e233f65c9645fbbec68adb7c756bb85a/cryptography-44.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6f76fdd6fd048576a04c5210d53aa04ca34d2ed63336d4abd306d0cbe298fddf", size = 4070666 }, - { url = "https://files.pythonhosted.org/packages/0f/10/cf91691064a9e0a88ae27e31779200b1505d3aee877dbe1e4e0d73b4f155/cryptography-44.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6c8acf6f3d1f47acb2248ec3ea261171a671f3d9428e34ad0357148d492c7864", size = 4288811 }, - { url = "https://files.pythonhosted.org/packages/ba/9f/1775600eb69e72d8f9931a104120f2667107a0ee478f6ad4fe4001559345/cryptography-44.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8272f257cf1cbd3f2e120f14c68bff2b6bdfcc157fafdee84a1b795efd72862", size = 3943269 }, - { url = "https://files.pythonhosted.org/packages/25/ba/e00d5ad6b58183829615be7f11f55a7b6baa5a06910faabdc9961527ba44/cryptography-44.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8d181e90a777b63f3f0caa836844a1182f1f265687fac2115fcf245f5fbec3", size = 4166461 }, - { url = "https://files.pythonhosted.org/packages/b3/45/690a02c748d719a95ab08b6e4decb9d81e0ec1bac510358f61624c86e8a3/cryptography-44.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:436df4f203482f41aad60ed1813811ac4ab102765ecae7a2bbb1dbb66dcff5a7", size = 3950314 }, - { url = "https://files.pythonhosted.org/packages/e6/50/bf8d090911347f9b75adc20f6f6569ed6ca9b9bff552e6e390f53c2a1233/cryptography-44.0.1-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4f422e8c6a28cf8b7f883eb790695d6d45b0c385a2583073f3cec434cc705e1a", size = 3686675 }, - { url = "https://files.pythonhosted.org/packages/e1/e7/cfb18011821cc5f9b21efb3f94f3241e3a658d267a3bf3a0f45543858ed8/cryptography-44.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:72198e2b5925155497a5a3e8c216c7fb3e64c16ccee11f0e7da272fa93b35c4c", size = 4190429 }, - { url = "https://files.pythonhosted.org/packages/07/ef/77c74d94a8bfc1a8a47b3cafe54af3db537f081742ee7a8a9bd982b62774/cryptography-44.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a46a89ad3e6176223b632056f321bc7de36b9f9b93b2cc1cccf935a3849dc62", size = 3950039 }, - { url = "https://files.pythonhosted.org/packages/6d/b9/8be0ff57c4592382b77406269b1e15650c9f1a167f9e34941b8515b97159/cryptography-44.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:53f23339864b617a3dfc2b0ac8d5c432625c80014c25caac9082314e9de56f41", size = 4189713 }, - { url = "https://files.pythonhosted.org/packages/78/e1/4b6ac5f4100545513b0847a4d276fe3c7ce0eacfa73e3b5ebd31776816ee/cryptography-44.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:888fcc3fce0c888785a4876ca55f9f43787f4c5c1cc1e2e0da71ad481ff82c5b", size = 4071193 }, - { url = "https://files.pythonhosted.org/packages/3d/cb/afff48ceaed15531eab70445abe500f07f8f96af2bb35d98af6bfa89ebd4/cryptography-44.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:00918d859aa4e57db8299607086f793fa7813ae2ff5a4637e318a25ef82730f7", size = 4289566 }, - { url = "https://files.pythonhosted.org/packages/e0/f1/7fb4982d59aa86e1a116c812b545e7fc045352be07738ae3fb278835a9a4/cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:610a83540765a8d8ce0f351ce42e26e53e1f774a6efb71eb1b41eb01d01c3d12", size = 3888155 }, - { url = "https://files.pythonhosted.org/packages/60/7b/cbc203838d3092203493d18b923fbbb1de64e0530b332a713ba376905b0b/cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:5fed5cd6102bb4eb843e3315d2bf25fede494509bddadb81e03a859c1bc17b83", size = 4106417 }, - { url = "https://files.pythonhosted.org/packages/12/c7/2fe59fb085ab418acc82e91e040a6acaa7b1696fcc1c1055317537fbf0d3/cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f4daefc971c2d1f82f03097dc6f216744a6cd2ac0f04c68fb935ea2ba2a0d420", size = 3887540 }, - { url = "https://files.pythonhosted.org/packages/48/89/09fc7b115f60f5bd970b80e32244f8e9aeeb9244bf870b63420cec3b5cd5/cryptography-44.0.1-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94f99f2b943b354a5b6307d7e8d19f5c423a794462bde2bf310c770ba052b1c4", size = 4106040 }, -] - -[[package]] -name = "cytoolz" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d9/f13d66c16cff1fa1cb6c234698029877c456f35f577ef274aba3b86e7c51/cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042", size = 403515 }, - { url = "https://files.pythonhosted.org/packages/4b/2d/4cdf848a69300c7d44984f2ebbebb3b8576e5449c8dea157298f3bdc4da3/cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608", size = 383936 }, - { url = "https://files.pythonhosted.org/packages/72/a4/ccfdd3f0ed9cc818f734b424261f6018fc61e3ec833bf85225a9aca0d994/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1", size = 1934569 }, - { url = "https://files.pythonhosted.org/packages/50/fc/38d5344fa595683ad10dc819cfc1d8b9d2b3391ccf3e8cb7bab4899a01f5/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da", size = 2015129 }, - { url = "https://files.pythonhosted.org/packages/28/29/75261748dc54a20a927f33641f4e9aac674cfc6d3fbd4f332e10d0b37639/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089", size = 2000506 }, - { url = "https://files.pythonhosted.org/packages/00/ae/e4ead004cc2698281d153c4a5388638d67cdb5544d6d6cc1e5b3db2bd2a3/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8", size = 1957537 }, - { url = "https://files.pythonhosted.org/packages/4a/ff/4f3aa07f4f47701f7f63df60ce0a5669fa09c256c3d4a33503a9414ea5cc/cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5", size = 1863331 }, - { url = "https://files.pythonhosted.org/packages/a2/29/654f57f2a9b8e9765a4ab876765f64f94530b61fc6471a07feea42ece6d4/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442", size = 1849938 }, - { url = "https://files.pythonhosted.org/packages/bc/7b/11f457db6b291060a98315ab2c7198077d8bddeeebe5f7126d9dad98cc54/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52", size = 1852345 }, - { url = "https://files.pythonhosted.org/packages/6b/92/0dccc96ce0323be236d404f5084479b79b747fa0e74e43a270e95868b5f9/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432", size = 1989877 }, - { url = "https://files.pythonhosted.org/packages/a3/c8/1c5203a81200bae51aa8f7b5fad613f695bf1afa03f16251ca23ecb2ef9f/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c", size = 1994492 }, - { url = "https://files.pythonhosted.org/packages/e2/8a/04bc193c4d7ced8ef6bb62cdcd0bf40b5e5eb26586ed2cfb4433ec7dfd0a/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78", size = 1896077 }, - { url = "https://files.pythonhosted.org/packages/21/a5/bee63a58f51d2c74856db66e6119a014464ff8cb1c9387fa4bd2d94e49b0/cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804", size = 322135 }, - { url = "https://files.pythonhosted.org/packages/e8/16/7abfb1685e8b7f2838264551ee33651748994813f566ac4c3d737dfe90e5/cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf", size = 363599 }, - { url = "https://files.pythonhosted.org/packages/dc/ea/8131ae39119820b8867cddc23716fa9f681f2b3bbce6f693e68dfb36b55b/cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6", size = 406162 }, - { url = "https://files.pythonhosted.org/packages/26/18/3d9bd4c146f6ea6e51300c242b20cb416966b21d481dac230e1304f1e54b/cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab", size = 384961 }, - { url = "https://files.pythonhosted.org/packages/e4/73/9034827907c7f85c7c484c9494e905d022fb8174526004e9ef332570349e/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30", size = 2091698 }, - { url = "https://files.pythonhosted.org/packages/74/af/d5c2733b0fde1a08254ff1a8a8d567874040c9eb1606363cfebc0713c73f/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b", size = 2188452 }, - { url = "https://files.pythonhosted.org/packages/6a/bb/77c71fa9c217260b4056a732d754748903423c2cdd82a673d6064741e375/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41", size = 2174203 }, - { url = "https://files.pythonhosted.org/packages/fc/a9/a5b4a3ff5d22faa1b60293bfe97362e2caf4a830c26d37ab5557f60d04b2/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd", size = 2099831 }, - { url = "https://files.pythonhosted.org/packages/35/08/7f6869ea1ff31ce5289a7d58d0e7090acfe7058baa2764473048ff61ea3c/cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3", size = 1996744 }, - { url = "https://files.pythonhosted.org/packages/46/b4/9ac424c994b51763fd1bbed62d95f8fba8fa0e45c8c3c583904fdaf8f51d/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7", size = 2013733 }, - { url = "https://files.pythonhosted.org/packages/3e/99/03009765c4b87d742d5b5a8670abb56a8c7ede033c2cdaa4be8662d3b001/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61", size = 1994850 }, - { url = "https://files.pythonhosted.org/packages/40/9a/8458af9a5557e177ea42f8cf7e477bede518b0bbef564e28c4151feaa52c/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3", size = 2155352 }, - { url = "https://files.pythonhosted.org/packages/5e/5c/2a701423e001fcbec288b4f3fc2bf67557d114c2388237fc1ae67e1e2686/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580", size = 2163515 }, - { url = "https://files.pythonhosted.org/packages/36/16/ee2e06e65d9d533bc05cd52a0b355ba9072fc8f60d77289e529c6d2e3750/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052", size = 2054431 }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2fac8315f210fa1bc7106e27c19e1211580aa25bb7fa17dfd79505e5baf2/cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead", size = 322004 }, - { url = "https://files.pythonhosted.org/packages/a9/9e/0b70b641850a95f9ff90adde9d094a4b1d81ec54dadfd97fec0a2aaf440e/cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c", size = 365358 }, - { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121 }, - { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904 }, - { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734 }, - { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933 }, - { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903 }, - { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270 }, - { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967 }, - { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695 }, - { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177 }, - { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321 }, - { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374 }, - { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911 }, - { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903 }, - { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490 }, - { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365 }, - { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233 }, - { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903 }, - { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517 }, - { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849 }, - { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302 }, - { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872 }, - { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430 }, - { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127 }, - { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369 }, - { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427 }, - { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785 }, - { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685 }, - { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898 }, - { url = "https://files.pythonhosted.org/packages/d9/f7/ef2a10daaec5c0f7d781d50758c6187eee484256e356ae8ef178d6c48497/cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96", size = 345702 }, - { url = "https://files.pythonhosted.org/packages/c8/14/53c84adddedb67ff1546abb86fea04d26e24298c3ceab8436d20122ed0b9/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10", size = 385695 }, - { url = "https://files.pythonhosted.org/packages/bd/80/3ae356c5e7b8d7dc7d1adb52f6932fee85cd748ed4e1217c269d2dfd610f/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee", size = 406261 }, - { url = "https://files.pythonhosted.org/packages/0c/31/8e43761ffc82d90bf9cab7e0959712eedcd1e33c211397e143dd42d7af57/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3", size = 397207 }, - { url = "https://files.pythonhosted.org/packages/d1/b9/fe9da37090b6444c65f848a83e390f87d8cb43d6a4df46de1556ad7e5ceb/cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47", size = 343358 }, -] - -[[package]] -name = "dacite" -version = "1.9.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600 }, -] - -[[package]] -name = "dataclasses-json" -version = "0.6.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "marshmallow" }, - { name = "typing-inspect" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686 }, -] - -[[package]] -name = "docformatter" -version = "1.7.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "charset-normalizer" }, - { name = "untokenize" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/44/aba2c40cf796121b35835ea8c00bc5d93f2f70730eca53b36b8bbbfaefe1/docformatter-1.7.5.tar.gz", hash = "sha256:ffed3da0daffa2e77f80ccba4f0e50bfa2755e1c10e130102571c890a61b246e", size = 25893 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/95/568a2fca29df365b82012b09b64964a05f4f20ac83c2137b262f3fa3188f/docformatter-1.7.5-py3-none-any.whl", hash = "sha256:a24f5545ed1f30af00d106f5d85dc2fce4959295687c24c8f39f5263afaf9186", size = 32798 }, -] - -[[package]] -name = "docutils" -version = "0.21.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, -] - -[[package]] -name = "eth-abi" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "parsimonious" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/71/d9e1380bd77fd22f98b534699af564f189b56d539cc2b9dab908d4e4c242/eth_abi-5.2.0.tar.gz", hash = "sha256:178703fa98c07d8eecd5ae569e7e8d159e493ebb6eeb534a8fe973fbc4e40ef0", size = 49797 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b4/2f3982c4cbcbf5eeb6aec62df1533c0e63c653b3021ff338d44944405676/eth_abi-5.2.0-py3-none-any.whl", hash = "sha256:17abe47560ad753f18054f5b3089fcb588f3e3a092136a416b6c1502cb7e8877", size = 28511 }, -] - -[[package]] -name = "eth-account" -version = "0.13.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "ckzg" }, - { name = "eth-abi" }, - { name = "eth-keyfile" }, - { name = "eth-keys" }, - { name = "eth-rlp" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "rlp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/23/0d/016e90c67a9c14cd38f4e7b46ef362795fe0f9be1ea4b26026846bdae68e/eth_account-0.13.5.tar.gz", hash = "sha256:010c9ce5f3d2688106cf9bfeb711bb8eaf0154ea6f85325f54fecea85c2b3759", size = 7793978 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/b9/d20fc50a5c04b23bd3e2f3d7864b529e0888f928d62b69209c778268e08e/eth_account-0.13.5-py3-none-any.whl", hash = "sha256:e43fd30c9a7fabb882b50e8c4c41d4486d2f3478ad97c66bb18cfcc872fdbec8", size = 580746 }, -] - -[[package]] -name = "eth-hash" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028 }, -] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-keys" }, - { name = "eth-utils" }, - { name = "pycryptodome" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510 }, -] - -[[package]] -name = "eth-keys" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ac/72/96db2e3d27c64d3e4a6bf1397447d029e4268fd70b0f1ee4192d6e8d75cd/eth_keys-0.6.1.tar.gz", hash = "sha256:a43e263cbcabfd62fa769168efc6c27b1f5603040e4de22bb84d12567e4fd962", size = 30090 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/67/c241c85e9cb9c4d8c14440dd82f7fbe39536592bf59c6b643004ac63eab2/eth_keys-0.6.1-py3-none-any.whl", hash = "sha256:7deae4cd56e862e099ec58b78176232b931c4ea5ecded2f50c7b1ccbc10c24cf", size = 21292 }, -] - -[[package]] -name = "eth-rlp" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "rlp" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/ea/ad39d001fa9fed07fad66edb00af701e29b48be0ed44a3bcf58cb3adf130/eth_rlp-2.2.0.tar.gz", hash = "sha256:5e4b2eb1b8213e303d6a232dfe35ab8c29e2d3051b86e8d359def80cd21db83d", size = 7720 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/3b/57efe2bc2df0980680d57c01a36516cd3171d2319ceb30e675de19fc2cc5/eth_rlp-2.2.0-py3-none-any.whl", hash = "sha256:5692d595a741fbaef1203db6a2fedffbd2506d31455a6ad378c8449ee5985c47", size = 4446 }, -] - -[[package]] -name = "eth-typing" -version = "5.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0f/6f/ecd98de0b67eefc68e17f6979433534a63e11aac88adaae7dede0b694567/eth_typing-5.1.0.tar.gz", hash = "sha256:8581f212ee6252aaa285377a77620f6e5f6e16ac3f144c61f098fafd47967b1a", size = 21727 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/2e/40e7577866f4378fb9737e0cb08e3e96e5a25b53821b0139dbfbd77dd66e/eth_typing-5.1.0-py3-none-any.whl", hash = "sha256:c0d6b93f5385aa84efc4b47ae2bd478da069bc0ffda8b67e0ccb573f43defd29", size = 19116 }, -] - -[[package]] -name = "eth-utils" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cytoolz", marker = "implementation_name == 'cpython'" }, - { name = "eth-hash" }, - { name = "eth-typing" }, - { name = "toolz", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/27/e9/f4210d19fa45a23b239017cd75b535d594d8945ef6afc4bb3ab9ee4ff269/eth_utils-5.2.0.tar.gz", hash = "sha256:17e474eb654df6e18f20797b22c6caabb77415a996b3ba0f3cc8df3437463134", size = 120366 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/88/e4e2cc869eaab9a830ac69f213d0609a4f5c5377cde10698cdef6ad2874e/eth_utils-5.2.0-py3-none-any.whl", hash = "sha256:4d43eeb6720e89a042ad5b28d4b2111630ae764f444b85cbafb708d7f076da10", size = 100516 }, -] - -[[package]] -name = "exceptiongroup" -version = "1.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, -] - -[[package]] -name = "frozenlist" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8f/ed/0f4cec13a93c02c47ec32d81d11c0c1efbadf4a471e3f3ce7cad366cbbd3/frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", size = 39930 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/79/29d44c4af36b2b240725dce566b20f63f9b36ef267aaaa64ee7466f4f2f8/frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a", size = 94451 }, - { url = "https://files.pythonhosted.org/packages/47/47/0c999aeace6ead8a44441b4f4173e2261b18219e4ad1fe9a479871ca02fc/frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb", size = 54301 }, - { url = "https://files.pythonhosted.org/packages/8d/60/107a38c1e54176d12e06e9d4b5d755b677d71d1219217cee063911b1384f/frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec", size = 52213 }, - { url = "https://files.pythonhosted.org/packages/17/62/594a6829ac5679c25755362a9dc93486a8a45241394564309641425d3ff6/frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5", size = 240946 }, - { url = "https://files.pythonhosted.org/packages/7e/75/6c8419d8f92c80dd0ee3f63bdde2702ce6398b0ac8410ff459f9b6f2f9cb/frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76", size = 264608 }, - { url = "https://files.pythonhosted.org/packages/88/3e/82a6f0b84bc6fb7e0be240e52863c6d4ab6098cd62e4f5b972cd31e002e8/frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17", size = 261361 }, - { url = "https://files.pythonhosted.org/packages/fd/85/14e5f9ccac1b64ff2f10c927b3ffdf88772aea875882406f9ba0cec8ad84/frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba", size = 231649 }, - { url = "https://files.pythonhosted.org/packages/ee/59/928322800306f6529d1852323014ee9008551e9bb027cc38d276cbc0b0e7/frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d", size = 241853 }, - { url = "https://files.pythonhosted.org/packages/7d/bd/e01fa4f146a6f6c18c5d34cab8abdc4013774a26c4ff851128cd1bd3008e/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2", size = 243652 }, - { url = "https://files.pythonhosted.org/packages/a5/bd/e4771fd18a8ec6757033f0fa903e447aecc3fbba54e3630397b61596acf0/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f", size = 241734 }, - { url = "https://files.pythonhosted.org/packages/21/13/c83821fa5544af4f60c5d3a65d054af3213c26b14d3f5f48e43e5fb48556/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c", size = 260959 }, - { url = "https://files.pythonhosted.org/packages/71/f3/1f91c9a9bf7ed0e8edcf52698d23f3c211d8d00291a53c9f115ceb977ab1/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab", size = 262706 }, - { url = "https://files.pythonhosted.org/packages/4c/22/4a256fdf5d9bcb3ae32622c796ee5ff9451b3a13a68cfe3f68e2c95588ce/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5", size = 250401 }, - { url = "https://files.pythonhosted.org/packages/af/89/c48ebe1f7991bd2be6d5f4ed202d94960c01b3017a03d6954dd5fa9ea1e8/frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb", size = 45498 }, - { url = "https://files.pythonhosted.org/packages/28/2f/cc27d5f43e023d21fe5c19538e08894db3d7e081cbf582ad5ed366c24446/frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4", size = 51622 }, - { url = "https://files.pythonhosted.org/packages/79/43/0bed28bf5eb1c9e4301003b74453b8e7aa85fb293b31dde352aac528dafc/frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30", size = 94987 }, - { url = "https://files.pythonhosted.org/packages/bb/bf/b74e38f09a246e8abbe1e90eb65787ed745ccab6eaa58b9c9308e052323d/frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5", size = 54584 }, - { url = "https://files.pythonhosted.org/packages/2c/31/ab01375682f14f7613a1ade30149f684c84f9b8823a4391ed950c8285656/frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778", size = 52499 }, - { url = "https://files.pythonhosted.org/packages/98/a8/d0ac0b9276e1404f58fec3ab6e90a4f76b778a49373ccaf6a563f100dfbc/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a", size = 276357 }, - { url = "https://files.pythonhosted.org/packages/ad/c9/c7761084fa822f07dac38ac29f841d4587570dd211e2262544aa0b791d21/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869", size = 287516 }, - { url = "https://files.pythonhosted.org/packages/a1/ff/cd7479e703c39df7bdab431798cef89dc75010d8aa0ca2514c5b9321db27/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d", size = 283131 }, - { url = "https://files.pythonhosted.org/packages/59/a0/370941beb47d237eca4fbf27e4e91389fd68699e6f4b0ebcc95da463835b/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45", size = 261320 }, - { url = "https://files.pythonhosted.org/packages/b8/5f/c10123e8d64867bc9b4f2f510a32042a306ff5fcd7e2e09e5ae5100ee333/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d", size = 274877 }, - { url = "https://files.pythonhosted.org/packages/fa/79/38c505601ae29d4348f21706c5d89755ceded02a745016ba2f58bd5f1ea6/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3", size = 269592 }, - { url = "https://files.pythonhosted.org/packages/19/e2/39f3a53191b8204ba9f0bb574b926b73dd2efba2a2b9d2d730517e8f7622/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a", size = 265934 }, - { url = "https://files.pythonhosted.org/packages/d5/c9/3075eb7f7f3a91f1a6b00284af4de0a65a9ae47084930916f5528144c9dd/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9", size = 283859 }, - { url = "https://files.pythonhosted.org/packages/05/f5/549f44d314c29408b962fa2b0e69a1a67c59379fb143b92a0a065ffd1f0f/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2", size = 287560 }, - { url = "https://files.pythonhosted.org/packages/9d/f8/cb09b3c24a3eac02c4c07a9558e11e9e244fb02bf62c85ac2106d1eb0c0b/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf", size = 277150 }, - { url = "https://files.pythonhosted.org/packages/37/48/38c2db3f54d1501e692d6fe058f45b6ad1b358d82cd19436efab80cfc965/frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942", size = 45244 }, - { url = "https://files.pythonhosted.org/packages/ca/8c/2ddffeb8b60a4bce3b196c32fcc30d8830d4615e7b492ec2071da801b8ad/frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d", size = 51634 }, - { url = "https://files.pythonhosted.org/packages/79/73/fa6d1a96ab7fd6e6d1c3500700963eab46813847f01ef0ccbaa726181dd5/frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", size = 94026 }, - { url = "https://files.pythonhosted.org/packages/ab/04/ea8bf62c8868b8eada363f20ff1b647cf2e93377a7b284d36062d21d81d1/frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", size = 54150 }, - { url = "https://files.pythonhosted.org/packages/d0/9a/8e479b482a6f2070b26bda572c5e6889bb3ba48977e81beea35b5ae13ece/frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", size = 51927 }, - { url = "https://files.pythonhosted.org/packages/e3/12/2aad87deb08a4e7ccfb33600871bbe8f0e08cb6d8224371387f3303654d7/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a", size = 282647 }, - { url = "https://files.pythonhosted.org/packages/77/f2/07f06b05d8a427ea0060a9cef6e63405ea9e0d761846b95ef3fb3be57111/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", size = 289052 }, - { url = "https://files.pythonhosted.org/packages/bd/9f/8bf45a2f1cd4aa401acd271b077989c9267ae8463e7c8b1eb0d3f561b65e/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", size = 291719 }, - { url = "https://files.pythonhosted.org/packages/41/d1/1f20fd05a6c42d3868709b7604c9f15538a29e4f734c694c6bcfc3d3b935/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", size = 267433 }, - { url = "https://files.pythonhosted.org/packages/af/f2/64b73a9bb86f5a89fb55450e97cd5c1f84a862d4ff90d9fd1a73ab0f64a5/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", size = 283591 }, - { url = "https://files.pythonhosted.org/packages/29/e2/ffbb1fae55a791fd6c2938dd9ea779509c977435ba3940b9f2e8dc9d5316/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", size = 273249 }, - { url = "https://files.pythonhosted.org/packages/2e/6e/008136a30798bb63618a114b9321b5971172a5abddff44a100c7edc5ad4f/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", size = 271075 }, - { url = "https://files.pythonhosted.org/packages/ae/f0/4e71e54a026b06724cec9b6c54f0b13a4e9e298cc8db0f82ec70e151f5ce/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", size = 285398 }, - { url = "https://files.pythonhosted.org/packages/4d/36/70ec246851478b1c0b59f11ef8ade9c482ff447c1363c2bd5fad45098b12/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", size = 294445 }, - { url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 }, - { url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 }, - { url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 }, - { url = "https://files.pythonhosted.org/packages/da/3b/915f0bca8a7ea04483622e84a9bd90033bab54bdf485479556c74fd5eaf5/frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", size = 91538 }, - { url = "https://files.pythonhosted.org/packages/c7/d1/a7c98aad7e44afe5306a2b068434a5830f1470675f0e715abb86eb15f15b/frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", size = 52849 }, - { url = "https://files.pythonhosted.org/packages/3a/c8/76f23bf9ab15d5f760eb48701909645f686f9c64fbb8982674c241fbef14/frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", size = 50583 }, - { url = "https://files.pythonhosted.org/packages/1f/22/462a3dd093d11df623179d7754a3b3269de3b42de2808cddef50ee0f4f48/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", size = 265636 }, - { url = "https://files.pythonhosted.org/packages/80/cf/e075e407fc2ae7328155a1cd7e22f932773c8073c1fc78016607d19cc3e5/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", size = 270214 }, - { url = "https://files.pythonhosted.org/packages/a1/58/0642d061d5de779f39c50cbb00df49682832923f3d2ebfb0fedf02d05f7f/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", size = 273905 }, - { url = "https://files.pythonhosted.org/packages/ab/66/3fe0f5f8f2add5b4ab7aa4e199f767fd3b55da26e3ca4ce2cc36698e50c4/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", size = 250542 }, - { url = "https://files.pythonhosted.org/packages/f6/b8/260791bde9198c87a465224e0e2bb62c4e716f5d198fc3a1dacc4895dbd1/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", size = 267026 }, - { url = "https://files.pythonhosted.org/packages/2e/a4/3d24f88c527f08f8d44ade24eaee83b2627793fa62fa07cbb7ff7a2f7d42/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", size = 257690 }, - { url = "https://files.pythonhosted.org/packages/de/9a/d311d660420b2beeff3459b6626f2ab4fb236d07afbdac034a4371fe696e/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", size = 253893 }, - { url = "https://files.pythonhosted.org/packages/c6/23/e491aadc25b56eabd0f18c53bb19f3cdc6de30b2129ee0bc39cd387cd560/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", size = 267006 }, - { url = "https://files.pythonhosted.org/packages/08/c4/ab918ce636a35fb974d13d666dcbe03969592aeca6c3ab3835acff01f79c/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", size = 276157 }, - { url = "https://files.pythonhosted.org/packages/c0/29/3b7a0bbbbe5a34833ba26f686aabfe982924adbdcafdc294a7a129c31688/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", size = 264642 }, - { url = "https://files.pythonhosted.org/packages/ab/42/0595b3dbffc2e82d7fe658c12d5a5bafcd7516c6bf2d1d1feb5387caa9c1/frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", size = 44914 }, - { url = "https://files.pythonhosted.org/packages/17/c4/b7db1206a3fea44bf3b838ca61deb6f74424a8a5db1dd53ecb21da669be6/frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", size = 51167 }, - { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, -] - -[[package]] -name = "grvt-pysdk" -version = "0.2.1" -source = { editable = "." } -dependencies = [ - { name = "aiohttp" }, - { name = "backports-weakref" }, - { name = "dacite" }, - { name = "dataclasses-json" }, - { name = "eth-account" }, - { name = "inflection" }, - { name = "requests" }, - { name = "websockets" }, -] - -[package.dev-dependencies] -dev = [ - { name = "bandit" }, - { name = "docformatter" }, - { name = "mypy" }, - { name = "pytest" }, - { name = "pytest-cov" }, - { name = "ruff" }, - { name = "twine" }, -] - -[package.metadata] -requires-dist = [ - { name = "aiohttp", specifier = ">=3.10.11" }, - { name = "backports-weakref", specifier = ">=1.0.post1" }, - { name = "dacite", specifier = ">=1.8.1" }, - { name = "dataclasses-json", specifier = ">=0.6.7" }, - { name = "eth-account", specifier = ">=0.13.4" }, - { name = "inflection", specifier = ">=0.5.1" }, - { name = "requests", specifier = ">=2.32.3" }, - { name = "websockets", specifier = "==13.1" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "bandit", specifier = ">=1.7.9" }, - { name = "docformatter", specifier = ">=1.7.5" }, - { name = "mypy", specifier = ">=1.11.2" }, - { name = "pytest", specifier = ">=8.3.2" }, - { name = "pytest-cov", specifier = ">=5.0.0" }, - { name = "ruff", specifier = ">=0.6.2" }, - { name = "twine", specifier = ">=5.1.1" }, -] - -[[package]] -name = "hexbytes" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/71/1a3f2439cf138b555c182fffeffbf67c090837e4570370af85ee8e57013f/hexbytes-1.3.0.tar.gz", hash = "sha256:4a61840c24b0909a6534350e2d28ee50159ca1c9e89ce275fd31c110312cf684", size = 8200 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/96/035871b535a728700d3cc5b94cf883706f345c5a088253f26f0bee0b7939/hexbytes-1.3.0-py3-none-any.whl", hash = "sha256:83720b529c6e15ed21627962938dc2dec9bb1010f17bbbd66bf1e6a8287d522c", size = 4902 }, -] - -[[package]] -name = "id" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/22/11/102da08f88412d875fa2f1a9a469ff7ad4c874b0ca6fed0048fe385bdb3d/id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d", size = 15237 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/cb/18326d2d89ad3b0dd143da971e77afd1e6ca6674f1b1c3df4b6bec6279fc/id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658", size = 13611 }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, -] - -[[package]] -name = "importlib-metadata" -version = "8.6.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "zipp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/33/08/c1395a292bb23fd03bdf572a1357c5a733d3eecbab877641ceacab23db6e/importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580", size = 55767 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/9d/0fb148dc4d6fa4a7dd1d8378168d9b4cd8d4560a6fbf6f0121c5fc34eb68/importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e", size = 26971 }, -] - -[[package]] -name = "inflection" -version = "0.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e1/7e/691d061b7329bc8d54edbf0ec22fbfb2afe61facb681f9aaa9bff7a27d04/inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", size = 15091 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2", size = 9454 }, -] - -[[package]] -name = "iniconfig" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, -] - -[[package]] -name = "jaraco-classes" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "more-itertools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777 }, -] - -[[package]] -name = "jaraco-context" -version = "6.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "backports-tarfile", marker = "python_full_version < '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", size = 13912 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", size = 6825 }, -] - -[[package]] -name = "jaraco-functools" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "more-itertools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ab/23/9894b3df5d0a6eb44611c36aec777823fc2e07740dabbd0b810e19594013/jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", size = 19159 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649", size = 10187 }, -] - -[[package]] -name = "jeepney" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/f4/154cf374c2daf2020e05c3c6a03c91348d59b23c5366e968feb198306fdf/jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806", size = 106005 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/72/2a1e2290f1ab1e06f71f3d0f1646c9e4634e70e1d37491535e19266e8dc9/jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755", size = 48435 }, -] - -[[package]] -name = "keyring" -version = "25.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "importlib-metadata", marker = "python_full_version < '3.12'" }, - { name = "jaraco-classes" }, - { name = "jaraco-context" }, - { name = "jaraco-functools" }, - { name = "jeepney", marker = "sys_platform == 'linux'" }, - { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, - { name = "secretstorage", marker = "sys_platform == 'linux'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/09/d904a6e96f76ff214be59e7aa6ef7190008f52a0ab6689760a98de0bf37d/keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", size = 62750 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd", size = 39085 }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, -] - -[[package]] -name = "marshmallow" -version = "3.26.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ab/5e/5e53d26b42ab75491cda89b871dab9e97c840bf12c63ec58a1919710cd06/marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6", size = 221825 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/75/51952c7b2d3873b44a0028b1bd26a25078c18f92f256608e8d1dc61b39fd/marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c", size = 50878 }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, -] - -[[package]] -name = "more-itertools" -version = "10.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/3b/7fa1fe835e2e93fd6d7b52b2f95ae810cf5ba133e1845f726f5a992d62c2/more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b", size = 125009 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/62/0fe302c6d1be1c777cab0616e6302478251dfbf9055ad426f5d0def75c89/more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89", size = 63038 }, -] - -[[package]] -name = "multidict" -version = "6.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/be/504b89a5e9ca731cd47487e91c469064f8ae5af93b7259758dcfc2b9c848/multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", size = 64002 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/68/259dee7fd14cf56a17c554125e534f6274c2860159692a414d0b402b9a6d/multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", size = 48628 }, - { url = "https://files.pythonhosted.org/packages/50/79/53ba256069fe5386a4a9e80d4e12857ced9de295baf3e20c68cdda746e04/multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", size = 29327 }, - { url = "https://files.pythonhosted.org/packages/ff/10/71f1379b05b196dae749b5ac062e87273e3f11634f447ebac12a571d90ae/multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", size = 29689 }, - { url = "https://files.pythonhosted.org/packages/71/45/70bac4f87438ded36ad4793793c0095de6572d433d98575a5752629ef549/multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", size = 126639 }, - { url = "https://files.pythonhosted.org/packages/80/cf/17f35b3b9509b4959303c05379c4bfb0d7dd05c3306039fc79cf035bbac0/multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", size = 134315 }, - { url = "https://files.pythonhosted.org/packages/ef/1f/652d70ab5effb33c031510a3503d4d6efc5ec93153562f1ee0acdc895a57/multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", size = 129471 }, - { url = "https://files.pythonhosted.org/packages/a6/64/2dd6c4c681688c0165dea3975a6a4eab4944ea30f35000f8b8af1df3148c/multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", size = 124585 }, - { url = "https://files.pythonhosted.org/packages/87/56/e6ee5459894c7e554b57ba88f7257dc3c3d2d379cb15baaa1e265b8c6165/multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", size = 116957 }, - { url = "https://files.pythonhosted.org/packages/36/9e/616ce5e8d375c24b84f14fc263c7ef1d8d5e8ef529dbc0f1df8ce71bb5b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db", size = 128609 }, - { url = "https://files.pythonhosted.org/packages/8c/4f/4783e48a38495d000f2124020dc96bacc806a4340345211b1ab6175a6cb4/multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", size = 123016 }, - { url = "https://files.pythonhosted.org/packages/3e/b3/4950551ab8fc39862ba5e9907dc821f896aa829b4524b4deefd3e12945ab/multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", size = 133542 }, - { url = "https://files.pythonhosted.org/packages/96/4d/f0ce6ac9914168a2a71df117935bb1f1781916acdecbb43285e225b484b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", size = 130163 }, - { url = "https://files.pythonhosted.org/packages/be/72/17c9f67e7542a49dd252c5ae50248607dfb780bcc03035907dafefb067e3/multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", size = 126832 }, - { url = "https://files.pythonhosted.org/packages/71/9f/72d719e248cbd755c8736c6d14780533a1606ffb3fbb0fbd77da9f0372da/multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", size = 26402 }, - { url = "https://files.pythonhosted.org/packages/04/5a/d88cd5d00a184e1ddffc82aa2e6e915164a6d2641ed3606e766b5d2f275a/multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", size = 28800 }, - { url = "https://files.pythonhosted.org/packages/93/13/df3505a46d0cd08428e4c8169a196131d1b0c4b515c3649829258843dde6/multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", size = 48570 }, - { url = "https://files.pythonhosted.org/packages/f0/e1/a215908bfae1343cdb72f805366592bdd60487b4232d039c437fe8f5013d/multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", size = 29316 }, - { url = "https://files.pythonhosted.org/packages/70/0f/6dc70ddf5d442702ed74f298d69977f904960b82368532c88e854b79f72b/multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", size = 29640 }, - { url = "https://files.pythonhosted.org/packages/d8/6d/9c87b73a13d1cdea30b321ef4b3824449866bd7f7127eceed066ccb9b9ff/multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", size = 131067 }, - { url = "https://files.pythonhosted.org/packages/cc/1e/1b34154fef373371fd6c65125b3d42ff5f56c7ccc6bfff91b9b3c60ae9e0/multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", size = 138507 }, - { url = "https://files.pythonhosted.org/packages/fb/e0/0bc6b2bac6e461822b5f575eae85da6aae76d0e2a79b6665d6206b8e2e48/multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", size = 133905 }, - { url = "https://files.pythonhosted.org/packages/ba/af/73d13b918071ff9b2205fcf773d316e0f8fefb4ec65354bbcf0b10908cc6/multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", size = 129004 }, - { url = "https://files.pythonhosted.org/packages/74/21/23960627b00ed39643302d81bcda44c9444ebcdc04ee5bedd0757513f259/multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", size = 121308 }, - { url = "https://files.pythonhosted.org/packages/8b/5c/cf282263ffce4a596ed0bb2aa1a1dddfe1996d6a62d08842a8d4b33dca13/multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", size = 132608 }, - { url = "https://files.pythonhosted.org/packages/d7/3e/97e778c041c72063f42b290888daff008d3ab1427f5b09b714f5a8eff294/multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", size = 127029 }, - { url = "https://files.pythonhosted.org/packages/47/ac/3efb7bfe2f3aefcf8d103e9a7162572f01936155ab2f7ebcc7c255a23212/multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", size = 137594 }, - { url = "https://files.pythonhosted.org/packages/42/9b/6c6e9e8dc4f915fc90a9b7798c44a30773dea2995fdcb619870e705afe2b/multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", size = 134556 }, - { url = "https://files.pythonhosted.org/packages/1d/10/8e881743b26aaf718379a14ac58572a240e8293a1c9d68e1418fb11c0f90/multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", size = 130993 }, - { url = "https://files.pythonhosted.org/packages/45/84/3eb91b4b557442802d058a7579e864b329968c8d0ea57d907e7023c677f2/multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", size = 26405 }, - { url = "https://files.pythonhosted.org/packages/9f/0b/ad879847ecbf6d27e90a6eabb7eff6b62c129eefe617ea45eae7c1f0aead/multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", size = 28795 }, - { url = "https://files.pythonhosted.org/packages/fd/16/92057c74ba3b96d5e211b553895cd6dc7cc4d1e43d9ab8fafc727681ef71/multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", size = 48713 }, - { url = "https://files.pythonhosted.org/packages/94/3d/37d1b8893ae79716179540b89fc6a0ee56b4a65fcc0d63535c6f5d96f217/multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", size = 29516 }, - { url = "https://files.pythonhosted.org/packages/a2/12/adb6b3200c363062f805275b4c1e656be2b3681aada66c80129932ff0bae/multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", size = 29557 }, - { url = "https://files.pythonhosted.org/packages/47/e9/604bb05e6e5bce1e6a5cf80a474e0f072e80d8ac105f1b994a53e0b28c42/multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", size = 130170 }, - { url = "https://files.pythonhosted.org/packages/7e/13/9efa50801785eccbf7086b3c83b71a4fb501a4d43549c2f2f80b8787d69f/multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", size = 134836 }, - { url = "https://files.pythonhosted.org/packages/bf/0f/93808b765192780d117814a6dfcc2e75de6dcc610009ad408b8814dca3ba/multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", size = 133475 }, - { url = "https://files.pythonhosted.org/packages/d3/c8/529101d7176fe7dfe1d99604e48d69c5dfdcadb4f06561f465c8ef12b4df/multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", size = 131049 }, - { url = "https://files.pythonhosted.org/packages/ca/0c/fc85b439014d5a58063e19c3a158a889deec399d47b5269a0f3b6a2e28bc/multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", size = 120370 }, - { url = "https://files.pythonhosted.org/packages/db/46/d4416eb20176492d2258fbd47b4abe729ff3b6e9c829ea4236f93c865089/multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", size = 125178 }, - { url = "https://files.pythonhosted.org/packages/5b/46/73697ad7ec521df7de5531a32780bbfd908ded0643cbe457f981a701457c/multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", size = 119567 }, - { url = "https://files.pythonhosted.org/packages/cd/ed/51f060e2cb0e7635329fa6ff930aa5cffa17f4c7f5c6c3ddc3500708e2f2/multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", size = 129822 }, - { url = "https://files.pythonhosted.org/packages/df/9e/ee7d1954b1331da3eddea0c4e08d9142da5f14b1321c7301f5014f49d492/multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", size = 128656 }, - { url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 }, - { url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 }, - { url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 }, - { url = "https://files.pythonhosted.org/packages/22/67/1c7c0f39fe069aa4e5d794f323be24bf4d33d62d2a348acdb7991f8f30db/multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", size = 48771 }, - { url = "https://files.pythonhosted.org/packages/3c/25/c186ee7b212bdf0df2519eacfb1981a017bda34392c67542c274651daf23/multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", size = 29533 }, - { url = "https://files.pythonhosted.org/packages/67/5e/04575fd837e0958e324ca035b339cea174554f6f641d3fb2b4f2e7ff44a2/multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", size = 29595 }, - { url = "https://files.pythonhosted.org/packages/d3/b2/e56388f86663810c07cfe4a3c3d87227f3811eeb2d08450b9e5d19d78876/multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", size = 130094 }, - { url = "https://files.pythonhosted.org/packages/6c/ee/30ae9b4186a644d284543d55d491fbd4239b015d36b23fea43b4c94f7052/multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", size = 134876 }, - { url = "https://files.pythonhosted.org/packages/84/c7/70461c13ba8ce3c779503c70ec9d0345ae84de04521c1f45a04d5f48943d/multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", size = 133500 }, - { url = "https://files.pythonhosted.org/packages/4a/9f/002af221253f10f99959561123fae676148dd730e2daa2cd053846a58507/multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", size = 131099 }, - { url = "https://files.pythonhosted.org/packages/82/42/d1c7a7301d52af79d88548a97e297f9d99c961ad76bbe6f67442bb77f097/multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", size = 120403 }, - { url = "https://files.pythonhosted.org/packages/68/f3/471985c2c7ac707547553e8f37cff5158030d36bdec4414cb825fbaa5327/multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", size = 125348 }, - { url = "https://files.pythonhosted.org/packages/67/2c/e6df05c77e0e433c214ec1d21ddd203d9a4770a1f2866a8ca40a545869a0/multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", size = 119673 }, - { url = "https://files.pythonhosted.org/packages/c5/cd/bc8608fff06239c9fb333f9db7743a1b2eafe98c2666c9a196e867a3a0a4/multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", size = 129927 }, - { url = "https://files.pythonhosted.org/packages/44/8e/281b69b7bc84fc963a44dc6e0bbcc7150e517b91df368a27834299a526ac/multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", size = 128711 }, - { url = "https://files.pythonhosted.org/packages/12/a4/63e7cd38ed29dd9f1881d5119f272c898ca92536cdb53ffe0843197f6c85/multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", size = 125519 }, - { url = "https://files.pythonhosted.org/packages/38/e0/4f5855037a72cd8a7a2f60a3952d9aa45feedb37ae7831642102604e8a37/multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", size = 26426 }, - { url = "https://files.pythonhosted.org/packages/7e/a5/17ee3a4db1e310b7405f5d25834460073a8ccd86198ce044dfaf69eac073/multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", size = 28531 }, - { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, -] - -[[package]] -name = "mypy" -version = "1.15.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mypy-extensions" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/f8/65a7ce8d0e09b6329ad0c8d40330d100ea343bd4dd04c4f8ae26462d0a17/mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13", size = 10738433 }, - { url = "https://files.pythonhosted.org/packages/b4/95/9c0ecb8eacfe048583706249439ff52105b3f552ea9c4024166c03224270/mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559", size = 9861472 }, - { url = "https://files.pythonhosted.org/packages/84/09/9ec95e982e282e20c0d5407bc65031dfd0f0f8ecc66b69538296e06fcbee/mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b", size = 11611424 }, - { url = "https://files.pythonhosted.org/packages/78/13/f7d14e55865036a1e6a0a69580c240f43bc1f37407fe9235c0d4ef25ffb0/mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3", size = 12365450 }, - { url = "https://files.pythonhosted.org/packages/48/e1/301a73852d40c241e915ac6d7bcd7fedd47d519246db2d7b86b9d7e7a0cb/mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b", size = 12551765 }, - { url = "https://files.pythonhosted.org/packages/77/ba/c37bc323ae5fe7f3f15a28e06ab012cd0b7552886118943e90b15af31195/mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828", size = 9274701 }, - { url = "https://files.pythonhosted.org/packages/03/bc/f6339726c627bd7ca1ce0fa56c9ae2d0144604a319e0e339bdadafbbb599/mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f", size = 10662338 }, - { url = "https://files.pythonhosted.org/packages/e2/90/8dcf506ca1a09b0d17555cc00cd69aee402c203911410136cd716559efe7/mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5", size = 9787540 }, - { url = "https://files.pythonhosted.org/packages/05/05/a10f9479681e5da09ef2f9426f650d7b550d4bafbef683b69aad1ba87457/mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e", size = 11538051 }, - { url = "https://files.pythonhosted.org/packages/e9/9a/1f7d18b30edd57441a6411fcbc0c6869448d1a4bacbaee60656ac0fc29c8/mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c", size = 12286751 }, - { url = "https://files.pythonhosted.org/packages/72/af/19ff499b6f1dafcaf56f9881f7a965ac2f474f69f6f618b5175b044299f5/mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f", size = 12421783 }, - { url = "https://files.pythonhosted.org/packages/96/39/11b57431a1f686c1aed54bf794870efe0f6aeca11aca281a0bd87a5ad42c/mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f", size = 9265618 }, - { url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981 }, - { url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175 }, - { url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675 }, - { url = "https://files.pythonhosted.org/packages/b3/d0/92ae4cde706923a2d3f2d6c39629134063ff64b9dedca9c1388363da072d/mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", size = 12410020 }, - { url = "https://files.pythonhosted.org/packages/46/8b/df49974b337cce35f828ba6fda228152d6db45fed4c86ba56ffe442434fd/mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", size = 12498582 }, - { url = "https://files.pythonhosted.org/packages/13/50/da5203fcf6c53044a0b699939f31075c45ae8a4cadf538a9069b165c1050/mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", size = 9366614 }, - { url = "https://files.pythonhosted.org/packages/6a/9b/fd2e05d6ffff24d912f150b87db9e364fa8282045c875654ce7e32fffa66/mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445", size = 10788592 }, - { url = "https://files.pythonhosted.org/packages/74/37/b246d711c28a03ead1fd906bbc7106659aed7c089d55fe40dd58db812628/mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d", size = 9753611 }, - { url = "https://files.pythonhosted.org/packages/a6/ac/395808a92e10cfdac8003c3de9a2ab6dc7cde6c0d2a4df3df1b815ffd067/mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5", size = 11438443 }, - { url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541 }, - { url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348 }, - { url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648 }, - { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777 }, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, -] - -[[package]] -name = "nh3" -version = "0.2.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/f2/eb781d94c7855e9129cbbdd3ab09a470441e4176a82a396ae1df270a7333/nh3-0.2.20.tar.gz", hash = "sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5", size = 17489 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/65/d31d93b6d1e5fe80d0cc18f0b96eaa561edfa0a15a6ef6b0fce50202a931/nh3-0.2.20-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db", size = 1202187 }, - { url = "https://files.pythonhosted.org/packages/b4/ae/5b03bf198e06921454012e4b9a51e676d26fd37d9fdc1f29371a0b380487/nh3-0.2.20-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a", size = 737822 }, - { url = "https://files.pythonhosted.org/packages/0a/53/a12dffb6ee3772deba82eb5997667fc835afd2e813d1f4080d8738f29eec/nh3-0.2.20-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c", size = 756643 }, - { url = "https://files.pythonhosted.org/packages/d0/0c/6cd2c5ac3e6e31f2a28721e8e2a924cb6b05ad054bf787bd1816ffd40b96/nh3-0.2.20-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2", size = 923415 }, - { url = "https://files.pythonhosted.org/packages/64/f0/229a6c8b81b86ba22d8e7f27ade62cb2fcfb987e570f49944fdd8490a76a/nh3-0.2.20-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5", size = 994959 }, - { url = "https://files.pythonhosted.org/packages/75/e3/62ae3d3b658739ee15b129356fe6d4c4bc8ab235d7bf2e0d2794d64f7bc6/nh3-0.2.20-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0", size = 915777 }, - { url = "https://files.pythonhosted.org/packages/45/bd/8405d03371e335f02eb72e09dcf73307f8fd3095e4165cec6836346fe3db/nh3-0.2.20-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208", size = 908614 }, - { url = "https://files.pythonhosted.org/packages/ee/f8/5d977f09cf82c1f22a864375f471db111530fc79c88efdf0659fe6d3d6bc/nh3-0.2.20-cp313-cp313t-win32.whl", hash = "sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886", size = 540482 }, - { url = "https://files.pythonhosted.org/packages/c5/f4/e34afe5fd8bed1920eac2974c9c853f548b4b65c139444285ffd2a68495d/nh3-0.2.20-cp313-cp313t-win_amd64.whl", hash = "sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150", size = 541302 }, - { url = "https://files.pythonhosted.org/packages/92/08/5e3b61eed1bc0efeb330ddc5cf5194f28a0b7be7943aa20bd44cfe14650b/nh3-0.2.20-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776", size = 1202141 }, - { url = "https://files.pythonhosted.org/packages/29/d2/3377f8006c71e95e007b07b5bfcac22c9de4744ca3efb23b396d3deb9581/nh3-0.2.20-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38", size = 760699 }, - { url = "https://files.pythonhosted.org/packages/37/d7/7077f925d7d680d53dcb6e18a4af13d1a7da59761c06c193bfa249a7470a/nh3-0.2.20-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7", size = 747353 }, - { url = "https://files.pythonhosted.org/packages/cb/59/6b2f32af477aae81f1454a7f6ef490ebc3c22dd9e1370e73fcfe243dc07a/nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace", size = 854125 }, - { url = "https://files.pythonhosted.org/packages/5b/f2/c3d2f7b801477b8b387b51fbefd16dc7ade888aeac547f18ba0558fd6f48/nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6", size = 817453 }, - { url = "https://files.pythonhosted.org/packages/42/4d/f7e3a35506a0eba6eedafc21ad52773985511eb838812e9f96354831ad3c/nh3-0.2.20-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b", size = 891694 }, - { url = "https://files.pythonhosted.org/packages/e6/0e/c499453c296fb40366e3069cd68fde77a10f0a30a17b9d3b491eb3ebc5bf/nh3-0.2.20-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b", size = 744388 }, - { url = "https://files.pythonhosted.org/packages/18/67/c3de8022ba2719bdbbdd3704d1e32dbc7d3f8ac8646247711645fc90d051/nh3-0.2.20-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d", size = 764831 }, - { url = "https://files.pythonhosted.org/packages/f0/14/a4ea40e2439717d11c3104fc2dc0ac412301b7aeb81d6a3d0e6505c77e7d/nh3-0.2.20-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a", size = 923334 }, - { url = "https://files.pythonhosted.org/packages/ed/ae/e8ee8afaf67903dd304f390056d1ea620327524e2ad66127a331b14d5d98/nh3-0.2.20-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397", size = 994873 }, - { url = "https://files.pythonhosted.org/packages/20/b5/02122cfe3b36cf0ba0fcd73a04fd462e1f7a9d91b456f6e0b70e46df21c7/nh3-0.2.20-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec", size = 915707 }, - { url = "https://files.pythonhosted.org/packages/47/d3/5df43cc3570cdc9eb1dc79a39191f89fedf8bcefd8d30a161ff1dffb146c/nh3-0.2.20-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330", size = 908539 }, - { url = "https://files.pythonhosted.org/packages/4f/fd/aa000f6c76a832c488eac26f20d2e8a221ba2b965efce692f14ebc4290bf/nh3-0.2.20-cp38-abi3-win32.whl", hash = "sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784", size = 540439 }, - { url = "https://files.pythonhosted.org/packages/19/31/d65594efd3b42b1de2335d576eb77525691fc320dbf8617948ee05c008e5/nh3-0.2.20-cp38-abi3-win_amd64.whl", hash = "sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b", size = 541249 }, -] - -[[package]] -name = "packaging" -version = "24.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427 }, -] - -[[package]] -name = "pbr" -version = "6.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "setuptools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/01/d2/510cc0d218e753ba62a1bc1434651db3cd797a9716a0a66cc714cb4f0935/pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b", size = 125702 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/ac/684d71315abc7b1214d59304e23a982472967f6bf4bde5a98f1503f648dc/pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76", size = 108997 }, -] - -[[package]] -name = "pluggy" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, -] - -[[package]] -name = "propcache" -version = "0.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/c8/2a13f78d82211490855b2fb303b6721348d0787fdd9a12ac46d99d3acde1/propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", size = 41735 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/a5/0ea64c9426959ef145a938e38c832fc551843481d356713ececa9a8a64e8/propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6", size = 79296 }, - { url = "https://files.pythonhosted.org/packages/76/5a/916db1aba735f55e5eca4733eea4d1973845cf77dfe67c2381a2ca3ce52d/propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2", size = 45622 }, - { url = "https://files.pythonhosted.org/packages/2d/62/685d3cf268b8401ec12b250b925b21d152b9d193b7bffa5fdc4815c392c2/propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea", size = 45133 }, - { url = "https://files.pythonhosted.org/packages/4d/3d/31c9c29ee7192defc05aa4d01624fd85a41cf98e5922aaed206017329944/propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212", size = 204809 }, - { url = "https://files.pythonhosted.org/packages/10/a1/e4050776f4797fc86140ac9a480d5dc069fbfa9d499fe5c5d2fa1ae71f07/propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3", size = 219109 }, - { url = "https://files.pythonhosted.org/packages/c9/c0/e7ae0df76343d5e107d81e59acc085cea5fd36a48aa53ef09add7503e888/propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d", size = 217368 }, - { url = "https://files.pythonhosted.org/packages/fc/e1/e0a2ed6394b5772508868a977d3238f4afb2eebaf9976f0b44a8d347ad63/propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634", size = 205124 }, - { url = "https://files.pythonhosted.org/packages/50/c1/e388c232d15ca10f233c778bbdc1034ba53ede14c207a72008de45b2db2e/propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2", size = 195463 }, - { url = "https://files.pythonhosted.org/packages/0a/fd/71b349b9def426cc73813dbd0f33e266de77305e337c8c12bfb0a2a82bfb/propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958", size = 198358 }, - { url = "https://files.pythonhosted.org/packages/02/f2/d7c497cd148ebfc5b0ae32808e6c1af5922215fe38c7a06e4e722fe937c8/propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c", size = 195560 }, - { url = "https://files.pythonhosted.org/packages/bb/57/f37041bbe5e0dfed80a3f6be2612a3a75b9cfe2652abf2c99bef3455bbad/propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583", size = 196895 }, - { url = "https://files.pythonhosted.org/packages/83/36/ae3cc3e4f310bff2f064e3d2ed5558935cc7778d6f827dce74dcfa125304/propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf", size = 207124 }, - { url = "https://files.pythonhosted.org/packages/8c/c4/811b9f311f10ce9d31a32ff14ce58500458443627e4df4ae9c264defba7f/propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034", size = 210442 }, - { url = "https://files.pythonhosted.org/packages/18/dd/a1670d483a61ecac0d7fc4305d91caaac7a8fc1b200ea3965a01cf03bced/propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b", size = 203219 }, - { url = "https://files.pythonhosted.org/packages/f9/2d/30ced5afde41b099b2dc0c6573b66b45d16d73090e85655f1a30c5a24e07/propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4", size = 40313 }, - { url = "https://files.pythonhosted.org/packages/23/84/bd9b207ac80da237af77aa6e153b08ffa83264b1c7882495984fcbfcf85c/propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba", size = 44428 }, - { url = "https://files.pythonhosted.org/packages/bc/0f/2913b6791ebefb2b25b4efd4bb2299c985e09786b9f5b19184a88e5778dd/propcache-0.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ffc3cca89bb438fb9c95c13fc874012f7b9466b89328c3c8b1aa93cdcfadd16", size = 79297 }, - { url = "https://files.pythonhosted.org/packages/cf/73/af2053aeccd40b05d6e19058419ac77674daecdd32478088b79375b9ab54/propcache-0.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f174bbd484294ed9fdf09437f889f95807e5f229d5d93588d34e92106fbf6717", size = 45611 }, - { url = "https://files.pythonhosted.org/packages/3c/09/8386115ba7775ea3b9537730e8cf718d83bbf95bffe30757ccf37ec4e5da/propcache-0.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:70693319e0b8fd35dd863e3e29513875eb15c51945bf32519ef52927ca883bc3", size = 45146 }, - { url = "https://files.pythonhosted.org/packages/03/7a/793aa12f0537b2e520bf09f4c6833706b63170a211ad042ca71cbf79d9cb/propcache-0.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b480c6a4e1138e1aa137c0079b9b6305ec6dcc1098a8ca5196283e8a49df95a9", size = 232136 }, - { url = "https://files.pythonhosted.org/packages/f1/38/b921b3168d72111769f648314100558c2ea1d52eb3d1ba7ea5c4aa6f9848/propcache-0.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d27b84d5880f6d8aa9ae3edb253c59d9f6642ffbb2c889b78b60361eed449787", size = 239706 }, - { url = "https://files.pythonhosted.org/packages/14/29/4636f500c69b5edea7786db3c34eb6166f3384b905665ce312a6e42c720c/propcache-0.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:857112b22acd417c40fa4595db2fe28ab900c8c5fe4670c7989b1c0230955465", size = 238531 }, - { url = "https://files.pythonhosted.org/packages/85/14/01fe53580a8e1734ebb704a3482b7829a0ef4ea68d356141cf0994d9659b/propcache-0.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6c4150f8c0e32d241436526f3c3f9cbd34429492abddbada2ffcff506c51af", size = 231063 }, - { url = "https://files.pythonhosted.org/packages/33/5c/1d961299f3c3b8438301ccfbff0143b69afcc30c05fa28673cface692305/propcache-0.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d4cfda1d8ed687daa4bc0274fcfd5267873db9a5bc0418c2da19273040eeb7", size = 220134 }, - { url = "https://files.pythonhosted.org/packages/00/d0/ed735e76db279ba67a7d3b45ba4c654e7b02bc2f8050671ec365d8665e21/propcache-0.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2f992c07c0fca81655066705beae35fc95a2fa7366467366db627d9f2ee097f", size = 220009 }, - { url = "https://files.pythonhosted.org/packages/75/90/ee8fab7304ad6533872fee982cfff5a53b63d095d78140827d93de22e2d4/propcache-0.2.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4a571d97dbe66ef38e472703067021b1467025ec85707d57e78711c085984e54", size = 212199 }, - { url = "https://files.pythonhosted.org/packages/eb/ec/977ffaf1664f82e90737275873461695d4c9407d52abc2f3c3e24716da13/propcache-0.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bb6178c241278d5fe853b3de743087be7f5f4c6f7d6d22a3b524d323eecec505", size = 214827 }, - { url = "https://files.pythonhosted.org/packages/57/48/031fb87ab6081764054821a71b71942161619549396224cbb242922525e8/propcache-0.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad1af54a62ffe39cf34db1aa6ed1a1873bd548f6401db39d8e7cd060b9211f82", size = 228009 }, - { url = "https://files.pythonhosted.org/packages/1a/06/ef1390f2524850838f2390421b23a8b298f6ce3396a7cc6d39dedd4047b0/propcache-0.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e7048abd75fe40712005bcfc06bb44b9dfcd8e101dda2ecf2f5aa46115ad07ca", size = 231638 }, - { url = "https://files.pythonhosted.org/packages/38/2a/101e6386d5a93358395da1d41642b79c1ee0f3b12e31727932b069282b1d/propcache-0.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:160291c60081f23ee43d44b08a7e5fb76681221a8e10b3139618c5a9a291b84e", size = 222788 }, - { url = "https://files.pythonhosted.org/packages/db/81/786f687951d0979007e05ad9346cd357e50e3d0b0f1a1d6074df334b1bbb/propcache-0.2.1-cp311-cp311-win32.whl", hash = "sha256:819ce3b883b7576ca28da3861c7e1a88afd08cc8c96908e08a3f4dd64a228034", size = 40170 }, - { url = "https://files.pythonhosted.org/packages/cf/59/7cc7037b295d5772eceb426358bb1b86e6cab4616d971bd74275395d100d/propcache-0.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:edc9fc7051e3350643ad929df55c451899bb9ae6d24998a949d2e4c87fb596d3", size = 44404 }, - { url = "https://files.pythonhosted.org/packages/4c/28/1d205fe49be8b1b4df4c50024e62480a442b1a7b818e734308bb0d17e7fb/propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", size = 79588 }, - { url = "https://files.pythonhosted.org/packages/21/ee/fc4d893f8d81cd4971affef2a6cb542b36617cd1d8ce56b406112cb80bf7/propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", size = 45825 }, - { url = "https://files.pythonhosted.org/packages/4a/de/bbe712f94d088da1d237c35d735f675e494a816fd6f54e9db2f61ef4d03f/propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", size = 45357 }, - { url = "https://files.pythonhosted.org/packages/7f/14/7ae06a6cf2a2f1cb382586d5a99efe66b0b3d0c6f9ac2f759e6f7af9d7cf/propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", size = 241869 }, - { url = "https://files.pythonhosted.org/packages/cc/59/227a78be960b54a41124e639e2c39e8807ac0c751c735a900e21315f8c2b/propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", size = 247884 }, - { url = "https://files.pythonhosted.org/packages/84/58/f62b4ffaedf88dc1b17f04d57d8536601e4e030feb26617228ef930c3279/propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", size = 248486 }, - { url = "https://files.pythonhosted.org/packages/1c/07/ebe102777a830bca91bbb93e3479cd34c2ca5d0361b83be9dbd93104865e/propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", size = 243649 }, - { url = "https://files.pythonhosted.org/packages/ed/bc/4f7aba7f08f520376c4bb6a20b9a981a581b7f2e385fa0ec9f789bb2d362/propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", size = 229103 }, - { url = "https://files.pythonhosted.org/packages/fe/d5/04ac9cd4e51a57a96f78795e03c5a0ddb8f23ec098b86f92de028d7f2a6b/propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", size = 226607 }, - { url = "https://files.pythonhosted.org/packages/e3/f0/24060d959ea41d7a7cc7fdbf68b31852331aabda914a0c63bdb0e22e96d6/propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", size = 221153 }, - { url = "https://files.pythonhosted.org/packages/77/a7/3ac76045a077b3e4de4859a0753010765e45749bdf53bd02bc4d372da1a0/propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", size = 222151 }, - { url = "https://files.pythonhosted.org/packages/e7/af/5e29da6f80cebab3f5a4dcd2a3240e7f56f2c4abf51cbfcc99be34e17f0b/propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", size = 233812 }, - { url = "https://files.pythonhosted.org/packages/8c/89/ebe3ad52642cc5509eaa453e9f4b94b374d81bae3265c59d5c2d98efa1b4/propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", size = 238829 }, - { url = "https://files.pythonhosted.org/packages/e9/2f/6b32f273fa02e978b7577159eae7471b3cfb88b48563b1c2578b2d7ca0bb/propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", size = 230704 }, - { url = "https://files.pythonhosted.org/packages/5c/2e/f40ae6ff5624a5f77edd7b8359b208b5455ea113f68309e2b00a2e1426b6/propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", size = 40050 }, - { url = "https://files.pythonhosted.org/packages/3b/77/a92c3ef994e47180862b9d7d11e37624fb1c00a16d61faf55115d970628b/propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", size = 44117 }, - { url = "https://files.pythonhosted.org/packages/0f/2a/329e0547cf2def8857157f9477669043e75524cc3e6251cef332b3ff256f/propcache-0.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aca405706e0b0a44cc6bfd41fbe89919a6a56999157f6de7e182a990c36e37bc", size = 77002 }, - { url = "https://files.pythonhosted.org/packages/12/2d/c4df5415e2382f840dc2ecbca0eeb2293024bc28e57a80392f2012b4708c/propcache-0.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:12d1083f001ace206fe34b6bdc2cb94be66d57a850866f0b908972f90996b3e9", size = 44639 }, - { url = "https://files.pythonhosted.org/packages/d0/5a/21aaa4ea2f326edaa4e240959ac8b8386ea31dedfdaa636a3544d9e7a408/propcache-0.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d93f3307ad32a27bda2e88ec81134b823c240aa3abb55821a8da553eed8d9439", size = 44049 }, - { url = "https://files.pythonhosted.org/packages/4e/3e/021b6cd86c0acc90d74784ccbb66808b0bd36067a1bf3e2deb0f3845f618/propcache-0.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba278acf14471d36316159c94a802933d10b6a1e117b8554fe0d0d9b75c9d536", size = 224819 }, - { url = "https://files.pythonhosted.org/packages/3c/57/c2fdeed1b3b8918b1770a133ba5c43ad3d78e18285b0c06364861ef5cc38/propcache-0.2.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e6281aedfca15301c41f74d7005e6e3f4ca143584ba696ac69df4f02f40d629", size = 229625 }, - { url = "https://files.pythonhosted.org/packages/9d/81/70d4ff57bf2877b5780b466471bebf5892f851a7e2ca0ae7ffd728220281/propcache-0.2.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b750a8e5a1262434fb1517ddf64b5de58327f1adc3524a5e44c2ca43305eb0b", size = 232934 }, - { url = "https://files.pythonhosted.org/packages/3c/b9/bb51ea95d73b3fb4100cb95adbd4e1acaf2cbb1fd1083f5468eeb4a099a8/propcache-0.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf72af5e0fb40e9babf594308911436c8efde3cb5e75b6f206c34ad18be5c052", size = 227361 }, - { url = "https://files.pythonhosted.org/packages/f1/20/3c6d696cd6fd70b29445960cc803b1851a1131e7a2e4ee261ee48e002bcd/propcache-0.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2d0a12018b04f4cb820781ec0dffb5f7c7c1d2a5cd22bff7fb055a2cb19ebce", size = 213904 }, - { url = "https://files.pythonhosted.org/packages/a1/cb/1593bfc5ac6d40c010fa823f128056d6bc25b667f5393781e37d62f12005/propcache-0.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e800776a79a5aabdb17dcc2346a7d66d0777e942e4cd251defeb084762ecd17d", size = 212632 }, - { url = "https://files.pythonhosted.org/packages/6d/5c/e95617e222be14a34c709442a0ec179f3207f8a2b900273720501a70ec5e/propcache-0.2.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4160d9283bd382fa6c0c2b5e017acc95bc183570cd70968b9202ad6d8fc48dce", size = 207897 }, - { url = "https://files.pythonhosted.org/packages/8e/3b/56c5ab3dc00f6375fbcdeefdede5adf9bee94f1fab04adc8db118f0f9e25/propcache-0.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b43e74f1359353341a7adb783c8f1b1c676367b011709f466f42fda2045e95", size = 208118 }, - { url = "https://files.pythonhosted.org/packages/86/25/d7ef738323fbc6ebcbce33eb2a19c5e07a89a3df2fded206065bd5e868a9/propcache-0.2.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:58791550b27d5488b1bb52bc96328456095d96206a250d28d874fafe11b3dfaf", size = 217851 }, - { url = "https://files.pythonhosted.org/packages/b3/77/763e6cef1852cf1ba740590364ec50309b89d1c818e3256d3929eb92fabf/propcache-0.2.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0f022d381747f0dfe27e99d928e31bc51a18b65bb9e481ae0af1380a6725dd1f", size = 222630 }, - { url = "https://files.pythonhosted.org/packages/4f/e9/0f86be33602089c701696fbed8d8c4c07b6ee9605c5b7536fd27ed540c5b/propcache-0.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:297878dc9d0a334358f9b608b56d02e72899f3b8499fc6044133f0d319e2ec30", size = 216269 }, - { url = "https://files.pythonhosted.org/packages/cc/02/5ac83217d522394b6a2e81a2e888167e7ca629ef6569a3f09852d6dcb01a/propcache-0.2.1-cp313-cp313-win32.whl", hash = "sha256:ddfab44e4489bd79bda09d84c430677fc7f0a4939a73d2bba3073036f487a0a6", size = 39472 }, - { url = "https://files.pythonhosted.org/packages/f4/33/d6f5420252a36034bc8a3a01171bc55b4bff5df50d1c63d9caa50693662f/propcache-0.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:556fc6c10989f19a179e4321e5d678db8eb2924131e64652a51fe83e4c3db0e1", size = 43363 }, - { url = "https://files.pythonhosted.org/packages/41/b6/c5319caea262f4821995dca2107483b94a3345d4607ad797c76cb9c36bcc/propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", size = 11818 }, -] - -[[package]] -name = "pycparser" -version = "2.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, -] - -[[package]] -name = "pycryptodome" -version = "3.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/52/13b9db4a913eee948152a079fe58d035bd3d1a519584155da8e786f767e6/pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297", size = 4818071 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/88/5e83de10450027c96c79dc65ac45e9d0d7a7fef334f39d3789a191f33602/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4", size = 2495937 }, - { url = "https://files.pythonhosted.org/packages/66/e1/8f28cd8cf7f7563319819d1e172879ccce2333781ae38da61c28fe22d6ff/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b", size = 1634629 }, - { url = "https://files.pythonhosted.org/packages/6a/c1/f75a1aaff0c20c11df8dc8e2bf8057e7f73296af7dfd8cbb40077d1c930d/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e", size = 2168708 }, - { url = "https://files.pythonhosted.org/packages/ea/66/6f2b7ddb457b19f73b82053ecc83ba768680609d56dd457dbc7e902c41aa/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8", size = 2254555 }, - { url = "https://files.pythonhosted.org/packages/2c/2b/152c330732a887a86cbf591ed69bd1b489439b5464806adb270f169ec139/pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1", size = 2294143 }, - { url = "https://files.pythonhosted.org/packages/55/92/517c5c498c2980c1b6d6b9965dffbe31f3cd7f20f40d00ec4069559c5902/pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a", size = 2160509 }, - { url = "https://files.pythonhosted.org/packages/39/1f/c74288f54d80a20a78da87df1818c6464ac1041d10988bb7d982c4153fbc/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2", size = 2329480 }, - { url = "https://files.pythonhosted.org/packages/39/1b/d0b013bf7d1af7cf0a6a4fce13f5fe5813ab225313755367b36e714a63f8/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93", size = 2254397 }, - { url = "https://files.pythonhosted.org/packages/14/71/4cbd3870d3e926c34706f705d6793159ac49d9a213e3ababcdade5864663/pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764", size = 1775641 }, - { url = "https://files.pythonhosted.org/packages/43/1d/81d59d228381576b92ecede5cd7239762c14001a828bdba30d64896e9778/pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53", size = 1812863 }, - { url = "https://files.pythonhosted.org/packages/25/b3/09ff7072e6d96c9939c24cf51d3c389d7c345bf675420355c22402f71b68/pycryptodome-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca", size = 1691593 }, - { url = "https://files.pythonhosted.org/packages/a8/91/38e43628148f68ba9b68dedbc323cf409e537fd11264031961fd7c744034/pycryptodome-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd", size = 1765997 }, - { url = "https://files.pythonhosted.org/packages/08/16/ae464d4ac338c1dd41f89c41f9488e54f7d2a3acf93bb920bb193b99f8e3/pycryptodome-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8", size = 1615855 }, - { url = "https://files.pythonhosted.org/packages/1e/8c/b0cee957eee1950ce7655006b26a8894cee1dc4b8747ae913684352786eb/pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6", size = 1650018 }, - { url = "https://files.pythonhosted.org/packages/93/4d/d7138068089b99f6b0368622e60f97a577c936d75f533552a82613060c58/pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0", size = 1687977 }, - { url = "https://files.pythonhosted.org/packages/96/02/90ae1ac9f28be4df0ed88c127bf4acc1b102b40053e172759d4d1c54d937/pycryptodome-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6", size = 1788273 }, -] - -[[package]] -name = "pydantic" -version = "2.10.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696 }, -] - -[[package]] -name = "pydantic-core" -version = "2.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938 }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684 }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169 }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227 }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695 }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662 }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370 }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813 }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287 }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414 }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301 }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685 }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876 }, - { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421 }, - { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998 }, - { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167 }, - { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071 }, - { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244 }, - { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470 }, - { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291 }, - { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613 }, - { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355 }, - { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661 }, - { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261 }, - { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361 }, - { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484 }, - { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102 }, - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159 }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331 }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467 }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797 }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839 }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861 }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582 }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985 }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715 }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, -] - -[[package]] -name = "pytest" -version = "8.3.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, -] - -[[package]] -name = "pytest-cov" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "coverage", extra = ["toml"] }, - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, -] - -[[package]] -name = "pywin32-ctypes" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756 }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199 }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758 }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463 }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280 }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239 }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802 }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527 }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052 }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774 }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, -] - -[[package]] -name = "readme-renderer" -version = "44.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "docutils" }, - { name = "nh3" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5a/a9/104ec9234c8448c4379768221ea6df01260cd6c2ce13182d4eac531c8342/readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1", size = 32056 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", size = 13310 }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674 }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684 }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589 }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511 }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149 }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707 }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702 }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976 }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397 }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726 }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098 }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325 }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277 }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197 }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714 }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042 }, - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669 }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684 }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589 }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121 }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275 }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257 }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727 }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667 }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963 }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700 }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592 }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929 }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213 }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734 }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052 }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781 }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455 }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759 }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976 }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077 }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160 }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896 }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997 }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725 }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481 }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896 }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138 }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692 }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135 }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567 }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525 }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324 }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617 }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023 }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072 }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130 }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857 }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006 }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650 }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545 }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045 }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182 }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733 }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122 }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545 }, -] - -[[package]] -name = "requests" -version = "2.32.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, -] - -[[package]] -name = "requests-toolbelt" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481 }, -] - -[[package]] -name = "rfc3986" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c", size = 49026 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd", size = 31326 }, -] - -[[package]] -name = "rich" -version = "13.9.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, -] - -[[package]] -name = "rlp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/2d/439b0728a92964a04d9c88ea1ca9ebb128893fbbd5834faa31f987f2fd4c/rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9", size = 33429 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973 }, -] - -[[package]] -name = "ruff" -version = "0.9.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2a/e1/e265aba384343dd8ddd3083f5e33536cd17e1566c41453a5517b5dd443be/ruff-0.9.6.tar.gz", hash = "sha256:81761592f72b620ec8fa1068a6fd00e98a5ebee342a3642efd84454f3031dca9", size = 3639454 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/e3/3d2c022e687e18cf5d93d6bfa2722d46afc64eaa438c7fbbdd603b3597be/ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba", size = 11714128 }, - { url = "https://files.pythonhosted.org/packages/e1/22/aff073b70f95c052e5c58153cba735748c9e70107a77d03420d7850710a0/ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504", size = 11682539 }, - { url = "https://files.pythonhosted.org/packages/75/a7/f5b7390afd98a7918582a3d256cd3e78ba0a26165a467c1820084587cbf9/ruff-0.9.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b109c0ad2ececf42e75fa99dc4043ff72a357436bb171900714a9ea581ddef83", size = 11132512 }, - { url = "https://files.pythonhosted.org/packages/a6/e3/45de13ef65047fea2e33f7e573d848206e15c715e5cd56095589a7733d04/ruff-0.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de4367cca3dac99bcbd15c161404e849bb0bfd543664db39232648dc00112dc", size = 11929275 }, - { url = "https://files.pythonhosted.org/packages/7d/f2/23d04cd6c43b2e641ab961ade8d0b5edb212ecebd112506188c91f2a6e6c/ruff-0.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac3ee4d7c2c92ddfdaedf0bf31b2b176fa7aa8950efc454628d477394d35638b", size = 11466502 }, - { url = "https://files.pythonhosted.org/packages/b5/6f/3a8cf166f2d7f1627dd2201e6cbc4cb81f8b7d58099348f0c1ff7b733792/ruff-0.9.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc1edd1775270e6aa2386119aea692039781429f0be1e0949ea5884e011aa8e", size = 12676364 }, - { url = "https://files.pythonhosted.org/packages/f5/c4/db52e2189983c70114ff2b7e3997e48c8318af44fe83e1ce9517570a50c6/ruff-0.9.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4a091729086dffa4bd070aa5dab7e39cc6b9d62eb2bef8f3d91172d30d599666", size = 13335518 }, - { url = "https://files.pythonhosted.org/packages/66/44/545f8a4d136830f08f4d24324e7db957c5374bf3a3f7a6c0bc7be4623a37/ruff-0.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1bbc6808bf7b15796cef0815e1dfb796fbd383e7dbd4334709642649625e7c5", size = 12823287 }, - { url = "https://files.pythonhosted.org/packages/c5/26/8208ef9ee7431032c143649a9967c3ae1aae4257d95e6f8519f07309aa66/ruff-0.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:589d1d9f25b5754ff230dce914a174a7c951a85a4e9270613a2b74231fdac2f5", size = 14592374 }, - { url = "https://files.pythonhosted.org/packages/31/70/e917781e55ff39c5b5208bda384fd397ffd76605e68544d71a7e40944945/ruff-0.9.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc61dd5131742e21103fbbdcad683a8813be0e3c204472d520d9a5021ca8b217", size = 12500173 }, - { url = "https://files.pythonhosted.org/packages/84/f5/e4ddee07660f5a9622a9c2b639afd8f3104988dc4f6ba0b73ffacffa9a8c/ruff-0.9.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5e2d9126161d0357e5c8f30b0bd6168d2c3872372f14481136d13de9937f79b6", size = 11906555 }, - { url = "https://files.pythonhosted.org/packages/f1/2b/6ff2fe383667075eef8656b9892e73dd9b119b5e3add51298628b87f6429/ruff-0.9.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:68660eab1a8e65babb5229a1f97b46e3120923757a68b5413d8561f8a85d4897", size = 11538958 }, - { url = "https://files.pythonhosted.org/packages/3c/db/98e59e90de45d1eb46649151c10a062d5707b5b7f76f64eb1e29edf6ebb1/ruff-0.9.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c4cae6c4cc7b9b4017c71114115db0445b00a16de3bcde0946273e8392856f08", size = 12117247 }, - { url = "https://files.pythonhosted.org/packages/ec/bc/54e38f6d219013a9204a5a2015c09e7a8c36cedcd50a4b01ac69a550b9d9/ruff-0.9.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19f505b643228b417c1111a2a536424ddde0db4ef9023b9e04a46ed8a1cb4656", size = 12554647 }, - { url = "https://files.pythonhosted.org/packages/a5/7d/7b461ab0e2404293c0627125bb70ac642c2e8d55bf590f6fce85f508f1b2/ruff-0.9.6-py3-none-win32.whl", hash = "sha256:194d8402bceef1b31164909540a597e0d913c0e4952015a5b40e28c146121b5d", size = 9949214 }, - { url = "https://files.pythonhosted.org/packages/ee/30/c3cee10f915ed75a5c29c1e57311282d1a15855551a64795c1b2bbe5cf37/ruff-0.9.6-py3-none-win_amd64.whl", hash = "sha256:03482d5c09d90d4ee3f40d97578423698ad895c87314c4de39ed2af945633caa", size = 10999914 }, - { url = "https://files.pythonhosted.org/packages/e8/a8/d71f44b93e3aa86ae232af1f2126ca7b95c0f515ec135462b3e1f351441c/ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a", size = 10177499 }, -] - -[[package]] -name = "secretstorage" -version = "3.3.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography" }, - { name = "jeepney" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", size = 19739 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", size = 15221 }, -] - -[[package]] -name = "setuptools" -version = "75.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/ec/089608b791d210aec4e7f97488e67ab0d33add3efccb83a056cbafe3a2a6/setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6", size = 1343222 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/8a/b9dc7678803429e4a3bc9ba462fa3dd9066824d3c607490235c6a796be5a/setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3", size = 1228782 }, -] - -[[package]] -name = "stevedore" -version = "5.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pbr" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4a/e9/4eedccff8332cc40cc60ddd3b28d4c3e255ee7e9c65679fa4533ab98f598/stevedore-5.4.0.tar.gz", hash = "sha256:79e92235ecb828fe952b6b8b0c6c87863248631922c8e8e0fa5b17b232c4514d", size = 513899 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/73/d0091d22a65b55e8fb6aca7b3b6713b5a261dd01cec4cfd28ed127ac0cfc/stevedore-5.4.0-py3-none-any.whl", hash = "sha256:b0be3c4748b3ea7b854b265dcb4caa891015e442416422be16f8b31756107857", size = 49534 }, -] - -[[package]] -name = "tomli" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, - { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, - { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, - { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, - { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, - { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, - { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, - { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, - { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, - { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, - { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, - { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, - { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, - { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, - { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, - { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, - { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, - { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, - { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, - { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, - { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, - { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, - { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, - { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, - { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, - { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, - { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, - { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, - { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, - { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, - { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, -] - -[[package]] -name = "toolz" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383 }, -] - -[[package]] -name = "twine" -version = "6.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "id" }, - { name = "keyring", marker = "platform_machine != 'ppc64le' and platform_machine != 's390x'" }, - { name = "packaging" }, - { name = "readme-renderer" }, - { name = "requests" }, - { name = "requests-toolbelt" }, - { name = "rfc3986" }, - { name = "rich" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c8/a2/6df94fc5c8e2170d21d7134a565c3a8fb84f9797c1dd65a5976aaf714418/twine-6.1.0.tar.gz", hash = "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd", size = 168404 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/b6/74e927715a285743351233f33ea3c684528a0d374d2e43ff9ce9585b73fe/twine-6.1.0-py3-none-any.whl", hash = "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384", size = 40791 }, -] - -[[package]] -name = "typing-extensions" -version = "4.12.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, -] - -[[package]] -name = "typing-inspect" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mypy-extensions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827 }, -] - -[[package]] -name = "untokenize" -version = "0.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz", hash = "sha256:3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2", size = 3099 } - -[[package]] -name = "urllib3" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, -] - -[[package]] -name = "websockets" -version = "13.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e2/73/9223dbc7be3dcaf2a7bbf756c351ec8da04b1fa573edaf545b95f6b0c7fd/websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", size = 158549 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/94/d15dbfc6a5eb636dbc754303fba18208f2e88cf97e733e1d64fb9cb5c89e/websockets-13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee", size = 157815 }, - { url = "https://files.pythonhosted.org/packages/30/02/c04af33f4663945a26f5e8cf561eb140c35452b50af47a83c3fbcfe62ae1/websockets-13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7", size = 155466 }, - { url = "https://files.pythonhosted.org/packages/35/e8/719f08d12303ea643655e52d9e9851b2dadbb1991d4926d9ce8862efa2f5/websockets-13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6", size = 155716 }, - { url = "https://files.pythonhosted.org/packages/91/e1/14963ae0252a8925f7434065d25dcd4701d5e281a0b4b460a3b5963d2594/websockets-13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b", size = 164806 }, - { url = "https://files.pythonhosted.org/packages/ec/fa/ab28441bae5e682a0f7ddf3d03440c0c352f930da419301f4a717f675ef3/websockets-13.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa", size = 163810 }, - { url = "https://files.pythonhosted.org/packages/44/77/dea187bd9d16d4b91566a2832be31f99a40d0f5bfa55eeb638eb2c3bc33d/websockets-13.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700", size = 164125 }, - { url = "https://files.pythonhosted.org/packages/cf/d9/3af14544e83f1437eb684b399e6ba0fa769438e869bf5d83d74bc197fae8/websockets-13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c", size = 164532 }, - { url = "https://files.pythonhosted.org/packages/1c/8a/6d332eabe7d59dfefe4b8ba6f46c8c5fabb15b71c8a8bc3d2b65de19a7b6/websockets-13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0", size = 163948 }, - { url = "https://files.pythonhosted.org/packages/1a/91/a0aeadbaf3017467a1ee03f8fb67accdae233fe2d5ad4b038c0a84e357b0/websockets-13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f", size = 163898 }, - { url = "https://files.pythonhosted.org/packages/71/31/a90fb47c63e0ae605be914b0b969d7c6e6ffe2038cd744798e4b3fbce53b/websockets-13.1-cp310-cp310-win32.whl", hash = "sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe", size = 158706 }, - { url = "https://files.pythonhosted.org/packages/93/ca/9540a9ba80da04dc7f36d790c30cae4252589dbd52ccdc92e75b0be22437/websockets-13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a", size = 159141 }, - { url = "https://files.pythonhosted.org/packages/b2/f0/cf0b8a30d86b49e267ac84addbebbc7a48a6e7bb7c19db80f62411452311/websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19", size = 157813 }, - { url = "https://files.pythonhosted.org/packages/bf/e7/22285852502e33071a8cf0ac814f8988480ec6db4754e067b8b9d0e92498/websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5", size = 155469 }, - { url = "https://files.pythonhosted.org/packages/68/d4/c8c7c1e5b40ee03c5cc235955b0fb1ec90e7e37685a5f69229ad4708dcde/websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd", size = 155717 }, - { url = "https://files.pythonhosted.org/packages/c9/e4/c50999b9b848b1332b07c7fd8886179ac395cb766fda62725d1539e7bc6c/websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02", size = 165379 }, - { url = "https://files.pythonhosted.org/packages/bc/49/4a4ad8c072f18fd79ab127650e47b160571aacfc30b110ee305ba25fffc9/websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7", size = 164376 }, - { url = "https://files.pythonhosted.org/packages/af/9b/8c06d425a1d5a74fd764dd793edd02be18cf6fc3b1ccd1f29244ba132dc0/websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096", size = 164753 }, - { url = "https://files.pythonhosted.org/packages/d5/5b/0acb5815095ff800b579ffc38b13ab1b915b317915023748812d24e0c1ac/websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084", size = 165051 }, - { url = "https://files.pythonhosted.org/packages/30/93/c3891c20114eacb1af09dedfcc620c65c397f4fd80a7009cd12d9457f7f5/websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3", size = 164489 }, - { url = "https://files.pythonhosted.org/packages/28/09/af9e19885539759efa2e2cd29b8b3f9eecef7ecefea40d46612f12138b36/websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9", size = 164438 }, - { url = "https://files.pythonhosted.org/packages/b6/08/6f38b8e625b3d93de731f1d248cc1493327f16cb45b9645b3e791782cff0/websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f", size = 158710 }, - { url = "https://files.pythonhosted.org/packages/fb/39/ec8832ecb9bb04a8d318149005ed8cee0ba4e0205835da99e0aa497a091f/websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557", size = 159137 }, - { url = "https://files.pythonhosted.org/packages/df/46/c426282f543b3c0296cf964aa5a7bb17e984f58dde23460c3d39b3148fcf/websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc", size = 157821 }, - { url = "https://files.pythonhosted.org/packages/aa/85/22529867010baac258da7c45848f9415e6cf37fef00a43856627806ffd04/websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49", size = 155480 }, - { url = "https://files.pythonhosted.org/packages/29/2c/bdb339bfbde0119a6e84af43ebf6275278698a2241c2719afc0d8b0bdbf2/websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd", size = 155715 }, - { url = "https://files.pythonhosted.org/packages/9f/d0/8612029ea04c5c22bf7af2fd3d63876c4eaeef9b97e86c11972a43aa0e6c/websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0", size = 165647 }, - { url = "https://files.pythonhosted.org/packages/56/04/1681ed516fa19ca9083f26d3f3a302257e0911ba75009533ed60fbb7b8d1/websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6", size = 164592 }, - { url = "https://files.pythonhosted.org/packages/38/6f/a96417a49c0ed132bb6087e8e39a37db851c70974f5c724a4b2a70066996/websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9", size = 165012 }, - { url = "https://files.pythonhosted.org/packages/40/8b/fccf294919a1b37d190e86042e1a907b8f66cff2b61e9befdbce03783e25/websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68", size = 165311 }, - { url = "https://files.pythonhosted.org/packages/c1/61/f8615cf7ce5fe538476ab6b4defff52beb7262ff8a73d5ef386322d9761d/websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14", size = 164692 }, - { url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 }, - { url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 }, - { url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 }, - { url = "https://files.pythonhosted.org/packages/51/20/2b99ca918e1cbd33c53db2cace5f0c0cd8296fc77558e1908799c712e1cd/websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", size = 157828 }, - { url = "https://files.pythonhosted.org/packages/b8/47/0932a71d3d9c0e9483174f60713c84cee58d62839a143f21a2bcdbd2d205/websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", size = 155487 }, - { url = "https://files.pythonhosted.org/packages/a9/60/f1711eb59ac7a6c5e98e5637fef5302f45b6f76a2c9d64fd83bbb341377a/websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", size = 155721 }, - { url = "https://files.pythonhosted.org/packages/6a/e6/ba9a8db7f9d9b0e5f829cf626ff32677f39824968317223605a6b419d445/websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", size = 165609 }, - { url = "https://files.pythonhosted.org/packages/c1/22/4ec80f1b9c27a0aebd84ccd857252eda8418ab9681eb571b37ca4c5e1305/websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", size = 164556 }, - { url = "https://files.pythonhosted.org/packages/27/ac/35f423cb6bb15600438db80755609d27eda36d4c0b3c9d745ea12766c45e/websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", size = 164993 }, - { url = "https://files.pythonhosted.org/packages/31/4e/98db4fd267f8be9e52e86b6ee4e9aa7c42b83452ea0ea0672f176224b977/websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", size = 165360 }, - { url = "https://files.pythonhosted.org/packages/3f/15/3f0de7cda70ffc94b7e7024544072bc5b26e2c1eb36545291abb755d8cdb/websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", size = 164745 }, - { url = "https://files.pythonhosted.org/packages/a1/6e/66b6b756aebbd680b934c8bdbb6dcb9ce45aad72cde5f8a7208dbb00dd36/websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", size = 164732 }, - { url = "https://files.pythonhosted.org/packages/35/c6/12e3aab52c11aeb289e3dbbc05929e7a9d90d7a9173958477d3ef4f8ce2d/websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", size = 158709 }, - { url = "https://files.pythonhosted.org/packages/41/d8/63d6194aae711d7263df4498200c690a9c39fb437ede10f3e157a6343e0d/websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", size = 159144 }, - { url = "https://files.pythonhosted.org/packages/2d/75/6da22cb3ad5b8c606963f9a5f9f88656256fecc29d420b4b2bf9e0c7d56f/websockets-13.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238", size = 155499 }, - { url = "https://files.pythonhosted.org/packages/c0/ba/22833d58629088fcb2ccccedfae725ac0bbcd713319629e97125b52ac681/websockets-13.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5", size = 155737 }, - { url = "https://files.pythonhosted.org/packages/95/54/61684fe22bdb831e9e1843d972adadf359cf04ab8613285282baea6a24bb/websockets-13.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9", size = 157095 }, - { url = "https://files.pythonhosted.org/packages/fc/f5/6652fb82440813822022a9301a30afde85e5ff3fb2aebb77f34aabe2b4e8/websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6", size = 156701 }, - { url = "https://files.pythonhosted.org/packages/67/33/ae82a7b860fa8a08aba68818bdf7ff61f04598aa5ab96df4cd5a3e418ca4/websockets-13.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a", size = 156654 }, - { url = "https://files.pythonhosted.org/packages/63/0b/a1b528d36934f833e20f6da1032b995bf093d55cb416b9f2266f229fb237/websockets-13.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23", size = 159192 }, - { url = "https://files.pythonhosted.org/packages/56/27/96a5cd2626d11c8280656c6c71d8ab50fe006490ef9971ccd154e0c42cd2/websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f", size = 152134 }, -] - -[[package]] -name = "yarl" -version = "1.18.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b7/9d/4b94a8e6d2b51b599516a5cb88e5bc99b4d8d4583e468057eaa29d5f0918/yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", size = 181062 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/98/e005bc608765a8a5569f58e650961314873c8469c333616eb40bff19ae97/yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34", size = 141458 }, - { url = "https://files.pythonhosted.org/packages/df/5d/f8106b263b8ae8a866b46d9be869ac01f9b3fb7f2325f3ecb3df8003f796/yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7", size = 94365 }, - { url = "https://files.pythonhosted.org/packages/56/3e/d8637ddb9ba69bf851f765a3ee288676f7cf64fb3be13760c18cbc9d10bd/yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed", size = 92181 }, - { url = "https://files.pythonhosted.org/packages/76/f9/d616a5c2daae281171de10fba41e1c0e2d8207166fc3547252f7d469b4e1/yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde", size = 315349 }, - { url = "https://files.pythonhosted.org/packages/bb/b4/3ea5e7b6f08f698b3769a06054783e434f6d59857181b5c4e145de83f59b/yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b", size = 330494 }, - { url = "https://files.pythonhosted.org/packages/55/f1/e0fc810554877b1b67420568afff51b967baed5b53bcc983ab164eebf9c9/yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5", size = 326927 }, - { url = "https://files.pythonhosted.org/packages/a9/42/b1753949b327b36f210899f2dd0a0947c0c74e42a32de3f8eb5c7d93edca/yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc", size = 319703 }, - { url = "https://files.pythonhosted.org/packages/f0/6d/e87c62dc9635daefb064b56f5c97df55a2e9cc947a2b3afd4fd2f3b841c7/yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd", size = 310246 }, - { url = "https://files.pythonhosted.org/packages/e3/ef/e2e8d1785cdcbd986f7622d7f0098205f3644546da7919c24b95790ec65a/yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990", size = 319730 }, - { url = "https://files.pythonhosted.org/packages/fc/15/8723e22345bc160dfde68c4b3ae8b236e868f9963c74015f1bc8a614101c/yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db", size = 321681 }, - { url = "https://files.pythonhosted.org/packages/86/09/bf764e974f1516efa0ae2801494a5951e959f1610dd41edbfc07e5e0f978/yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62", size = 324812 }, - { url = "https://files.pythonhosted.org/packages/f6/4c/20a0187e3b903c97d857cf0272d687c1b08b03438968ae8ffc50fe78b0d6/yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760", size = 337011 }, - { url = "https://files.pythonhosted.org/packages/c9/71/6244599a6e1cc4c9f73254a627234e0dad3883ece40cc33dce6265977461/yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b", size = 338132 }, - { url = "https://files.pythonhosted.org/packages/af/f5/e0c3efaf74566c4b4a41cb76d27097df424052a064216beccae8d303c90f/yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690", size = 331849 }, - { url = "https://files.pythonhosted.org/packages/8a/b8/3d16209c2014c2f98a8f658850a57b716efb97930aebf1ca0d9325933731/yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6", size = 84309 }, - { url = "https://files.pythonhosted.org/packages/fd/b7/2e9a5b18eb0fe24c3a0e8bae994e812ed9852ab4fd067c0107fadde0d5f0/yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8", size = 90484 }, - { url = "https://files.pythonhosted.org/packages/40/93/282b5f4898d8e8efaf0790ba6d10e2245d2c9f30e199d1a85cae9356098c/yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069", size = 141555 }, - { url = "https://files.pythonhosted.org/packages/6d/9c/0a49af78df099c283ca3444560f10718fadb8a18dc8b3edf8c7bd9fd7d89/yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193", size = 94351 }, - { url = "https://files.pythonhosted.org/packages/5a/a1/205ab51e148fdcedad189ca8dd587794c6f119882437d04c33c01a75dece/yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889", size = 92286 }, - { url = "https://files.pythonhosted.org/packages/ed/fe/88b690b30f3f59275fb674f5f93ddd4a3ae796c2b62e5bb9ece8a4914b83/yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8", size = 340649 }, - { url = "https://files.pythonhosted.org/packages/07/eb/3b65499b568e01f36e847cebdc8d7ccb51fff716dbda1ae83c3cbb8ca1c9/yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca", size = 356623 }, - { url = "https://files.pythonhosted.org/packages/33/46/f559dc184280b745fc76ec6b1954de2c55595f0ec0a7614238b9ebf69618/yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8", size = 354007 }, - { url = "https://files.pythonhosted.org/packages/af/ba/1865d85212351ad160f19fb99808acf23aab9a0f8ff31c8c9f1b4d671fc9/yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae", size = 344145 }, - { url = "https://files.pythonhosted.org/packages/94/cb/5c3e975d77755d7b3d5193e92056b19d83752ea2da7ab394e22260a7b824/yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3", size = 336133 }, - { url = "https://files.pythonhosted.org/packages/19/89/b77d3fd249ab52a5c40859815765d35c91425b6bb82e7427ab2f78f5ff55/yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb", size = 347967 }, - { url = "https://files.pythonhosted.org/packages/35/bd/f6b7630ba2cc06c319c3235634c582a6ab014d52311e7d7c22f9518189b5/yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e", size = 346397 }, - { url = "https://files.pythonhosted.org/packages/18/1a/0b4e367d5a72d1f095318344848e93ea70da728118221f84f1bf6c1e39e7/yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59", size = 350206 }, - { url = "https://files.pythonhosted.org/packages/b5/cf/320fff4367341fb77809a2d8d7fe75b5d323a8e1b35710aafe41fdbf327b/yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d", size = 362089 }, - { url = "https://files.pythonhosted.org/packages/57/cf/aadba261d8b920253204085268bad5e8cdd86b50162fcb1b10c10834885a/yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e", size = 366267 }, - { url = "https://files.pythonhosted.org/packages/54/58/fb4cadd81acdee6dafe14abeb258f876e4dd410518099ae9a35c88d8097c/yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a", size = 359141 }, - { url = "https://files.pythonhosted.org/packages/9a/7a/4c571597589da4cd5c14ed2a0b17ac56ec9ee7ee615013f74653169e702d/yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1", size = 84402 }, - { url = "https://files.pythonhosted.org/packages/ae/7b/8600250b3d89b625f1121d897062f629883c2f45339623b69b1747ec65fa/yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5", size = 91030 }, - { url = "https://files.pythonhosted.org/packages/33/85/bd2e2729752ff4c77338e0102914897512e92496375e079ce0150a6dc306/yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", size = 142644 }, - { url = "https://files.pythonhosted.org/packages/ff/74/1178322cc0f10288d7eefa6e4a85d8d2e28187ccab13d5b844e8b5d7c88d/yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", size = 94962 }, - { url = "https://files.pythonhosted.org/packages/be/75/79c6acc0261e2c2ae8a1c41cf12265e91628c8c58ae91f5ff59e29c0787f/yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", size = 92795 }, - { url = "https://files.pythonhosted.org/packages/6b/32/927b2d67a412c31199e83fefdce6e645247b4fb164aa1ecb35a0f9eb2058/yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", size = 332368 }, - { url = "https://files.pythonhosted.org/packages/19/e5/859fca07169d6eceeaa4fde1997c91d8abde4e9a7c018e371640c2da2b71/yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", size = 342314 }, - { url = "https://files.pythonhosted.org/packages/08/75/76b63ccd91c9e03ab213ef27ae6add2e3400e77e5cdddf8ed2dbc36e3f21/yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", size = 341987 }, - { url = "https://files.pythonhosted.org/packages/1a/e1/a097d5755d3ea8479a42856f51d97eeff7a3a7160593332d98f2709b3580/yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", size = 336914 }, - { url = "https://files.pythonhosted.org/packages/0b/42/e1b4d0e396b7987feceebe565286c27bc085bf07d61a59508cdaf2d45e63/yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", size = 325765 }, - { url = "https://files.pythonhosted.org/packages/7e/18/03a5834ccc9177f97ca1bbb245b93c13e58e8225276f01eedc4cc98ab820/yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", size = 344444 }, - { url = "https://files.pythonhosted.org/packages/c8/03/a713633bdde0640b0472aa197b5b86e90fbc4c5bc05b727b714cd8a40e6d/yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", size = 340760 }, - { url = "https://files.pythonhosted.org/packages/eb/99/f6567e3f3bbad8fd101886ea0276c68ecb86a2b58be0f64077396cd4b95e/yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", size = 346484 }, - { url = "https://files.pythonhosted.org/packages/8e/a9/84717c896b2fc6cb15bd4eecd64e34a2f0a9fd6669e69170c73a8b46795a/yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", size = 359864 }, - { url = "https://files.pythonhosted.org/packages/1e/2e/d0f5f1bef7ee93ed17e739ec8dbcb47794af891f7d165fa6014517b48169/yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", size = 364537 }, - { url = "https://files.pythonhosted.org/packages/97/8a/568d07c5d4964da5b02621a517532adb8ec5ba181ad1687191fffeda0ab6/yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", size = 357861 }, - { url = "https://files.pythonhosted.org/packages/7d/e3/924c3f64b6b3077889df9a1ece1ed8947e7b61b0a933f2ec93041990a677/yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", size = 84097 }, - { url = "https://files.pythonhosted.org/packages/34/45/0e055320daaabfc169b21ff6174567b2c910c45617b0d79c68d7ab349b02/yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", size = 90399 }, - { url = "https://files.pythonhosted.org/packages/30/c7/c790513d5328a8390be8f47be5d52e141f78b66c6c48f48d241ca6bd5265/yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb", size = 140789 }, - { url = "https://files.pythonhosted.org/packages/30/aa/a2f84e93554a578463e2edaaf2300faa61c8701f0898725842c704ba5444/yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa", size = 94144 }, - { url = "https://files.pythonhosted.org/packages/c6/fc/d68d8f83714b221a85ce7866832cba36d7c04a68fa6a960b908c2c84f325/yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782", size = 91974 }, - { url = "https://files.pythonhosted.org/packages/56/4e/d2563d8323a7e9a414b5b25341b3942af5902a2263d36d20fb17c40411e2/yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0", size = 333587 }, - { url = "https://files.pythonhosted.org/packages/25/c9/cfec0bc0cac8d054be223e9f2c7909d3e8442a856af9dbce7e3442a8ec8d/yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482", size = 344386 }, - { url = "https://files.pythonhosted.org/packages/ab/5d/4c532190113b25f1364d25f4c319322e86232d69175b91f27e3ebc2caf9a/yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186", size = 345421 }, - { url = "https://files.pythonhosted.org/packages/23/d1/6cdd1632da013aa6ba18cee4d750d953104a5e7aac44e249d9410a972bf5/yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58", size = 339384 }, - { url = "https://files.pythonhosted.org/packages/9a/c4/6b3c39bec352e441bd30f432cda6ba51681ab19bb8abe023f0d19777aad1/yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53", size = 326689 }, - { url = "https://files.pythonhosted.org/packages/23/30/07fb088f2eefdc0aa4fc1af4e3ca4eb1a3aadd1ce7d866d74c0f124e6a85/yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2", size = 345453 }, - { url = "https://files.pythonhosted.org/packages/63/09/d54befb48f9cd8eec43797f624ec37783a0266855f4930a91e3d5c7717f8/yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8", size = 341872 }, - { url = "https://files.pythonhosted.org/packages/91/26/fd0ef9bf29dd906a84b59f0cd1281e65b0c3e08c6aa94b57f7d11f593518/yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1", size = 347497 }, - { url = "https://files.pythonhosted.org/packages/d9/b5/14ac7a256d0511b2ac168d50d4b7d744aea1c1aa20c79f620d1059aab8b2/yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a", size = 359981 }, - { url = "https://files.pythonhosted.org/packages/ca/b3/d493221ad5cbd18bc07e642894030437e405e1413c4236dd5db6e46bcec9/yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10", size = 366229 }, - { url = "https://files.pythonhosted.org/packages/04/56/6a3e2a5d9152c56c346df9b8fb8edd2c8888b1e03f96324d457e5cf06d34/yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8", size = 360383 }, - { url = "https://files.pythonhosted.org/packages/fd/b7/4b3c7c7913a278d445cc6284e59b2e62fa25e72758f888b7a7a39eb8423f/yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d", size = 310152 }, - { url = "https://files.pythonhosted.org/packages/f5/d5/688db678e987c3e0fb17867970700b92603cadf36c56e5fb08f23e822a0c/yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c", size = 315723 }, - { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109 }, -] - -[[package]] -name = "zipp" -version = "3.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/50/bad581df71744867e9468ebd0bcd6505de3b275e06f202c2cb016e3ff56f/zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", size = 24545 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/1a/7e4798e9339adc931158c9d69ecc34f5e6791489d469f5e50ec15e35f458/zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931", size = 9630 }, -] diff --git a/src/exchanges/grvt/gateway.ts b/src/exchanges/grvt/gateway.ts index fe38376..9ab7318 100644 --- a/src/exchanges/grvt/gateway.ts +++ b/src/exchanges/grvt/gateway.ts @@ -2,6 +2,7 @@ import { setInterval, clearInterval } from "timers"; import { randomInt } from "crypto"; import axios, { AxiosHeaders } from "axios"; import { TDG, MDG } from "@grvt/client"; +import { WS, EStream, type TWSRequest } from "@grvt/client/ws"; import { ECandlestickInterval } from "@grvt/client/interfaces/codegen/enums/candlestick-interval"; import { ECandlestickType } from "@grvt/client/interfaces/codegen/enums/candlestick-type"; import { ETimeInForce } from "@grvt/client/interfaces/codegen/enums/time-in-force"; @@ -217,10 +218,16 @@ export class GrvtGateway { private accountSnapshot: AsterAccountSnapshot | null = null; private openOrders: AsterOrder[] = []; private positions: AsterAccountPosition[] = []; + private lastPositionsUpdateAt: number = 0; private depthSnapshot: AsterDepth | null = null; private tickerSnapshot: AsterTicker | null = null; private klineCache: KlineCache | null = null; + // WebSocket state + private ws: WS | null = null; + private wsConnected = false; + private positionsRefreshTimer: ReturnType | null = null; + private accountListeners = new Set<(snapshot: AsterAccountSnapshot) => void>(); private ordersListeners = new Set<(orders: AsterOrder[]) => void>(); private depthListeners = new Set<(depth: AsterDepth) => void>(); @@ -305,6 +312,7 @@ export class GrvtGateway { this.refreshKlines(), ]); this.startPolling(); + this.startWebsocket(); this.initialized = true; } @@ -417,6 +425,9 @@ export class GrvtGateway { const response = await this.tdg.createOrder({ order: toApiOrderPayload(signedOrder) }); const order = mapCreateOrderResponse(response, this.symbol); this.mergeOrder(order); + if (signedOrder.reduce_only) { + void this.refreshPositions().catch((error) => this.logger("postOrderPositionRefresh", error)); + } return order; } catch (error) { const payload = { @@ -500,6 +511,87 @@ export class GrvtGateway { } } + private startWebsocket(): void { + try { + if (this.ws) { + this.ws.disconnect(); + this.ws = null; + } + const base = this.hosts.trades.replace(/\/?$/g, ""); + const url = new URL(base.replace(/^http/, "ws") + "/ws/lite"); + // Pass auth as query params (server reads headers/cookies from params per client implementation) + const params: Record = {}; + for (const [key, value] of Object.entries(this.headers)) { + params[key] = value; + } + const ws = new WS({ + url: url.toString(), + timeout: 10000, + reconnectStrategy: (retries: number) => { + const attempt = Math.max(0, retries); + const base = 1000 * Math.pow(2, Math.min(8, attempt)); + const jitter = Math.floor(Math.random() * 250); + return Math.min(30000, base + jitter); + }, + }); + ws.setParams(params); + ws.onConnect(() => { + this.wsConnected = true; + // Prefer WS: pause HTTP position polling when connected + if (this.accountTimer) { + clearInterval(this.accountTimer); + this.accountTimer = null; + } + // Subscribe to position/order/state feeds + const subs: TWSRequest[] = [ + { + stream: EStream.POSITION, + params: { sub_account_id: this.subAccountId, instrument: this.instrument }, + onData: () => this.schedulePositionsRefresh(150), + } as any, + { + stream: EStream.ORDER, + params: { sub_account_id: this.subAccountId, instrument: this.instrument }, + onData: () => this.schedulePositionsRefresh(100), + } as any, + { + stream: EStream.STATE, + params: { sub_account_id: this.subAccountId, instrument: this.instrument }, + onData: () => this.schedulePositionsRefresh(100), + } as any, + ]; + ws.subscribes(...subs); + }); + ws.onClose(() => { + this.wsConnected = false; + // Resume HTTP position polling when WS closes + if (!this.accountTimer) { + this.accountTimer = setInterval(() => { + void this.refreshAccountSnapshot().catch((error) => this.logger("accountPoll", error)); + void this.refreshPositions().catch((error) => this.logger("positionPoll", error)); + }, this.pollIntervals.account); + } + }); + ws.onError((e) => { + this.logger("ws", e); + }); + ws.connect(); + this.ws = ws; + } catch (error) { + this.logger("startWebsocket", error); + } + } + + private schedulePositionsRefresh(delayMs: number): void { + if (this.positionsRefreshTimer) { + clearTimeout(this.positionsRefreshTimer); + } + this.positionsRefreshTimer = setTimeout(() => { + this.positionsRefreshTimer = null; + void this.refreshPositions().catch((error) => this.logger("wsPositionsRefresh", error)); + }, Math.max(0, delayMs)); + } + private async refreshAccountSnapshot(): Promise { const response = await this.tdg.subAccountSummary({ sub_account_id: this.subAccountId }); const snapshot = mapAccountSnapshot(response, this.symbol, this.instrument); @@ -509,7 +601,13 @@ export class GrvtGateway { private async refreshPositions(): Promise { const response = await this.tdg.positions({ sub_account_id: this.subAccountId }); - this.positions = mapPositions(response, this.symbol, this.instrument); + const mapped = mapPositions(response, this.symbol, this.instrument); + const newestEventTime = getNewestPositionEventTime(mapped); + if (newestEventTime < this.lastPositionsUpdateAt) { + return; + } + this.positions = mapped; + this.lastPositionsUpdateAt = newestEventTime; const snapshot = this.accountSnapshot; if (snapshot) { snapshot.positions = this.positions.map((position) => ({ ...position })); @@ -929,6 +1027,11 @@ function sumUnrealized(positions: AsterAccountPosition[]): number { return positions.reduce((total, position) => total + Number(position.unrealizedProfit ?? 0), 0); } +function getNewestPositionEventTime(positions: AsterAccountPosition[]): number { + if (!positions.length) return Date.now(); + return positions.reduce((max, p) => Math.max(max, Number(p.updateTime) || 0), 0); +} + function mapAccountSnapshot( response: IApiSubAccountSummaryResponse, symbol: string,