From c7a3b0cfa99aba1cf58b6a6e23abc481bae15fd1 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:26:34 +0300 Subject: [PATCH 01/17] . --- poetry.lock | 473 +++++++++++---------- pyproject.toml | 4 +- suvvyapi/__init__.py | 29 -- suvvyapi/_utils.py | 8 - suvvyapi/{asynchronous => api}/__init__.py | 0 suvvyapi/api/async.py | 20 + suvvyapi/asynchronous/wrapper.py | 211 --------- suvvyapi/enums/__init__.py | 10 - suvvyapi/exceptions/api.py | 56 --- suvvyapi/history/__init__.py | 77 ---- suvvyapi/models/__init__.py | 0 suvvyapi/models/history.py | 41 -- suvvyapi/models/responses.py | 35 -- suvvyapi/sync/__init__.py | 0 suvvyapi/sync/wrapper.py | 212 --------- suvvyapi/{exceptions => types}/__init__.py | 0 suvvyapi/types/exceptions.py | 22 + suvvyapi/wrapper/__init__.py | 278 ------------ 18 files changed, 298 insertions(+), 1178 deletions(-) delete mode 100644 suvvyapi/_utils.py rename suvvyapi/{asynchronous => api}/__init__.py (100%) create mode 100644 suvvyapi/api/async.py delete mode 100644 suvvyapi/asynchronous/wrapper.py delete mode 100644 suvvyapi/enums/__init__.py delete mode 100644 suvvyapi/exceptions/api.py delete mode 100644 suvvyapi/history/__init__.py delete mode 100644 suvvyapi/models/__init__.py delete mode 100644 suvvyapi/models/history.py delete mode 100644 suvvyapi/models/responses.py delete mode 100644 suvvyapi/sync/__init__.py delete mode 100644 suvvyapi/sync/wrapper.py rename suvvyapi/{exceptions => types}/__init__.py (100%) create mode 100644 suvvyapi/types/exceptions.py delete mode 100644 suvvyapi/wrapper/__init__.py diff --git a/poetry.lock b/poetry.lock index f300510..a6ea58f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,37 +1,37 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "annotated-types" -version = "0.6.0" +version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, + {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.2.0" +version = "4.7.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, - {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, + {file = "anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352"}, + {file = "anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7)", "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)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] +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)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +trio = ["trio (>=0.26.1)"] [[package]] name = "asttokens" @@ -99,24 +99,24 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [package.dependencies] @@ -165,13 +165,13 @@ pygments = ">=2.15.0" [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -179,13 +179,13 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "2.0.1" +version = "2.1.0" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, + {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, + {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, ] [package.extras] @@ -204,13 +204,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.2" +version = "1.0.7" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, - {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, ] [package.dependencies] @@ -221,7 +221,7 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.23.0)"] +trio = ["trio (>=0.22.0,<1.0)"] [[package]] name = "httpx" @@ -249,15 +249,18 @@ socks = ["socksio (==1.*)"] [[package]] name = "idna" -version = "3.6" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {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 = "iniconfig" version = "2.0.0" @@ -285,47 +288,53 @@ colors = ["colorama (>=0.4.6)"] [[package]] name = "mypy" -version = "1.8.0" +version = "1.14.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, - {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, - {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, - {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, - {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, - {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, - {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, - {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, - {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, - {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, - {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, - {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, - {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, - {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, - {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, - {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, - {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, - {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, - {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, - {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, - {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, - {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, - {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, + {file = "mypy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e971c1c667007f9f2b397ffa80fa8e1e0adccff336e5e77e74cb5f22868bee87"}, + {file = "mypy-1.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e86aaeaa3221a278c66d3d673b297232947d873773d61ca3ee0e28b2ff027179"}, + {file = "mypy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1628c5c3ce823d296e41e2984ff88c5861499041cb416a8809615d0c1f41740e"}, + {file = "mypy-1.14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7fadb29b77fc14a0dd81304ed73c828c3e5cde0016c7e668a86a3e0dfc9f3af3"}, + {file = "mypy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:3fa76988dc760da377c1e5069200a50d9eaaccf34f4ea18428a3337034ab5a44"}, + {file = "mypy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6e73c8a154eed31db3445fe28f63ad2d97b674b911c00191416cf7f6459fd49a"}, + {file = "mypy-1.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:273e70fcb2e38c5405a188425aa60b984ffdcef65d6c746ea5813024b68c73dc"}, + {file = "mypy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1daca283d732943731a6a9f20fdbcaa927f160bc51602b1d4ef880a6fb252015"}, + {file = "mypy-1.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7e68047bedb04c1c25bba9901ea46ff60d5eaac2d71b1f2161f33107e2b368eb"}, + {file = "mypy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:7a52f26b9c9b1664a60d87675f3bae00b5c7f2806e0c2800545a32c325920bcc"}, + {file = "mypy-1.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d5326ab70a6db8e856d59ad4cb72741124950cbbf32e7b70e30166ba7bbf61dd"}, + {file = "mypy-1.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bf4ec4980bec1e0e24e5075f449d014011527ae0055884c7e3abc6a99cd2c7f1"}, + {file = "mypy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:390dfb898239c25289495500f12fa73aa7f24a4c6d90ccdc165762462b998d63"}, + {file = "mypy-1.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7e026d55ddcd76e29e87865c08cbe2d0104e2b3153a523c529de584759379d3d"}, + {file = "mypy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:585ed36031d0b3ee362e5107ef449a8b5dfd4e9c90ccbe36414ee405ee6b32ba"}, + {file = "mypy-1.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9f6f4c0b27401d14c483c622bc5105eff3911634d576bbdf6695b9a7c1ba741"}, + {file = "mypy-1.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b2280cedcb312c7a79f5001ae5325582d0d339bce684e4a529069d0e7ca1e7"}, + {file = "mypy-1.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:342de51c48bab326bfc77ce056ba08c076d82ce4f5a86621f972ed39970f94d8"}, + {file = "mypy-1.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00df23b42e533e02a6f0055e54de9a6ed491cd8b7ea738647364fd3a39ea7efc"}, + {file = "mypy-1.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:e8c8387e5d9dff80e7daf961df357c80e694e942d9755f3ad77d69b0957b8e3f"}, + {file = "mypy-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b16738b1d80ec4334654e89e798eb705ac0c36c8a5c4798496cd3623aa02286"}, + {file = "mypy-1.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:10065fcebb7c66df04b05fc799a854b1ae24d9963c8bb27e9064a9bdb43aa8ad"}, + {file = "mypy-1.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fbb7d683fa6bdecaa106e8368aa973ecc0ddb79a9eaeb4b821591ecd07e9e03c"}, + {file = "mypy-1.14.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3498cb55448dc5533e438cd13d6ddd28654559c8c4d1fd4b5ca57a31b81bac01"}, + {file = "mypy-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:c7b243408ea43755f3a21a0a08e5c5ae30eddb4c58a80f415ca6b118816e60aa"}, + {file = "mypy-1.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14117b9da3305b39860d0aa34b8f1ff74d209a368829a584eb77524389a9c13e"}, + {file = "mypy-1.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af98c5a958f9c37404bd4eef2f920b94874507e146ed6ee559f185b8809c44cc"}, + {file = "mypy-1.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0b343a1d3989547024377c2ba0dca9c74a2428ad6ed24283c213af8dbb0710b"}, + {file = "mypy-1.14.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cdb5563c1726c85fb201be383168f8c866032db95e1095600806625b3a648cb7"}, + {file = "mypy-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:74e925649c1ee0a79aa7448baf2668d81cc287dc5782cff6a04ee93f40fb8d3f"}, + {file = "mypy-1.14.0-py3-none-any.whl", hash = "sha256:2238d7f93fc4027ed1efc944507683df3ba406445a2b6c96e79666a045aadfab"}, + {file = "mypy-1.14.0.tar.gz", hash = "sha256:822dbd184d4a9804df5a7d5335a68cf7662930e70b8c1bc976645d1509f9a9d6"}, ] [package.dependencies] -mypy-extensions = ">=1.0.0" +mypy_extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=4.1.0" +typing_extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] @@ -343,13 +352,13 @@ files = [ [[package]] name = "packaging" -version = "23.2" +version = "24.2" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -365,28 +374,29 @@ files = [ [[package]] name = "platformdirs" -version = "4.1.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -395,135 +405,131 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pydantic" -version = "2.5.3" +version = "2.10.4" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, - {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, + {file = "pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d"}, + {file = "pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06"}, ] [package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.14.6" -typing-extensions = ">=4.6.1" +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.14.6" -description = "" +version = "2.27.2" +description = "Core functionality for Pydantic validation and serialization" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, - {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, - {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, - {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, - {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, - {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, - {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, - {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, - {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, - {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, - {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, - {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, - {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, - {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, - {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, - {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, + {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] @@ -531,28 +537,27 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -568,17 +573,17 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.23.2" +version = "0.23.8" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.2.tar.gz", hash = "sha256:c16052382554c7b22d48782ab3438d5b10f8cf7a4bdcae7f0f67f097d95beecc"}, - {file = "pytest_asyncio-0.23.2-py3-none-any.whl", hash = "sha256:ea9021364e32d58f0be43b91c6233fb8d2224ccef2398d6837559e587682808f"}, + {file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"}, + {file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"}, ] [package.dependencies] -pytest = ">=7.0.0" +pytest = ">=7.0.0,<9" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] @@ -586,49 +591,79 @@ testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] name = "sniffio" -version = "1.3.0" +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.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] [[package]] name = "tomli" -version = "2.0.1" +version = "2.2.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [metadata] lock-version = "2.0" -python-versions = ">=3.10" -content-hash = "ea5f86949707db386188c825bccde87a71925f2d87e5c888abcfa69fb13410e2" +python-versions = ">=3.10,<4.0" +content-hash = "d3ee56169973209f66424c1b05f9633c538bd4729f2136a2b5ab07756018df4a" diff --git a/pyproject.toml b/pyproject.toml index f045559..594563c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "suvvyapi" -version = "1.0.2" +version = "2.0" description = "A Python API wrapper for Suvvy AI API" authors = ["Roman Poltorabatko "] license = "MIT" @@ -23,7 +23,7 @@ repository = "https://github.com/suvvyai/suvvyapi" "Documentation" = "https://github.com/suvvyai/suvvyapi/wiki" [tool.poetry.dependencies] -python = ">=3.10" +python = ">=3.10,<4.0" httpx = "^0.26.0" pydantic = "^2.5.3" deprecation = "^2.1.0" diff --git a/suvvyapi/__init__.py b/suvvyapi/__init__.py index 567ed29..e69de29 100644 --- a/suvvyapi/__init__.py +++ b/suvvyapi/__init__.py @@ -1,29 +0,0 @@ -from suvvyapi.asynchronous.wrapper import AsyncSuvvyAPIWrapper -from suvvyapi.models.history import ( - ChatHistory, - Message, - HistoryMessage, - FunctionDetails, -) -from suvvyapi.models.responses import ( - Prediction, - LLMResult, - TokenUsage, - BalanceUsage, -) -from suvvyapi.sync.wrapper import SuvvyAPIWrapper -from suvvyapi.wrapper import Suvvy - -__all__ = [ - "AsyncSuvvyAPIWrapper", - "SuvvyAPIWrapper", - "Suvvy", - "Prediction", - "LLMResult", - "TokenUsage", - "BalanceUsage", - "ChatHistory", - "Message", - "HistoryMessage", - "FunctionDetails", -] diff --git a/suvvyapi/_utils.py b/suvvyapi/_utils.py deleted file mode 100644 index 67784e6..0000000 --- a/suvvyapi/_utils.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Any - - -def _merge_dicts(*dicts: dict[Any, Any]) -> dict[Any, Any]: - merged_dict: dict[Any, Any] = {} - for d in dicts: - merged_dict |= d - return merged_dict diff --git a/suvvyapi/asynchronous/__init__.py b/suvvyapi/api/__init__.py similarity index 100% rename from suvvyapi/asynchronous/__init__.py rename to suvvyapi/api/__init__.py diff --git a/suvvyapi/api/async.py b/suvvyapi/api/async.py new file mode 100644 index 0000000..8263bae --- /dev/null +++ b/suvvyapi/api/async.py @@ -0,0 +1,20 @@ +import httpx + + +class AsyncSuvvy(httpx.AsyncClient): + """Asynchronous client for Suvvy AI API""" + def __init__( + self, + token: str, + *, + base_url: str = "https://api.suvvy.ai", + ) -> None: + super().__init__( + base_url=base_url, + headers={ + "Authorization": f"Bearer {token}" + }, + timeout=30, + ) + + async def diff --git a/suvvyapi/asynchronous/wrapper.py b/suvvyapi/asynchronous/wrapper.py deleted file mode 100644 index f1cb405..0000000 --- a/suvvyapi/asynchronous/wrapper.py +++ /dev/null @@ -1,211 +0,0 @@ -from typing import Literal - -import deprecation -import httpx - -from suvvyapi.exceptions.api import ( - HistoryNotFoundError, - HistoryStoppedError, - HistoryTooLongError, - InternalAPIError, - InvalidAPITokenError, - MessageLimitExceededError, - NegativeBalanceError, - UnknownAPIError, -) -from suvvyapi.models.history import ChatHistory, Message -from suvvyapi.models.responses import Prediction - - -class AsyncSuvvyAPIWrapper: - @deprecation.deprecated( - deprecated_in="1.0.0", - removed_in="2.0.0", - details="Use the Suvvy() class instead", - ) - def __init__( - self, - token: str, - base_url: str = "https://api.suvvy.ai/", - placeholders: dict | None = None, - custom_log_info: dict | None = None, - ) -> None: - self.token = token - self.base_url = base_url.lstrip("/") - self.placeholders = placeholders or {} - self.custom_log_info = custom_log_info or {} - - async def _make_request( - self, - method: Literal["GET", "POST", "PUT", "DELETE"], - path: str, - body: dict | None = None, - ) -> httpx.Response: - headers = {"Authorization": f"bearer {self.token}"} - async with httpx.AsyncClient( - headers=headers, base_url=self.base_url, timeout=300 - ) as c: - response = await c.request(method=method, url=path, json=body) - if response.status_code == 401: - raise InvalidAPITokenError("API Token is invalid.") - if response.status_code == 402: - raise NegativeBalanceError.from_detail(response.json()["detail"]) - if response.status_code == 500: - raise InternalAPIError( - "Internal API error occurred. Contact suvvy.ai support." - ) - return response - - async def get_history(self, unique_id: str) -> ChatHistory: - response = await self._make_request( - method="GET", path=f"/api/v1/history?unique_id={unique_id}" - ) - json = response.json() - history = ChatHistory(**json) - return history - - async def reset_history(self, unique_id: str) -> None: - await self._make_request( - method="PUT", path=f"/api/v1/history?unique_id={unique_id}" - ) - - async def add_message( - self, - message: Message | list[Message], - unique_id: str, - pass_ai_as_employee: bool = True, - ) -> None: - if not isinstance(message, list): - message = [message] - - _ms = [] - for m in message: - _ms.append(m.model_dump()) - - message = _ms - - body = {"messages": message, "pass_ai_as_employee": pass_ai_as_employee} - await self._make_request( - method="POST", - path=f"/api/v1/history/message?unique_id={unique_id}", - body=body, - ) - - async def predict_from_history( - self, - unique_id: str, - placeholders: dict | None = None, - auto_insert_ai: bool = True, - custom_log_info: dict | None = None, - raise_if_dialog_stopped: bool = False, - ) -> Prediction: - placeholders = placeholders or {} - custom_log_info = custom_log_info or {} - - custom_log_info = dict(**self.custom_log_info, **custom_log_info) - placeholders = dict(**self.placeholders, **placeholders) - - body = { - "placeholders": placeholders, - "custom_log_info": custom_log_info, - "auto_insert_ai": auto_insert_ai, - } - response = await self._make_request( - method="POST", - path=f"/api/v1/history/predict?unique_id={unique_id}", - body=body, - ) - match response.status_code: - case 202: - if raise_if_dialog_stopped: - raise HistoryStoppedError("History is marked as stopped") - else: - prediction = Prediction() - return prediction - case 404: - raise HistoryNotFoundError() - case 413: - json = response.json() - detail = json["detail"] - if detail.startswith("Maximum token limit"): - raise HistoryTooLongError("History is too long to process") - else: - raise MessageLimitExceededError( - "Message limit for that instance is exceeded" - ) - case 200: - pass - case _: - raise UnknownAPIError( - f"We don't know what happened. Status code is {response.status_code}" - ) - - json = response.json() - prediction = Prediction(**json) - return prediction - - async def predict( - self, - message: Message | list[Message], - unique_id: str, - pass_ai_as_employee: bool = True, - placeholders: dict | None = None, - auto_insert_ai: bool = True, - custom_log_info: dict | None = None, - raise_if_dialog_stopped: bool = False, - ) -> Prediction: - placeholders = placeholders or {} - custom_log_info = custom_log_info or {} - - custom_log_info = dict(**self.custom_log_info, **custom_log_info) - placeholders = dict(**self.placeholders, **placeholders) - - if not isinstance(message, list): - message = [message] - - _ms = [] - for m in message: - _ms.append(m.model_dump()) - - message = _ms - - body = { - "placeholders": placeholders, - "custom_log_info": custom_log_info, - "auto_insert_ai": auto_insert_ai, - "messages": message, - "pass_ai_as_employee": pass_ai_as_employee, - } - response = await self._make_request( - method="POST", - path=f"/api/v1/history/message/predict?unique_id={unique_id}", - body=body, - ) - match response.status_code: - case 202: - if raise_if_dialog_stopped: - raise HistoryStoppedError("History is marked as stopped") - else: - prediction = Prediction() - return prediction - case 404: - raise HistoryNotFoundError() - case 413: - json = response.json() - detail = json["detail"] - if detail.startswith("Maximum token limit"): - raise HistoryTooLongError("History is too long to process") - else: - raise MessageLimitExceededError( - "Message limit for that instance is exceeded" - ) - case 200: - pass - case _: - raise UnknownAPIError( - f"We don't know what happened. Status code is {response.status_code}" - ) - - json = response.json() - prediction = Prediction(**json) - return prediction diff --git a/suvvyapi/enums/__init__.py b/suvvyapi/enums/__init__.py deleted file mode 100644 index fc803bb..0000000 --- a/suvvyapi/enums/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from enum import Enum - - -class Role(str, Enum): - HUMAN = "human" - AI = "ai" - FUNCTION_CALL = "function_call" - FUNCTION_RESULT = "function_result" - IMAGE_MESSAGE = "sent_image" - AUDIO_MESSAGE = "audio_message" diff --git a/suvvyapi/exceptions/api.py b/suvvyapi/exceptions/api.py deleted file mode 100644 index 2708425..0000000 --- a/suvvyapi/exceptions/api.py +++ /dev/null @@ -1,56 +0,0 @@ -import re -from typing import Optional - - -class InvalidAPITokenError(BaseException): - """Raised, when API token is invalid""" - - -class NegativeBalanceError(BaseException): - """Raised, when your Suvvy AI balance is under zero""" - - balance: Optional[int] = None - - @classmethod - def from_detail(cls, detail: str) -> "NegativeBalanceError": - exc = cls("Your balance is under zero") - - balance_match = re.search(pattern=r"(\(\d*\))", string=detail) - if balance_match is None: - return exc - - balance = int(balance_match.group(0).strip("()")) - exc.balance = balance - return exc - - -class HistoryStoppedError(BaseException): - """Raised, when history is marked as stopped""" - - -class HistoryNotFoundError(BaseException): - """Raised, when history with this unique id is not found""" - - -class MessageNotFoundError(BaseException): - """Raised, when message with this message_id is not found""" - - -class InternalMessageAdded(BaseException): - """Raised, when message with internal role or role-specific information is added""" - - -class HistoryTooLongError(BaseException): - """Raised, when history is too long to process""" - - -class MessageLimitExceededError(BaseException): - """Raised, when message limit for that instance is exceeded""" - - -class UnknownAPIError(BaseException): - """Raised, when WE DON'T KNOW WHAT HAPPENED""" - - -class InternalAPIError(BaseException): - """Raised, when internal api error occurred""" diff --git a/suvvyapi/history/__init__.py b/suvvyapi/history/__init__.py deleted file mode 100644 index 1d37673..0000000 --- a/suvvyapi/history/__init__.py +++ /dev/null @@ -1,77 +0,0 @@ -from suvvyapi import Suvvy, Prediction, Message, ChatHistory - - -class History(object): - def __init__(self, unique_id: str, suvvy: Suvvy): - self._suvvy = suvvy - self.unique_id = unique_id - - def predict( - self, - placeholders: dict | None = None, - custom_log_info: dict | None = None, - source: str | None = None, - ) -> Prediction | None: - """Get answer from AI""" - return self._suvvy.predict_history( - self.unique_id, placeholders, custom_log_info, source - ) - - async def apredict( - self, - placeholders: dict | None = None, - custom_log_info: dict | None = None, - source: str | None = None, - ) -> Prediction | None: - """Get answer from AI""" - return await self._suvvy.apredict_history( - self.unique_id, placeholders, custom_log_info, source - ) - - def predict_add_message( - self, - message: list[Message] | Message, - placeholders: dict | None = None, - custom_log_info: dict | None = None, - source: str | None = None, - ) -> Prediction | None: - """Add message and get answer from AI""" - return self._suvvy.predict_history_add_message( - self.unique_id, message, placeholders, custom_log_info, source - ) - - async def apredict_add_message( - self, - message: list[Message] | Message, - placeholders: dict | None = None, - custom_log_info: dict | None = None, - source: str | None = None, - ) -> Prediction | None: - """Add message and get answer from AI""" - return await self._suvvy.apredict_history_add_message( - self.unique_id, message, placeholders, custom_log_info, source - ) - - def get(self) -> ChatHistory: - """Get history""" - return self._suvvy.get_history(self.unique_id) - - async def aget(self) -> ChatHistory: - """Get history""" - return await self._suvvy.aget_history(self.unique_id) - - def reset(self) -> ChatHistory: - """Reset history""" - return self._suvvy.reset_history(self.unique_id) - - async def areset(self) -> ChatHistory: - """Reset history""" - return await self._suvvy.areset_history(self.unique_id) - - def add_message(self, message: list[Message] | Message) -> ChatHistory: - """Get history""" - return self._suvvy.add_message_to_history(self.unique_id, message) - - async def async_add_message(self, message: list[Message] | Message) -> ChatHistory: - """Get history""" - return await self._suvvy.async_add_message_to_history(self.unique_id, message) diff --git a/suvvyapi/models/__init__.py b/suvvyapi/models/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/suvvyapi/models/history.py b/suvvyapi/models/history.py deleted file mode 100644 index ea993b0..0000000 --- a/suvvyapi/models/history.py +++ /dev/null @@ -1,41 +0,0 @@ -from datetime import datetime -from typing import Optional - -from pydantic import BaseModel, ConfigDict, Field - -from suvvyapi.enums import Role - - -class FunctionDetails(BaseModel): - name: str - args: Optional[dict] = None - - -class Message(BaseModel): - model_config = ConfigDict(use_enum_values=True) - - text: str = Field(default="", description="Message text, function result") - role: Role = Role.HUMAN - function: Optional[FunctionDetails] = Field( - default=None, - description='Needed for functions. Unused if role != "function_*".', - ) - - -class HistoryMessage(Message): - tokens: int = 0 - time: datetime - message_id: int - context: str = "" - - -class ChatHistory(BaseModel): - history: list[HistoryMessage] - unique_id: str - stopped: bool = False - stop_reason: str = "unknown" - last_interaction_time: datetime - created_time: datetime - channel_name: str - last_source: str | None = None - last_instance_id: int | None = None diff --git a/suvvyapi/models/responses.py b/suvvyapi/models/responses.py deleted file mode 100644 index 03b6c56..0000000 --- a/suvvyapi/models/responses.py +++ /dev/null @@ -1,35 +0,0 @@ -from pydantic import BaseModel - -from suvvyapi.models.history import HistoryMessage - - -class TokenUsage(BaseModel): - prompt_tokens: int = 0 - completion_tokens: int = 0 - total_tokens: int = 0 - - -class BalanceUsage(BaseModel): - prompt_tokens: int = 0 - completion_tokens: int = 0 - knowledge_usage: int = 0 - function_usage: int = 0 - total_tokens: int = 0 - token_multiplier: float = 1.0 - - -class LLMResult(BaseModel): - token_usage: TokenUsage = TokenUsage() - balance_usage: BalanceUsage = BalanceUsage() - - -class Prediction(BaseModel): - generation_info: LLMResult = LLMResult() - new_messages: list[HistoryMessage] = [] - - @property - def actual_response(self) -> HistoryMessage | None: - if self.new_messages: - return self.new_messages[-1] - else: - return None diff --git a/suvvyapi/sync/__init__.py b/suvvyapi/sync/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/suvvyapi/sync/wrapper.py b/suvvyapi/sync/wrapper.py deleted file mode 100644 index 22cdba2..0000000 --- a/suvvyapi/sync/wrapper.py +++ /dev/null @@ -1,212 +0,0 @@ -from typing import Literal - -import deprecation -import httpx - -from suvvyapi.exceptions.api import ( - HistoryNotFoundError, - HistoryStoppedError, - HistoryTooLongError, - InternalAPIError, - InvalidAPITokenError, - MessageLimitExceededError, - NegativeBalanceError, - UnknownAPIError, -) -from suvvyapi.models.history import ChatHistory, Message -from suvvyapi.models.responses import Prediction - - -class SuvvyAPIWrapper: - @deprecation.deprecated( - deprecated_in="1.0.0", - removed_in="2.0.0", - details="Use the Suvvy() class instead", - ) - def __init__( - self, - token: str, - base_url: str = "https://api.suvvy.ai/", - check_connection: bool = True, - placeholders: dict | None = None, - custom_log_info: dict | None = None, - ): - self.token = token - self.base_url = base_url.lstrip("/") - self.placeholders = placeholders or {} - self.custom_log_info = custom_log_info or {} - - if check_connection: - self._make_request("GET", "/api/check") - - def _make_request( - self, - method: Literal["GET", "POST", "PUT", "DELETE"], - path: str, - body: dict | None = None, - ) -> httpx.Response: - headers = {"Authorization": f"bearer {self.token}"} - with httpx.Client(headers=headers, base_url=self.base_url, timeout=300) as c: - response = c.request(method=method, url=path, json=body) - if response.status_code == 401: - raise InvalidAPITokenError("API Token is invalid.") - if response.status_code == 402: - raise NegativeBalanceError.from_detail(response.json()["detail"]) - if response.status_code == 500: - raise InternalAPIError( - "Internal API error occurred. Contact suvvy.ai support." - ) - return response - - def get_history(self, unique_id: str) -> ChatHistory: - response = self._make_request( - method="GET", path=f"/api/v1/history?unique_id={unique_id}" - ) - json = response.json() - history = ChatHistory(**json) - return history - - def reset_history(self, unique_id: str) -> None: - self._make_request(method="PUT", path=f"/api/v1/history?unique_id={unique_id}") - - def add_message( - self, - message: Message | list[Message], - unique_id: str, - pass_ai_as_employee: bool = True, - ) -> None: - if not isinstance(message, list): - message = [message] - - _ms = [] - for m in message: - _ms.append(m.model_dump()) - - message = _ms - - body = {"messages": message, "pass_ai_as_employee": pass_ai_as_employee} - self._make_request( - method="POST", - path=f"/api/v1/history/message?unique_id={unique_id}", - body=body, - ) - - def predict_from_history( - self, - unique_id: str, - placeholders: dict | None = None, - auto_insert_ai: bool = True, - custom_log_info: dict | None = None, - raise_if_dialog_stopped: bool = False, - ) -> Prediction: - placeholders = placeholders or {} - custom_log_info = custom_log_info or {} - - custom_log_info = dict(**self.custom_log_info, **custom_log_info) - placeholders = dict(**self.placeholders, **placeholders) - - body = { - "placeholders": placeholders, - "custom_log_info": custom_log_info, - "auto_insert_ai": auto_insert_ai, - } - response = self._make_request( - method="POST", - path=f"/api/v1/history/predict?unique_id={unique_id}", - body=body, - ) - match response.status_code: - case 202: - if raise_if_dialog_stopped: - raise HistoryStoppedError("History is marked as stopped") - else: - prediction = Prediction() - return prediction - case 404: - raise HistoryNotFoundError() - case 413: - json = response.json() - detail = json["detail"] - if detail.startswith("Maximum token limit"): - raise HistoryTooLongError("History is too long to process") - else: - raise MessageLimitExceededError( - "Message limit for that instance is exceeded" - ) - case 200: - pass - case _: - raise UnknownAPIError( - f"We don't know what happened. Status code is {response.status_code}" - ) - - json = response.json() - prediction = Prediction(**json) - return prediction - - def predict( - self, - message: Message | list[Message], - unique_id: str, - pass_ai_as_employee: bool = True, - placeholders: dict | None = None, - auto_insert_ai: bool = True, - custom_log_info: dict | None = None, - raise_if_dialog_stopped: bool = False, - ) -> Prediction: - placeholders = placeholders or {} - custom_log_info = custom_log_info or {} - - if not isinstance(message, list): - message = [message] - - _ms = [] - for m in message: - _ms.append(m.model_dump()) - - message = _ms - - custom_log_info = dict(**self.custom_log_info, **custom_log_info) - placeholders = dict(**self.placeholders, **placeholders) - - body = { - "messages": message, - "pass_ai_as_employee": pass_ai_as_employee, - "placeholders": placeholders, - "custom_log_info": custom_log_info, - "auto_insert_ai": auto_insert_ai, - } - - response = self._make_request( - method="POST", - path=f"/api/v1/history/message/predict?unique_id={unique_id}", - body=body, - ) - match response.status_code: - case 202: - if raise_if_dialog_stopped: - raise HistoryStoppedError("History is marked as stopped") - else: - prediction = Prediction() - return prediction - case 404: - raise HistoryNotFoundError() - case 413: - json = response.json() - detail = json["detail"] - if detail.startswith("Maximum token limit"): - raise HistoryTooLongError("History is too long to process") - else: - raise MessageLimitExceededError( - "Message limit for that instance is exceeded" - ) - case 200: - pass - case _: - raise UnknownAPIError( - f"We don't know what happened. Status code is {response.status_code}" - ) - - json = response.json() - prediction = Prediction(**json) - return prediction diff --git a/suvvyapi/exceptions/__init__.py b/suvvyapi/types/__init__.py similarity index 100% rename from suvvyapi/exceptions/__init__.py rename to suvvyapi/types/__init__.py diff --git a/suvvyapi/types/exceptions.py b/suvvyapi/types/exceptions.py new file mode 100644 index 0000000..ed3c965 --- /dev/null +++ b/suvvyapi/types/exceptions.py @@ -0,0 +1,22 @@ +class SuvvyError(Exception): + """Error in Suvvy API""" + + +class InvalidToken(SuvvyError): + """Invalid Suvvy AI token""" + + +class CustomChannelDisabled(SuvvyError): + """Bot custom channel is disabled.""" + + +class NegativeBalance(SuvvyError): + """Your Suvvy balance is below zero.""" + + +class InvalidFileType(SuvvyError): + """File type is not supported or invalid.""" + + +class ValidationError(SuvvyError): + """Validation error.""" diff --git a/suvvyapi/wrapper/__init__.py b/suvvyapi/wrapper/__init__.py deleted file mode 100644 index 023c3d6..0000000 --- a/suvvyapi/wrapper/__init__.py +++ /dev/null @@ -1,278 +0,0 @@ -from typing import Type - -import httpx - -from suvvyapi import ChatHistory, Message, Prediction -from suvvyapi.exceptions.api import ( - InvalidAPITokenError, - NegativeBalanceError, - HistoryTooLongError, - InternalAPIError, - HistoryNotFoundError, - InternalMessageAdded, -) - - -def _handle_error(response: httpx.Response) -> None: - if response.status_code <= 299: - return - - exceptions = { - 401: InvalidAPITokenError, - 402: NegativeBalanceError.from_detail, - 406: InternalMessageAdded, - 413: HistoryTooLongError, - 404: HistoryNotFoundError, - 500: InternalAPIError, - } - exception: Type[BaseException] = exceptions[response.status_code] # type: ignore - raise exception(response.json().get("detail", None)) - - -class Suvvy(object): - def __init__( - self, - api_token: str, - api_url: str = "https://api.suvvy.ai", - placeholders: dict | None = None, - custom_log_info: dict | None = None, - source: str | None = None, - ): - self.placeholders = placeholders or {} - self.custom_log_info = custom_log_info or {} - self.source = source or "https://github.com/suvvyai/suvvyapi" - - self._headers = {"Authorization": f"Bearer {api_token}"} - self._api_url = api_url.rstrip("/ \\\n") - - def _get_placeholders(self, placeholders: dict | None = None) -> dict: - placeholders = placeholders or {} - return {**self.placeholders, **placeholders} - - def _get_custom_log_info(self, custom_log_info: dict | None = None) -> dict: - custom_log_info = custom_log_info or {} - return {**self.custom_log_info, **custom_log_info} - - def _sync_request( - self, - method: str, - path: str, - body_json: dict | None = None, - params: dict | None = None, - ) -> httpx.Response: - with httpx.Client( - headers=self._headers, base_url=self._api_url, timeout=300 - ) as client: - r = client.request(method, path, json=body_json, params=params) - _handle_error(r) - return r - - async def _async_request( - self, - method: str, - path: str, - body_json: dict | None = None, - params: dict | None = None, - ) -> httpx.Response: - async with httpx.AsyncClient( - headers=self._headers, base_url=self._api_url, timeout=300 - ) as client: - r = await client.request(method, path, json=body_json, params=params) - _handle_error(r) - return r - - def check_connection(self) -> bool: - """Check connection and API token""" - self._sync_request("GET", "/api/check") - return True - - async def acheck_connection(self) -> bool: - """Check connection and API token""" - await self._async_request("GET", "/api/check") - return True - - def get_history(self, unique_id: str) -> ChatHistory: - """Get history by unique_id""" - r = self._sync_request( - "GET", "/api/v1/history", params={"unique_id": unique_id} - ) - return ChatHistory(**r.json()) - - async def aget_history(self, unique_id: str) -> ChatHistory: - """Get history by unique_id""" - r = await self._async_request( - "GET", "/api/v1/history", params={"unique_id": unique_id} - ) - return ChatHistory(**r.json()) - - def reset_history(self, unique_id: str) -> ChatHistory: - """Reset history by unique_id and return deleted history""" - r = self._sync_request( - "PUT", "/api/v1/history", params={"unique_id": unique_id} - ) - if r.status_code == 202: - raise HistoryNotFoundError - return ChatHistory(**r.json()["deleted_history"]) - - async def areset_history(self, unique_id: str) -> ChatHistory: - """Reset history by unique_id and return deleted history""" - r = await self._async_request( - "PUT", "/api/v1/history", params={"unique_id": unique_id} - ) - if r.status_code == 202: - raise HistoryNotFoundError - return ChatHistory(**r.json()["deleted_history"]) - - def add_message_to_history( - self, unique_id: str, message: list[Message] | Message - ) -> ChatHistory: - """Add message to history by unique_id""" - if not isinstance(message, list): - message = [message] - message = [m.model_dump() for m in message] - - r = self._sync_request( - "POST", - "/api/v1/history/message", - params={"unique_id": unique_id}, - body_json={"messages": message}, - ) - return ChatHistory(**r.json()) - - async def async_add_message_to_history( - self, unique_id: str, message: list[Message] | Message - ) -> ChatHistory: - """Add message to history by unique_id""" - if not isinstance(message, list): - message = [message] - message = [m.model_dump() for m in message] - - r = await self._async_request( - "POST", - "/api/v1/history/message", - params={"unique_id": unique_id}, - body_json={"messages": message}, - ) - return ChatHistory(**r.json()) - - def predict_history( - self, - unique_id: str, - placeholders: dict | None = None, - custom_log_info: dict | None = None, - source: str | None = None, - ) -> Prediction | None: - """Get answer from AI by unique_id. - None means API refused to answer""" - - r = self._sync_request( - method="POST", - path="/api/v1/history/predict", - params={"unique_id": unique_id}, - body_json={ - "placeholders": self._get_placeholders(placeholders), - "custom_log_info": self._get_custom_log_info(custom_log_info), - "source": source or self.source, - }, - ) - - if r.status_code == 202: - return None - - return Prediction(**r.json()) - - async def apredict_history( - self, - unique_id: str, - placeholders: dict | None = None, - custom_log_info: dict | None = None, - source: str | None = None, - ) -> Prediction | None: - """Get answer from AI by unique_id. - None means API refused to answer""" - - r = await self._async_request( - method="POST", - path="/api/v1/history/predict", - params={"unique_id": unique_id}, - body_json={ - "placeholders": self._get_placeholders(placeholders), - "custom_log_info": self._get_custom_log_info(custom_log_info), - "source": source or self.source, - }, - ) - - if r.status_code == 202: - return None - - return Prediction(**r.json()) - - def predict_history_add_message( - self, - unique_id: str, - message: list[Message] | Message, - placeholders: dict | None = None, - custom_log_info: dict | None = None, - source: str | None = None, - ) -> Prediction | None: - """Add message and get answer from AI by unique_id. - None means API refused to answer""" - - if not isinstance(message, list): - message = [message] - message = [m.model_dump() for m in message] - - r = self._sync_request( - method="POST", - path="/api/v1/history/message/predict", - params={"unique_id": unique_id}, - body_json={ - "placeholders": self._get_placeholders(placeholders), - "custom_log_info": self._get_custom_log_info(custom_log_info), - "source": source or self.source, - "messages": message, - }, - ) - - if r.status_code == 202: - return None - - return Prediction(**r.json()) - - async def apredict_history_add_message( - self, - unique_id: str, - message: list[Message] | Message, - placeholders: dict | None = None, - custom_log_info: dict | None = None, - source: str | None = None, - ) -> Prediction | None: - """Add message and get answer from AI by unique_id. - None means API refused to answer""" - - if not isinstance(message, list): - message = [message] - message = [m.model_dump() for m in message] - - r = await self._async_request( - method="POST", - path="/api/v1/history/message/predict", - params={"unique_id": unique_id}, - body_json={ - "placeholders": self._get_placeholders(placeholders), - "custom_log_info": self._get_custom_log_info(custom_log_info), - "source": source or self.source, - "messages": message, - }, - ) - - if r.status_code == 202: - return None - - return Prediction(**r.json()) - - def as_history(self, unique_id: str) -> "History": # type: ignore - """Represent history as a History object""" - from suvvyapi.history import History - - return History(unique_id, self) # type: ignore From 69f1bdd8ce816df6fa85f03f57518aefa636c7a7 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:26:57 +0300 Subject: [PATCH 02/17] it'll be 3.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 594563c..d19c992 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "suvvyapi" -version = "2.0" +version = "3.0" description = "A Python API wrapper for Suvvy AI API" authors = ["Roman Poltorabatko "] license = "MIT" From 7dd4df376385ad245e680b453e3c8a98ee0f0b51 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:32:26 +0300 Subject: [PATCH 03/17] add types --- suvvyapi/types/attachment.py | 11 +++++++++++ suvvyapi/types/enum.py | 7 +++++++ suvvyapi/types/link.py | 10 ++++++++++ 3 files changed, 28 insertions(+) create mode 100644 suvvyapi/types/attachment.py create mode 100644 suvvyapi/types/enum.py create mode 100644 suvvyapi/types/link.py diff --git a/suvvyapi/types/attachment.py b/suvvyapi/types/attachment.py new file mode 100644 index 0000000..2013183 --- /dev/null +++ b/suvvyapi/types/attachment.py @@ -0,0 +1,11 @@ +from dataclasses import dataclass +from typing import Literal + + +@dataclass +class Attachment: + """Attachment""" + file_name: str + file_type: Literal["image", "audio"] + data: str + message_id: str diff --git a/suvvyapi/types/enum.py b/suvvyapi/types/enum.py new file mode 100644 index 0000000..9d132a0 --- /dev/null +++ b/suvvyapi/types/enum.py @@ -0,0 +1,7 @@ +from enum import StrEnum + + +class SuvvyMessageSender(StrEnum): + CUSTOMER = "customer" + EMPLOYEE = "employee" + diff --git a/suvvyapi/types/link.py b/suvvyapi/types/link.py new file mode 100644 index 0000000..7af36ae --- /dev/null +++ b/suvvyapi/types/link.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass +from typing import Literal + + +@dataclass +class Link: + """Link""" + url: str + hint: str | None = None + type: Literal["user", "chat", "phone", "lead", "other"] = "other" From fcf20be040e1927003f2456110e3d004f089bbbe Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:32:30 +0300 Subject: [PATCH 04/17] 3.0 --- poetry.lock | 145 +------------------------------------------------ pyproject.toml | 1 - 2 files changed, 1 insertion(+), 145 deletions(-) diff --git a/poetry.lock b/poetry.lock index a6ea58f..5a717a2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,16 +1,5 @@ # This file is automatically @generated by Poetry 1.8.5 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.7.0" @@ -403,138 +392,6 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "pydantic" -version = "2.10.4" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d"}, - {file = "pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06"}, -] - -[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.18.0" @@ -666,4 +523,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.10,<4.0" -content-hash = "d3ee56169973209f66424c1b05f9633c538bd4729f2136a2b5ab07756018df4a" +content-hash = "285456c664fb47e21d6e78c479210ca81eb78db1b73fe315a1927df2e81041dc" diff --git a/pyproject.toml b/pyproject.toml index d19c992..853c130 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,6 @@ repository = "https://github.com/suvvyai/suvvyapi" [tool.poetry.dependencies] python = ">=3.10,<4.0" httpx = "^0.26.0" -pydantic = "^2.5.3" deprecation = "^2.1.0" [tool.poetry.group.dev.dependencies] From 4ef9d5bc7d770953bcd2b586a49789244f119425 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:33:44 +0300 Subject: [PATCH 05/17] python-magic --- poetry.lock | 13 ++++++++++++- pyproject.toml | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 5a717a2..9c0c1cd 100644 --- a/poetry.lock +++ b/poetry.lock @@ -446,6 +446,17 @@ pytest = ">=7.0.0,<9" docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] +[[package]] +name = "python-magic" +version = "0.4.27" +description = "File type identification using libmagic" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "python-magic-0.4.27.tar.gz", hash = "sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b"}, + {file = "python_magic-0.4.27-py2.py3-none-any.whl", hash = "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3"}, +] + [[package]] name = "six" version = "1.17.0" @@ -523,4 +534,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.10,<4.0" -content-hash = "285456c664fb47e21d6e78c479210ca81eb78db1b73fe315a1927df2e81041dc" +content-hash = "9a22e5e25535bf14ffe4dc36b54db2342702c5a93952a1b3bc46ce7af11499ae" diff --git a/pyproject.toml b/pyproject.toml index 853c130..318d9c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ repository = "https://github.com/suvvyai/suvvyapi" python = ">=3.10,<4.0" httpx = "^0.26.0" deprecation = "^2.1.0" +python-magic = "^0.4.27" [tool.poetry.group.dev.dependencies] devtools = "^0.12.2" From 7d0ef415fa6b25e382fe754cff35b45f84bdf6b3 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:47:08 +0300 Subject: [PATCH 06/17] add input_to_attachments --- suvvyapi/types/attachment.py | 79 +++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/suvvyapi/types/attachment.py b/suvvyapi/types/attachment.py index 2013183..9f23ff4 100644 --- a/suvvyapi/types/attachment.py +++ b/suvvyapi/types/attachment.py @@ -1,5 +1,24 @@ +import base64 +import string from dataclasses import dataclass -from typing import Literal +from random import choices +from typing import Literal, BinaryIO + +import magic + +MIME_TO_EXTENSION: dict[str, str] = { + "audio/ogg": "ogg", + "audio/mpeg": "mp3", + "audio/mp4": "mp4", + "audio/wav": "wav", + "audio/webm": "webm", + "audio/x-wav": "wav", + "audio/m4a": "m4a", + "audio/x-m4a": "m4a", + "image/png": "png", + "image/jpeg": "jpeg", + "image/gif": "gif", +} @dataclass @@ -9,3 +28,61 @@ class Attachment: file_type: Literal["image", "audio"] data: str message_id: str + + +def determine_attachment_type(mybytes: bytes) -> Literal["image", "audio"]: + mime_type = magic.from_buffer(mybytes, mime=True) + if mime_type in ["image/png", "image/jpeg", "image/gif"]: + return "image" + elif mime_type in ["audio/ogg", "audio/mpeg", "audio/wav", "audio/x-wav", "audio/webm", "audio/mp4", "audio/m4a", "audio/x-m4a"]: + return "audio" + else: + raise ValueError("Invalid file type") + + +def determine_extension(mybytes: bytes) -> str: + mime_type = magic.from_buffer(mybytes, mime=True) + return MIME_TO_EXTENSION[mime_type] + + +def input_to_attachments(input_list: list[Attachment | str | tuple[str, bytes] | BinaryIO]) -> list[Attachment]: + attachments: list[Attachment] = [] + for a in input_list: + if isinstance(a, Attachment): + attachments.append(a) + elif isinstance(a, str): + with open(a, "rb") as file: + data = file.read() + attachments.append( + Attachment( + file_name=file.name, + file_type=determine_attachment_type(data), + data=base64.b64encode(data).decode("utf-8"), + message_id="".join(choices(string.ascii_letters + string.digits, k=10)) + ) + ) + elif isinstance(a, tuple): + if not isinstance(a[0], str) or not isinstance(a[1], bytes): + raise ValueError("Invalid attachment") + + attachments.append( + Attachment( + file_name=a[0], + file_type=determine_attachment_type(a[1]), + data=base64.b64encode(a[1]).decode("utf-8"), + message_id="".join(choices(string.ascii_letters + string.digits, k=10)) + ) + ) + elif isinstance(a, BinaryIO): + data = a.read() + attachments.append( + Attachment( + file_name=a.name or "unknown", + file_type=determine_attachment_type(data), + data=base64.b64encode(data).decode("utf-8"), + message_id="".join(choices(string.ascii_letters + string.digits, k=10)) + ) + ) + else: + raise ValueError("Invalid attachment") + return attachments From 4ef977964010a6821f2cc7e9abe31a4572175a54 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:48:49 +0300 Subject: [PATCH 07/17] to_dict --- suvvyapi/types/attachment.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/suvvyapi/types/attachment.py b/suvvyapi/types/attachment.py index 9f23ff4..c404906 100644 --- a/suvvyapi/types/attachment.py +++ b/suvvyapi/types/attachment.py @@ -29,6 +29,14 @@ class Attachment: data: str message_id: str + def to_dict(self) -> dict: + return { + "file_name": self.file_name, + "file_type": self.file_type, + "data": self.data, + "message_id": self.message_id, + } + def determine_attachment_type(mybytes: bytes) -> Literal["image", "audio"]: mime_type = magic.from_buffer(mybytes, mime=True) From 3e1dfc4f84fb5d169cf61c12353b988dbc19181f Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:50:04 +0300 Subject: [PATCH 08/17] send_message --- suvvyapi/api/async.py | 63 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/suvvyapi/api/async.py b/suvvyapi/api/async.py index 8263bae..0759bd9 100644 --- a/suvvyapi/api/async.py +++ b/suvvyapi/api/async.py @@ -1,8 +1,17 @@ +import string +from random import choices +from typing import BinaryIO + import httpx +from suvvyapi.types.attachment import Attachment, input_to_attachments +from suvvyapi.types.enum import SuvvyMessageSender +from suvvyapi.types.link import Link + class AsyncSuvvy(httpx.AsyncClient): """Asynchronous client for Suvvy AI API""" + def __init__( self, token: str, @@ -11,10 +20,56 @@ def __init__( ) -> None: super().__init__( base_url=base_url, - headers={ - "Authorization": f"Bearer {token}" - }, + headers={"Authorization": f"Bearer {token}"}, timeout=30, ) - async def + async def send_message( + self, + chat_id: str, + source: str, + text: str | None = None, + attachments: list[Attachment | str | tuple[str, bytes] | BinaryIO] + | None = None, + placeholders: dict[str, str] | None = None, + link: Link | None = None, + client_name: str | None = None, + client_phone: str | None = None, + message_sender: SuvvyMessageSender = SuvvyMessageSender.CUSTOMER, + message_id: str | None = None, + ) -> None: + """Send message to Suvvy + + :param chat_id: Chat ID + :param source: Source + :param text: Message text. Required if attachments are not specified. + :param attachments: Attachments. Required if text is not specified. + :param placeholders: Instruction placeholders + :param link: Link + :param client_name: Client name + :param client_phone: Client phone + :param message_sender: Message sender (customer or employee) + :param message_id: Message ID. Used to prevent repeated answers. Created randomly if not specified. + """ + message_id = message_id or "".join( + choices(string.ascii_letters + string.digits, k=10) + ) + if text is None and not attachments: + raise ValueError("Either text or attachments must be specified") + + await self.post( + "/api/webhook/custom/message", + json={ + "api_version": 1, + "chat_id": chat_id, + "source": source, + "text": text, + "attachments": [a.to_dict() for a in input_to_attachments(attachments)] if attachments else [], + "placeholders": placeholders, + "link": link, + "client_name": client_name, + "client_phone": client_phone, + "message_sender": message_sender.value, + "message_id": message_id, + }, + ) From 30e51b77420346033b441807a2d612de4fd37f17 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:52:23 +0300 Subject: [PATCH 09/17] errors --- suvvyapi/api/async.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/suvvyapi/api/async.py b/suvvyapi/api/async.py index 0759bd9..323cb11 100644 --- a/suvvyapi/api/async.py +++ b/suvvyapi/api/async.py @@ -6,6 +6,10 @@ from suvvyapi.types.attachment import Attachment, input_to_attachments from suvvyapi.types.enum import SuvvyMessageSender +from suvvyapi.types.exceptions import ( + InvalidToken, CustomChannelDisabled, InvalidFileType, NegativeBalance, + ValidationError, SuvvyError +) from suvvyapi.types.link import Link @@ -57,7 +61,7 @@ async def send_message( if text is None and not attachments: raise ValueError("Either text or attachments must be specified") - await self.post( + response = await self.post( "/api/webhook/custom/message", json={ "api_version": 1, @@ -73,3 +77,19 @@ async def send_message( "message_id": message_id, }, ) + + match response.status_code: + case 200: + return + case 401: + raise InvalidToken + case 424: + raise CustomChannelDisabled + case 415: + raise InvalidFileType(f"Allowed types: {response.json()["allowed_mime_types"]}") + case 402: + raise NegativeBalance + case 422: + raise ValidationError + case _: + raise SuvvyError(response.json()) From 0a4de5352fa8f452c3ae42e08af4e544671be51d Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:53:27 +0300 Subject: [PATCH 10/17] . --- poetry.lock | 155 +---------------------------------------- pyproject.toml | 4 -- suvvyapi/types/link.py | 7 ++ tests/__init__.py | 0 tests/test_basic.py | 128 ---------------------------------- tests/test_history.py | 77 -------------------- 6 files changed, 8 insertions(+), 363 deletions(-) delete mode 100644 tests/__init__.py delete mode 100644 tests/test_basic.py delete mode 100644 tests/test_history.py diff --git a/poetry.lock b/poetry.lock index 9c0c1cd..83371e7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -22,24 +22,6 @@ 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)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] -[[package]] -name = "asttokens" -version = "2.4.1" -description = "Annotate AST trees with source code positions" -optional = false -python-versions = "*" -files = [ - {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, - {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, -] - -[package.dependencies] -six = ">=1.12.0" - -[package.extras] -astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] -test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] - [[package]] name = "black" version = "23.12.1" @@ -122,36 +104,6 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "deprecation" -version = "2.1.0" -description = "A library to handle automated deprecations" -optional = false -python-versions = "*" -files = [ - {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, - {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, -] - -[package.dependencies] -packaging = "*" - -[[package]] -name = "devtools" -version = "0.12.2" -description = "Python's missing debug print command, and more." -optional = false -python-versions = ">=3.7" -files = [ - {file = "devtools-0.12.2-py3-none-any.whl", hash = "sha256:c366e3de1df4cdd635f1ad8cbcd3af01a384d7abda71900e68d43b04eb6aaca7"}, - {file = "devtools-0.12.2.tar.gz", hash = "sha256:efceab184cb35e3a11fa8e602cc4fadacaa2e859e920fc6f87bf130b69885507"}, -] - -[package.dependencies] -asttokens = ">=2.0.0,<3.0.0" -executing = ">=1.1.1" -pygments = ">=2.15.0" - [[package]] name = "exceptiongroup" version = "1.2.2" @@ -166,20 +118,6 @@ files = [ [package.extras] test = ["pytest (>=6)"] -[[package]] -name = "executing" -version = "2.1.0" -description = "Get the currently executing AST node of a frame, and other information" -optional = false -python-versions = ">=3.8" -files = [ - {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"}, - {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"}, -] - -[package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] - [[package]] name = "h11" version = "0.14.0" @@ -250,17 +188,6 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - [[package]] name = "isort" version = "5.13.2" @@ -377,75 +304,6 @@ docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-a test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] type = ["mypy (>=1.11.2)"] -[[package]] -name = "pluggy" -version = "1.5.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "pygments" -version = "2.18.0" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, -] - -[package.extras] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "pytest" -version = "7.4.4" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} - -[package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "pytest-asyncio" -version = "0.23.8" -description = "Pytest support for asyncio" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"}, - {file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"}, -] - -[package.dependencies] -pytest = ">=7.0.0,<9" - -[package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] -testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] - [[package]] name = "python-magic" version = "0.4.27" @@ -457,17 +315,6 @@ files = [ {file = "python_magic-0.4.27-py2.py3-none-any.whl", hash = "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3"}, ] -[[package]] -name = "six" -version = "1.17.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, - {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, -] - [[package]] name = "sniffio" version = "1.3.1" @@ -534,4 +381,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.10,<4.0" -content-hash = "9a22e5e25535bf14ffe4dc36b54db2342702c5a93952a1b3bc46ce7af11499ae" +content-hash = "e3536e935e5d4659e627b23ccac13d735f90c946079a7bf5bd6edff3118447a8" diff --git a/pyproject.toml b/pyproject.toml index 318d9c0..d6cebb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,15 +25,11 @@ repository = "https://github.com/suvvyai/suvvyapi" [tool.poetry.dependencies] python = ">=3.10,<4.0" httpx = "^0.26.0" -deprecation = "^2.1.0" python-magic = "^0.4.27" [tool.poetry.group.dev.dependencies] -devtools = "^0.12.2" black = "^23.12.0" isort = "^5.13.2" -pytest = "^7.4.3" -pytest-asyncio = "^0.23.2" mypy = "^1.8.0" [tool.isort] diff --git a/suvvyapi/types/link.py b/suvvyapi/types/link.py index 7af36ae..0c6f5d1 100644 --- a/suvvyapi/types/link.py +++ b/suvvyapi/types/link.py @@ -8,3 +8,10 @@ class Link: url: str hint: str | None = None type: Literal["user", "chat", "phone", "lead", "other"] = "other" + + def to_dict(self) -> dict: + return { + "url": self.url, + "hint": self.hint, + "type": self.type + } diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/test_basic.py b/tests/test_basic.py deleted file mode 100644 index a4b22c8..0000000 --- a/tests/test_basic.py +++ /dev/null @@ -1,128 +0,0 @@ -# mypy: ignore_errors -import datetime -import os -import random -import string - -from devtools import debug - -from suvvyapi import Suvvy, Message - -suvvy = Suvvy(os.getenv("TEST1_SUVVY_TOKEN"), api_url="https://test.api.suvvy.ai") - - -def generate_unique_id() -> str: - """Generate a unique dialog ID""" - return ( - f"pytest-" - f"{datetime.datetime.utcnow().isoformat()}-" - f"{''.join(random.choices(string.digits + string.ascii_letters, k=50))}" - ) - - -unique_id = generate_unique_id() -async_unique_id = generate_unique_id() - - -def test_check_connection(): - assert suvvy.check_connection() - - -async def test_async_check_connection(): - assert await suvvy.acheck_connection() - - -def test_add_message(): - r = suvvy.add_message_to_history( - unique_id, - Message(text="Привет!"), - ) - debug(r) - - -async def test_async_add_message(): - r = await suvvy.async_add_message_to_history( - async_unique_id, - Message(text="Привет!"), - ) - debug(r) - - -def test_predict_history(): - r = suvvy.predict_history(unique_id) - assert r is not None - debug(r) - - -async def test_apredict_history(): - r = await suvvy.apredict_history(async_unique_id) - assert r is not None - debug(r) - - -def test_predict_history_refuse_to_answer(): - suvvy.add_message_to_history( - unique_id, - Message(text="Хорошо, подождите минутку"), - ) - r = suvvy.predict_history(unique_id) - assert r is None - - -async def test_apredict_history_refuse_to_answer(): - await suvvy.async_add_message_to_history( - async_unique_id, - Message(text="Хорошо, подождите минутку"), - ) - r = await suvvy.apredict_history(async_unique_id) - assert r is None - - -def test_get_history(): - r = suvvy.get_history(unique_id) - debug(r) - - -def test_reset_history(): - r = suvvy.reset_history(unique_id) - debug(r) - - -async def test_aget_history(): - r = await suvvy.aget_history(async_unique_id) - debug(r) - - -async def test_areset_history(): - r = await suvvy.areset_history(async_unique_id) - debug(r) - - -def test_predict_history_add_message(): - r = suvvy.predict_history_add_message(unique_id, Message(text="Привет!")) - assert r is not None - debug(r) - - -async def test_apredict_history_add_message(): - r = await suvvy.apredict_history_add_message( - async_unique_id, Message(text="Привет!") - ) - assert r is not None - debug(r) - - -def test_predict_history_add_message_refuse_to_answer(): - r = suvvy.predict_history_add_message( - unique_id, - Message(text="Хорошо, подождите минутку"), - ) - assert r is None - - -async def test_apredict_history_add_message_refuse_to_answer(): - r = await suvvy.apredict_history_add_message( - async_unique_id, - Message(text="Хорошо, подождите минутку"), - ) - assert r is None diff --git a/tests/test_history.py b/tests/test_history.py deleted file mode 100644 index d72fa52..0000000 --- a/tests/test_history.py +++ /dev/null @@ -1,77 +0,0 @@ -# mypy: ignore_errors -import datetime -import os -import random -import string - -from devtools import debug - -from suvvyapi import Suvvy, Message - -suvvy = Suvvy(os.getenv("TEST1_SUVVY_TOKEN"), api_url="https://test.api.suvvy.ai") - - -def generate_unique_id() -> str: - """Generate a unique dialog ID""" - return ( - f"pytest-" - f"{datetime.datetime.utcnow().isoformat()}-" - f"{''.join(random.choices(string.digits + string.ascii_letters, k=50))}" - ) - - -unique_id = generate_unique_id() -async_unique_id = generate_unique_id() - -history = suvvy.as_history(unique_id) -async_history = suvvy.as_history(async_unique_id) - - -def test_get(): - r = history.get() - debug(r) - - -async def test_aget(): - r = await async_history.aget() - debug(r) - - -def test_add_message(): - r = history.add_message(Message(text="Привет!")) - debug(r) - - -async def test_async_add_message(): - r = await async_history.async_add_message(Message(text="Привет!")) - debug(r) - - -def test_predict(): - r = history.predict() - debug(r) - - -async def test_apredict(): - r = await async_history.apredict() - debug(r) - - -def test_reset(): - r = history.reset() - debug(r) - - -async def test_areset(): - r = await async_history.areset() - debug(r) - - -def test_predict_add_message(): - r = history.predict_add_message(Message(text="Привет!")) - debug(r) - - -async def test_apredict_add_message(): - r = await async_history.apredict_add_message(Message(text="Привет!")) - debug(r) From 50a01c3e1e8941aa9eb4a695e70546dccf0e4c0e Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:53:44 +0300 Subject: [PATCH 11/17] to dict --- suvvyapi/api/async.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suvvyapi/api/async.py b/suvvyapi/api/async.py index 323cb11..93d3b08 100644 --- a/suvvyapi/api/async.py +++ b/suvvyapi/api/async.py @@ -70,7 +70,7 @@ async def send_message( "text": text, "attachments": [a.to_dict() for a in input_to_attachments(attachments)] if attachments else [], "placeholders": placeholders, - "link": link, + "link": link.to_dict(), "client_name": client_name, "client_phone": client_phone, "message_sender": message_sender.value, From 9c14d56b27145f0642830b2dc9949e1a958e1ff5 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:54:14 +0300 Subject: [PATCH 12/17] all --- suvvyapi/__init__.py | 3 +++ suvvyapi/api/{async.py => async_.py} | 0 2 files changed, 3 insertions(+) rename suvvyapi/api/{async.py => async_.py} (100%) diff --git a/suvvyapi/__init__.py b/suvvyapi/__init__.py index e69de29..060fa6d 100644 --- a/suvvyapi/__init__.py +++ b/suvvyapi/__init__.py @@ -0,0 +1,3 @@ +from suvvyapi.api.async_ import AsyncSuvvy + +__all__ = ["AsyncSuvvy"] diff --git a/suvvyapi/api/async.py b/suvvyapi/api/async_.py similarity index 100% rename from suvvyapi/api/async.py rename to suvvyapi/api/async_.py From 4b4c582aa6feeb0faf28b0fa18f5ec7b22772668 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:58:56 +0300 Subject: [PATCH 13/17] none --- suvvyapi/api/async_.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suvvyapi/api/async_.py b/suvvyapi/api/async_.py index 93d3b08..c4893d9 100644 --- a/suvvyapi/api/async_.py +++ b/suvvyapi/api/async_.py @@ -70,7 +70,7 @@ async def send_message( "text": text, "attachments": [a.to_dict() for a in input_to_attachments(attachments)] if attachments else [], "placeholders": placeholders, - "link": link.to_dict(), + "link": link.to_dict() if link is not None else None, "client_name": client_name, "client_phone": client_phone, "message_sender": message_sender.value, From c122c843560128293521258bc12c31350b162925 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 17:59:29 +0300 Subject: [PATCH 14/17] {} --- suvvyapi/api/async_.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/suvvyapi/api/async_.py b/suvvyapi/api/async_.py index c4893d9..258cfdc 100644 --- a/suvvyapi/api/async_.py +++ b/suvvyapi/api/async_.py @@ -69,7 +69,7 @@ async def send_message( "source": source, "text": text, "attachments": [a.to_dict() for a in input_to_attachments(attachments)] if attachments else [], - "placeholders": placeholders, + "placeholders": placeholders or {}, "link": link.to_dict() if link is not None else None, "client_name": client_name, "client_phone": client_phone, @@ -90,6 +90,6 @@ async def send_message( case 402: raise NegativeBalance case 422: - raise ValidationError + raise ValidationError(response.json()) case _: raise SuvvyError(response.json()) From a95ec3431a1b917e130117b17e4d469921ea83b0 Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 18:01:39 +0300 Subject: [PATCH 15/17] update readme --- README.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4787290..0437b6c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ## About SuvvyAPI 📘 -SuvvyAPI is an asynchronous Python API wrapper built on top of `httpx` and `pydantic` for the Suvvy AI API, offering an easy and Pythonic way to interact with the Suvvy AI services. +SuvvyAPI is an asynchronous Python API wrapper built on top of `httpx` for the Suvvy AI API, offering an easy and Pythonic way to interact with the Suvvy AI services. ## Installation 🛠️ @@ -25,18 +25,26 @@ pip install -U suvvyapi ## Usage 🚀 -### Synchronous Usage +### Asynchronous Usage -You can use SuvvyAPI synchronously as follows: +You can use SuvvyAPI asynchronously as follows: ```python -from suvvyapi import Suvvy, Message +import asyncio +from suvvyapi import AsyncSuvvy + + +async def main(): + async with AsyncSuvvy( + token="", + ) as suvvy: + await suvvy.send_message(chat_id="somechat1", text="Привет!", source="Иван") + + +asyncio.run(main()) -suvvy = Suvvy("YOUR_TOKEN") -history = suvvy.as_history("random_id") -response = history.predict_add_message(Message(text="Say hello to Python!")) ``` -*Note: Replace "YOUR_TOKEN" with your actual token from [Suvvy AI](https://home.suvvy.ai/).* +*Note: Replace "your token" with your actual token from [Suvvy AI](https://app.suvvy.ai/).* ### [More in documentation](https://github.com/suvvyai/suvvyapi/wiki) @@ -50,4 +58,4 @@ Contributions are welcome. Please fork the repository, make your changes, and su ## License 📄 -SuvvyAPI is released under the [MIT License](https://github.com/suvvyai/suvvyapi/blob/main/LICENSE). \ No newline at end of file +SuvvyAPI is released under the [MIT License](https://github.com/suvvyai/suvvyapi/blob/main/LICENSE). From fa05cf9a2b1afb7bad31b522904b31dce8ffc44a Mon Sep 17 00:00:00 2001 From: sushka Date: Sun, 29 Dec 2024 18:08:00 +0300 Subject: [PATCH 16/17] actions --- .github/workflows/code-linting.yml | 49 ++++++++++++++++++++++++++++++ .github/workflows/publish.yml | 30 ++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 .github/workflows/code-linting.yml create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/code-linting.yml b/.github/workflows/code-linting.yml new file mode 100644 index 0000000..a98e531 --- /dev/null +++ b/.github/workflows/code-linting.yml @@ -0,0 +1,49 @@ +name: Code linting + +on: + pull_request: + branches: [master] + +jobs: + black: + runs-on: ubuntu-latest + steps: + - name: Check Out Repository + uses: actions/checkout@v4 + + - name: Run black + uses: psf/black@stable + with: + options: "--check --diff --config pyproject.toml" + + isort: + runs-on: ubuntu-latest + steps: + - name: Check Out Repository + uses: actions/checkout@v4 + + - name: Run isort + uses: isort/isort-action@master + + mypy: + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + steps: + - name: Check Out Repository + uses: actions/checkout@v4 + + - name: Set up python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install Poetry + uses: snok/install-poetry@v1 + + - name: Install dependencies + run: poetry install --no-interaction --no-root --all-extras + + - name: Check + run: poetry run mypy . --config-file pyproject.toml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..88d5850 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,30 @@ +name: Release +on: + release: + types: + - published + +jobs: + publish: + strategy: + fail-fast: false + matrix: + python-version: [3.12] + poetry-version: [1.8.2] + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Run image + uses: abatilo/actions-poetry@v2.0.0 + with: + poetry-version: ${{ matrix.poetry-version }} + - name: Publish + env: + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + run: | + poetry config pypi-token.pypi $PYPI_TOKEN + poetry publish --build From 8163e51bd4e8c893655d534f1cf2e71f2f4d957c Mon Sep 17 00:00:00 2001 From: sushka Date: Mon, 30 Dec 2024 16:23:58 +0300 Subject: [PATCH 17/17] =?UTF-8?q?=D1=83=D0=B1=D1=80=D0=B0=D0=BB=20message?= =?UTF-8?q?=5Fid=20=D0=B8=D0=B7=20attachment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- suvvyapi/types/attachment.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/suvvyapi/types/attachment.py b/suvvyapi/types/attachment.py index c404906..beb1951 100644 --- a/suvvyapi/types/attachment.py +++ b/suvvyapi/types/attachment.py @@ -27,14 +27,12 @@ class Attachment: file_name: str file_type: Literal["image", "audio"] data: str - message_id: str def to_dict(self) -> dict: return { "file_name": self.file_name, "file_type": self.file_type, "data": self.data, - "message_id": self.message_id, }