From 3845a3e5052fe7a38b270a81658f95c824d79c73 Mon Sep 17 00:00:00 2001 From: djeck1432 Date: Tue, 21 Jan 2025 19:27:47 +0100 Subject: [PATCH 01/42] remove duplicated code --- apps/data_handler/handlers/loan_states/zklend/events.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/data_handler/handlers/loan_states/zklend/events.py b/apps/data_handler/handlers/loan_states/zklend/events.py index dd3ef084..8b23f844 100644 --- a/apps/data_handler/handlers/loan_states/zklend/events.py +++ b/apps/data_handler/handlers/loan_states/zklend/events.py @@ -319,7 +319,6 @@ def process_withdrawal_event(self, event: pd.Series) -> None: # Update the user's deposit and collateral values self.loan_entities[user].deposit.increase_value(token=token, value=-raw_amount) - self.loan_entities[user].deposit.increase_value(token=token, value=-raw_amount) if self.loan_entities[user].collateral_enabled[token]: self.loan_entities[user].collateral.increase_value( From 88488e5256453d6d7bd07d038a9ba03b20617403 Mon Sep 17 00:00:00 2001 From: djeck1432 Date: Tue, 21 Jan 2025 19:34:41 +0100 Subject: [PATCH 02/42] add order_book test cases --- apps/data_handler/tests/order_book/__init__.py | 0 apps/data_handler/tests/order_book/test_ekubo.py | 0 apps/data_handler/tests/order_book/test_haiko.py | 0 apps/data_handler/tests/order_book/test_myswap.py | 0 apps/data_handler/tests/order_book/test_uniswap.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/data_handler/tests/order_book/__init__.py create mode 100644 apps/data_handler/tests/order_book/test_ekubo.py create mode 100644 apps/data_handler/tests/order_book/test_haiko.py create mode 100644 apps/data_handler/tests/order_book/test_myswap.py create mode 100644 apps/data_handler/tests/order_book/test_uniswap.py diff --git a/apps/data_handler/tests/order_book/__init__.py b/apps/data_handler/tests/order_book/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/data_handler/tests/order_book/test_ekubo.py b/apps/data_handler/tests/order_book/test_ekubo.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/data_handler/tests/order_book/test_haiko.py b/apps/data_handler/tests/order_book/test_haiko.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/data_handler/tests/order_book/test_myswap.py b/apps/data_handler/tests/order_book/test_myswap.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/data_handler/tests/order_book/test_uniswap.py b/apps/data_handler/tests/order_book/test_uniswap.py new file mode 100644 index 00000000..e69de29b From f8dd444420f0dddddaa22c20c195fa03a551cd98 Mon Sep 17 00:00:00 2001 From: djeck1432 Date: Tue, 21 Jan 2025 19:49:19 +0100 Subject: [PATCH 03/42] init sdk project --- apps/sdk/README.md | 11 + apps/sdk/__init__.py | 0 apps/sdk/api/__init__.py | 0 apps/sdk/api/main.py | 0 apps/sdk/main.py | 7 + apps/sdk/poetry.lock | 990 +++++++++++++++++++++++++++++++++++ apps/sdk/pyproject.toml | 17 + apps/sdk/schemas/__init__.py | 0 8 files changed, 1025 insertions(+) create mode 100644 apps/sdk/README.md create mode 100644 apps/sdk/__init__.py create mode 100644 apps/sdk/api/__init__.py create mode 100644 apps/sdk/api/main.py create mode 100644 apps/sdk/main.py create mode 100644 apps/sdk/poetry.lock create mode 100644 apps/sdk/pyproject.toml create mode 100644 apps/sdk/schemas/__init__.py diff --git a/apps/sdk/README.md b/apps/sdk/README.md new file mode 100644 index 00000000..2edd33f0 --- /dev/null +++ b/apps/sdk/README.md @@ -0,0 +1,11 @@ +# How to install project + +1. In `sdk` folder run next commands: + - Add environment: `python -m venv .venv` + - Activate environment: `source .venv/bin/activate` + - Install requirements: `poetry install` + - Activate poetry shell: `poetry shell` + +2. In `sdk` folder run next commands to run the project: + - Run the project: `poetry run uvicorn main:app --reload` + \ No newline at end of file diff --git a/apps/sdk/__init__.py b/apps/sdk/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/sdk/api/__init__.py b/apps/sdk/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/sdk/api/main.py b/apps/sdk/api/main.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/sdk/main.py b/apps/sdk/main.py new file mode 100644 index 00000000..18d0eb59 --- /dev/null +++ b/apps/sdk/main.py @@ -0,0 +1,7 @@ +from fastapi import FastAPI + +app = FastAPI() + + + + diff --git a/apps/sdk/poetry.lock b/apps/sdk/poetry.lock new file mode 100644 index 00000000..661d043b --- /dev/null +++ b/apps/sdk/poetry.lock @@ -0,0 +1,990 @@ +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "anyio" +version = "4.8.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.9" +files = [ + {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, + {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, +] + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +trio = ["trio (>=0.26.1)"] + +[[package]] +name = "backports-tarfile" +version = "1.2.0" +description = "Backport of CPython tarfile module" +optional = false +python-versions = ">=3.8" +files = [ + {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, + {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"] + +[[package]] +name = "certifi" +version = "2024.12.14" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, +] + +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.4.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +files = [ + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, +] + +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cryptography" +version = "44.0.0" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = "!=3.9.0,!=3.9.1,>=3.7" +files = [ + {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, + {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, + {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, + {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, + {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, + {file = "cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd"}, + {file = "cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, + {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, + {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, + {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, + {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, + {file = "cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa"}, + {file = "cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c"}, + {file = "cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02"}, +] + +[package.dependencies] +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +sdist = ["build (>=1.0.0)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi (>=2024)", "cryptography-vectors (==44.0.0)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "docutils" +version = "0.21.2" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.9" +files = [ + {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, + {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, +] + +[[package]] +name = "fastapi" +version = "0.115.6" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"}, + {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"}, +] + +[package.dependencies] +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.40.0,<0.42.0" +typing-extensions = ">=4.8.0" + +[package.extras] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "importlib-metadata" +version = "8.6.1" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.9" +files = [ + {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, + {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, +] + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "jaraco-classes" +version = "3.4.0" +description = "Utility functions for Python class constructs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, + {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, +] + +[package.dependencies] +more-itertools = "*" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "jaraco-context" +version = "6.0.1" +description = "Useful decorators and context managers" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, + {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, +] + +[package.dependencies] +"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} + +[package.extras] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "jaraco-functools" +version = "4.1.0" +description = "Functools like those found in stdlib" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649"}, + {file = "jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d"}, +] + +[package.dependencies] +more-itertools = "*" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"] +type = ["pytest-mypy"] + +[[package]] +name = "jeepney" +version = "0.8.0" +description = "Low-level, pure Python DBus protocol wrapper." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"}, + {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"}, +] + +[package.extras] +test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] +trio = ["async_generator", "trio"] + +[[package]] +name = "keyring" +version = "25.6.0" +description = "Store and access your passwords safely." +optional = false +python-versions = ">=3.9" +files = [ + {file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"}, + {file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"}, +] + +[package.dependencies] +importlib_metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} +"jaraco.classes" = "*" +"jaraco.context" = "*" +"jaraco.functools" = "*" +jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} +pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +completion = ["shtab (>=1.1.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["pyfakefs", "pytest (>=6,!=8.1.*)"] +type = ["pygobject-stubs", "pytest-mypy", "shtab", "types-pywin32"] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "more-itertools" +version = "10.6.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.9" +files = [ + {file = "more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b"}, + {file = "more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"}, +] + +[[package]] +name = "nh3" +version = "0.2.20" +description = "Python binding to Ammonia HTML sanitizer Rust crate" +optional = false +python-versions = ">=3.8" +files = [ + {file = "nh3-0.2.20-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db"}, + {file = "nh3-0.2.20-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a"}, + {file = "nh3-0.2.20-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c"}, + {file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2"}, + {file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5"}, + {file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0"}, + {file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208"}, + {file = "nh3-0.2.20-cp313-cp313t-win32.whl", hash = "sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886"}, + {file = "nh3-0.2.20-cp313-cp313t-win_amd64.whl", hash = "sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150"}, + {file = "nh3-0.2.20-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776"}, + {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38"}, + {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7"}, + {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace"}, + {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6"}, + {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b"}, + {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b"}, + {file = "nh3-0.2.20-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d"}, + {file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a"}, + {file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397"}, + {file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec"}, + {file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330"}, + {file = "nh3-0.2.20-cp38-abi3-win32.whl", hash = "sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784"}, + {file = "nh3-0.2.20-cp38-abi3-win_amd64.whl", hash = "sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b"}, + {file = "nh3-0.2.20.tar.gz", hash = "sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5"}, +] + +[[package]] +name = "packaging" +version = "24.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "pkginfo" +version = "1.12.0" +description = "Query metadata from sdists / bdists / installed packages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pkginfo-1.12.0-py3-none-any.whl", hash = "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088"}, + {file = "pkginfo-1.12.0.tar.gz", hash = "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf"}, +] + +[package.extras] +testing = ["pytest", "pytest-cov", "wheel"] + +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + +[[package]] +name = "pydantic" +version = "2.10.5" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, + {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.27.2" +typing-extensions = ">=4.12.2" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] + +[[package]] +name = "pydantic-core" +version = "2.27.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, + {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, + {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, + {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, + {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, + {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, + {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, + {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, + {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, + {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, + {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, + {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, + {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, + {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, + {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, + {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, + {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, + {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, + {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, + {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, + {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, + {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, + {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, + {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, + {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, + {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pygments" +version = "2.19.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, + {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, +] + +[[package]] +name = "readme-renderer" +version = "44.0" +description = "readme_renderer is a library for rendering readme descriptions for Warehouse" +optional = false +python-versions = ">=3.9" +files = [ + {file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"}, + {file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"}, +] + +[package.dependencies] +docutils = ">=0.21.2" +nh3 = ">=0.2.14" +Pygments = ">=2.5.1" + +[package.extras] +md = ["cmarkgfm (>=0.8.0)"] + +[[package]] +name = "requests" +version = "2.32.3" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +description = "A utility belt for advanced users of python-requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, +] + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +name = "rfc3986" +version = "2.0.0" +description = "Validating URI References per RFC 3986" +optional = false +python-versions = ">=3.7" +files = [ + {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, + {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, +] + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "rich" +version = "13.9.4" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "secretstorage" +version = "3.3.3" +description = "Python bindings to FreeDesktop.org Secret Service API" +optional = false +python-versions = ">=3.6" +files = [ + {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, + {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, +] + +[package.dependencies] +cryptography = ">=2.0" +jeepney = ">=0.6" + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "starlette" +version = "0.41.3" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.8" +files = [ + {file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"}, + {file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"}, +] + +[package.dependencies] +anyio = ">=3.4.0,<5" + +[package.extras] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] + +[[package]] +name = "twine" +version = "6.0.1" +description = "Collection of utilities for publishing packages on PyPI" +optional = false +python-versions = ">=3.8" +files = [ + {file = "twine-6.0.1-py3-none-any.whl", hash = "sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218"}, + {file = "twine-6.0.1.tar.gz", hash = "sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27"}, +] + +[package.dependencies] +keyring = {version = ">=15.1", markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} +packaging = "*" +pkginfo = ">=1.8.1" +readme-renderer = ">=35.0" +requests = ">=2.20" +requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" +rfc3986 = ">=1.4.0" +rich = ">=12.0.0" +urllib3 = ">=1.26.0" + +[package.extras] +keyring = ["keyring (>=15.1)"] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "urllib3" +version = "2.3.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +files = [ + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "uvicorn" +version = "0.34.0" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.9" +files = [ + {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, + {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, +] + +[package.dependencies] +click = ">=7.0" +h11 = ">=0.8" + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "zipp" +version = "3.21.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.9" +files = [ + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.11" +content-hash = "ed5ae763b2eb186671ab2b7287acebe916c260de1c379249f41ec97a801bf646" diff --git a/apps/sdk/pyproject.toml b/apps/sdk/pyproject.toml new file mode 100644 index 00000000..39aa9819 --- /dev/null +++ b/apps/sdk/pyproject.toml @@ -0,0 +1,17 @@ +[tool.poetry] +name = "derisk sdk" +version = "0.1.0" +description = "" +authors = ["djeck1432 "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.11" +twine = "^6.0.1" +fastapi = "^0.115.6" +uvicorn = "^0.34.0" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/apps/sdk/schemas/__init__.py b/apps/sdk/schemas/__init__.py new file mode 100644 index 00000000..e69de29b From ce30d5110690a653decf8eeb6d6cb11fc461efd2 Mon Sep 17 00:00:00 2001 From: djeck1432 Date: Tue, 21 Jan 2025 20:16:29 +0100 Subject: [PATCH 04/42] add mock data --- apps/sdk/api/main.py | 0 apps/sdk/mock_data.csv | 101 ++++++++++++++++++++++++++++++++++++++++ apps/sdk/poetry.lock | 2 +- apps/sdk/pyproject.toml | 1 + 4 files changed, 103 insertions(+), 1 deletion(-) delete mode 100644 apps/sdk/api/main.py create mode 100644 apps/sdk/mock_data.csv diff --git a/apps/sdk/api/main.py b/apps/sdk/api/main.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/sdk/mock_data.csv b/apps/sdk/mock_data.csv new file mode 100644 index 00000000..b0cb379a --- /dev/null +++ b/apps/sdk/mock_data.csv @@ -0,0 +1,101 @@ +#,block,timestamp,protocol_id,user,collateral,debt,deposit,id +1,61611,1684875854,zkLend,0x0514f1498aed7c2e4499fb8a9bc216aeef4d4eed13fff28d7ff54d6d6bb01e61,"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 1715403.2769719926}",{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 1715403.2769719926}",0d5e0ecc-4a7a-41e7-9603-d5243ec44a0d +2,85603,1687169814,zkLend,0x04ac055dfef29b0c0180755dbcaefe684158b15b2677ed3d03757f896cda161a,{},{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 5.884258476915483e+16}",74ec527c-9202-4fc5-b364-862ea58bc0dd +3,61611,1684875854,zkLend,0x07f07fa75dce9ef8c1ad1af5abed35eb44505fac86eea61b2cae7169a093291c,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1.3047584849033636e+16}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 30021523.549181923}",ec994981-74f0-4a85-9c72-7762471812a7 +4,75607,1686154030,zkLend,0x007d4bf9fe59d781198af72e8b2152bb3cf127c0052f0c027b2cebef2598442b,{},{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 7999331321764696.0}",d18d8211-a805-424f-bd2a-037086a74877 +5,79607,1686494339,zkLend,0x03c64c1adff8cd145f4193c08ea9c76daabe04c860990a068f157fe9ac81e35b,{},{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 6679645.777178112}",7902334c-40d0-4b93-8af7-3a182d23650d +6,61611,1684875854,zkLend,0x062d1d2e137c260eeeddc6b78a4dd6d199ab4870ec97eeedbfb385764a5769a9,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 4375955424430207.0}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 4375955424430207.0}",c985cef2-3e27-4352-b5da-599ecc0c8f82 +7,61611,1684875854,zkLend,0x073c32c7287d1d768c008ca127aa551fa30cf87484a5e3d5740147f8a0a4330f,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 9.999776949957578e+16}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 9.999776949957578e+16}",f643a5f3-7775-4e63-ae08-4c73fb95ec51 +8,61611,1684875854,zkLend,0x02b565c74b86051102ba70caf0aa0c434284cf7ec65ede5658307b2da24dbda7,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3096742317368203.5}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3096742317368203.5}",94fbb184-2e6a-4908-8317-36fbdd587c11 +9,73608,1685990194,zkLend,0x03e8998a82aa1a245754530cdeaea48c02aa3cbaf9177b42ca988d9babd149b7,{},"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": -26575855.0}",{},74be2957-7de9-4705-8acb-e2143acbb773 +10,87603,1687430027,zkLend,0x016fb92417edbde99359f72e4233316407b17cd94b60066e9ced64405303f702,"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 17399350.29157371}",{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 17399350.29157371}",4cd1b4c8-7b08-427d-a797-a2b2c96750a2 +11,61611,1684875854,zkLend,0x01bf6ae2ad13308fc9bd3358cba241890bb704687bbfbf9fd4eacf92de4746da,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 121997278586476.3}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 121997278586476.3}",51c2f279-8114-4e88-aab6-6ec1b9c61fcb +12,59612,1684626391,zkLend,0x070225e5d6afc2b9132c716b434ba864e23805bb8ea48d5c972ee4a4d497833e,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 4.9400683292592696e+16}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 1158195.7527528764}",6a906512-3a6a-4923-8666-6e3715a28d52 +13,59612,1684626391,zkLend,0x05c8b14d0e2ae3b68b111b0d7cd112a55682cacedc900febdb46905b0fd9d65a,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 7.799002778451026e+16}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 1812655.954566153}",4321c3e7-4734-4938-8cdb-d1561673926e +14,61611,1684875854,zkLend,0x015430f5bd7573cb3ded9c326b7375f670b83e6d63baa8eee0d568e5b5c2e9c2,"{""0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3"": 9.19465434558463e+17}",{},"{""0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3"": 9.19465434558463e+17}",2951ea99-595d-4bc5-9aef-0d0b1af99e02 +15,61611,1684875854,zkLend,0x03eb266094d13d11b7b19e3d777c88dcc75b2f364cc0d3417bd3042634f6821f,"{""0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3"": 9.940216017490213e+17}",{},"{""0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3"": 9.940216017490213e+17}",f5a81600-1cb2-4ade-87be-168d541c0cac +16,61611,1684875854,zkLend,0x0509dbfb262e61307fff8890615f7fd4bdb6e0fc204fef680effac2c80ab84ff,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 0.0}","{""0x0000000000000000000000000000000000000000000000000597c6c5391e3de9"": -4.17404284944524e+75}",8d323231-31de-44f8-a783-ff0c7d2f7b8b +17,61611,1684875854,zkLend,0x04b57d1a217b75610cd7808b2feeac8737aff413745b20970ba617ae1bdc94ae,{},{},"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 26977936.716226805}",1f964880-9ba2-4cb8-b0f4-6f8de0c345af +18,59612,1684626391,zkLend,0x06db5e5560de4a1d209bdfdb7159078686fa2d5e3275798c13ff285430f3096b,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": -2.168290301468851e+16}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 1549423.9894622408}",7c8c705c-3473-4d72-84c6-fcbdd0c669da +19,61611,1684875854,zkLend,0x016fe69358a1344f1004d7629c5f033a2995b6135db32ef1a6cd75bc853caba8,"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 238871.82836611467}",{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 238871.82836611467}",a274dbb1-02f9-420f-b2ba-cddb6af67c3e +20,75607,1686154030,zkLend,0x0205658da74b2534f8123976bb5bc766d7df2be75c2dd14d477bca3add0d3d0f,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": -6891083896654415.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1.0499121236159634e+16}",ac3da125-d9ff-4938-adcc-44fe2ecfb1f3 +21,81604,1686676010,zkLend,0x02896582232078fdc016f3e958ca108c585ce57ff13a931397bbc37f158ef178,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 4.999490626755813e+16}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 4.999490626755813e+16}",d9ba85c3-bed8-4ca7-b804-8f6652013284 +22,87603,1687430027,zkLend,0x067a37bd5fe7b63a3d545ff007db4dd40d39150fbb8e17459438d95a64f685fb,{},{},"{""0x000000000000000000000000000000000000000000000000063f9d7202c633e3"": -4.17404284944524e+75}",cf05f596-1519-4206-bfb8-a6ec78c13d4b +23,135603,1690724042,zkLend,0x02f5d193a9e31053cf409ae820e4ecc73fb2fd1b0b66ee58cb8a781d93a0f3cd,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3599196522409003.5}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3599196522409003.5}",8e93c8fb-3e30-4035-a44b-2e52f343c667 +24,75607,1686154030,zkLend,0x062b15e65a1e5b1b65b5f15570cde669aa02b17e606ebc667e0309bc59253bcf,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": -7191478304156717.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 8999247422305284.0}",06d29c7a-7092-435a-9b1d-139aea200257 +25,85603,1687169814,zkLend,0x05f61d5f1b5b4f485fc6e355c6b46137c94136f70d7c7a0446ac90802442c0dd,{},{},{},8c507f02-e178-46f3-8a49-24466975345d +26,63610,1685027240,zkLend,0x02db1a8d576b5cac866b43c11b44f4ee8150106b1fce46567fd543503d09a5f0,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 33551092978967.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 59997974840308.484}",8aea2404-0444-4bca-b920-51f170f03441 +27,57612,1684449503,zkLend,0x040d3d9bc588b40cb0e5b97e7adea134e4dea32bc0dcc08ff4e84442169871fa,{},{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 34121.349716157674}",8b7d1a45-f446-4ff6-9554-29350a1ea056 +28,59612,1684626391,zkLend,0x01566778cea6c27771b15cb0c00d75a75f710365fc231b6a12d2d61829a5c89f,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 16313997.0}",{},4ecf198c-cbec-4b0f-aaab-bb6debee4f7c +29,59612,1684626391,zkLend,0x02b549ef65b26e236ff8d6a9c988cd077fa311358d5b746334039afaee85d783,"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 21528997.28861783}",{},"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 21528997.28861783}",4470548e-9d9e-47a3-8449-103bd82f651a +30,59612,1684626391,zkLend,0x07e522ac331392f1524aa8f89bedaaabb500471811f8fb68af3e1d11a87a9104,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 421897988767450.3}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 421897988767450.3}",388913f8-3d7c-43fa-a67a-9ea376f3057f +31,59612,1684626391,zkLend,0x01c8a4c7661db38b59f10ab88e8e25fd07fbf9e14db1b33120402d46e388bd5d,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3105618594106283.0}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3105618594106283.0}",7fdecead-434f-4790-8866-14a4dff9cdba +32,59612,1684626391,zkLend,0x0022b064455c3c84f21d610bad448789f2a061b3de3473661d6ef6e4dcef5146,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 16628991.0}",{},0c3683ed-44b1-4994-bb70-405f185436ba +33,59612,1684626391,zkLend,0x014141ec501f93ad22a74b0fc9dff2deb033aea912de39a2ff8dd4a09d4856ad,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 16501746.0}",{},b720d27d-5b37-45f0-888c-384553f2f81e +34,59612,1684626391,zkLend,0x03d01c93c5fc60caa1b57acceb367e1593a87fefa08e96b7ff7c0a9f4bc1abf8,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 1542760.0}",{},1b0fed5c-c7aa-4e4c-85c2-3c9ec6c9f2f5 +35,59612,1684626391,zkLend,0x05adc8f6f70ab519656ac6a3e0720b68f8cbfe50a656ab50bc8995511cb6754a,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 113998047788280.95}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 113998047788280.95}",0b829831-069c-40ec-89f4-eb93b570c21a +36,59612,1684626391,zkLend,0x0075dd0ffe9ae2b5e9d1aa19daf1ecd1e99e7d6898eeea5add935c9b0b478eb1,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": -32327959.0}","{""0x0000000000000000000000000000000000000000000000000069c51c3a65516c"": -4.17404284944524e+75}",22814196-6193-416d-b533-c870859240f6 +37,59612,1684626391,zkLend,0x00b12ca9e6eeb969b2295747a9750ff0c3c7a50595ff3fad307ed89ecffa053c,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 7244059641688963.0}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 7244059641688963.0}",8509fbd1-c66f-4b1e-a91a-834a3379e958 +38,59612,1684626391,zkLend,0x06b3c97638130ecdd9bb396c1e8c59253762d37bd878c4d15fd82f9c6ea4c340,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 15017449.0}",{},87f45bf1-195b-42b3-92da-2bc0aefdaeb1 +39,59612,1684626391,zkLend,0x03e6f95dd0c1dad7dbc00df06b3f98ea0b70c3b7213dbee8c4795ef5f1ee19c8,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 9999828698286534.0}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 109983.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 9999828698286534.0, ""0x0000000000000000000000000000000000000000000000000023411618fa1a69"": -4.17404284944524e+75}",0ff2fc2e-32a2-4c3a-baff-94a258bd837d +40,59612,1684626391,zkLend,0x006d14f1dcf6c0173703a1f127757efad5fbb05b8e9d7c09b8408829215da91e,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 999982869828653.5}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 999982869828653.5}",885d2d2e-35f4-45ea-8a9f-cb29e6b99bbd +41,59612,1684626391,zkLend,0x009166e5afbea54582335ee704e2887faaf96c1d2581b9f70ad562c17b4c7904,"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 15550683.806861384}",{},"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 15550683.806861384, ""0x0000000000000000000000000000000000000000000000000000000000e3da74"": -5.9343481008916564e+75}",67c8fb3a-cc7b-405a-8b0b-e049092e4a8c +42,59612,1684626391,zkLend,0x0783b1c91fb8602203ef9e4b8b5a2f76d981427c33b60e03a88ebb3c2a8e5414,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 999982867721933.0}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 724662.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 999982867721933.0}",6843a6e5-d58d-47a7-b7d1-49d53217a640 +43,61611,1684875854,zkLend,0x06af64e8f8c190cb02427761fca3c47c6c210b38105bde5f8dfe8687ef59bea8,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 122997255171472.03}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 122997255171472.03}",4a8a5e09-9339-436a-b37f-a481a7c830b3 +44,61611,1684875854,zkLend,0x05edab6a2f2ec49b060a5a2c3b585f519b3aed55cd43c6feccac73338cdb4833,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 499988842160455.44}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 499988842160455.44}",62e5c5f2-ded9-4130-8988-35f3dbd03481 +45,59612,1684626391,zkLend,0x004dcf79146caaae58163bc3679ff19653a54f28c0dbff3b48f6cfb32376f338,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 2.684984147071774e+16}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 625961.9187331528}",2ea8913c-03bd-4025-a13a-db250e00e929 +46,61611,1684875854,zkLend,0x03c9cbff880281a3457f580f667e78e3e8a9277741273b5979cca28469ea3bde,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 519988395048107.06}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 519988395048107.06}",2d3602af-0f8e-4ed4-81e3-d573b33f257d +47,61611,1684875854,zkLend,0x0043cc9f78a97ee58a67faaf7558a6113f3ded96899909fee140c382d300b922,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1.2629718133572292e+16}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1.2629718133572292e+16, ""0x000000000000000000000000000000000000000000000000002cddc3559d4400"": -4.17404284944524e+75}",71868ee5-4908-460d-b658-7006c142913d +48,61611,1684875854,zkLend,0x04ec9f751c4f16279a56afcd2a834009e395d611d3d45c7b0634cc95e1167883,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1.6199638427682366e+16}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1.6199638427682366e+16, ""0x00000000000000000000000000000000000000000000000000398bfec4126000"": -4.17404284944524e+75}",543bd4d9-b42c-432e-9034-3141fa6ad077 +49,61611,1684875854,zkLend,0x04149d3dc55c5547130a952c843143ad06c8b9975b93fdde67fe5d02da7f8ca3,"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 11807102.361621851}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 0.0}","{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 11807102.361621851, ""0x0000000000000000000000000000000000000000000000000000000000b43858"": -5.9343481008916564e+75}",005967ef-576c-4af1-aa83-d6c53f023c37 +50,61611,1684875854,zkLend,0x01c0b416dc591d6869b1a843c7c2ccd9e1f3d132915d2424ff9e99a76374b2a1,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 529988169655133.4}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 529988169655133.4}",68fbc104-a05f-4b90-b0c8-2efa962bb215 +51,61611,1684875854,zkLend,0x0414612b30a448d7547b8e307c08380d80256d24ba32ef13fbf3004b8d1c0127,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1733777018152083.2}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1733777018152083.2}",38202a9d-961d-4597-9c99-b78408e79b13 +52,61611,1684875854,zkLend,0x034f10f63672626fb1719ff31b948d0f98f1605fbd79889749133992ea2982ae,"{""0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac"": 0.0, ""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 0.0, ""0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3"": 0.0, ""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 0.0, ""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 0.0}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 0.0, ""0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3"": 0.0, ""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 0.0, ""0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac"": 0.0, ""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 0.0}",d5bc36e0-8e71-47d0-bdc1-cfa7f81673d8 +53,61611,1684875854,zkLend,0x047995626ddd0043523da0a25d6fc7b6cb9700e168c9288e28bef204cd2065b6,{},{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 4999888413924106.0}",863e2810-91da-4ceb-a8e7-053f4b8855ed +54,85603,1687169814,zkLend,0x060d4b837062a60a5668f44bda5abf329cee185fccbb1e72f96e0914f21f2499,{},{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 99962856.01549998}",4c27b1d6-a112-4c15-b6ea-5ec664ab67ba +55,59612,1684626391,zkLend,0x0212072728239a357fe4ecbbf24537322915d64d93b03e20b4d2f06b88d9b761,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": -1.588599229238132e+16}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 1464686.094966671}",9de887cc-2899-42e3-a49b-13e1c6e7e1bd +56,61611,1684875854,zkLend,0x006dafad566e06f656027bb46c32ad4b065777905eca7cda5a890bc77b9051dc,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": -2719947840475234.0}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 88570006.7596581}",75905a23-f707-4f48-95eb-e1e649d2e232 +57,81604,1686676010,zkLend,0x028ad0710469c4fd6167a44a1192e785155bedfbc8fd6bb45b77eb4e9b3d552d,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 4.324884341693242e+16}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 4.324884341693242e+16}",2ab2f622-65a2-46d9-b93d-8ab4063579ce +58,87603,1687430027,zkLend,0x02094e9e2f307b938c6e0317b6ad726c4cf7120ea23490bfa8a6bba1f5876f17,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 0.0}","{""0x00000000000000000000000000000000000000000000000000a87b1a04d55168"": -4.17404284944524e+75}",4d508da1-e12b-4fc4-a9c1-44f66a84c401 +59,81604,1686676010,zkLend,0x033878d42af615430f94b209b4050a6c0bfbeb695053fd8ef84ab637fff74b7c,{},{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 2040601247872122.0}",58668808-f885-4166-9a54-3d18432a999f +60,61611,1684875854,zkLend,0x0146664998753c30c70f1ed76ee23c8dbc35b2b19f6d58962df5c0bce38a177a,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3.499921865449341e+16}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 0.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3.499921865449341e+16}",73736b5b-0e92-4c16-b917-7a5cf75bf73d +61,61611,1684875854,zkLend,0x03f2985089e790e1550eaa5a02068bbc188c79720ee513670d1d47234020d4aa,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 35999196261683.39}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 35999196261683.39}",090d5ce8-5616-4b3a-a5d1-734e1add5a96 +62,59612,1684626391,zkLend,0x07bab7ba876ed300ddec11bde9811ed2978bf1df6574b2e688e466a48c87e335,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": -7960037.0}",{},5480a9ba-2e07-4f9f-9c9a-835a0cfa138a +63,99603,1688846108,zkLend,0x072d236cb5708128eb07a35bcd1d41d58aea48f2a46240f1806f1bd5b7b9250d,"{""0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3"": 1.0562186673181542e+19}",{},"{""0x00da114221cb83fa859dbdb4c44beeaa0bb37c7537ad5ae66fe5e0efd20e6eb3"": 1.0562186673181542e+19}",85388237-f72c-4b04-bcba-b9d948793aa3 +64,85603,1687169814,zkLend,0x0621ef3c36b0cb9643b0262a13838f0b7039595a291e53702266750cc2787e0d,"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 867954252.1936822}",{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 867954252.1936822, ""0x0000000000000000000000000000000000000000000000000000000033c13ddd"": -4.737153647675251e+75}",11bfea8f-8948-4884-a537-bdc554d8af5c +65,59612,1684626391,zkLend,0x028d0cb0f87e7aea15064d6d35bc8282279e4c5e2f9800c252a00001dd61735d,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 15130115.0}",{},0ec3a5d6-e1e1-48ad-90dc-82ecc2467024 +66,59612,1684626391,zkLend,0x0577d9adbe6691d59b8cff768ab5d4bce8bd0a7aac9ecfd8dcdbcf608d16c491,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 19321118.0}",{},95f0b4f9-b294-48fa-a68c-2fb0058cfec6 +67,59612,1684626391,zkLend,0x034a7e18986ac4a34c6ea3dd7dd5fdb4669c65f9d7cc9a552aa5de827e1f015b,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 18833276.0}",{},368a5df1-100b-4f4a-a079-864c51b8c5d1 +68,59612,1684626391,zkLend,0x0317a4a079a276fb4c19c7378f5c8ca42687953c3d6c563b79effdbbde77761b,"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 9999771.125805598}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 7997828.0}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 9999771.125805598}",fd490e04-843f-45fa-9d45-4a7042a0e34b +69,59612,1684626391,zkLend,0x05ed35e61326179c0d5257fae96b6b05c3c9b917dd0efba42cb4cad07f331e39,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 15147344.0}",{},21534864-c87f-429b-91c3-538ce9e1443c +70,59612,1684626391,zkLend,0x06583ac0c8b0f92fb1032d780f16bdeae7daa1168d4137a88fb69b790c4390f6,"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 26999381.969801985}",{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 26999381.969801985}",ad01e5ce-0aa6-4fc7-9e59-d8af27b29c8f +71,59612,1684626391,zkLend,0x0061465a045190922d8570ce72fe84df6d39df85a1401ff5ba61ebdded84da97,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 23935597.0}",{},6266a724-f0f4-4b04-9297-803da1004bba +72,59612,1684626391,zkLend,0x07246a11843495bebfb7ac518aae9b33d5a5059babaec8598363fd0fab22f336,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 23934067.0}",{},3cf881af-e081-4785-b49a-14493e27fc31 +73,59612,1684626391,zkLend,0x008bf411b3380bdff6ba14f4c077308c2a9709fbd7477148397352a50f3950c8,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 395993108368267.1}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 395993108368267.1}",1c6be2bb-6297-456a-b760-c396e7bd8299 +74,59612,1684626391,zkLend,0x06b584d232673b6f4e4967f2be78bb4ee449d9efa5cd59f5e545f26db8f1cb5a,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 16030297.0}",{},1251c19c-232a-4319-94f6-80e356735041 +75,59612,1684626391,zkLend,0x07ea1afdb478c6eaddafd4e1f2b801530023347ac502a4f385d92fb6e27a1d9d,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 5999895581337381.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 2399139291027880.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 5999895581337381.0}",68be826e-5d95-46ca-a520-142fc652651e +76,59612,1684626391,zkLend,0x0469ff606007d5ac037a70b9f23c5d0fdb37a1b48fc2ebe08046c89e7374e7b6,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 18654642.0}",{},7554931f-8ec1-41a9-beb6-dec0cf642bc7 +77,59612,1684626391,zkLend,0x07f750eef7be4cc707117ba4165ad566297d5f3c2e5053699ae83ed2eb8c7045,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 18087631.0}",{},c578d31f-1cd2-4f43-9beb-66d380113d7a +78,59612,1684626391,zkLend,0x0793aad8330464de5f17be42934c6b3ac289bac0d43f12ed394f0354174d437c,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 22085281.0}",{},eb46ce57-1b4e-4b18-aa22-e2fb55ac641a +79,59612,1684626391,zkLend,0x0771e8852b0447fde64b555e9f6d88718ce599dc723346ff472b73a1012ea8ea,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 14868287.0}",{},027b37f1-c6d5-4717-ab8a-19e9cae8e18f +80,59612,1684626391,zkLend,0x071cd9ea331c000f5bab56085a95f1a835aa5fd947e4eff1656dedd7239a17f0,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 5999895557545727.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 2447122067144755.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 5999895557545727.0}",2d3799c8-ff1f-496b-b7c5-1d897fd049f9 +81,59612,1684626391,zkLend,0x01f2d930571648e273cf6f8627128d02d7779686c5e857b311a3fb97fb6ff157,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 5999895557545727.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 2351156429049209.0}","{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 5999895557545727.0}",b1d0e3a1-abb0-40de-97d2-991fab8fbf4e +82,59612,1684626391,zkLend,0x02ae87a4e4b863541bdbf2045c7f30de2e8d003d368c614e33979e5e50262c41,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 18538692.0}",{},a7557695-8065-430b-b525-bf96f4c3f9bb +83,59612,1684626391,zkLend,0x069b20add092b89c0bb8cf28d29f7a01fe61de98696514ebd95c9afcdcebc06a,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 18147943.0}",{},d6172bc1-5eed-4adc-81f3-0984e2a29c44 +84,59612,1684626391,zkLend,0x054b8a0dc79bc5a7ac25fdfac76ae68c386766a37b29f637feeaa86f60a09154,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 1779560.0}",{},80792a17-01f9-4e24-a389-803993f86925 +85,59612,1684626391,zkLend,0x076c57e5adcfcaea1d98e1e74071c6d7d5305b4edcff5d7437e151067a3c2f19,{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 15058699.0}",{},dc686e70-b899-4dac-aced-dde05425db45 +86,59612,1684626391,zkLend,0x0726ac02881f36637857d3e672e30dfe653c35941d5bbf4d458d99dbdcb47a1d,{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3.382691600687096e+16}","{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 822071.473575848}",93deb0b5-8a9f-4c48-a5bb-38e55c2a9b3f +87,61611,1684875854,zkLend,0x02102e19e847ab312701ae853ddf7d65570346c8aebbdaf85f0c7f3b8f7272b6,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1.6732027324039864e+16}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1.6732027324039864e+16}",d2c95d54-25af-4837-ae0d-21383480d2c6 +88,61611,1684875854,zkLend,0x030d0b091fceea6ddc993ecd862f5e94cfb0e329a773f8cbdfd49a19c80f8d59,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 123997231358727.6}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 123997231358727.6}",6b2ecb17-a7b3-4a61-8013-7aa8ce090a55 +89,61611,1684875854,zkLend,0x05c191ee3b004f0dd3c0f534ceb3dabc22401d2dde4ed2e6c292b1c36fc4283d,"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 51998001.02119159}",{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 51998001.02119159, ""0x00000000000000000000000000000000000000000000000000000000031960af"": -4.737153647675251e+75}",a139bfb3-761a-4b0d-b8de-3baae7603d8d +90,61611,1684875854,zkLend,0x06adddf42b87a1cfca6ce8612ae75adb34c3a4f5f18d7e11ff182f6c33391293,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 529988165082026.7}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 529988165082026.7}",593ad2fa-67b7-4c78-bc78-a92d47c9ce2e +91,61611,1684875854,zkLend,0x020b3815f18bc43b981b0727a09a0e54a04c067a03a5c2dac535d2644ffcce28,"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 59575.86155839251}","{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 20862.0}","{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 59575.86155839251}",afad3f1c-b929-409c-8f6b-ab2f649ad26f +92,61611,1684875854,zkLend,0x018e81504fedef74ab1a6c7dd1333041531c5dacbd4853e3d490c0f8ee93e3b1,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 584814278997958.8}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 584814278997958.8}",e2eca423-eddd-40de-a660-939fb251f5c1 +93,61611,1684875854,zkLend,0x03967e284f9870e6b8870f5ed4967a4731c3e80e6a8f3852f32efc7bd85a729b,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 119997319904692.12}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 119997319904692.12}",78872b4e-cfe6-4cbf-a08e-f464128a7e0b +94,61611,1684875854,zkLend,0x05b45afebd840f23c11db25650a6fd96e575b2d8235e8bff378534977bee48ae,{},"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 20484268.0}",{},7f954f73-8046-4735-9f00-bd133faf5ce1 +95,79607,1686494339,zkLend,0x065180ed76f151e811b5a82ed2e9ada77793d033d29c94b92fb0c16f6f278f1d,{},{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 1317233289293662.0}",4a45578b-00f6-4559-a545-2f68f2e020ce +96,61611,1684875854,zkLend,0x07c00cbe1999de4ffe94ade82174dd4057788281169d3e19b1e68a01683f1429,"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 26762449.047038414, ""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3720041396012704.5}",{},"{""0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"": 26762449.047038414, ""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 3720041396012704.5}",6373c0fa-0cad-4829-ba18-e32839a9802f +97,61611,1684875854,zkLend,0x022834e46f112471d426834494feea67a29096acf18b20670392b16397e3bc61,"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 500414.83294993953}","{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 79655.0}","{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 500414.83294993953}",5cd43cef-2c78-48c1-99d8-f10c30c146d1 +98,61611,1684875854,zkLend,0x037b63c8137434b093c0f0d442422a9b999708de645e3b41c39ef41d697773ed,"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 519988385181088.0}",{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 519988385181088.0}",b6f6e652-2dec-4ee6-9cb0-931dd4862956 +99,73608,1685990194,zkLend,0x05f21e7acf61eac8209d6ea75f6fa1a977dc4e32674b72639b5b9ac36ac2154c,{},{},"{""0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"": 999924789753291.0}",88ed2bbf-9474-4ca9-b9d5-967cea385b11 +100,61611,1684875854,zkLend,0x047f8aa321cdb3ef5defcc2f4884aeecddd47f7daaf0fbd2e4a978fef3dfaac4,"{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 13994094.60013445}","{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 0.0}","{""0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"": 13994094.60013445, ""0x0000000000000000000000000000000000000000000000000000000000d59a18"": -5.9343481008916564e+75}",28496cf1-687e-4989-ac8f-8856c14ba600 diff --git a/apps/sdk/poetry.lock b/apps/sdk/poetry.lock index 661d043b..ca95904c 100644 --- a/apps/sdk/poetry.lock +++ b/apps/sdk/poetry.lock @@ -987,4 +987,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "ed5ae763b2eb186671ab2b7287acebe916c260de1c379249f41ec97a801bf646" +content-hash = "9275cbe6f1f1e141d493def45a624ae011d2cd0efa37aac7682806d7e53307db" diff --git a/apps/sdk/pyproject.toml b/apps/sdk/pyproject.toml index 39aa9819..932aa586 100644 --- a/apps/sdk/pyproject.toml +++ b/apps/sdk/pyproject.toml @@ -10,6 +10,7 @@ python = "^3.11" twine = "^6.0.1" fastapi = "^0.115.6" uvicorn = "^0.34.0" +pydantic = "^2.10.5" [build-system] From 437625b343f3b06e3fbe84851c0e8a78427a099b Mon Sep 17 00:00:00 2001 From: djeck1432 Date: Wed, 22 Jan 2025 22:13:17 +0100 Subject: [PATCH 05/42] update poetry version --- apps/data_handler/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/data_handler/Dockerfile b/apps/data_handler/Dockerfile index 7cdbc54a..38e54c16 100644 --- a/apps/data_handler/Dockerfile +++ b/apps/data_handler/Dockerfile @@ -5,7 +5,7 @@ WORKDIR /code COPY data_handler/poetry.lock data_handler/pyproject.toml /code/ COPY data_handler/entrypoint.sh /code/entrypoint.sh -RUN pip install poetry \ +RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=/usr/local/ POETRY_VERSION=1.8.3 python3 -\ && poetry config virtualenvs.create false \ && poetry install --no-dev From e903d310eed11f3d0850f6b6e3e4a0798899f12f Mon Sep 17 00:00:00 2001 From: djeck1432 Date: Wed, 22 Jan 2025 22:29:24 +0100 Subject: [PATCH 06/42] fix test cases --- .../tests/loan_state/test_zklend_state_entity.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/data_handler/tests/loan_state/test_zklend_state_entity.py b/apps/data_handler/tests/loan_state/test_zklend_state_entity.py index 5f773ea5..12007379 100644 --- a/apps/data_handler/tests/loan_state/test_zklend_state_entity.py +++ b/apps/data_handler/tests/loan_state/test_zklend_state_entity.py @@ -115,11 +115,11 @@ def test_process_withdrawal_event(self, zklend_state, sample_event, mock_portfol """Test withdrawal event processing""" mock_parsed_data = MagicMock() mock_parsed_data.user = "0x123" - mock_parsed_data.token = "0x456" + mock_parsed_data.amount = "123" mock_parsed_data.face_amount = int(1e18) with patch( - "data_handler.handler_tools.data_parser.zklend.ZklendDataParser.parse_withdrawal_event", + "data_handler.handlers.loan_states.zklend.events.ZklendDataParser.parse_withdrawal_event", return_value=mock_parsed_data, ): user = mock_parsed_data.user @@ -131,7 +131,6 @@ def test_process_withdrawal_event(self, zklend_state, sample_event, mock_portfol loan_entity.extra_info = MagicMock() zklend_state.loan_entities[user] = loan_entity - zklend_state.process_withdrawal_event(sample_event) mock_portfolio.increase_value.assert_called() From 845de5998b4e39beaaece5a12ec6825f70d670b0 Mon Sep 17 00:00:00 2001 From: binayak9932 Date: Thu, 23 Jan 2025 04:07:37 +0530 Subject: [PATCH 07/42] first --- .../tests/order_book/test_myswap.py | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/apps/data_handler/tests/order_book/test_myswap.py b/apps/data_handler/tests/order_book/test_myswap.py index e69de29b..e0b08c2a 100644 --- a/apps/data_handler/tests/order_book/test_myswap.py +++ b/apps/data_handler/tests/order_book/test_myswap.py @@ -0,0 +1,109 @@ +""" Test Cases for MySwap""" + +import asyncio +import math +from decimal import Decimal +from unittest.mock import AsyncMock, Mock, patch + +import pytest + +from ...handlers.order_books.myswap.main import MySwapOrderBook + +MAX_MYSWAP_TICK = Decimal("1774532") + + +@pytest.fixture +def order_book(): + """Mocks""" + obj = MySwapOrderBook( + base_token="0x12345", quote_token="0x67890", apply_filtering=True + ) + obj.base_token = "0x12345" + obj.quote_token = "0x67890" + return obj + + +def test_order_book_initialization(order_book): + """Test that the order book is initialized correctly.""" + assert order_book.base_token == "0x12345" + assert order_book.quote_token == "0x67890" + assert order_book.apply_filtering is True + + +def test_price_to_tick(order_book): + """Test conversion of price to tick.""" + order_book._decimals_diff = Decimal(1) + price = Decimal("1.0001") + tick = order_book._price_to_tick(price) + expected_tick = ( + round( + Decimal(math.log(price / (Decimal(2**128) * order_book._decimals_diff))) + / Decimal(math.log(Decimal("1.0001"))) + ) + + MAX_MYSWAP_TICK + ) + assert tick == expected_tick + + +@patch.object(MySwapOrderBook, "_get_clean_addresses", return_value=("0x123", "0x456")) +def test_filter_pools_data(mock_get_clean_addresses, order_book): + """Test that the pool data is correctly filtered.""" + all_pools = { + "pools": [ + {"token0": {"address": "0x123"}, "token1": {"address": "0x456"}}, + {"token0": {"address": "0x999"}, "token1": {"address": "0x888"}}, + ] + } + filtered = order_book._filter_pools_data(all_pools) + assert len(filtered) == 1 + assert filtered[0]["token0"]["address"] == "0x123" + + +@patch.object( + MySwapOrderBook, "_filter_pools_data", return_value=[{"poolkey": "test_pool"}] +) +@patch.object(MySwapOrderBook, "_calculate_order_book", new_callable=AsyncMock) +def test_async_fetch_price_and_liquidity( + mock_calculate_order_book, mock_filter_pools, order_book +): + """Test the async fetching of price and liquidity.""" + order_book.connector = Mock() + order_book.connector.get_pools_data = Mock(return_value={"pools": []}) + + async def run_test(): + await order_book._async_fetch_price_and_liquidity() + + asyncio.run(run_test()) + mock_calculate_order_book.assert_awaited_once_with("test_pool") + + +@patch.object(MySwapOrderBook, "_get_clean_addresses", return_value=("0x123", "0x456")) +def test_filter_pools_data_no_match(mock_get_clean_addresses, order_book): + """Test filtering when no pools match.""" + all_pools = { + "pools": [ + {"token0": {"address": "0x999"}, "token1": {"address": "0x888"}}, + ] + } + filtered = order_book._filter_pools_data(all_pools) + assert len(filtered) == 0 + + +def test_price_to_tick_invalid(order_book): + """Test invalid price leading to ValueError.""" + order_book._decimals_diff = Decimal(1) + with pytest.raises(ValueError): + order_book._price_to_tick(Decimal(0)) + + +@patch.object(MySwapOrderBook, "_filter_pools_data", return_value=[]) +def test_async_fetch_price_and_liquidity_no_pools(mock_filter_pools, order_book): + """Test the async fetching when no pools are available.""" + order_book.connector = Mock() + order_book.connector.get_pools_data = Mock(return_value={"pools": []}) + + async def run_test(): + await order_book._async_fetch_price_and_liquidity() + + asyncio.run(run_test()) + mock_filter_pools.assert_called_once() From 273cc80d00c50e1a06a07ee7b06676d18c08dbd9 Mon Sep 17 00:00:00 2001 From: codebestia Date: Thu, 23 Jan 2025 01:55:22 +0100 Subject: [PATCH 08/42] chore: initial uniswapv2 test implementation --- .gitignore | 1 + .../tests/order_book/test_uniswap.py | 104 ++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/.gitignore b/.gitignore index 2f1b0d1f..41292be9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__ .vscode .env storage_credentials.json +env/ diff --git a/apps/data_handler/tests/order_book/test_uniswap.py b/apps/data_handler/tests/order_book/test_uniswap.py index e69de29b..5e2b8552 100644 --- a/apps/data_handler/tests/order_book/test_uniswap.py +++ b/apps/data_handler/tests/order_book/test_uniswap.py @@ -0,0 +1,104 @@ +from collections.abc import Iterable +from decimal import Decimal + +import pytest +from data_handler.handlers.order_books.processing import OrderBookProcessor +from data_handler.handlers.order_books.uniswap_v2 import main + + +@pytest.fixture +def order_book(): + """ + Fixture for the order book setup. + token_a and token_b gotten from constants (data_handlers.handlers.order_books.constants) + """ + token_a = "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" + token_b = "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8" + order_book = main.UniswapV2OrderBook(token_a, token_b) + return order_book + + +class TestUniswapV2OrderBook: + def test_set_token_name(self, order_book: main.UniswapV2OrderBook): + """ + Unit Test for UniswapV2OrderBook._set_token_names. + """ + # check that token_names has not been set + assert not getattr(order_book, "token_a_name"), "Token_a_name should be None" + assert not getattr(order_book, "token_b_name"), "Token_b_name should be None" + + # set token name + order_book._set_token_names() + + # check that token_names has been set + assert order_book.token_a_name, "token_a_name should be set" + assert order_book.token_b_name, "token_b_name should be set" + + # check that token_names match their mappings + assert order_book.token_a_name == "ETH", "token_a_name should be ETH" + assert order_book.token_b_name == "USDC", "token_b_name should be USDC" + + def test_tick_to_price(self, order_book: main.UniswapV2OrderBook): + """ + Unit test for UniswapV2OrderBook.tick_to_price + Note: calculation is based on the ETH/USDC pair + """ + tick_value = 1000 + price_value = 1.10517 + uniswap_price_value = order_book.tick_to_price(tick_value) + assert price_value == uniswap_price_value, "Invalid tick to price conversion" + + def test_add_quantities_data(self, order_book: main.UniswapV2OrderBook): + pass + + def test_calculate_liquidity_amount(self): + pass + + def test_get_prices_ranges(self, order_book: main.UniswapV2OrderBook): + """ + Unit test for UniswapV2OrderBook.get_price_ranges + """ + price_ranges = order_book.get_prices_range(Decimal("3012.92")) + assert isinstance(price_ranges, Iterable), "Price ranges should be a iterable" + assert ( + len(price_ranges) > 1 + ), "Price ranges list length should be greater than 1" + + def test_fetch_price_and_liquidity(self): + pass + + +class TestUniswapV2OrderBookProcessor: + def test_calculate_price_change_successful(self): + """ + Check whether calculate_price_change method call is successful + """ + processor = OrderBookProcessor( + "Starknet", + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", + ) + price = processor.calculate_price_change(Decimal("0.05")) + assert isinstance(price, Decimal) # :) + + def test_calculate_price_change_fail_with_invalid_args(self): + """ + Check that ValueError is raised when price_change_ratio argument is + greater than 1 or less than 0 or equal to zero + """ + processor = OrderBookProcessor( + "Starknet", + "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", + ) + with pytest.raises(ValueError, match="Provide valid price change ratio."): + # check whether it is greater than + price = processor.calculate_price_change(Decimal("5")) + + with pytest.raises(ValueError, match="Provide valid price change ratio."): + # fails when it is less than + price = processor.calculate_price_change(Decimal("-1")) + + with pytest.raises(ValueError, match="Current price of the pair is zero."): + # check whether it is greater than + price = processor.calculate_price_change(Decimal("0")) From e13d67ae22ae5cf5bc350d5a16e771982f3e2e06 Mon Sep 17 00:00:00 2001 From: Julius Shedrack <114742986+sheddiboo@users.noreply.github.com> Date: Thu, 23 Jan 2025 03:43:03 +0000 Subject: [PATCH 09/42] add user collateral endpoint --- apps/sdk/api/user.py | 67 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 apps/sdk/api/user.py diff --git a/apps/sdk/api/user.py b/apps/sdk/api/user.py new file mode 100644 index 00000000..90c1983c --- /dev/null +++ b/apps/sdk/api/user.py @@ -0,0 +1,67 @@ +from typing import Dict +from fastapi import APIRouter, HTTPException +from pydantic import BaseModel +import pandas as pd +import json +from pathlib import Path + +router = APIRouter( + prefix="/user", + tags=["user"], + responses={404: {"description": "Not found"}}, +) + +class UserCollateralResponse(BaseModel): + wallet_id: str + protocol_name: str + collateral: Dict[str, float] + +@router.get("/debt", response_model=UserCollateralResponse) +async def get_user_debt(wallet_id: str, protocol_name: str) -> UserCollateralResponse: + """ + Get user's collateral information for a specific protocol. + + Args: + wallet_id (str): The wallet ID of the user + protocol_name (str): The name of the protocol (e.g., 'zkLend') + + Returns: + UserCollateralResponse: User's collateral information + + Raises: + HTTPException: If user or protocol not found + """ + try: + data_path = "apps/sdk/mock_data.csv" + df = pd.read_csv(data_path) + + user_data = df[ + (df['user'] == wallet_id) & + (df['protocol_id'] == protocol_name) + ] + + if user_data.empty: + raise HTTPException( + status_code=404, + detail=f"No data found for wallet {wallet_id} in protocol {protocol_name}" + ) + latest_entry = user_data.sort_values('timestamp', ascending=False).iloc[0] + + try: + collateral = json.loads(latest_entry['collateral'].replace("'", '"')) + if not collateral: + collateral = {} + except (json.JSONDecodeError, AttributeError): + collateral = {} + + return UserCollateralResponse( + wallet_id=wallet_id, + protocol_name=protocol_name, + collateral=collateral + ) + + except Exception as e: + raise HTTPException( + status_code=500, + detail=f"Internal server error: {str(e)}" + ) \ No newline at end of file From 5ea83bc384fc35c96bd400f686d7689c5a5902e6 Mon Sep 17 00:00:00 2001 From: JoE11-y Date: Thu, 23 Jan 2025 10:37:45 +0100 Subject: [PATCH 10/42] add endpoint structure --- apps/sdk/api/loan_state.py | 15 +++++++++++++++ apps/sdk/api/routes.py | 17 +++++++++++++++++ apps/sdk/schemas/schemas.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 apps/sdk/api/loan_state.py create mode 100644 apps/sdk/api/routes.py create mode 100644 apps/sdk/schemas/schemas.py diff --git a/apps/sdk/api/loan_state.py b/apps/sdk/api/loan_state.py new file mode 100644 index 00000000..bed8582b --- /dev/null +++ b/apps/sdk/api/loan_state.py @@ -0,0 +1,15 @@ +from typing import Optional + +class LoanStateService: + async def get_user_loans_by_wallet_id( + protocol_name: str, + wallet_id: str, + start_block: Optional[int], + end_block: Optional[int] + ): + return { + "protocol_name": protocol_name, + "wallet_id": wallet_id, + "start_block": start_block, + "end_block": end_block + } diff --git a/apps/sdk/api/routes.py b/apps/sdk/api/routes.py new file mode 100644 index 00000000..ab6e3631 --- /dev/null +++ b/apps/sdk/api/routes.py @@ -0,0 +1,17 @@ +from fastapi import APIRouter, Depends +from loan_state import LoanStateService +from schemas.schemas import UserLoanByWalletParams, UserLoanByWalletResponse + +api_router = APIRouter +loan_state_service = LoanStateService() + + +@api_router.get("/loan_data_by_wallet_id", response_model=UserLoanByWalletResponse) +async def get_loans_by_wallet_id(params: UserLoanByWalletParams = Depends()): + loans = loan_state_service.get_user_loans_by_wallet_id( + protocol_name=params.protocol_name, + wallet_id=params.wallet_id, + start_block=params.start_block, + end_block=params.end_block + ) + return loans diff --git a/apps/sdk/schemas/schemas.py b/apps/sdk/schemas/schemas.py new file mode 100644 index 00000000..ec9a3131 --- /dev/null +++ b/apps/sdk/schemas/schemas.py @@ -0,0 +1,34 @@ +from pydantic import BaseModel +from typing import Dict, Optional + + +class UserLoanByWalletParams(BaseModel): + """ + Data model representing the parameters required to query a user's loan details by wallet ID. + + Attributes: + protocol_name: The name of the loan protocol (e.g., zkLend, Nostra). + wallet_id: The unique identifier of the user's wallet address. + start_block: The starting block number to filter loan data (inclusive). + end_block: The ending block number to filter loan data (inclusive). + """ + protocol_name: str + wallet_id: str + start_block: Optional[int] + end_block: Optional[int] + + +class UserLoanByWalletResponse(BaseModel): + """ + Data model representing the response for user loan details by wallet ID. + + Attributes: + wallet_id: The unique identifier of the user's wallet address. + collateral: A dictionary mapping token addresses to collateral values. + debt: A dictionary mapping token addresses to debt values. + deposit: A dictionary mapping token addresses to deposit values. + """ + wallet_id: str + collateral: Dict[str, float] + debt: Dict[str, float] + deposit: Dict[str, float] From 64ea8e046dd5e8411b3fb342cf2cd4232ce0b5c6 Mon Sep 17 00:00:00 2001 From: JoE11-y Date: Thu, 23 Jan 2025 12:22:24 +0100 Subject: [PATCH 11/42] finalize endpoint --- apps/sdk/api/loan_state.py | 91 +++++++++++++++++++++++++++++++------- apps/sdk/api/routes.py | 17 ------- apps/sdk/main.py | 5 ++- 3 files changed, 80 insertions(+), 33 deletions(-) delete mode 100644 apps/sdk/api/routes.py diff --git a/apps/sdk/api/loan_state.py b/apps/sdk/api/loan_state.py index bed8582b..8507b970 100644 --- a/apps/sdk/api/loan_state.py +++ b/apps/sdk/api/loan_state.py @@ -1,15 +1,76 @@ -from typing import Optional - -class LoanStateService: - async def get_user_loans_by_wallet_id( - protocol_name: str, - wallet_id: str, - start_block: Optional[int], - end_block: Optional[int] - ): - return { - "protocol_name": protocol_name, - "wallet_id": wallet_id, - "start_block": start_block, - "end_block": end_block - } +from fastapi import APIRouter, HTTPException +from schemas.schemas import UserLoanByWalletParams, UserLoanByWalletResponse +import pandas as pd + +loan_router = APIRouter + +@loan_router.get("/loan_data_by_wallet_id", response_model=UserLoanByWalletResponse) +async def get_loans_by_wallet_id(params: UserLoanByWalletParams = Depends()): + """ + Retrieve loan data associated with a specific wallet ID. + + endpoint allows users to query their loan details by providing a + wallet ID and optional block range parameters. The response includes + information about the user's collateral, debt, and deposits across + the specified loan protocol. + + Args: + wallet_id (str): The wallet ID of the user + protocol_name (str): The name of the loan protocol + start_block (int): The start block + end_block (int): The end block + + Returns: + UserLoanByWalletResponse: User loan Information + + Raises: + HTTPException: If address is not mapped + """ + + try: + data_path = "apps/sdk/mock_data.csv" + df = pd.read_csv(data_path) + + filter_df = df[ + (df['user'] == params.wallet_id) & + (df['protocol_id'] == params.protocol_name) + ] + + if params.start_block is not None: + filter_df = filter_df[filter_df['block'] >= params.start_block] + + if params.end_block is not None: + filter_df = filter_df[filter_df['block'] <= params.end_block] + + if filter_df.empty: + raise HTTPException( + status_code=404, + detail=f"No data found for user {params.wallet_id} in protocol {params.protocol_name}" + ) + + collateral_map = {} + debt_map = {} + deposit_map ={} + + for _, row in filter_df.iterrows(): + for token, value in row['collateral'].items(): + collateral_map[token] = collateral_map.get(token, 0) + value + for token, value in row['debt'].items(): + debt_map[token] = debt_map.get(token, 0) + value + for token, value in row['deposit'].items(): + deposit_map[token] = deposit_map.get(token, 0) + value + + return UserLoanByWalletResponse( + wallet_id=params.wallet_id, + protocol_name=params.protocol_name, + collateral=collateral_map, + debt=debt_map, + deposit=deposit_map + ) + + except Exception as e: + raise HTTPException( + status_code=500, + detail=f"Internal server error: {str(e)}" + ) + \ No newline at end of file diff --git a/apps/sdk/api/routes.py b/apps/sdk/api/routes.py deleted file mode 100644 index ab6e3631..00000000 --- a/apps/sdk/api/routes.py +++ /dev/null @@ -1,17 +0,0 @@ -from fastapi import APIRouter, Depends -from loan_state import LoanStateService -from schemas.schemas import UserLoanByWalletParams, UserLoanByWalletResponse - -api_router = APIRouter -loan_state_service = LoanStateService() - - -@api_router.get("/loan_data_by_wallet_id", response_model=UserLoanByWalletResponse) -async def get_loans_by_wallet_id(params: UserLoanByWalletParams = Depends()): - loans = loan_state_service.get_user_loans_by_wallet_id( - protocol_name=params.protocol_name, - wallet_id=params.wallet_id, - start_block=params.start_block, - end_block=params.end_block - ) - return loans diff --git a/apps/sdk/main.py b/apps/sdk/main.py index 18d0eb59..05b00c80 100644 --- a/apps/sdk/main.py +++ b/apps/sdk/main.py @@ -1,7 +1,10 @@ from fastapi import FastAPI +from api.loan_state import loan_router app = FastAPI() +version = "v1" +version_prefix = f"/api/{version}" - +app.include_router(loan_router, prefix=f"{version_prefix}/loans", tags=["loans"]) \ No newline at end of file From 33916fbb6fbb77acf9da35be63d57573a51fc59c Mon Sep 17 00:00:00 2001 From: Julius Shedrack <114742986+sheddiboo@users.noreply.github.com> Date: Thu, 23 Jan 2025 11:27:23 +0000 Subject: [PATCH 12/42] add user collateral endpoint --- apps/sdk/api/user.py | 6 +----- apps/sdk/api/user_model.py | 7 +++++++ 2 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 apps/sdk/api/user_model.py diff --git a/apps/sdk/api/user.py b/apps/sdk/api/user.py index 90c1983c..50b80809 100644 --- a/apps/sdk/api/user.py +++ b/apps/sdk/api/user.py @@ -1,9 +1,9 @@ from typing import Dict from fastapi import APIRouter, HTTPException -from pydantic import BaseModel import pandas as pd import json from pathlib import Path +from user_model import UserCollateralResponse router = APIRouter( prefix="/user", @@ -11,10 +11,6 @@ responses={404: {"description": "Not found"}}, ) -class UserCollateralResponse(BaseModel): - wallet_id: str - protocol_name: str - collateral: Dict[str, float] @router.get("/debt", response_model=UserCollateralResponse) async def get_user_debt(wallet_id: str, protocol_name: str) -> UserCollateralResponse: diff --git a/apps/sdk/api/user_model.py b/apps/sdk/api/user_model.py new file mode 100644 index 00000000..7c1233df --- /dev/null +++ b/apps/sdk/api/user_model.py @@ -0,0 +1,7 @@ +from typing import Dict +from pydantic import BaseModel + +class UserCollateralResponse(BaseModel): + wallet_id: str + protocol_name: str + collateral: Dict[str, float] \ No newline at end of file From f08e12c901b8d5d7ac1acddd2aeff7f88619aa49 Mon Sep 17 00:00:00 2001 From: Ryzen XP Date: Thu, 23 Jan 2025 17:04:04 +0530 Subject: [PATCH 13/42] [SDK] Add DatabaseConnector --- apps/sdk/.env.dev | 6 +++ apps/sdk/db_connector.py | 85 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 apps/sdk/.env.dev create mode 100644 apps/sdk/db_connector.py diff --git a/apps/sdk/.env.dev b/apps/sdk/.env.dev new file mode 100644 index 00000000..989b2e78 --- /dev/null +++ b/apps/sdk/.env.dev @@ -0,0 +1,6 @@ +# postgresql + +DB_HOST=your_host +DB_NAME=your_database +DB_USER=your_username +DB_PASSWORD=your_password \ No newline at end of file diff --git a/apps/sdk/db_connector.py b/apps/sdk/db_connector.py new file mode 100644 index 00000000..2353ef15 --- /dev/null +++ b/apps/sdk/db_connector.py @@ -0,0 +1,85 @@ +import psycopg2 +from dotenv import load_dotenv +import os + +class DBConnector: + def __init__(self): + + load_dotenv() + host = os.getenv("DB_HOST") + database = os.getenv("DB_NAME") + user = os.getenv("DB_USER") + password = os.getenv("DB_PASSWORD") + + try: + self.conn = psycopg2.connect( + host=host, + database=database, + user=user, + password=password + ) + self.cur = self.conn.cursor() + print("connected to PostgreSQL successfully.") + except (Exception, psycopg2.Error) as error: + print("Error while connecting to PostgreSQL:", error) + + def get_user_debt(self, protocol_id, wallet_id): + + try: + sql = """ + SELECT debt + FROM user_data + WHERE protocol_id = %s AND user = %s; + """ + self.cur.execute(sql, (protocol_id, wallet_id)) + result = self.cur.fetchone() + if result: + return result[0] + else: + return None + except (Exception, psycopg2.Error) as error: + print("Error while fetching user debt:", error) + return None + + def get_user_collateral(self, protocol_id, wallet_id): + + try: + sql = """ + SELECT collateral + FROM user_data + WHERE protocol_id = %s AND user = %s; + """ + self.cur.execute(sql, (protocol_id, wallet_id)) + result = self.cur.fetchone() + if result: + return result[0] + else: + return None + except (Exception, psycopg2.Error) as error: + print("Error while fetching user collateral:", error) + return None + + def get_loan_state(self, protocol_id, wallet_id): + # loan_state not in the test file + try: + sql = """ + SELECT loan_state + FROM user_data + WHERE protocol_id = %s AND user = %s; + """ + self.cur.execute(sql, (protocol_id, wallet_id)) + result = self.cur.fetchone() + if result: + return result[0] + else: + return None + except (Exception, psycopg2.Error) as error: + print("Error while fetching user loan state:", error) + return None + + def close_connection(self): + + if self.conn: + self.cur.close() + self.conn.close() + print("postgre sql connection closed.") From 6eed8d3e6d231c67e9b1c9fff25b98edebbdbe4d Mon Sep 17 00:00:00 2001 From: EjembiEmmanuel Date: Thu, 23 Jan 2025 13:46:07 +0100 Subject: [PATCH 14/42] feat: configure docker for sdk project --- apps/sdk/Dockerfile | 22 ++++++++++ apps/sdk/README.md | 83 ++++++++++++++++++++++++++++++++---- apps/sdk/docker-compose.yaml | 24 +++++++++++ 3 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 apps/sdk/Dockerfile create mode 100644 apps/sdk/docker-compose.yaml diff --git a/apps/sdk/Dockerfile b/apps/sdk/Dockerfile new file mode 100644 index 00000000..c4bced2e --- /dev/null +++ b/apps/sdk/Dockerfile @@ -0,0 +1,22 @@ +FROM python:3.11-slim + +WORKDIR /app + +RUN apt-get update && apt-get install -y \ + curl \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +RUN pip install --no-cache-dir poetry + +RUN poetry config virtualenvs.create false + +COPY pyproject.toml poetry.lock ./ + +RUN poetry install --no-root --only main + +COPY . . + +EXPOSE 8000 + +CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/apps/sdk/README.md b/apps/sdk/README.md index 2edd33f0..65e5047b 100644 --- a/apps/sdk/README.md +++ b/apps/sdk/README.md @@ -1,11 +1,76 @@ -# How to install project +# Derisk SDK -1. In `sdk` folder run next commands: - - Add environment: `python -m venv .venv` - - Activate environment: `source .venv/bin/activate` - - Install requirements: `poetry install` - - Activate poetry shell: `poetry shell` +This project is a FastAPI-based application, set up with Poetry for dependency management and Docker for containerization. -2. In `sdk` folder run next commands to run the project: - - Run the project: `poetry run uvicorn main:app --reload` - \ No newline at end of file +## Requirements + +- Docker +- Docker Compose + +## Project Setup + +### Run the Project + +1. **Build and Run the Services** + + Use `docker-compose` to build and run the project: + + ```bash + docker-compose up --build + ``` + + • The backend service will be accessible at http://localhost:8000. + + • The Redis service will run on port 6379. + +2. **Stop the Services** + + To stop the running containers, use: + + ```bash + docker-compose down + ``` + +## Access the API + +Once the services are up, visit http://localhost:8000/docs to access the interactive API documentation (Swagger UI). + +## Local Development Without Docker + +If you prefer running the project locally without Docker: + +1. **Create a virtual environment** + + ```bash + python -m venv .venv + ``` + +2. **Activate virtual environment** + + ```bash + source .venv/bin/activate + ``` + +3. **Install Poetry** + + ```bash + pip install poetry + ``` + +4. **Install Dependencies** + + ```bash + poetry install + ``` + +5. **Activate Poetry shell** + + ```bash + poetry shell + ``` + +6. **Run the Application** + + ```bash + uvicorn main:app --host 0.0.0.0 --port 8000 + ``` diff --git a/apps/sdk/docker-compose.yaml b/apps/sdk/docker-compose.yaml new file mode 100644 index 00000000..35011528 --- /dev/null +++ b/apps/sdk/docker-compose.yaml @@ -0,0 +1,24 @@ +version: "3.8" + +services: + backend: + build: + context: . + dockerfile: Dockerfile + ports: + - "8000:8000" + environment: + - PYTHONUNBUFFERED=1 + depends_on: + - redis + + redis: + image: redis:latest + restart: always + ports: + - "6379:6379" + volumes: + - redis_data:/data + +volumes: + redis_data: \ No newline at end of file From f67497e70991cd02b4953820b96c39901a9239ee Mon Sep 17 00:00:00 2001 From: EjembiEmmanuel Date: Thu, 23 Jan 2025 14:41:14 +0100 Subject: [PATCH 15/42] feat: use poetry fix version in Dockerfile --- apps/sdk/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sdk/Dockerfile b/apps/sdk/Dockerfile index c4bced2e..04dadaab 100644 --- a/apps/sdk/Dockerfile +++ b/apps/sdk/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get update && apt-get install -y \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* -RUN pip install --no-cache-dir poetry +RUN curl -sSL https://install.python-poetry.org/ | POETRY_HOME=/usr/local/ POETRY_VERSION=1.8.3 python3 - RUN poetry config virtualenvs.create false From 705f81a9fbee4612da51b62adcf8b5d30fefa58f Mon Sep 17 00:00:00 2001 From: codebestia Date: Thu, 23 Jan 2025 14:49:06 +0100 Subject: [PATCH 16/42] chore: finish implementation of unit test for uniswapv2_orderbook --- .../tests/order_book/test_uniswap.py | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/apps/data_handler/tests/order_book/test_uniswap.py b/apps/data_handler/tests/order_book/test_uniswap.py index 5e2b8552..1ee8d1b7 100644 --- a/apps/data_handler/tests/order_book/test_uniswap.py +++ b/apps/data_handler/tests/order_book/test_uniswap.py @@ -1,7 +1,9 @@ from collections.abc import Iterable from decimal import Decimal +from unittest.mock import MagicMock, patch import pytest +from data_handler.db.crud import DBConnector from data_handler.handlers.order_books.processing import OrderBookProcessor from data_handler.handlers.order_books.uniswap_v2 import main @@ -23,10 +25,6 @@ def test_set_token_name(self, order_book: main.UniswapV2OrderBook): """ Unit Test for UniswapV2OrderBook._set_token_names. """ - # check that token_names has not been set - assert not getattr(order_book, "token_a_name"), "Token_a_name should be None" - assert not getattr(order_book, "token_b_name"), "Token_b_name should be None" - # set token name order_book._set_token_names() @@ -43,16 +41,18 @@ def test_tick_to_price(self, order_book: main.UniswapV2OrderBook): Unit test for UniswapV2OrderBook.tick_to_price Note: calculation is based on the ETH/USDC pair """ - tick_value = 1000 - price_value = 1.10517 + tick_value = Decimal("500") uniswap_price_value = order_book.tick_to_price(tick_value) - assert price_value == uniswap_price_value, "Invalid tick to price conversion" - - def test_add_quantities_data(self, order_book: main.UniswapV2OrderBook): - pass + assert isinstance(uniswap_price_value, Decimal), "price should be a decimal" - def test_calculate_liquidity_amount(self): - pass + def test_calculate_liquidity_amount(self, order_book: main.UniswapV2OrderBook): + """ " + Unit test for UniswapV2OrderBook.calculate_liquidity_amount + """ + tick = Decimal("500") + final_value = Decimal("9.997500313723646666869072034E-15") + liquidity_amount = order_book.calculate_liquidity_amount(tick, Decimal("10000")) + assert final_value == liquidity_amount, "liquidity amount does not match" def test_get_prices_ranges(self, order_book: main.UniswapV2OrderBook): """ @@ -64,15 +64,23 @@ def test_get_prices_ranges(self, order_book: main.UniswapV2OrderBook): len(price_ranges) > 1 ), "Price ranges list length should be greater than 1" - def test_fetch_price_and_liquidity(self): - pass + def test_fetch_price_and_liquidity(self, order_book: main.UniswapV2OrderBook): + """ + Unit test for UniswapV2OrderBook.fetch_price_and_liquidity + """ + with patch( + "data_handler.handlers.order_books.uniswap_v2.main.UniswapV2OrderBook._async_fetch_price_and_liquidity", + ) as mock_fetch_price_and_liquidity: + order_book.fetch_price_and_liquidity() + mock_fetch_price_and_liquidity.assert_called() class TestUniswapV2OrderBookProcessor: - def test_calculate_price_change_successful(self): + def test_calculate_price_change_successful(self, mock_db_connector, monkeypatch): """ Check whether calculate_price_change method call is successful """ + monkeypatch.setattr(DBConnector, "__new__", mock_db_connector) processor = OrderBookProcessor( "Starknet", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", @@ -81,24 +89,27 @@ def test_calculate_price_change_successful(self): price = processor.calculate_price_change(Decimal("0.05")) assert isinstance(price, Decimal) # :) - def test_calculate_price_change_fail_with_invalid_args(self): + def test_calculate_price_change_fail_with_invalid_args( + self, mock_db_connector, monkeypatch + ): """ Check that ValueError is raised when price_change_ratio argument is greater than 1 or less than 0 or equal to zero """ + monkeypatch.setattr(DBConnector, "__new__", mock_db_connector) processor = OrderBookProcessor( "Starknet", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", ) - with pytest.raises(ValueError, match="Provide valid price change ratio."): + with pytest.raises(ValueError): # check whether it is greater than price = processor.calculate_price_change(Decimal("5")) - with pytest.raises(ValueError, match="Provide valid price change ratio."): + with pytest.raises(ValueError): # fails when it is less than price = processor.calculate_price_change(Decimal("-1")) - with pytest.raises(ValueError, match="Current price of the pair is zero."): + with pytest.raises(ValueError): # check whether it is greater than price = processor.calculate_price_change(Decimal("0")) From d7b6488336a3f09015868f27a058d3df12ea830d Mon Sep 17 00:00:00 2001 From: JoE11-y Date: Thu, 23 Jan 2025 15:25:25 +0100 Subject: [PATCH 17/42] resolve issues --- apps/sdk/api/loan_state.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/sdk/api/loan_state.py b/apps/sdk/api/loan_state.py index 8507b970..5d5c6973 100644 --- a/apps/sdk/api/loan_state.py +++ b/apps/sdk/api/loan_state.py @@ -1,9 +1,19 @@ from fastapi import APIRouter, HTTPException from schemas.schemas import UserLoanByWalletParams, UserLoanByWalletResponse +import json import pandas as pd loan_router = APIRouter +def parse_json(data): + try: + parsed = json.loads(data.replace("'", '"')) + if not parsed: + parsed = {} + return parsed + except (json.JSONDecodeError, AttributeError, TypeError): + return {} + @loan_router.get("/loan_data_by_wallet_id", response_model=UserLoanByWalletResponse) async def get_loans_by_wallet_id(params: UserLoanByWalletParams = Depends()): """ @@ -47,25 +57,19 @@ async def get_loans_by_wallet_id(params: UserLoanByWalletParams = Depends()): status_code=404, detail=f"No data found for user {params.wallet_id} in protocol {params.protocol_name}" ) - - collateral_map = {} - debt_map = {} - deposit_map ={} - - for _, row in filter_df.iterrows(): - for token, value in row['collateral'].items(): - collateral_map[token] = collateral_map.get(token, 0) + value - for token, value in row['debt'].items(): - debt_map[token] = debt_map.get(token, 0) + value - for token, value in row['deposit'].items(): - deposit_map[token] = deposit_map.get(token, 0) + value + + latest_entry = filter_df.sort_values('timestamp', ascending=False).iloc[0] + collateral = parse_json(latest_entry['collateral']) + debt = parse_json(latest_entry['debt']) + deposit = parse_json(latest_entry['deposit']) + return UserLoanByWalletResponse( wallet_id=params.wallet_id, protocol_name=params.protocol_name, - collateral=collateral_map, - debt=debt_map, - deposit=deposit_map + collateral=collateral, + debt=debt, + deposit=deposit ) except Exception as e: @@ -73,4 +77,4 @@ async def get_loans_by_wallet_id(params: UserLoanByWalletParams = Depends()): status_code=500, detail=f"Internal server error: {str(e)}" ) - \ No newline at end of file + From fb20f5103fbb32603eec17bf4d2e9d56dd961a5d Mon Sep 17 00:00:00 2001 From: JoE11-y Date: Thu, 23 Jan 2025 16:51:35 +0100 Subject: [PATCH 18/42] switch to strings --- apps/sdk/schemas/schemas.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/sdk/schemas/schemas.py b/apps/sdk/schemas/schemas.py index ec9a3131..8197d12d 100644 --- a/apps/sdk/schemas/schemas.py +++ b/apps/sdk/schemas/schemas.py @@ -29,6 +29,6 @@ class UserLoanByWalletResponse(BaseModel): deposit: A dictionary mapping token addresses to deposit values. """ wallet_id: str - collateral: Dict[str, float] - debt: Dict[str, float] - deposit: Dict[str, float] + collateral: Dict[str, str] + debt: Dict[str, str] + deposit: Dict[str, str] From aae132719fce5898f0a7d7fb465413a7c27186ab Mon Sep 17 00:00:00 2001 From: JoE11-y Date: Thu, 23 Jan 2025 16:55:11 +0100 Subject: [PATCH 19/42] clean up --- apps/sdk/api/loan_state.py | 1 - apps/sdk/main.py | 2 +- apps/sdk/schemas/schemas.py | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sdk/api/loan_state.py b/apps/sdk/api/loan_state.py index 5d5c6973..6549810a 100644 --- a/apps/sdk/api/loan_state.py +++ b/apps/sdk/api/loan_state.py @@ -77,4 +77,3 @@ async def get_loans_by_wallet_id(params: UserLoanByWalletParams = Depends()): status_code=500, detail=f"Internal server error: {str(e)}" ) - diff --git a/apps/sdk/main.py b/apps/sdk/main.py index 05b00c80..a363df1a 100644 --- a/apps/sdk/main.py +++ b/apps/sdk/main.py @@ -7,4 +7,4 @@ version_prefix = f"/api/{version}" -app.include_router(loan_router, prefix=f"{version_prefix}/loans", tags=["loans"]) \ No newline at end of file +app.include_router(loan_router, prefix=f"{version_prefix}/loans", tags=["loans"]) diff --git a/apps/sdk/schemas/schemas.py b/apps/sdk/schemas/schemas.py index 8197d12d..4eeeef7c 100644 --- a/apps/sdk/schemas/schemas.py +++ b/apps/sdk/schemas/schemas.py @@ -32,3 +32,4 @@ class UserLoanByWalletResponse(BaseModel): collateral: Dict[str, str] debt: Dict[str, str] deposit: Dict[str, str] + \ No newline at end of file From 6c1b7ce0d71ad4ee54496d2e2295198f63ff1ead Mon Sep 17 00:00:00 2001 From: Julius Shedrack <114742986+sheddiboo@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:05:55 +0000 Subject: [PATCH 20/42] add user collateral endpoint --- apps/data_handler/db/schemas.py | 6 ++++++ apps/sdk/api/user.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/data_handler/db/schemas.py b/apps/data_handler/db/schemas.py index 45bcede3..2fb17c1f 100644 --- a/apps/data_handler/db/schemas.py +++ b/apps/data_handler/db/schemas.py @@ -73,3 +73,9 @@ def validate_block(cls, value: int | None) -> int: if value is None: return 0 return value + +class UserCollateralResponse(BaseModel): + """ Base class for UserCollateralResponse """ + wallet_id: str + protocol_name: str + collateral: Dict[str, float] diff --git a/apps/sdk/api/user.py b/apps/sdk/api/user.py index 50b80809..26a0bb1b 100644 --- a/apps/sdk/api/user.py +++ b/apps/sdk/api/user.py @@ -3,7 +3,7 @@ import pandas as pd import json from pathlib import Path -from user_model import UserCollateralResponse +from apps.data_handler.db.schemas import UserCollateralResponse router = APIRouter( prefix="/user", From 60c393d51f79099dc8d2b869e7725f309a562ae8 Mon Sep 17 00:00:00 2001 From: Ryzen XP Date: Thu, 23 Jan 2025 22:00:40 +0530 Subject: [PATCH 21/42] requested changes --- apps/sdk/db_connector.py | 99 +++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 32 deletions(-) diff --git a/apps/sdk/db_connector.py b/apps/sdk/db_connector.py index 2353ef15..82857e0a 100644 --- a/apps/sdk/db_connector.py +++ b/apps/sdk/db_connector.py @@ -1,11 +1,25 @@ import psycopg2 from dotenv import load_dotenv import os +import logging + +load_dotenv() class DBConnector: - def __init__(self): - - load_dotenv() + """ + DBConnector manages PostgreSQL database connection and operations. + + Methods: + get_user_debt(protocol_id: str, wallet_id: str) -> float | None: Fetches user debt. + get_user_collateral(protocol_id: str, wallet_id: str) -> float | None: Fetches user collateral. + get_loan_state(protocol_id: str, wallet_id: str) -> str | None: Fetches loan state. + close_connection() -> None: Closes the database connection. + """ + + def __init__(self): + """ + Initializes DBConnector by connecting to the PostgreSQL database. + """ host = os.getenv("DB_HOST") database = os.getenv("DB_NAME") user = os.getenv("DB_USER") @@ -19,12 +33,22 @@ def __init__(self): password=password ) self.cur = self.conn.cursor() - print("connected to PostgreSQL successfully.") + logging.info("Connected to PostgreSQL successfully.") except (Exception, psycopg2.Error) as error: - print("Error while connecting to PostgreSQL:", error) + logging.info(f"Error while connecting to PostgreSQL: {error}") + raise + + def get_user_debt(self, protocol_id: str, wallet_id: str) -> float | None: + """ + fetches user debt for a given protocol and wallet. + + Args: + protocol_id (str): Protocol ID. + wallet_id (str): User's wallet ID. - def get_user_debt(self, protocol_id, wallet_id): - + Returns: + float | None: User debt if found, otherwise None. + """ try: sql = """ SELECT debt @@ -33,16 +57,22 @@ def get_user_debt(self, protocol_id, wallet_id): """ self.cur.execute(sql, (protocol_id, wallet_id)) result = self.cur.fetchone() - if result: - return result[0] - else: - return None + return result[0] if result else None except (Exception, psycopg2.Error) as error: - print("Error while fetching user debt:", error) - return None + logging.info(f"Error while fetching user debt: {error}") + raise - def get_user_collateral(self, protocol_id, wallet_id): - + def get_user_collateral(self, protocol_id: str, wallet_id: str) -> float | None: + """ + fetches user collateral for a given protocol and wallet. + + Args: + protocol_id (str): protocol ID + wallet_id (str): user wallet ID. + + Returns: + float | None: User collateral if found, otherwise None. + """ try: sql = """ SELECT collateral @@ -51,16 +81,22 @@ def get_user_collateral(self, protocol_id, wallet_id): """ self.cur.execute(sql, (protocol_id, wallet_id)) result = self.cur.fetchone() - if result: - return result[0] - else: - return None + return result[0] if result else None except (Exception, psycopg2.Error) as error: - print("Error while fetching user collateral:", error) - return None + logging.info(f"Error while fetching user collateral: {error}") + raise + + def get_loan_state(self, protocol_id: str, wallet_id: str) -> str | None: + """ + fetches user loan state for a given protocol and wallet. + + Args: + protocol_id (str): Protocol ID. + wallet_id (str): User's wallet ID. - def get_loan_state(self, protocol_id, wallet_id): - # loan_state not in the test file + Returns: + str | None: User's loan state if found, otherwise None. + """ try: sql = """ SELECT loan_state @@ -69,17 +105,16 @@ def get_loan_state(self, protocol_id, wallet_id): """ self.cur.execute(sql, (protocol_id, wallet_id)) result = self.cur.fetchone() - if result: - return result[0] - else: - return None + return result[0] if result else None except (Exception, psycopg2.Error) as error: - print("Error while fetching user loan state:", error) - return None + logging.info(f"Error while fetching user loan state: {error}") + raise - def close_connection(self): - + def close_connection(self) -> None: + """ + closes the database connection if open. + """ if self.conn: self.cur.close() self.conn.close() - print("postgre sql connection closed.") + logging.info("PostgreSQL connection closed.") From 379534b51404dddf8fe89507ce40b0b031d07b1b Mon Sep 17 00:00:00 2001 From: sudiptapaul Date: Thu, 23 Jan 2025 23:17:29 +0530 Subject: [PATCH 22/42] feat: implement rate limiting with SlowAPI --- apps/sdk/main.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/apps/sdk/main.py b/apps/sdk/main.py index 18d0eb59..a49f5a7c 100644 --- a/apps/sdk/main.py +++ b/apps/sdk/main.py @@ -1,7 +1,42 @@ -from fastapi import FastAPI +from fastapi import FastAPI, Request +from slowapi import Limiter, _rate_limit_exceeded_handler +from slowapi.util import get_remote_address +from slowapi.errors import RateLimitExceeded +from slowapi.middleware import SlowAPIMiddleware +import redis + app = FastAPI() +redis_client = redis.Redis(host='localhost', port=6379, db=0) + + +limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379") +app.state.limiter = limiter + +app.add_middleware(SlowAPIMiddleware) + +app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) + +@app.get("/test/") +@limiter.limit("1/second") +async def test_endpoint(request: Request): + return {"message": "This is a test endpoint"} + +@app.get("/debug/rate-limit") +async def debug_rate_limit(request: Request): + + client_ip = get_remote_address(request) + key = f"rate_limit:{client_ip}" + remaining_requests = redis_client.get(key) + return { + "client_ip": client_ip, + "remaining_requests": int(remaining_requests) if remaining_requests else "No limit set" + } +# Health check endpoint +@app.get("/health/") +async def health_check(): + return {"status": "ok"} \ No newline at end of file From 38a8d28341d25561c4e62da920633e6c41490784 Mon Sep 17 00:00:00 2001 From: sudiptapaul Date: Thu, 23 Jan 2025 23:20:46 +0530 Subject: [PATCH 23/42] Revert "feat: implement rate limiting with SlowAPI" This reverts commit 379534b51404dddf8fe89507ce40b0b031d07b1b. --- apps/sdk/main.py | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/apps/sdk/main.py b/apps/sdk/main.py index a49f5a7c..18d0eb59 100644 --- a/apps/sdk/main.py +++ b/apps/sdk/main.py @@ -1,42 +1,7 @@ -from fastapi import FastAPI, Request -from slowapi import Limiter, _rate_limit_exceeded_handler -from slowapi.util import get_remote_address -from slowapi.errors import RateLimitExceeded -from slowapi.middleware import SlowAPIMiddleware -import redis - +from fastapi import FastAPI app = FastAPI() -redis_client = redis.Redis(host='localhost', port=6379, db=0) - - -limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379") -app.state.limiter = limiter - -app.add_middleware(SlowAPIMiddleware) - -app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) - -@app.get("/test/") -@limiter.limit("1/second") -async def test_endpoint(request: Request): - return {"message": "This is a test endpoint"} - -@app.get("/debug/rate-limit") -async def debug_rate_limit(request: Request): - - client_ip = get_remote_address(request) - key = f"rate_limit:{client_ip}" - remaining_requests = redis_client.get(key) - return { - "client_ip": client_ip, - "remaining_requests": int(remaining_requests) if remaining_requests else "No limit set" - } -# Health check endpoint -@app.get("/health/") -async def health_check(): - return {"status": "ok"} \ No newline at end of file From 3d25189e9c5e420a9c6b7aacbcbc34f0283b995f Mon Sep 17 00:00:00 2001 From: Sagar Rana Date: Thu, 23 Jan 2025 23:28:05 +0530 Subject: [PATCH 24/42] added user.py --- apps/sdk/api/user.py | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 apps/sdk/api/user.py diff --git a/apps/sdk/api/user.py b/apps/sdk/api/user.py new file mode 100644 index 00000000..ddabca18 --- /dev/null +++ b/apps/sdk/api/user.py @@ -0,0 +1,57 @@ +from fastapi import FastAPI +from pydantic import BaseModel +from typing import Dict +import pandas as pd +import json + +app = FastAPI() + + +class ResponseModel(BaseModel): + wallet_id: str + protocol_name: str + debt: Dict[str, float] + + +file_path = "../mock_data.csv" +mock_data = pd.read_csv(file_path) + +def parse_debt_data(row): + try: + return json.loads(row) if row.strip() else {} + except json.JSONDecodeError: + return {} + +mock_data["debt"] = mock_data["debt"].apply(parse_debt_data) + + +debt_data = {} +for _, row in mock_data.iterrows(): + wallet_id = row["user"] + protocol = row["protocol_id"] + debt = row["debt"] + if wallet_id not in debt_data: + debt_data[wallet_id] = {} + debt_data[wallet_id][protocol] = debt + +@app.get("/get_user_debt", response_model=ResponseModel) +def get_user_debt(wallet_id: str, protocol_name: str): + """ + Endpoint to get the debt details of a user for a specific protocol. + + Args: + wallet_id (str): The wallet ID of the user. + protocol_name (str): The protocol name for which debt details are requested. + + Returns: + ResponseModel: The debt details including wallet ID, protocol name, and token-value pairs. + """ + wallet_data = debt_data.get(wallet_id) + if not wallet_data: + return {"wallet_id": wallet_id, "protocol_name": protocol_name, "debt": {}} + + protocol_data = wallet_data.get(protocol_name) + if not protocol_data: + return {"wallet_id": wallet_id, "protocol_name": protocol_name, "debt": {}} + + return {"wallet_id": wallet_id, "protocol_name": protocol_name, "debt": protocol_data} \ No newline at end of file From df6b2b74f6af51b04688bcefa7791e2b6325fbee Mon Sep 17 00:00:00 2001 From: sudiptapaul Date: Thu, 23 Jan 2025 23:36:05 +0530 Subject: [PATCH 25/42] feat: add rate limiting endpoints --- apps/sdk/main.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/sdk/main.py b/apps/sdk/main.py index 18d0eb59..c4dad58e 100644 --- a/apps/sdk/main.py +++ b/apps/sdk/main.py @@ -1,7 +1,34 @@ -from fastapi import FastAPI +from fastapi import FastAPI, Request +from slowapi import Limiter, _rate_limit_exceeded_handler +from slowapi.util import get_remote_address +from slowapi.errors import RateLimitExceeded +from slowapi.middleware import SlowAPIMiddleware +import redis app = FastAPI() +redis_client = redis.Redis(host='localhost', port=6379, db=0) +limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379") +app.state.limiter = limiter +app.add_middleware(SlowAPIMiddleware) +app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) +@app.get("/test/") +@limiter.limit("1/second") +async def test_endpoint(request: Request): + return {"message": "This is a test endpoint"} +@app.get("/debug/rate-limit") +async def debug_rate_limit(request: Request): + + client_ip = get_remote_address(request) + key = f"rate_limit:{client_ip}" + remaining_requests = redis_client.get(key) + return { + "client_ip": client_ip, + "remaining_requests": int(remaining_requests) if remaining_requests else "No limit set" + } +@app.get("/health/") +async def health_check(): + return {"status": "ok"} \ No newline at end of file From a4b9ca72d6d0e2176f2019388da6908b1e48944c Mon Sep 17 00:00:00 2001 From: Ryzen XP Date: Fri, 24 Jan 2025 02:54:42 +0530 Subject: [PATCH 26/42] requested changes --- apps/sdk/db_connector.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/sdk/db_connector.py b/apps/sdk/db_connector.py index 82857e0a..a34e1222 100644 --- a/apps/sdk/db_connector.py +++ b/apps/sdk/db_connector.py @@ -20,20 +20,30 @@ def __init__(self): """ Initializes DBConnector by connecting to the PostgreSQL database. """ + self.conn, self.cur = self.connect_to_db() + + def connect_to_db(self): + """ + make connection to the PostgreSQL DB and returns the connection and cursor. + + Returns: + tuple: (conn, cur) where conn is connection object and cur is cursor object. + """ host = os.getenv("DB_HOST") database = os.getenv("DB_NAME") user = os.getenv("DB_USER") password = os.getenv("DB_PASSWORD") try: - self.conn = psycopg2.connect( + conn = psycopg2.connect( host=host, database=database, user=user, password=password ) - self.cur = self.conn.cursor() - logging.info("Connected to PostgreSQL successfully.") + cur = conn.cursor() + logging.info("Connected to PostgreSQL successfully.") + return conn, cur except (Exception, psycopg2.Error) as error: logging.info(f"Error while connecting to PostgreSQL: {error}") raise From dcc18fb08b8b6087563849b925a90a4f33d63ddd Mon Sep 17 00:00:00 2001 From: Julius Shedrack <114742986+sheddiboo@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:43:35 +0000 Subject: [PATCH 27/42] add user collateral endpoint --- apps/sdk/api/user.py | 2 +- apps/sdk/schemas/schemas.py | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/sdk/api/user.py b/apps/sdk/api/user.py index 26a0bb1b..635d8315 100644 --- a/apps/sdk/api/user.py +++ b/apps/sdk/api/user.py @@ -3,7 +3,7 @@ import pandas as pd import json from pathlib import Path -from apps.data_handler.db.schemas import UserCollateralResponse +from sdk.schemas.schemas import UserCollateralResponse router = APIRouter( prefix="/user", diff --git a/apps/sdk/schemas/schemas.py b/apps/sdk/schemas/schemas.py index 4eeeef7c..290bc915 100644 --- a/apps/sdk/schemas/schemas.py +++ b/apps/sdk/schemas/schemas.py @@ -32,4 +32,16 @@ class UserLoanByWalletResponse(BaseModel): collateral: Dict[str, str] debt: Dict[str, str] deposit: Dict[str, str] - \ No newline at end of file + + +class UserCollateralResponse(BaseModel): + """ Base class for UserCollateralResponse + + Attributes: + wallet_id: The unique identifier of the user's wallet address. + protocol_name: The name of the loan protocol (e.g., zkLend, Nostra). + collateral: A dictionary mapping token addresses to collateral values. + """ + wallet_id: str + protocol_name: str + collateral: Dict[str, float] From be495967b27e35535240afba4683f693db5b8e5f Mon Sep 17 00:00:00 2001 From: sudiptapaul Date: Fri, 24 Jan 2025 08:41:26 +0530 Subject: [PATCH 28/42] Updated packages --- apps/sdk/api/loan_state.py | 26 +++++++---- apps/sdk/main.py | 33 +++++++++++-- apps/sdk/poetry.lock | 96 ++++++++++++++++++++++++++++++++++++-- apps/sdk/pyproject.toml | 1 + 4 files changed, 142 insertions(+), 14 deletions(-) diff --git a/apps/sdk/api/loan_state.py b/apps/sdk/api/loan_state.py index 6549810a..28e3d453 100644 --- a/apps/sdk/api/loan_state.py +++ b/apps/sdk/api/loan_state.py @@ -1,18 +1,28 @@ from fastapi import APIRouter, HTTPException +from fastapi import Depends from schemas.schemas import UserLoanByWalletParams, UserLoanByWalletResponse import json import pandas as pd -loan_router = APIRouter +loan_router = APIRouter() + +# def parse_json(data): +# try: +# parsed = json.loads(data.replace("'", '"')) +# if not parsed: +# parsed = {} +# return parsed +# except (json.JSONDecodeError, AttributeError, TypeError): +# return {} def parse_json(data): - try: - parsed = json.loads(data.replace("'", '"')) - if not parsed: - parsed = {} - return parsed - except (json.JSONDecodeError, AttributeError, TypeError): - return {} + if isinstance(data, str): + try: + return json.loads(data.replace("'", '"')) + except json.JSONDecodeError: + pass + return {} + @loan_router.get("/loan_data_by_wallet_id", response_model=UserLoanByWalletResponse) async def get_loans_by_wallet_id(params: UserLoanByWalletParams = Depends()): diff --git a/apps/sdk/main.py b/apps/sdk/main.py index a363df1a..608d4fe3 100644 --- a/apps/sdk/main.py +++ b/apps/sdk/main.py @@ -1,10 +1,37 @@ -from fastapi import FastAPI -from api.loan_state import loan_router +from fastapi import FastAPI, Request, HTTPException +from fastapi.routing import APIRouter +from slowapi import Limiter +from slowapi.util import get_remote_address +from slowapi.errors import RateLimitExceeded +from api.loan_state import loan_router # Use the imported loan_router directly +from pydantic import BaseModel +import redis app = FastAPI() version = "v1" version_prefix = f"/api/{version}" +redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True) -app.include_router(loan_router, prefix=f"{version_prefix}/loans", tags=["loans"]) +limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379") + +app.state.limiter = limiter + +@app.middleware("http") +async def rate_limiter_middleware(request: Request, call_next): + try: + response = await limiter(request=request, call_next=call_next) + return response + except RateLimitExceeded: + raise HTTPException( + status_code=429, + detail="Too Many Requests. Please try again later." + ) + +app.include_router(loan_router, prefix=f"{version_prefix}/loans", tags=["loans"]) # Use loan_router from loan_state + +@app.get("/test") +@limiter.limit("5/minute") +async def test_endpoint(request: Request): + return {"message": "This is a rate-limited endpoint"} diff --git a/apps/sdk/poetry.lock b/apps/sdk/poetry.lock index ca95904c..3330d572 100644 --- a/apps/sdk/poetry.lock +++ b/apps/sdk/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -6,6 +6,7 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -17,6 +18,7 @@ version = "4.8.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, @@ -32,12 +34,27 @@ doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_full_version < \"3.11.3\"" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] + [[package]] name = "backports-tarfile" version = "1.2.0" description = "Backport of CPython tarfile module" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version < \"3.12\"" files = [ {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, @@ -53,6 +70,7 @@ version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, @@ -64,6 +82,8 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -143,6 +163,7 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, @@ -244,6 +265,7 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -258,6 +280,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +markers = "platform_system == \"Windows\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -269,6 +293,8 @@ version = "44.0.0" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\"" files = [ {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, @@ -318,6 +344,7 @@ version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, @@ -329,6 +356,7 @@ version = "0.115.6" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"}, {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"}, @@ -349,6 +377,7 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, @@ -360,6 +389,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -374,6 +404,8 @@ version = "8.6.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version < \"3.12\"" files = [ {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, @@ -397,6 +429,8 @@ version = "3.4.0" description = "Utility functions for Python class constructs" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, @@ -415,6 +449,8 @@ version = "6.0.1" description = "Useful decorators and context managers" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, @@ -433,6 +469,8 @@ version = "4.1.0" description = "Functools like those found in stdlib" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649"}, {file = "jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d"}, @@ -455,6 +493,8 @@ version = "0.8.0" description = "Low-level, pure Python DBus protocol wrapper." optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\"" files = [ {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"}, {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"}, @@ -470,6 +510,8 @@ version = "25.6.0" description = "Store and access your passwords safely." optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"}, {file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"}, @@ -499,6 +541,7 @@ version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, @@ -523,6 +566,7 @@ version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, @@ -534,6 +578,8 @@ version = "10.6.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b"}, {file = "more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"}, @@ -545,6 +591,7 @@ version = "0.2.20" description = "Python binding to Ammonia HTML sanitizer Rust crate" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "nh3-0.2.20-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db"}, {file = "nh3-0.2.20-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a"}, @@ -578,6 +625,7 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -589,6 +637,7 @@ version = "1.12.0" description = "Query metadata from sdists / bdists / installed packages." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pkginfo-1.12.0-py3-none-any.whl", hash = "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088"}, {file = "pkginfo-1.12.0.tar.gz", hash = "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf"}, @@ -603,6 +652,8 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -614,6 +665,7 @@ version = "2.10.5" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, @@ -634,6 +686,7 @@ version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, @@ -746,6 +799,7 @@ version = "2.19.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, @@ -760,6 +814,8 @@ version = "0.2.3" description = "A (partial) reimplementation of pywin32 using ctypes/cffi" optional = false python-versions = ">=3.6" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"win32\"" files = [ {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, @@ -771,6 +827,7 @@ version = "44.0" description = "readme_renderer is a library for rendering readme descriptions for Warehouse" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"}, {file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"}, @@ -784,12 +841,32 @@ Pygments = ">=2.5.1" [package.extras] md = ["cmarkgfm (>=0.8.0)"] +[[package]] +name = "redis" +version = "5.2.1" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"}, + {file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"}, +] + +[package.dependencies] +async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} + +[package.extras] +hiredis = ["hiredis (>=3.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==23.2.1)", "requests (>=2.31.0)"] + [[package]] name = "requests" version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -811,6 +888,7 @@ version = "1.0.0" description = "A utility belt for advanced users of python-requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, @@ -825,6 +903,7 @@ version = "2.0.0" description = "Validating URI References per RFC 3986" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, @@ -839,6 +918,7 @@ version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, @@ -857,6 +937,8 @@ version = "3.3.3" description = "Python bindings to FreeDesktop.org Secret Service API" optional = false python-versions = ">=3.6" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\"" files = [ {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, @@ -872,6 +954,7 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -883,6 +966,7 @@ version = "0.41.3" description = "The little ASGI library that shines." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"}, {file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"}, @@ -900,6 +984,7 @@ version = "6.0.1" description = "Collection of utilities for publishing packages on PyPI" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "twine-6.0.1-py3-none-any.whl", hash = "sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218"}, {file = "twine-6.0.1.tar.gz", hash = "sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27"}, @@ -925,6 +1010,7 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -936,6 +1022,7 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, @@ -953,6 +1040,7 @@ version = "0.34.0" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, @@ -971,6 +1059,8 @@ version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version < \"3.12\"" files = [ {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, @@ -985,6 +1075,6 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", type = ["pytest-mypy"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.11" -content-hash = "9275cbe6f1f1e141d493def45a624ae011d2cd0efa37aac7682806d7e53307db" +content-hash = "252bb6ac9d035a43b7db91ecd0d1131ce793fb9c42fba70e125bf0a5861416ba" diff --git a/apps/sdk/pyproject.toml b/apps/sdk/pyproject.toml index 932aa586..06f28bbc 100644 --- a/apps/sdk/pyproject.toml +++ b/apps/sdk/pyproject.toml @@ -11,6 +11,7 @@ twine = "^6.0.1" fastapi = "^0.115.6" uvicorn = "^0.34.0" pydantic = "^2.10.5" +redis = "^5.0.0" [build-system] From 0a79be4bc53e499bd2d17a0f40fd90477207d1aa Mon Sep 17 00:00:00 2001 From: sudiptapaul Date: Fri, 24 Jan 2025 08:46:59 +0530 Subject: [PATCH 29/42] Package changes --- apps/sdk/main.py | 49 ++- apps/sdk/poetry.lock | 844 +++++++--------------------------------- apps/sdk/pyproject.toml | 1 + 3 files changed, 157 insertions(+), 737 deletions(-) diff --git a/apps/sdk/main.py b/apps/sdk/main.py index c4dad58e..f277a960 100644 --- a/apps/sdk/main.py +++ b/apps/sdk/main.py @@ -1,34 +1,33 @@ -from fastapi import FastAPI, Request -from slowapi import Limiter, _rate_limit_exceeded_handler +from fastapi import FastAPI, Request, HTTPException +from fastapi.routing import APIRouter +from slowapi import Limiter from slowapi.util import get_remote_address from slowapi.errors import RateLimitExceeded -from slowapi.middleware import SlowAPIMiddleware +from api.loan_state import loan_router # Use the imported loan_router directly +from pydantic import BaseModel import redis app = FastAPI() +version = "v1" +version_prefix = f"/api/{version}" + +redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True) -redis_client = redis.Redis(host='localhost', port=6379, db=0) limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379") app.state.limiter = limiter -app.add_middleware(SlowAPIMiddleware) -app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) -@app.get("/test/") -@limiter.limit("1/second") -async def test_endpoint(request: Request): - return {"message": "This is a test endpoint"} - -@app.get("/debug/rate-limit") -async def debug_rate_limit(request: Request): - - client_ip = get_remote_address(request) - key = f"rate_limit:{client_ip}" - remaining_requests = redis_client.get(key) - return { - "client_ip": client_ip, - "remaining_requests": int(remaining_requests) if remaining_requests else "No limit set" - } - -@app.get("/health/") -async def health_check(): - return {"status": "ok"} \ No newline at end of file +@app.middleware("http") +async def rate_limiter_middleware(request: Request, call_next): + try: + response = await limiter(request=request, call_next=call_next) + return response + except RateLimitExceeded: + raise HTTPException( + status_code=429, + detail="Too Many Requests. Please try again later." + ) +app.include_router(loan_router, prefix=f"{version_prefix}/loans", tags=["loans"]) # Use loan_router from loan_state +@app.get("/test") +@limiter.limit("5/minute") +async def test_endpoint(request: Request): + return {"message": "This is a rate-limited endpoint"} \ No newline at end of file diff --git a/apps/sdk/poetry.lock b/apps/sdk/poetry.lock index ca95904c..b2c028cd 100644 --- a/apps/sdk/poetry.lock +++ b/apps/sdk/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -6,985 +6,405 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, -] - -[[package]] -name = "anyio" -version = "4.8.0" +@@ -17,6 +18,7 @@ version = "4.8.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, -] - -[package.dependencies] -idna = ">=2.8" -sniffio = ">=1.1" -typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} - -[package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +@@ -32,12 +34,27 @@ doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_full_version < \"3.11.3\"" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] [[package]] name = "backports-tarfile" version = "1.2.0" description = "Backport of CPython tarfile module" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version < \"3.12\"" files = [ {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"] - -[[package]] -name = "certifi" -version = "2024.12.14" +@@ -53,6 +70,7 @@ version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, -] - -[[package]] -name = "cffi" -version = "1.17.1" +@@ -64,6 +82,8 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, -] - -[package.dependencies] -pycparser = "*" - -[[package]] -name = "charset-normalizer" -version = "3.4.1" +@@ -143,6 +163,7 @@ version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, - {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, - {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, -] - -[[package]] -name = "click" -version = "8.1.8" +@@ -244,6 +265,7 @@ version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" +@@ -258,6 +280,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +markers = "platform_system == \"Windows\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "cryptography" -version = "44.0.0" +@@ -269,6 +293,8 @@ version = "44.0.0" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\"" files = [ {file = "cryptography-44.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123"}, {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b"}, - {file = "cryptography-44.0.0-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543"}, - {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e"}, - {file = "cryptography-44.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e"}, - {file = "cryptography-44.0.0-cp37-abi3-win32.whl", hash = "sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053"}, - {file = "cryptography-44.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd"}, - {file = "cryptography-44.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7"}, - {file = "cryptography-44.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c"}, - {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64"}, - {file = "cryptography-44.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285"}, - {file = "cryptography-44.0.0-cp39-abi3-win32.whl", hash = "sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417"}, - {file = "cryptography-44.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa"}, - {file = "cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c"}, - {file = "cryptography-44.0.0.tar.gz", hash = "sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02"}, -] - -[package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} - -[package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"] -docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] -nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"] -pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] -sdist = ["build (>=1.0.0)"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==44.0.0)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] -test-randomorder = ["pytest-randomly"] - -[[package]] -name = "docutils" -version = "0.21.2" +@@ -318,6 +344,7 @@ version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, -] - -[[package]] -name = "fastapi" -version = "0.115.6" +@@ -329,6 +356,7 @@ version = "0.115.6" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"}, {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"}, -] - -[package.dependencies] -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.40.0,<0.42.0" -typing-extensions = ">=4.8.0" - -[package.extras] -all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] - -[[package]] -name = "h11" -version = "0.14.0" +@@ -349,6 +377,7 @@ version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] - -[[package]] -name = "idna" -version = "3.10" +@@ -360,6 +389,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, -] - -[package.extras] -all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] - -[[package]] -name = "importlib-metadata" -version = "8.6.1" +@@ -374,6 +404,8 @@ version = "8.6.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version < \"3.12\"" files = [ {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, -] - -[package.dependencies] -zipp = ">=3.20" - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -perf = ["ipython"] -test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] -type = ["pytest-mypy"] - -[[package]] -name = "jaraco-classes" -version = "3.4.0" +@@ -397,6 +429,8 @@ version = "3.4.0" description = "Utility functions for Python class constructs" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, -] - -[package.dependencies] -more-itertools = "*" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - -[[package]] -name = "jaraco-context" -version = "6.0.1" +@@ -415,6 +449,8 @@ version = "6.0.1" description = "Useful decorators and context managers" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, -] - -[package.dependencies] -"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} - -[package.extras] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] - -[[package]] -name = "jaraco-functools" -version = "4.1.0" +@@ -433,6 +469,8 @@ version = "4.1.0" description = "Functools like those found in stdlib" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649"}, {file = "jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d"}, -] - -[package.dependencies] -more-itertools = "*" - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"] -type = ["pytest-mypy"] - -[[package]] -name = "jeepney" -version = "0.8.0" +@@ -455,6 +493,8 @@ version = "0.8.0" description = "Low-level, pure Python DBus protocol wrapper." optional = false python-versions = ">=3.7" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\"" files = [ {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"}, {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"}, -] - -[package.extras] -test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] -trio = ["async_generator", "trio"] - -[[package]] -name = "keyring" -version = "25.6.0" +@@ -470,6 +510,8 @@ version = "25.6.0" description = "Store and access your passwords safely." optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"}, {file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"}, -] - -[package.dependencies] -importlib_metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} -"jaraco.classes" = "*" -"jaraco.context" = "*" -"jaraco.functools" = "*" -jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} -pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} -SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -completion = ["shtab (>=1.1.0)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["pyfakefs", "pytest (>=6,!=8.1.*)"] -type = ["pygobject-stubs", "pytest-mypy", "shtab", "types-pywin32"] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" +@@ -499,6 +541,7 @@ version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, -] - -[package.dependencies] -mdurl = ">=0.1,<1.0" - -[package.extras] -benchmarking = ["psutil", "pytest", "pytest-benchmark"] -code-style = ["pre-commit (>=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] -linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] -profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - -[[package]] -name = "mdurl" -version = "0.1.2" +@@ -523,6 +566,7 @@ version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, -] - -[[package]] -name = "more-itertools" -version = "10.6.0" +@@ -534,6 +578,8 @@ version = "10.6.0" description = "More routines for operating on iterables, beyond itertools" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" files = [ {file = "more-itertools-10.6.0.tar.gz", hash = "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b"}, {file = "more_itertools-10.6.0-py3-none-any.whl", hash = "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89"}, -] - -[[package]] -name = "nh3" -version = "0.2.20" +@@ -545,6 +591,7 @@ version = "0.2.20" description = "Python binding to Ammonia HTML sanitizer Rust crate" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "nh3-0.2.20-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db"}, {file = "nh3-0.2.20-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a"}, - {file = "nh3-0.2.20-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c"}, - {file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2"}, - {file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5"}, - {file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0"}, - {file = "nh3-0.2.20-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208"}, - {file = "nh3-0.2.20-cp313-cp313t-win32.whl", hash = "sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886"}, - {file = "nh3-0.2.20-cp313-cp313t-win_amd64.whl", hash = "sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150"}, - {file = "nh3-0.2.20-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776"}, - {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38"}, - {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7"}, - {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace"}, - {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6"}, - {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b"}, - {file = "nh3-0.2.20-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b"}, - {file = "nh3-0.2.20-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d"}, - {file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a"}, - {file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397"}, - {file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec"}, - {file = "nh3-0.2.20-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330"}, - {file = "nh3-0.2.20-cp38-abi3-win32.whl", hash = "sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784"}, - {file = "nh3-0.2.20-cp38-abi3-win_amd64.whl", hash = "sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b"}, - {file = "nh3-0.2.20.tar.gz", hash = "sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5"}, -] - -[[package]] -name = "packaging" -version = "24.2" +@@ -578,6 +625,7 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, -] - -[[package]] -name = "pkginfo" -version = "1.12.0" +@@ -589,6 +637,7 @@ version = "1.12.0" description = "Query metadata from sdists / bdists / installed packages." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pkginfo-1.12.0-py3-none-any.whl", hash = "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088"}, {file = "pkginfo-1.12.0.tar.gz", hash = "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf"}, -] - -[package.extras] -testing = ["pytest", "pytest-cov", "wheel"] - -[[package]] -name = "pycparser" -version = "2.22" +@@ -603,6 +652,8 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, -] - -[[package]] -name = "pydantic" -version = "2.10.5" +@@ -614,6 +665,7 @@ version = "2.10.5" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic-2.10.5-py3-none-any.whl", hash = "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53"}, {file = "pydantic-2.10.5.tar.gz", hash = "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff"}, -] - -[package.dependencies] -annotated-types = ">=0.6.0" -pydantic-core = "2.27.2" -typing-extensions = ">=4.12.2" - -[package.extras] -email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata"] - -[[package]] -name = "pydantic-core" -version = "2.27.2" +@@ -634,6 +686,7 @@ version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, - {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, - {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, - {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, - {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, - {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, - {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, - {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, - {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, - {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, - {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, - {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, - {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, - {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, - {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, - {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, - {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, -] - -[package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" - -[[package]] -name = "pygments" -version = "2.19.1" +@@ -746,6 +799,7 @@ version = "2.19.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, -] - -[package.extras] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "pywin32-ctypes" -version = "0.2.3" +@@ -760,6 +814,8 @@ version = "0.2.3" description = "A (partial) reimplementation of pywin32 using ctypes/cffi" optional = false python-versions = ">=3.6" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"win32\"" files = [ {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, -] - -[[package]] -name = "readme-renderer" -version = "44.0" +@@ -771,6 +827,7 @@ version = "44.0" description = "readme_renderer is a library for rendering readme descriptions for Warehouse" optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"}, {file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"}, -] - -[package.dependencies] -docutils = ">=0.21.2" -nh3 = ">=0.2.14" -Pygments = ">=2.5.1" - +@@ -784,12 +841,32 @@ Pygments = ">=2.5.1" [package.extras] md = ["cmarkgfm (>=0.8.0)"] +[[package]] +name = "redis" +version = "5.2.1" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4"}, + {file = "redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f"}, +] +[package.dependencies] +async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} +[package.extras] +hiredis = ["hiredis (>=3.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==23.2.1)", "requests (>=2.31.0)"] [[package]] name = "requests" version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "requests-toolbelt" -version = "1.0.0" +@@ -811,6 +888,7 @@ version = "1.0.0" description = "A utility belt for advanced users of python-requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] files = [ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, -] - -[package.dependencies] -requests = ">=2.0.1,<3.0.0" - -[[package]] -name = "rfc3986" -version = "2.0.0" +@@ -825,6 +903,7 @@ version = "2.0.0" description = "Validating URI References per RFC 3986" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, -] - -[package.extras] -idna2008 = ["idna"] - -[[package]] -name = "rich" -version = "13.9.4" +@@ -839,6 +918,7 @@ version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" +groups = ["main"] files = [ {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, -] - -[package.dependencies] -markdown-it-py = ">=2.2.0" -pygments = ">=2.13.0,<3.0.0" - -[package.extras] -jupyter = ["ipywidgets (>=7.5.1,<9)"] - -[[package]] -name = "secretstorage" -version = "3.3.3" +@@ -857,6 +937,8 @@ version = "3.3.3" description = "Python bindings to FreeDesktop.org Secret Service API" optional = false python-versions = ">=3.6" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\"" files = [ {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, -] - -[package.dependencies] -cryptography = ">=2.0" -jeepney = ">=0.6" - -[[package]] -name = "sniffio" -version = "1.3.1" +@@ -872,6 +954,7 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - -[[package]] -name = "starlette" -version = "0.41.3" +@@ -883,6 +966,7 @@ version = "0.41.3" description = "The little ASGI library that shines." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"}, {file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"}, -] - -[package.dependencies] -anyio = ">=3.4.0,<5" - -[package.extras] -full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] - -[[package]] -name = "twine" -version = "6.0.1" +@@ -900,6 +984,7 @@ version = "6.0.1" description = "Collection of utilities for publishing packages on PyPI" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "twine-6.0.1-py3-none-any.whl", hash = "sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218"}, {file = "twine-6.0.1.tar.gz", hash = "sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27"}, -] - -[package.dependencies] -keyring = {version = ">=15.1", markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} -packaging = "*" -pkginfo = ">=1.8.1" -readme-renderer = ">=35.0" -requests = ">=2.20" -requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" -rfc3986 = ">=1.4.0" -rich = ">=12.0.0" -urllib3 = ">=1.26.0" - -[package.extras] -keyring = ["keyring (>=15.1)"] - -[[package]] -name = "typing-extensions" -version = "4.12.2" +@@ -925,6 +1010,7 @@ version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, -] - -[[package]] -name = "urllib3" -version = "2.3.0" +@@ -936,6 +1022,7 @@ version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "uvicorn" -version = "0.34.0" +@@ -953,6 +1040,7 @@ version = "0.34.0" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.9" +groups = ["main"] files = [ {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, -] - -[package.dependencies] -click = ">=7.0" -h11 = ">=0.8" - -[package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] - -[[package]] -name = "zipp" -version = "3.21.0" +@@ -971,6 +1059,8 @@ version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" +groups = ["main"] +markers = "(platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version < \"3.12\"" files = [ {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, -] - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +@@ -985,6 +1075,6 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", type = ["pytest-mypy"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.11" -content-hash = "9275cbe6f1f1e141d493def45a624ae011d2cd0efa37aac7682806d7e53307db" +content-hash = "252bb6ac9d035a43b7db91ecd0d1131ce793fb9c42fba70e125bf0a5861416ba" \ No newline at end of file diff --git a/apps/sdk/pyproject.toml b/apps/sdk/pyproject.toml index 932aa586..06f28bbc 100644 --- a/apps/sdk/pyproject.toml +++ b/apps/sdk/pyproject.toml @@ -11,6 +11,7 @@ twine = "^6.0.1" fastapi = "^0.115.6" uvicorn = "^0.34.0" pydantic = "^2.10.5" +redis = "^5.0.0" [build-system] From 7947e91cc7b225e0669b4b362fe62d6572181dcd Mon Sep 17 00:00:00 2001 From: Sandeep chauhan <92181599+ryzen-xp@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:03:18 +0530 Subject: [PATCH 30/42] Update db_connector.py --- apps/sdk/db_connector.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/sdk/db_connector.py b/apps/sdk/db_connector.py index a34e1222..d77048eb 100644 --- a/apps/sdk/db_connector.py +++ b/apps/sdk/db_connector.py @@ -20,6 +20,12 @@ def __init__(self): """ Initializes DBConnector by connecting to the PostgreSQL database. """ + + host = os.getenv("DB_HOST") + database = os.getenv("DB_NAME") + user = os.getenv("DB_USER") + password = os.getenv("DB_PASSWORD") + self.conn, self.cur = self.connect_to_db() def connect_to_db(self): @@ -29,11 +35,7 @@ def connect_to_db(self): Returns: tuple: (conn, cur) where conn is connection object and cur is cursor object. """ - host = os.getenv("DB_HOST") - database = os.getenv("DB_NAME") - user = os.getenv("DB_USER") - password = os.getenv("DB_PASSWORD") - + try: conn = psycopg2.connect( host=host, From ad83fd2a24e50fe3f510374e56307a5604f560b5 Mon Sep 17 00:00:00 2001 From: Julius Shedrack <114742986+sheddiboo@users.noreply.github.com> Date: Fri, 24 Jan 2025 07:50:38 +0000 Subject: [PATCH 31/42] remove uncessary file --- apps/data_handler/db/schemas.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/data_handler/db/schemas.py b/apps/data_handler/db/schemas.py index 2fb17c1f..45bcede3 100644 --- a/apps/data_handler/db/schemas.py +++ b/apps/data_handler/db/schemas.py @@ -73,9 +73,3 @@ def validate_block(cls, value: int | None) -> int: if value is None: return 0 return value - -class UserCollateralResponse(BaseModel): - """ Base class for UserCollateralResponse """ - wallet_id: str - protocol_name: str - collateral: Dict[str, float] From 067fb6da027e78cd83de6b475cb03a3b5d5e7c9f Mon Sep 17 00:00:00 2001 From: Julius Shedrack <114742986+sheddiboo@users.noreply.github.com> Date: Fri, 24 Jan 2025 08:29:43 +0000 Subject: [PATCH 32/42] remove unnecessary file --- apps/sdk/api/user_model.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 apps/sdk/api/user_model.py diff --git a/apps/sdk/api/user_model.py b/apps/sdk/api/user_model.py deleted file mode 100644 index 7c1233df..00000000 --- a/apps/sdk/api/user_model.py +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Dict -from pydantic import BaseModel - -class UserCollateralResponse(BaseModel): - wallet_id: str - protocol_name: str - collateral: Dict[str, float] \ No newline at end of file From 0b5b81f2ceb24c2d9aebc4433584cac30dd3b7f8 Mon Sep 17 00:00:00 2001 From: sudiptapaul Date: Fri, 24 Jan 2025 16:15:33 +0530 Subject: [PATCH 33/42] requested changes --- apps/sdk/main.py | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/apps/sdk/main.py b/apps/sdk/main.py index 34477ebc..933590b5 100644 --- a/apps/sdk/main.py +++ b/apps/sdk/main.py @@ -3,8 +3,7 @@ from slowapi import Limiter from slowapi.util import get_remote_address from slowapi.errors import RateLimitExceeded -from api.loan_state import loan_router # Use the imported loan_router directly -from pydantic import BaseModel +from api.loan_state import loan_router import redis app = FastAPI() @@ -15,29 +14,6 @@ redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True) limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379") -app.state.limiter = limiter -@app.middleware("http") -async def rate_limiter_middleware(request: Request, call_next): - try: - response = await limiter(request=request, call_next=call_next) - return response - except RateLimitExceeded: - raise HTTPException( - status_code=429, - detail="Too Many Requests. Please try again later." - ) -app.include_router(loan_router, prefix=f"{version_prefix}/loans", tags=["loans"]) # Use loan_router from loan_state -@app.get("/test") -@limiter.limit("5/minute") -async def test_endpoint(request: Request): - return {"message": "This is a rate-limited endpoint"} -version = "v1" -version_prefix = f"/api/{version}" - -redis_client = redis.Redis(host='localhost', port=6379, decode_responses=True) - -limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379") - app.state.limiter = limiter @app.middleware("http") @@ -51,9 +27,9 @@ async def rate_limiter_middleware(request: Request, call_next): detail="Too Many Requests. Please try again later." ) -app.include_router(loan_router, prefix=f"{version_prefix}/loans", tags=["loans"]) # Use loan_router from loan_state +app.include_router(loan_router, prefix=f"{version_prefix}/loans", tags=["loans"]) @app.get("/test") @limiter.limit("5/minute") async def test_endpoint(request: Request): - return {"message": "This is a rate-limited endpoint"} + return {"message": "This is a rate-limited endpoint"} \ No newline at end of file From 30b537c5ec3d1eb8474df446b53ffa9384a58b15 Mon Sep 17 00:00:00 2001 From: Sagar Rana Date: Fri, 24 Jan 2025 17:40:29 +0530 Subject: [PATCH 34/42] refactor responsemodel --- apps/data_handler/db/schemas.py | 5 +++++ apps/sdk/api/user.py | 10 ++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/data_handler/db/schemas.py b/apps/data_handler/db/schemas.py index 45bcede3..9f4aec3c 100644 --- a/apps/data_handler/db/schemas.py +++ b/apps/data_handler/db/schemas.py @@ -73,3 +73,8 @@ def validate_block(cls, value: int | None) -> int: if value is None: return 0 return value + +class ResponseModel(BaseModel): + wallet_id: str + protocol_name: str + debt: Dict[str, float] diff --git a/apps/sdk/api/user.py b/apps/sdk/api/user.py index ddabca18..da276b0c 100644 --- a/apps/sdk/api/user.py +++ b/apps/sdk/api/user.py @@ -3,15 +3,9 @@ from typing import Dict import pandas as pd import json +from data_handler.db.schemas import ResponseModel -app = FastAPI() - - -class ResponseModel(BaseModel): - wallet_id: str - protocol_name: str - debt: Dict[str, float] - +app = FastAPI() file_path = "../mock_data.csv" mock_data = pd.read_csv(file_path) From 2af33900637719181b76ccc7e60f0d73208ad72c Mon Sep 17 00:00:00 2001 From: Sagar Rana Date: Fri, 24 Jan 2025 17:40:59 +0530 Subject: [PATCH 35/42] Update apps/sdk/api/user.py Co-authored-by: djeck1432 --- apps/sdk/api/user.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/sdk/api/user.py b/apps/sdk/api/user.py index da276b0c..6dc82fb5 100644 --- a/apps/sdk/api/user.py +++ b/apps/sdk/api/user.py @@ -41,6 +41,8 @@ def get_user_debt(wallet_id: str, protocol_name: str): ResponseModel: The debt details including wallet ID, protocol name, and token-value pairs. """ wallet_data = debt_data.get(wallet_id) + debt_data = debt_data.get(protocol) + return {"wallet_id": wallet_id, "protocol": protocol, "debt": debt_data} if not wallet_data: return {"wallet_id": wallet_id, "protocol_name": protocol_name, "debt": {}} From 21d1d04272ddbdf142813ddaab2f38d12a5cf619 Mon Sep 17 00:00:00 2001 From: Sagar Rana Date: Fri, 24 Jan 2025 18:56:27 +0530 Subject: [PATCH 36/42] fixes --- apps/sdk/api/user.py | 12 ++---------- apps/sdk/schemas/schemas.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 apps/sdk/schemas/schemas.py diff --git a/apps/sdk/api/user.py b/apps/sdk/api/user.py index 6dc82fb5..db8c1a42 100644 --- a/apps/sdk/api/user.py +++ b/apps/sdk/api/user.py @@ -3,7 +3,7 @@ from typing import Dict import pandas as pd import json -from data_handler.db.schemas import ResponseModel +from sdk.schemas.schemas import ResponseModel app = FastAPI() @@ -42,12 +42,4 @@ def get_user_debt(wallet_id: str, protocol_name: str): """ wallet_data = debt_data.get(wallet_id) debt_data = debt_data.get(protocol) - return {"wallet_id": wallet_id, "protocol": protocol, "debt": debt_data} - if not wallet_data: - return {"wallet_id": wallet_id, "protocol_name": protocol_name, "debt": {}} - - protocol_data = wallet_data.get(protocol_name) - if not protocol_data: - return {"wallet_id": wallet_id, "protocol_name": protocol_name, "debt": {}} - - return {"wallet_id": wallet_id, "protocol_name": protocol_name, "debt": protocol_data} \ No newline at end of file + return {"wallet_id": wallet_id, "protocol": protocol, "debt": debt_data} \ No newline at end of file diff --git a/apps/sdk/schemas/schemas.py b/apps/sdk/schemas/schemas.py new file mode 100644 index 00000000..d69f1519 --- /dev/null +++ b/apps/sdk/schemas/schemas.py @@ -0,0 +1,11 @@ +import decimal +from decimal import Decimal +from typing import Dict, List, Optional +from pydantic import BaseModel, field_validator + + + +class ResponseModel(BaseModel): + wallet_id: str + protocol_name: str + debt: Dict[str, float] \ No newline at end of file From f2e46be469edbacd4d3b9101ff599351a0a5da89 Mon Sep 17 00:00:00 2001 From: djeck1432 Date: Fri, 24 Jan 2025 16:49:33 +0100 Subject: [PATCH 37/42] Update loan_state.py --- apps/sdk/api/loan_state.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/sdk/api/loan_state.py b/apps/sdk/api/loan_state.py index 28e3d453..82b56bba 100644 --- a/apps/sdk/api/loan_state.py +++ b/apps/sdk/api/loan_state.py @@ -6,15 +6,6 @@ loan_router = APIRouter() -# def parse_json(data): -# try: -# parsed = json.loads(data.replace("'", '"')) -# if not parsed: -# parsed = {} -# return parsed -# except (json.JSONDecodeError, AttributeError, TypeError): -# return {} - def parse_json(data): if isinstance(data, str): try: From c8144ae68b6286eb33d672c09fed83d306363d08 Mon Sep 17 00:00:00 2001 From: Sagar Rana Date: Fri, 24 Jan 2025 22:53:36 +0530 Subject: [PATCH 38/42] remove schema from data_handler --- apps/data_handler/db/schemas.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/data_handler/db/schemas.py b/apps/data_handler/db/schemas.py index 9f4aec3c..45bcede3 100644 --- a/apps/data_handler/db/schemas.py +++ b/apps/data_handler/db/schemas.py @@ -73,8 +73,3 @@ def validate_block(cls, value: int | None) -> int: if value is None: return 0 return value - -class ResponseModel(BaseModel): - wallet_id: str - protocol_name: str - debt: Dict[str, float] From 45d641b4f20ba7f306df08ac64f1cf6d148aa320 Mon Sep 17 00:00:00 2001 From: Ryzen XP Date: Fri, 24 Jan 2025 23:11:02 +0530 Subject: [PATCH 39/42] change --- apps/sdk/.env.dev | 10 +++---- apps/sdk/db_connector.py | 61 ++++++++++++++++++++++------------------ 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/apps/sdk/.env.dev b/apps/sdk/.env.dev index 989b2e78..b34e30bb 100644 --- a/apps/sdk/.env.dev +++ b/apps/sdk/.env.dev @@ -1,6 +1,6 @@ # postgresql - -DB_HOST=your_host -DB_NAME=your_database -DB_USER=your_username -DB_PASSWORD=your_password \ No newline at end of file +DB_HOST= +DB_NAME= +DB_USER= +DB_PASSWORD= +DB_PORT= diff --git a/apps/sdk/db_connector.py b/apps/sdk/db_connector.py index d77048eb..01596f55 100644 --- a/apps/sdk/db_connector.py +++ b/apps/sdk/db_connector.py @@ -20,39 +20,43 @@ def __init__(self): """ Initializes DBConnector by connecting to the PostgreSQL database. """ + self.host = os.getenv("DB_HOST") + self.database = os.getenv("DB_NAME") + self.user = os.getenv("DB_USER") + self.password = os.getenv("DB_PASSWORD") + self.port = os.getenv("DB_PORT") - host = os.getenv("DB_HOST") - database = os.getenv("DB_NAME") - user = os.getenv("DB_USER") - password = os.getenv("DB_PASSWORD") - - self.conn, self.cur = self.connect_to_db() + self.conn = None + self.cur = None + self.connect_to_db() def connect_to_db(self): """ - make connection to the PostgreSQL DB and returns the connection and cursor. + Make connection to the PostgreSQL DB and set the connection and cursor. Returns: - tuple: (conn, cur) where conn is connection object and cur is cursor object. + None """ - - try: - conn = psycopg2.connect( - host=host, - database=database, - user=user, - password=password - ) - cur = conn.cursor() - logging.info("Connected to PostgreSQL successfully.") - return conn, cur - except (Exception, psycopg2.Error) as error: - logging.info(f"Error while connecting to PostgreSQL: {error}") - raise + if self.conn is None: + try: + self.conn = psycopg2.connect( + host=self.host, + database=self.database, + user=self.user, + password=self.password, + port=self.port + + ) + self.cur = self.conn.cursor() + except psycopg2.DatabaseError as e: + logging.error(e) + raise e + finally: + logging.info('Connection opened successfully.') def get_user_debt(self, protocol_id: str, wallet_id: str) -> float | None: """ - fetches user debt for a given protocol and wallet. + Fetches user debt for a given protocol and wallet. Args: protocol_id (str): Protocol ID. @@ -76,11 +80,11 @@ def get_user_debt(self, protocol_id: str, wallet_id: str) -> float | None: def get_user_collateral(self, protocol_id: str, wallet_id: str) -> float | None: """ - fetches user collateral for a given protocol and wallet. + Fetches user collateral for a given protocol and wallet. Args: - protocol_id (str): protocol ID - wallet_id (str): user wallet ID. + protocol_id (str): Protocol ID + wallet_id (str): User wallet ID. Returns: float | None: User collateral if found, otherwise None. @@ -100,7 +104,7 @@ def get_user_collateral(self, protocol_id: str, wallet_id: str) -> float | None: def get_loan_state(self, protocol_id: str, wallet_id: str) -> str | None: """ - fetches user loan state for a given protocol and wallet. + Fetches user loan state for a given protocol and wallet. Args: protocol_id (str): Protocol ID. @@ -124,9 +128,10 @@ def get_loan_state(self, protocol_id: str, wallet_id: str) -> str | None: def close_connection(self) -> None: """ - closes the database connection if open. + Closes the database connection if open. """ if self.conn: self.cur.close() self.conn.close() logging.info("PostgreSQL connection closed.") + From d2050ebe07dae3e20bc98a8eff4a471c554fa0d9 Mon Sep 17 00:00:00 2001 From: Ryzen XP Date: Sat, 25 Jan 2025 00:17:42 +0530 Subject: [PATCH 40/42] change --- apps/sdk/db_connector.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/apps/sdk/db_connector.py b/apps/sdk/db_connector.py index 01596f55..0571c654 100644 --- a/apps/sdk/db_connector.py +++ b/apps/sdk/db_connector.py @@ -45,14 +45,12 @@ def connect_to_db(self): user=self.user, password=self.password, port=self.port - ) self.cur = self.conn.cursor() + logging.info("Connection opened successfully.") except psycopg2.DatabaseError as e: - logging.error(e) + logging.error(f"Error while connecting to the database: {e}") raise e - finally: - logging.info('Connection opened successfully.') def get_user_debt(self, protocol_id: str, wallet_id: str) -> float | None: """ @@ -67,15 +65,15 @@ def get_user_debt(self, protocol_id: str, wallet_id: str) -> float | None: """ try: sql = """ - SELECT debt - FROM user_data + SELECT CAST(debt->>'amount' AS FLOAT) AS debt_value + FROM mytable WHERE protocol_id = %s AND user = %s; """ self.cur.execute(sql, (protocol_id, wallet_id)) result = self.cur.fetchone() - return result[0] if result else None + return float(result[0]) if result and result[0] is not None else None except (Exception, psycopg2.Error) as error: - logging.info(f"Error while fetching user debt: {error}") + logging.error(f"Error while fetching user debt: {error}") raise def get_user_collateral(self, protocol_id: str, wallet_id: str) -> float | None: @@ -83,23 +81,23 @@ def get_user_collateral(self, protocol_id: str, wallet_id: str) -> float | None: Fetches user collateral for a given protocol and wallet. Args: - protocol_id (str): Protocol ID - wallet_id (str): User wallet ID. + protocol_id (str): Protocol ID. + wallet_id (str): User's wallet ID. Returns: float | None: User collateral if found, otherwise None. """ try: sql = """ - SELECT collateral - FROM user_data + SELECT CAST(collateral->>'amount' AS FLOAT) AS collateral_value + FROM mytable WHERE protocol_id = %s AND user = %s; """ self.cur.execute(sql, (protocol_id, wallet_id)) result = self.cur.fetchone() - return result[0] if result else None + return float(result[0]) if result and result[0] is not None else None except (Exception, psycopg2.Error) as error: - logging.info(f"Error while fetching user collateral: {error}") + logging.error(f"Error while fetching user collateral: {error}") raise def get_loan_state(self, protocol_id: str, wallet_id: str) -> str | None: @@ -115,15 +113,15 @@ def get_loan_state(self, protocol_id: str, wallet_id: str) -> str | None: """ try: sql = """ - SELECT loan_state - FROM user_data + SELECT loan_state + FROM mytable WHERE protocol_id = %s AND user = %s; """ self.cur.execute(sql, (protocol_id, wallet_id)) result = self.cur.fetchone() - return result[0] if result else None + return str(result[0]) if result and result[0] is not None else None except (Exception, psycopg2.Error) as error: - logging.info(f"Error while fetching user loan state: {error}") + logging.error(f"Error while fetching user loan state: {error}") raise def close_connection(self) -> None: From efb370cd35e35b06d989ca1bb474ee7919e14fbf Mon Sep 17 00:00:00 2001 From: Sebastian Salazar Date: Fri, 24 Jan 2025 23:10:30 -0600 Subject: [PATCH 41/42] feat: add test cases for ekubo order book --- .../tests/order_book/test_ekubo.py | 162 ++++++++++++++++++ pyproject.toml | 0 2 files changed, 162 insertions(+) create mode 100644 pyproject.toml diff --git a/apps/data_handler/tests/order_book/test_ekubo.py b/apps/data_handler/tests/order_book/test_ekubo.py index e69de29b..00d51af3 100644 --- a/apps/data_handler/tests/order_book/test_ekubo.py +++ b/apps/data_handler/tests/order_book/test_ekubo.py @@ -0,0 +1,162 @@ +"""Tests for the EkuboOrderBook class.""" +from decimal import Decimal +from unittest.mock import Mock, patch, MagicMock + +import pandas as pd +import pytest +from data_handler.handlers.order_books.ekubo.main import EkuboOrderBook + +@pytest.fixture +def mock_connector(): + """Create a mock EkuboAPIConnector.""" + with patch('data_handler.handlers.order_books.ekubo.main.EkuboAPIConnector') as mock: + connector = mock.return_value + connector.get_pair_price.return_value = {"price": "1.5"} + connector.get_pools.return_value = [{ + "token0": "0x1", + "token1": "0x2", + "key_hash": "0xabc", + "liquidity": "1000000", + "lastUpdate": {"event_id": "123"}, + "tick": 100, + "tick_spacing": 10 + }] + connector.get_pool_liquidity.return_value = { + "data": [ + {"tick": 90, "net_liquidity_delta_diff": "100"}, + {"tick": 100, "net_liquidity_delta_diff": "200"}, + {"tick": 110, "net_liquidity_delta_diff": "300"} + ] + } + yield connector + +@pytest.fixture +def order_book(mock_connector): + """Create an EkuboOrderBook instance with mocked connector.""" + book = EkuboOrderBook("0x1", "0x2") + # Set decimals for token precision + book.token_a_decimal = 18 + book.token_b_decimal = 18 + return book + +def test_initialization(order_book): + """Test EkuboOrderBook initialization.""" + assert order_book.DEX == "Ekubo" + assert order_book.token_a == "0x1" + assert order_book.token_b == "0x2" + assert order_book.asks == [] + assert order_book.bids == [] + +def test_set_current_price(order_book): + """Test setting current price.""" + order_book.set_current_price() + assert order_book.current_price == Decimal("1.5") + +def test_fetch_price_and_liquidity(order_book): + """Test fetching price and liquidity data.""" + order_book.fetch_price_and_liquidity() + assert order_book.block == "123" + assert len(order_book.asks) > 0 + assert len(order_book.bids) > 0 + +def test_calculate_order_book(order_book): + """Test order book calculation.""" + # Create test data with ticks both above and below the current tick (100) + liquidity_data = [ + {"tick": 90, "net_liquidity_delta_diff": "100"}, + {"tick": 95, "net_liquidity_delta_diff": "150"}, + {"tick": 100, "net_liquidity_delta_diff": "200"}, + {"tick": 105, "net_liquidity_delta_diff": "250"}, + {"tick": 110, "net_liquidity_delta_diff": "300"} + ] + + # Create a pandas Series for the row + row_data = { + "tick": 100, + "tick_spacing": 5, + "liquidity": "1000000" + } + row = pd.Series(row_data) + + # Set current price for price range calculation + order_book.current_price = Decimal("1.5") + + # Calculate order book + order_book._calculate_order_book(liquidity_data, 1000000, row) + + # Verify that both asks and bids are populated + assert len(order_book.asks) > 0, "Asks should not be empty" + assert len(order_book.bids) > 0, "Bids should not be empty" + + # Verify the structure of asks and bids + for price, supply in order_book.asks: + assert isinstance(price, Decimal), "Price should be Decimal" + assert isinstance(supply, Decimal), "Supply should be Decimal" + assert price > 0, "Price should be positive" + assert supply > 0, "Supply should be positive" + + for price, supply in order_book.bids: + assert isinstance(price, Decimal), "Price should be Decimal" + assert isinstance(supply, Decimal), "Supply should be Decimal" + assert price > 0, "Price should be positive" + assert supply > 0, "Supply should be positive" + +def test_get_pure_sqrt_ratio(order_book): + """Test square root ratio calculation.""" + result = order_book._get_pure_sqrt_ratio(Decimal("1")) + assert isinstance(result, Decimal) + assert result > 0 + +def test_sort_ticks_by_asks_and_bids(): + """Test sorting ticks into asks and bids.""" + liquidity_data = [ + {"tick": 90}, + {"tick": 100}, + {"tick": 110} + ] + current_tick = 100 + asks, bids = EkuboOrderBook.sort_ticks_by_asks_and_bids(liquidity_data, current_tick) + assert len(asks) == 1 + assert len(bids) == 2 + assert all(tick["tick"] > current_tick for tick in asks) + assert all(tick["tick"] <= current_tick for tick in bids) + +def test_calculate_liquidity_amount(order_book): + """Test liquidity amount calculation.""" + # Set token decimals for proper calculation + order_book.token_a_decimal = 18 + order_book.token_b_decimal = 18 + + tick = Decimal("100") + liquidity_total = Decimal("1000000") + result = order_book.calculate_liquidity_amount(tick, liquidity_total) + assert isinstance(result, Decimal) + assert result > 0 + +@pytest.mark.parametrize("tick,expected_sign", [ + (1000, 1), # positive tick + (-1000, -1), # negative tick + (0, 0) # zero tick +]) +def test_tick_edge_cases(order_book, tick, expected_sign): + """Test tick calculations with edge cases.""" + result = order_book._get_pure_sqrt_ratio(Decimal(tick)) + assert isinstance(result, Decimal) + assert result > 0 # sqrt ratio should always be positive + if expected_sign > 0: + assert result > 1 + elif expected_sign < 0: + assert result < 1 + +def test_empty_liquidity_data(order_book): + """Test behavior with empty liquidity data.""" + row_data = { + "tick": 100, + "tick_spacing": 5, + "liquidity": "1000000" + } + row = pd.Series(row_data) + + order_book._calculate_order_book([], 1000000, row) + assert len(order_book.asks) == 0 + assert len(order_book.bids) == 0 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..e69de29b From b9350ea6a289f63bcddf5401d4214d1e1d4c209d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Salazar?= Date: Sat, 25 Jan 2025 03:55:34 -0600 Subject: [PATCH 42/42] fix: remove empty file --- pyproject.toml | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index e69de29b..00000000