diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bebb8841af94c89f199de0e5a93b1a4871327eea..af3e307b09afb4454b67aebbcbf43790a68e76d5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -27,10 +27,6 @@ default: pre_commit_checks: stage: static_code_analysis extends: .pre_commit_checks_template - before_script: - - !reference [.pre_commit_checks_template, before_script] - - poetry install --no-root --extras api_generation - - pip list #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<| STATIC CODE ANALYSIS |<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -41,8 +37,6 @@ tests: extends: .project_develop_configuration_template needs: [ ] # to start immediately, without waiting for previous stages script: - - poetry install --no-root --extras api_generation - - pip list - pytest tests/ #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<| TESTS |<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff --git a/poetry.lock b/poetry.lock index caf8c7b1e15ccccd56f83a21ee26fb025cfd0c62..1c92fd0280639780862aef5300ac157b293237b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,83 +1,5 @@ # This file is automatically @generated by Poetry 2.1.3 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 = true -python-versions = ">=3.8" -groups = ["main"] -markers = "extra == \"api-generation\"" -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 = "argcomplete" -version = "3.6.2" -description = "Bash tab completion for argparse" -optional = true -python-versions = ">=3.8" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "argcomplete-3.6.2-py3-none-any.whl", hash = "sha256:65b3133a29ad53fb42c48cf5114752c7ab66c1c38544fdf6460f450c09b42591"}, - {file = "argcomplete-3.6.2.tar.gz", hash = "sha256:d0519b1bc867f5f4f4713c41ad0aba73a4a5f007449716b16f385f2166dc6adf"}, -] - -[package.extras] -test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] - -[[package]] -name = "black" -version = "23.3.0" -description = "The uncompromising code formatter." -optional = true -python-versions = ">=3.7" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, - {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, - {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, - {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, - {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, - {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, - {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, - {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, - {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, - {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, - {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, - {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, - {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, - {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "cfgv" version = "3.4.0" @@ -90,66 +12,18 @@ files = [ {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] -[[package]] -name = "click" -version = "8.1.8" -description = "Composable command line interface toolkit" -optional = true -python-versions = ">=3.7" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, - {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] +groups = ["dev"] +markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {main = "extra == \"api-generation\" and platform_system == \"Windows\"", dev = "sys_platform == \"win32\""} - -[[package]] -name = "datamodel-code-generator" -version = "0.30.1" -description = "Datamodel Code Generator" -optional = true -python-versions = ">=3.9" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "datamodel_code_generator-0.30.1-py3-none-any.whl", hash = "sha256:9601dfa3da8aa8d8d54e182059f78836b1768a807d5c26df798db12d4054c8f3"}, - {file = "datamodel_code_generator-0.30.1.tar.gz", hash = "sha256:d125012face4cd1eca6c9300297a1f5775a9d5ff8fc3f68d34d0944a7beea105"}, -] - -[package.dependencies] -argcomplete = ">=2.10.1,<4" -black = ">=19.10b0" -genson = ">=1.2.1,<2" -inflect = ">=4.1,<8" -isort = ">=4.3.21,<7" -jinja2 = ">=2.10.1,<4" -packaging = "*" -pydantic = ">=1.5" -pyyaml = ">=6.0.1" - -[package.extras] -all = ["graphql-core (>=3.2.3)", "httpx (>=0.24.1)", "openapi-spec-validator (>=0.2.8,<0.7)", "prance (>=0.18.2)", "pysnooper (>=0.4.1,<2)", "ruff (>=0.9.10)"] -debug = ["pysnooper (>=0.4.1,<2)"] -graphql = ["graphql-core (>=3.2.3)"] -http = ["httpx (>=0.24.1)"] -ruff = ["ruff (>=0.9.10)"] -validation = ["openapi-spec-validator (>=0.2.8,<0.7)", "prance (>=0.18.2)"] [[package]] name = "distlib" @@ -180,19 +54,6 @@ docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3) testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""] -[[package]] -name = "genson" -version = "1.3.0" -description = "GenSON is a powerful, user-friendly JSON Schema generator." -optional = true -python-versions = "*" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "genson-1.3.0-py3-none-any.whl", hash = "sha256:468feccd00274cc7e4c09e84b08704270ba8d95232aa280f65b986139cec67f7"}, - {file = "genson-1.3.0.tar.gz", hash = "sha256:e02db9ac2e3fd29e65b5286f7135762e2cd8a986537c075b06fc5f1517308e37"}, -] - [[package]] name = "identify" version = "2.6.9" @@ -208,31 +69,6 @@ files = [ [package.extras] license = ["ukkonen"] -[[package]] -name = "inflect" -version = "7.5.0" -description = "Correctly generate plurals, singular nouns, ordinals, indefinite articles" -optional = true -python-versions = ">=3.9" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "inflect-7.5.0-py3-none-any.whl", hash = "sha256:2aea70e5e70c35d8350b8097396ec155ffd68def678c7ff97f51aa69c1d92344"}, - {file = "inflect-7.5.0.tar.gz", hash = "sha256:faf19801c3742ed5a05a8ce388e0d8fe1a07f8d095c82201eb904f5d27ad571f"}, -] - -[package.dependencies] -more_itertools = ">=8.5.0" -typeguard = ">=4.0.1" - -[package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] -cover = ["pytest-cov"] -doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -enabler = ["pytest-enabler (>=2.2)"] -test = ["pygments", "pytest (>=6,!=8.1.*)"] -type = ["pytest-mypy"] - [[package]] name = "iniconfig" version = "2.1.0" @@ -245,127 +81,6 @@ files = [ {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] -[[package]] -name = "isort" -version = "6.0.1" -description = "A Python utility / library to sort Python imports." -optional = true -python-versions = ">=3.9.0" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615"}, - {file = "isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450"}, -] - -[package.extras] -colors = ["colorama"] -plugins = ["setuptools"] - -[[package]] -name = "jinja2" -version = "3.1.6" -description = "A very fast and expressive template engine." -optional = true -python-versions = ">=3.7" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, - {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, -] - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "markupsafe" -version = "3.0.2" -description = "Safely add untrusted strings to HTML/XML markup." -optional = true -python-versions = ">=3.9" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, - {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, - {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, - {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, - {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, - {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, - {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, - {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, -] - -[[package]] -name = "more-itertools" -version = "10.7.0" -description = "More routines for operating on iterables, beyond itertools" -optional = true -python-versions = ">=3.9" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e"}, - {file = "more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3"}, -] - [[package]] name = "msgspec" version = "0.18.6" @@ -472,12 +187,11 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" -groups = ["main", "dev"] +groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -markers = {main = "extra == \"api-generation\""} [[package]] name = "nodeenv" @@ -497,25 +211,11 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] +groups = ["dev"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] -markers = {main = "extra == \"api-generation\""} - -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = true -python-versions = ">=3.8" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] [[package]] name = "platformdirs" @@ -523,12 +223,11 @@ version = "4.3.7" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.9" -groups = ["main", "dev"] +groups = ["dev"] files = [ {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, ] -markers = {main = "extra == \"api-generation\""} [package.extras] docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] @@ -570,142 +269,6 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" -[[package]] -name = "pydantic" -version = "2.11.7" -description = "Data validation using Python type hints" -optional = true -python-versions = ">=3.9" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"}, - {file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"}, -] - -[package.dependencies] -annotated-types = ">=0.6.0" -pydantic-core = "2.33.2" -typing-extensions = ">=4.12.2" -typing-inspection = ">=0.4.0" - -[package.extras] -email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] - -[[package]] -name = "pydantic-core" -version = "2.33.2" -description = "Core functionality for Pydantic validation and serialization" -optional = true -python-versions = ">=3.9" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, - {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, - {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, - {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, - {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, - {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, - {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, - {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, - {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, - {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, - {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, - {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, - {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, - {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, - {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, - {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, - {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, - {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, - {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, - {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, - {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, - {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, - {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, - {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, - {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, - {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, - {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, - {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, - {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, - {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, - {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, - {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, - {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, - {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, - {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, - {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, - {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, - {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, - {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, - {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, - {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, - {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, - {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, - {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, - {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, - {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, - {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, - {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, - {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, - {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, - {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, - {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, - {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, - {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, - {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, - {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, - {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, - {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, - {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, - {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, - {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, - {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, - {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, - {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, - {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, - {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, - {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, - {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, - {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, - {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, - {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, - {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, - {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, - {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, - {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, - {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, - {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, - {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, - {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, - {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, - {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, - {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, - {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, - {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, - {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, - {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, - {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, - {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, - {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, - {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, - {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, - {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, - {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, - {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, - {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, - {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, - {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, - {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, - {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, -] - -[package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" - [[package]] name = "pytest" version = "8.3.5" @@ -752,7 +315,7 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] +groups = ["dev"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -808,16 +371,14 @@ files = [ {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] -markers = {main = "extra == \"api-generation\""} [[package]] name = "ruff" version = "0.11.5" description = "An extremely fast Python linter and code formatter, written in Rust." -optional = true +optional = false python-versions = ">=3.7" -groups = ["main"] -markers = "extra == \"api-generation\"" +groups = ["dev"] files = [ {file = "ruff-0.11.5-py3-none-linux_armv6l.whl", hash = "sha256:2561294e108eb648e50f210671cc56aee590fb6167b594144401532138c66c7b"}, {file = "ruff-0.11.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac12884b9e005c12d0bd121f56ccf8033e1614f736f766c118ad60780882a077"}, @@ -839,54 +400,17 @@ files = [ {file = "ruff-0.11.5.tar.gz", hash = "sha256:cae2e2439cb88853e421901ec040a758960b576126dab520fa08e9de431d1bef"}, ] -[[package]] -name = "typeguard" -version = "4.4.2" -description = "Run-time type checker for Python" -optional = true -python-versions = ">=3.9" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "typeguard-4.4.2-py3-none-any.whl", hash = "sha256:77a78f11f09777aeae7fa08585f33b5f4ef0e7335af40005b0c422ed398ff48c"}, - {file = "typeguard-4.4.2.tar.gz", hash = "sha256:a6f1065813e32ef365bc3b3f503af8a96f9dd4e0033a02c28c4a4983de8c6c49"}, -] - -[package.dependencies] -typing_extensions = ">=4.10.0" - -[package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)"] -test = ["coverage[toml] (>=7)", "mypy (>=1.2.0) ; platform_python_implementation != \"PyPy\"", "pytest (>=7)"] - [[package]] name = "typing-extensions" version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] +groups = ["dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] -markers = {main = "extra == \"api-generation\""} - -[[package]] -name = "typing-inspection" -version = "0.4.1" -description = "Runtime typing introspection tools" -optional = true -python-versions = ">=3.9" -groups = ["main"] -markers = "extra == \"api-generation\"" -files = [ - {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, - {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, -] - -[package.dependencies] -typing-extensions = ">=4.12.0" [[package]] name = "virtualenv" @@ -909,10 +433,7 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] -[extras] -api-generation = ["datamodel-code-generator", "ruff"] - [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "e0be11a5275a2d7971a3f13c0bc476f036102dde0418cdbf5e83dd2b7a614dd7" +content-hash = "7b1d4122f9ba7db18921b7654a67f5f972a9faa3d49b13f86ad8eab3364bf86b" diff --git a/pyproject.toml b/pyproject.toml index f66811938a5eb90c056ad25ce095d509c68192db..21261f77dc93694e19cf4d81dd128bfbe801b737 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,17 +23,13 @@ packages = [ [tool.poetry.dependencies] python = "^3.12" msgspec = "0.18.6" -datamodel-code-generator = { version = "0.30.1", optional = true } -ruff = { version = "0.11.5", optional = true } -[tool.poetry.extras] -api_generation = ["datamodel-code-generator", "ruff"] - -[tool.poetry.dev-dependencies] +[tool.poetry.group.dev.dependencies] pytest = "8.3.5" pytest-asyncio = "0.25.3" mypy = "1.11.2" pre-commit = "2.21.0" +ruff = "0.11.5" [tool.poetry-dynamic-versioning] enable = true @@ -103,5 +99,3 @@ log_cli = true log_level = "INFO" log_format = "%(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)" log_date_format = "%Y-%m-%d %H:%M:" -asyncio_mode = "auto" -asyncio_default_fixture_loop_scope = "function" diff --git a/schemas/apis/api_client_generator/__init__.py b/schemas/apis/api_client_generator/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/schemas/apis/api_client_generator/_private/__init__.py b/schemas/apis/api_client_generator/_private/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/schemas/apis/api_client_generator/_private/check_whether_was_ran_as_script.py b/schemas/apis/api_client_generator/_private/check_whether_was_ran_as_script.py deleted file mode 100644 index 3db468231a82c96a69e5e94862319b7b71e9a2b4..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/check_whether_was_ran_as_script.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import annotations - -from schemas.apis.api_client_generator.exceptions import RunningScriptWithoutAppropriateFlagError - - -def check_whether_was_ran_as_script() -> None: - """Check if the script is run as a script. If so, raise an error.""" - - if __name__ == "__main__": - if __package__ is None: - raise RunningScriptWithoutAppropriateFlagError diff --git a/schemas/apis/api_client_generator/_private/client_class_factory/__init__.py b/schemas/apis/api_client_generator/_private/client_class_factory/__init__.py deleted file mode 100644 index 9771065d90ae019ce716cda0612ee2c97ea93b9c..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/client_class_factory/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .json_rpc import create_api_client as create_json_rpc_api_client - -__all__ = ["create_json_rpc_api_client"] diff --git a/schemas/apis/api_client_generator/_private/client_class_factory/common.py b/schemas/apis/api_client_generator/_private/client_class_factory/common.py deleted file mode 100644 index eb646a6211586c226d60bc840e5db21d97061c9e..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/client_class_factory/common.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -import ast - -from schemas.apis.api_client_generator._private.common.converters import snake_to_camel -from schemas.apis.api_client_generator._private.common.models_aliased import ( - BaseApiClass, - EndpointsDescription, - EndpointsFactory, -) -from schemas.apis.api_client_generator._private.resolve_needed_imports import is_struct -from schemas.apis.api_client_generator.exceptions import EndpointParamsIsNotMsgspecStructError - - -def create_api_client( # NOQA: PLR0913 - api_name: str, - endpoints: EndpointsDescription, - endpoint_factory: EndpointsFactory, - base_class: type[BaseApiClass] | str, - endpoint_decorator: str, - *, - asynchronous: bool = True, -) -> ast.ClassDef: - """ - Creates a client class for the given API name and endpoints. - - Args: - api_name: The name of the API. Will be used as class name (converted to the CamelCase). - endpoints: The endpoints description for the API. - endpoint_factory: The factory function to create endpoints. - base_class: The base class for the API client. - endpoint_decorator: The name of the endpoint decorator to be used. - asynchronous: If True, the endpoints will be created as asynchronous methods. - - Raises: - EndpointParamsIsNotDataclassError: If the endpoint parameters are not a dataclass. - """ - methods = [] - - for endpoint_name, endpoint_parameters in endpoints.items(): - params = endpoint_parameters.get("params", None) - - if params is not None and not is_struct(params): - raise EndpointParamsIsNotMsgspecStructError(endpoint_name) - - result = endpoint_parameters.get("result", None) - description = endpoint_parameters.get("description", None) - response_array = endpoint_parameters.get("response_array", False) - - methods.append( - endpoint_factory( - endpoint_name, - params, - result, - endpoint_decorator, - str(description) if description else None, - response_array=response_array, - asynchronous=asynchronous, - ) - ) - - base_class_name = base_class if isinstance(base_class, str) else base_class.__name__ - - endpoint_decorator_assign = ast.Assign( # Assign endpoint decorator as class variable - targets=[ast.Name(id=endpoint_decorator)], - value=ast.Attribute( - value=ast.Name(id=base_class_name), - attr=endpoint_decorator, - ), - ) - - body: list[ast.stmt] = [endpoint_decorator_assign, *methods] - - return ast.ClassDef( - name=snake_to_camel(api_name), - bases=[ast.Name(id=base_class_name)], - keywords=[], - body=body, - decorator_list=[], - type_params=[], - ) diff --git a/schemas/apis/api_client_generator/_private/client_class_factory/json_rpc.py b/schemas/apis/api_client_generator/_private/client_class_factory/json_rpc.py deleted file mode 100644 index 3174105616915f31d73f1ae7457903fbef9d1a33..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/client_class_factory/json_rpc.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from schemas.apis.api_client_generator._private.client_class_factory.common import ( - create_api_client as common_create_api_client, -) -from schemas.apis.api_client_generator._private.common.defaults import DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME -from schemas.apis.api_client_generator._private.common.models_aliased import ( - BaseApiClass, - EndpointsDescription, -) -from schemas.apis.api_client_generator._private.endpoints_factory import create_json_rpc_endpoint - -if TYPE_CHECKING: - import ast - - -def create_api_client( - api_name: str, - endpoints: EndpointsDescription, - base_class: type[BaseApiClass] | str, - endpoint_decorator: str = DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME, - *, - asynchronous: bool = True, -) -> ast.ClassDef: - """ - Creates a client class for the given API name and endpoints. - - - Args: - api_name: The name of the API. Will be used as class name (converted to the CamelCase). - endpoints: The endpoints description for the API. - base_class: The base class for the API client. - endpoint_decorator: The name of the endpoint decorator to be used. - asynchronous: If True, the endpoints will be created as asynchronous methods. - """ - - return common_create_api_client( - api_name, - endpoints, - create_json_rpc_endpoint, # type: ignore[arg-type] - base_class, - endpoint_decorator, - asynchronous=asynchronous, - ) diff --git a/schemas/apis/api_client_generator/_private/common/__init__.py b/schemas/apis/api_client_generator/_private/common/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/schemas/apis/api_client_generator/_private/common/converters.py b/schemas/apis/api_client_generator/_private/common/converters.py deleted file mode 100644 index e6cbed30c5c5ad4e851a31e17817303796df53f5..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/common/converters.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import annotations - -import re - - -def snake_to_camel(name: str) -> str: - """Converts a snake_case string to CamelCase.""" - return "".join(word.capitalize() for word in name.split("_")) - - -def camel_to_snake(name: str) -> str: - """Converts a CamelCase string to snake_case.""" - s1 = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", name) - return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s1).lower() - - -def hyphen_to_snake(name: str) -> str: - """Converts a hyphenated-string to snake_case.""" - return name.replace("-", "_") diff --git a/schemas/apis/api_client_generator/_private/common/defaults.py b/schemas/apis/api_client_generator/_private/common/defaults.py deleted file mode 100644 index 0056c060dba93859ab3e7772bb13c03c4676c129..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/common/defaults.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import annotations - -from typing import Final - -DEFAULT_API_COLLECTION_NAME: Final[str] = "ApiCollection" -DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME: Final[str] = "endpoint_jsonrpc" -DEFAULT_ENDPOINT_REST_DECORATOR_NAME: Final[str] = "endpoint_rest" -DEFAULT_IMPORT_LEVEL: Final[int] = 0 -DEFAULT_LINE_LENGTH_FOR_RUFF: Final[int] = 120 diff --git a/schemas/apis/api_client_generator/_private/common/generated_class.py b/schemas/apis/api_client_generator/_private/common/generated_class.py deleted file mode 100644 index 6e07e634f89c423dccdf4509f906480a40f17154..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/common/generated_class.py +++ /dev/null @@ -1,15 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - import ast - - -@dataclass -class GeneratedClass: - """Represents a generated class with its definition and imports.""" - - class_def: ast.ClassDef - imports: list[ast.ImportFrom] diff --git a/schemas/apis/api_client_generator/_private/common/get_type_from_ref_in_camel.py b/schemas/apis/api_client_generator/_private/common/get_type_from_ref_in_camel.py deleted file mode 100644 index a77a1fe970bb0ff615c1768db7f73872ee518cd7..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/common/get_type_from_ref_in_camel.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import annotations - -from schemas.apis.api_client_generator._private.common.converters import snake_to_camel -from schemas.apis.api_client_generator._private.description_tools import get_last_part_of_ref - - -def get_type_from_ref_in_camel(ref: str) -> str: - """Get type from OpenAPI $ref property and convert it to the CamelCase.""" - last_part = get_last_part_of_ref(ref) - type_name = last_part.split(".")[-1] if "." in last_part else last_part - - return snake_to_camel(type_name) diff --git a/schemas/apis/api_client_generator/_private/common/models_aliased.py b/schemas/apis/api_client_generator/_private/common/models_aliased.py deleted file mode 100644 index f69b91bc4308e6c4aa6bea0d650d1862d1358ae0..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/common/models_aliased.py +++ /dev/null @@ -1,69 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, Protocol, TypeAlias, cast - -if TYPE_CHECKING: - import ast - from struct import Struct - -AnyJson: TypeAlias = dict[str, "AnyJson"] | list["AnyJson"] | tuple["AnyJson", ...] | str | int | float | bool | None -SwaggerReadyForExtraction: TypeAlias = dict[str, AnyJson] - -EndpointDescriptionBeforeProcessing: TypeAlias = dict[str, str | bool] -""" -A description of an endpoint, params, result, description and response_array boolean parameter. -This is used before processing the endpoint description. At this stage, the params and result are still strings. -""" -ApiDescriptionBeforeProcessing: TypeAlias = dict[str, dict[str, EndpointDescriptionBeforeProcessing]] -EndpointsDescription: TypeAlias = dict[str, dict[str, Any]] -ApiDescription: TypeAlias = dict[str, EndpointsDescription] - - -class Importable(Protocol): - """A protocol that defines the structure of an importable object.""" - - __module__: str - __name__: str - - -class EndpointsFactory(Protocol): - def __call__( # NOQA: PLR0913 - self, - name: str, - params: Struct | None, - result: Importable | None, - endpoint_decorator: str, - description: str | None, - *, - response_array: bool, - asynchronous: bool, - ) -> ast.AsyncFunctionDef | ast.FunctionDef: ... - - -class BaseApiClass(Protocol): - """A protocol that defines the structure of a base class.""" - - __module__: str - __name__: str - - endpoint: EndpointsFactory - - -def ensure_is_importable(potential_importable: Any) -> Importable: - """Ensure that the object is importable.""" - assert hasattr(potential_importable, "__module__") and hasattr( - potential_importable, "__name__" - ), f"Object {potential_importable} is not importable. It must have __module__ and __name__ attributes." - return cast(Importable, potential_importable) - - -class ClientClassFactory(Protocol): - def __call__( - self, - api_name: str, - endpoints: EndpointsDescription, - base_class: type[BaseApiClass] | str, - endpoint_decorator: str, - *, - asynchronous: bool, - ) -> ast.ClassDef: ... diff --git a/schemas/apis/api_client_generator/_private/common/openapi_to_python_type.py b/schemas/apis/api_client_generator/_private/common/openapi_to_python_type.py deleted file mode 100644 index b4d6d474c4936814829e2b3b55f10fa8d01d4384..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/common/openapi_to_python_type.py +++ /dev/null @@ -1,32 +0,0 @@ -from __future__ import annotations - -OPENAPI_BASIC_TYPES_MAPPING: dict[str, type] = { - "string": str, - "integer": int, - "number": float, - "boolean": bool, - "array": list, - "object": dict, -} - - -def convert_openapi_type_to_python_type(openapi_type: str) -> type: - """ - Convert OpenAPI type to Python type. - - Args: - openapi_type: The OpenAPI type to convert. - - Returns: - The corresponding Python type. - - Raises: - ValueError: If the OpenAPI type is not supported. - """ - - if openapi_type not in OPENAPI_BASIC_TYPES_MAPPING: - raise ValueError( - f"Unsupported OpenAPI type: {openapi_type}. Supported types are: {', '.join(OPENAPI_BASIC_TYPES_MAPPING.keys())}." - ) - - return OPENAPI_BASIC_TYPES_MAPPING[openapi_type] diff --git a/schemas/apis/api_client_generator/_private/create_collection_class.py b/schemas/apis/api_client_generator/_private/create_collection_class.py deleted file mode 100644 index f9557f012b2c3e64b328bfac1297d2dd6c0d2ca8..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/create_collection_class.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import annotations - -import ast -from typing import Iterable - -from schemas.apis.api_client_generator._private.common.converters import camel_to_snake - - -def create_collection_class(collection_name: str, api_client_classes: Iterable[ast.ClassDef]) -> ast.ClassDef: - """ - Creates a collection class for the given API client classes. - - Args: - collection_name: The name of the collection class. - api_client_classes An iterable of API client class definitions. - - Example: - create_collection_class("MyCollection", [FirstApiClientClass, SecondApiClientClass]) - - output: - class MyCollection: - def __init__(self): - super().__init__() - self.first_api_client_class = FirstApiClientClass - self.second_api_client_class = SecondApiClientClass - """ - init_body: list[ast.stmt] = [ - ast.Assign( - targets=[ - ast.Attribute( - value=ast.Name( - id="self", - ), - attr=camel_to_snake(api_client.name), - ) - ], - value=ast.Name(id=api_client.name), - ) - for api_client in api_client_classes - ] - - class_body: list[ast.stmt] = [ - ast.FunctionDef( - name="__init__", - args=ast.arguments( - posonlyargs=[], - args=[ast.arg(arg="self")], - kwonlyargs=[], - kw_defaults=[], - defaults=[], - ), - body=init_body, - decorator_list=[], - returns=None, - type_params=[], - ) - ] - - return ast.ClassDef( - name=collection_name, - bases=[], - keywords=[], - body=class_body, - decorator_list=[], - type_params=[], - ) diff --git a/schemas/apis/api_client_generator/_private/description_tools.py b/schemas/apis/api_client_generator/_private/description_tools.py deleted file mode 100644 index 651fdf08c8e57e9de3073a7849ff397c4b237e0f..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/description_tools.py +++ /dev/null @@ -1,295 +0,0 @@ -from __future__ import annotations - -import ast -from typing import Any, TypeAlias - -from schemas.apis.api_client_generator._private.common.models_aliased import ( - ApiDescription, - SwaggerReadyForExtraction, -) - -AliasToAssign: TypeAlias = tuple[str, type] - - -def get_value_from_swagger_part_recursively( - swagger_part: SwaggerReadyForExtraction, - keys: tuple[str, ...], -) -> Any: - """Get a value from the swagger part by a path of keys.""" - assert isinstance(swagger_part, dict), "This swagger part must be a dictionary." - - key = keys[0] - value = swagger_part[key] - - if len(keys) == 1: # Last key in the path - return searched value - return value - - assert isinstance(value, dict), "This swagger part must be a dictionary." - - return get_value_from_swagger_part_recursively(value, keys[1:]) - - -def get_ref_from_schema(response: SwaggerReadyForExtraction) -> str: - """ - Resolve the reference from the schema. - - Example: - some_responses = { - "responses": { - "200": { - "description": "Some operation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/some_response" - } - } - } - } - } - } - - get_ref_from_schema(some_responses["responses"]["200"]) - >>> "#/components/schemas/some_response" - """ - ref = get_value_from_swagger_part_recursively( - response, - ( - "content", - "application/json", - "schema", - "$ref", - ), - ) - assert isinstance(ref, str), "Reference must be a string." - - return ref - - -def get_last_part_of_ref(ref: str) -> str: - """Return the last part of the #ref string.""" - - return ref.split("/")[-1] - - -def get_description_for_endpoint(endpoint_properties: SwaggerReadyForExtraction) -> str: - """ - Resolve the description from the endpoint properties. - - Example: - example = { - "some_api.some_endpoint": { - "post": { - "tags": ["some_api"], - "summary": "Just example.", - "description": "Some description.", - } - } - } - - get_description_for_endpoint(example["some_api.some_endpoint"]) - >>> "Some description." - """ - post_properties = endpoint_properties["post"] - - assert isinstance(post_properties, dict), "Post properties must be a dictionary." - - description = post_properties.get("description", "") - assert isinstance(description, str), "Description must of the endpoint be a string." - - return description - - -def get_result_name_for_endpoint(endpoint_properties: SwaggerReadyForExtraction) -> str: - """ - Resolve the result from the endpoint properties. - - Example: - example = { - "some_api.some_endpoint": { - "post": { - "responses": { - "200": { - "description": "Successful operation", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/some_endpoint_response" - } - } - } - } - } - } - } - } - get_result_name_for_endpoint(example["some_api.some_endpoint"]) - >>> "some_endpoint_response" - """ - response = get_value_from_swagger_part_recursively( - endpoint_properties, - ( - "post", - "responses", - "200", - ), - ) - ref = get_ref_from_schema(response) - return get_last_part_of_ref(ref) - - -def get_params_name_for_endpoint(endpoint_properties: SwaggerReadyForExtraction) -> str | None: - """ - Resolve the params from the endpoint properties. - - Example: - example = { - "some_api.some_endpoint": { - "post": { - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/some_ednpoint" - } - } - }, - "required": true - }, - } - } - } - get_params_name_for_endpoint(example["some_api.some_endpoint"]) - >>> "some_ednpoint" - """ - post_properties = endpoint_properties["post"] - - assert isinstance(post_properties, dict), "Post properties must be a dictionary." - - request_body = post_properties.get("requestBody") - if request_body is None: - return None - - assert isinstance(request_body, dict), "Request body must be a dictionary." - ref = get_ref_from_schema(request_body) - - return get_last_part_of_ref(ref) - - -def is_result_array(result: str, components: SwaggerReadyForExtraction) -> bool: - """Check if the response of the endpoint is an array.""" - - response_schema = components.get(result) - assert response_schema is not None, f"Not found response schema for the {result}." - - assert isinstance(response_schema, dict), "Response schema must be a dictionary." - return response_schema.get("type") == "array" - - -def create_api_description_module( - api_description_name: str, - api_description: ApiDescription, - additional_aliases: tuple[AliasToAssign] | None = None, -) -> ast.Module: - assign = ast.Assign( - targets=[ast.Name(id=api_description_name, ctx=ast.Store())], - value=ast.Dict( - keys=[ast.Constant(value=api_name) for api_name in api_description], - values=[ - ast.Dict( - keys=[ast.Constant(value=endpoint) for endpoint in api_description[api_name]], - values=[ - ast.Dict( - keys=[ast.Constant(value=param_name) for param_name in params], - values=[ - ast.Name(id=param_value, ctx=ast.Load()) - if param_name not in ("response_array", "description") - else ast.Constant(value=param_value) - for param_name, param_value in params.items() - ], - ) - for params in api_description[api_name].values() - ], - ) - for api_name in api_description - ], - ), - ) - - body: list[ast.stmt] = [assign] - - if additional_aliases: - for alias in additional_aliases: - body.insert( - 0, - ast.Assign( - targets=[ast.Name(id=alias[0])], - value=ast.Name(id=alias[1].__name__), - ), - ) - - return ast.Module(body=body, type_ignores=[]) - - -def get_api_name_from_server_property(swagger: SwaggerReadyForExtraction) -> str: - """ - Get the API name from the server property of the swagger. - - Example: - swagger = { - "servers": [ - { - "url": "/some-api, - } - ] - } - - get_api_name_from_server_property(swagger) - >>> "some-api" - """ - servers = swagger["servers"] - assert isinstance(servers, list), "Servers must be a list." - - assert len(servers) == 1, "Swagger must have exactly one server." - - server = servers[0] - assert isinstance(server, dict), "Server must be a dictionary." - server_url = server["url"] - - assert isinstance(server_url, str), "Server URL must be a string." - - split_server_url = server_url.split("/") - split_server_url.remove("") # Remove empty strings from the list - - if len(split_server_url) > 1: - return "_".join(split_server_url) # If the URL contains slashes, join them with underscores - - return split_server_url[0] - - -def get_types_name_from_components(swagger: SwaggerReadyForExtraction) -> str: - """ - Get the names of the types from the components of the swagger. - - Example: - swagger = "components": { - "schemas": { - "some_types.some_type": { - "type": "string", - "enum": [ - "post", - "comment", - "all" - ] - }, - } - } - - get_types_name_from_components(components) - >>> "some_types" - """ - schemas_in_swagger = get_value_from_swagger_part_recursively(swagger, ("components", "schemas")) - - first_type = next(iter(schemas_in_swagger)) - assert isinstance(first_type, str), "First type in the schemas must be a string." - return first_type.split(".")[0] diff --git a/schemas/apis/api_client_generator/_private/endpoints_factory/__init__.py b/schemas/apis/api_client_generator/_private/endpoints_factory/__init__.py deleted file mode 100644 index 45a844958ef6c6e0ad0c7968b1441fcaeba3be8e..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/endpoints_factory/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import annotations - -from .json_rpc import create_endpoint as create_json_rpc_endpoint - -__all__ = [ - "create_json_rpc_endpoint", -] diff --git a/schemas/apis/api_client_generator/_private/endpoints_factory/common.py b/schemas/apis/api_client_generator/_private/endpoints_factory/common.py deleted file mode 100644 index af42c40602472f21b83b0a788ef18ffbbc2ed62f..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/endpoints_factory/common.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import annotations - -import ast - -from schemas.apis.api_client_generator._private.common.models_aliased import Importable - - -def create_endpoint( # NOQA: PLR0913 - name: str, - endpoint_arguments: ast.arguments, - endpoint_decorator: str, - result_type: Importable | str | None = None, - description: str | None = None, - *, - response_array: bool = False, - asynchronous: bool = True, -) -> ast.AsyncFunctionDef | ast.FunctionDef: - """ - Create endpoint method. - - Args: - name: The name of the endpoint. - endpoint_arguments: The arguments for the endpoint. - endpoint_decorator: The name of the endpoint decorator to be used. - result_type: The type of the result. - description: The description of the endpoint. - response_array: If True, the result type will be a list of the result type. - asynchronous: If True, the endpoint will be created as an asynchronous method. - - Notes: - - The method body contains an ellipsis (`...`), decorator do all the work. - - If `result_type` is provided, it will be used as the return type hint. - - The first argument is always `self` (function always add it automatically). - - Returns: - ast.AsyncFunctionDef | ast.FunctionDef: The AST representation of the endpoint method. - """ - endpoint_arguments.args.insert(0, ast.arg(arg="self")) - body: list[ast.stmt] = [ - ast.Expr(value=ast.Constant(value=Ellipsis)) - if not description - else ast.Expr(value=ast.Constant(value=description)) - ] - - returns: ast.Name | None - - if isinstance(result_type, str): - returns = ast.Name(id=result_type) - else: - returns = ( - ast.Name(id=result_type.__name__ if not response_array else f"list[{result_type.__name__}]") - if result_type is not None - else None - ) - - function_def: type[ast.FunctionDef] | type[ast.AsyncFunctionDef] = ( - ast.AsyncFunctionDef if asynchronous else ast.FunctionDef - ) - - return function_def( - name=name, - args=endpoint_arguments, - body=body, - decorator_list=[ast.Name(id=endpoint_decorator)], - returns=returns, - type_params=[], - ) diff --git a/schemas/apis/api_client_generator/_private/endpoints_factory/json_rpc.py b/schemas/apis/api_client_generator/_private/endpoints_factory/json_rpc.py deleted file mode 100644 index 9f36e95b13743b8ef68cfffb630f613a12edd02c..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/endpoints_factory/json_rpc.py +++ /dev/null @@ -1,107 +0,0 @@ -from __future__ import annotations - -import ast - -from msgspec import NODEFAULT, Struct -from msgspec.structs import fields - -from schemas.apis.api_client_generator._private.common.defaults import DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME -from schemas.apis.api_client_generator._private.common.models_aliased import Importable -from schemas.apis.api_client_generator._private.endpoints_factory.common import ( - create_endpoint as create_endpoint_common, -) -from schemas.apis.api_client_generator._private.resolve_needed_imports import is_struct -from schemas.apis.api_client_generator.exceptions import EndpointParamsIsNotMsgspecStructError - - -def create_endpoint( # NOQA: PLR0913 - name: str, - params: Struct | None = None, - result: Importable | None = None, - endpoint_decorator: str = DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME, - description: str | None = None, - *, - response_array: bool = False, - asynchronous: bool = True, -) -> ast.AsyncFunctionDef | ast.FunctionDef: - """ - Create JSON-RPC endpoint method. - - Args: - name: The name of the endpoint. - params: A msgspec struct of parameters. - result: The type of the result. - endpoint_decorator: The decorator for the endpoint. - description: The description of the endpoint. - response_array: If True, the result type will be a list of the result type. - asynchronous: If True, the endpoint will be created as an asynchronous method. - - Notice: - Please note that the `params` argument is expected to be a msgspec struct. - - Returns: - ast.AsyncFunctionDef | ast.FunctionDef: The AST representation of the endpoint method. - - Raises: - EndpointParamsIsNotMsgspecStructError: If the params is not a msgspec struct. - """ - - return create_endpoint_common( - name, - get_endpoint_args(params), - endpoint_decorator, - result, - description, - response_array=response_array, - asynchronous=asynchronous, - ) - - -def get_endpoint_args(params: Struct | None) -> ast.arguments: - """ - Generate arguments for the json-rpc api endpoint method. - - Args: - params: The msgspec struct representing the parameters for the API endpoint. - - Returns: - ast.arguments: The arguments for the API endpoint method. - - Raises: - EndpointParamsIsNotMsgspecStructError: If the params is not a msgspec struct. - """ - - arguments = ast.arguments( - posonlyargs=[], - args=[], - kwonlyargs=[], - kw_defaults=[], - kwarg=None, - defaults=[], - ) - - if params is None: - return arguments - - kwonlyargs: list[ast.arg] = [] - defaults: list[ast.expr | None] = [] - - if not is_struct(params): - raise EndpointParamsIsNotMsgspecStructError - - for param in fields(params): - if param.default is not NODEFAULT: - defaults.append(ast.Constant(value=param.default)) - else: - defaults.append(None) - - kwonlyargs.append( - ast.arg( - arg=param.name, - annotation=ast.Name(id=param.type.__name__), - ) - ) - - arguments.kwonlyargs = kwonlyargs - arguments.kw_defaults = defaults - return arguments diff --git a/schemas/apis/api_client_generator/_private/endpoints_factory/rest.py b/schemas/apis/api_client_generator/_private/endpoints_factory/rest.py deleted file mode 100644 index 0bca9c43ccebc68aa0fc78fa192d36393fed35db..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/endpoints_factory/rest.py +++ /dev/null @@ -1,133 +0,0 @@ -from __future__ import annotations - -import ast -from typing import TYPE_CHECKING - -from schemas.apis.api_client_generator._private.common.converters import hyphen_to_snake -from schemas.apis.api_client_generator._private.common.defaults import DEFAULT_ENDPOINT_REST_DECORATOR_NAME -from schemas.apis.api_client_generator._private.common.get_type_from_ref_in_camel import get_type_from_ref_in_camel -from schemas.apis.api_client_generator._private.common.models_aliased import Importable -from schemas.apis.api_client_generator._private.common.openapi_to_python_type import convert_openapi_type_to_python_type -from schemas.apis.api_client_generator._private.description_tools import get_value_from_swagger_part_recursively -from schemas.apis.api_client_generator._private.endpoints_factory.common import ( - create_endpoint as create_endpoint_common, -) -from schemas.apis.api_client_generator._private.rest_api_tools.models_aliased import ( - PathParam, - QueryParam, - RestApiMethodType, -) - -if TYPE_CHECKING: - from schemas.apis.api_client_generator._private.rest_api_tools.rest_method_model import RestApiMethod - - -def create_endpoint( # NOQA: PLR0913 - name: str, - url_path: str, - method: RestApiMethod | None = None, - result: Importable | str | None = None, - method_type: RestApiMethodType = "get", - endpoint_decorator: str = DEFAULT_ENDPOINT_REST_DECORATOR_NAME, - description: str | None = None, - *, - response_array: bool = False, - asynchronous: bool = True, -) -> ast.AsyncFunctionDef | ast.FunctionDef: - """ - Create an endpoint function definition. - - Args: - name: The name of the endpoint function. - url_path: The URL path of the endpoint. - method: The REST API method. - result: The expected result type of the endpoint. If str, will be used as a type hint exactly as it was passed. - method_type: The type of the REST API method (e.g., "get", "post"). - endpoint_decorator: The decorator to use for the endpoint. Note that method_type will be appended to it. - description: A description of the endpoint. - response_array: Whether the response is an array. - asynchronous: Whether the endpoint function should be asynchronous. - - Returns: - An AST representing the endpoint function definition. - """ - - endpoint_decorator += f""".{method_type}("{url_path}")""" - return create_endpoint_common( - name, - get_endpoint_args(method), - endpoint_decorator, - result, - description, - response_array=response_array, - asynchronous=asynchronous, - ) - - -def get_endpoint_args(params: RestApiMethod | None) -> ast.arguments: - arguments = ast.arguments( - posonlyargs=[], - args=[], - kwonlyargs=[], - kw_defaults=[], - kwarg=None, - defaults=[], - ) - - if params is None or params.parameters is None: - return arguments - - args: list[PathParam] = [] - kwonlyargs: list[QueryParam] = [] - defaults: list[ast.expr | None] = [] - - for param in params.parameters: - assert isinstance(param, dict), "Parameter of the REST API endpoint must be a dictionary." - - schema = param["schema"] - assert isinstance(schema, dict), "Parameter schema must be a dictionary." - default = schema.get("default", None) - - if ( - default is not None or param["in"] == "query" - ): # query param must have a default value to properly generate as the kwonly argument - defaults.append(ast.Constant(value=default)) - - annotation = ast.Name( - id=convert_openapi_type_to_python_type( - get_value_from_swagger_part_recursively( - param, - ( - "schema", - "type", - ), - ) - ).__name__ - if param["schema"].get("type") # type: ignore[union-attr] - else get_type_from_ref_in_camel( - get_value_from_swagger_part_recursively( - param, - ( - "schema", - "$ref", - ), - ) - ) - ) - - if not param.get("required"): - annotation.id += " | None" - - argument_name = param.get("name") - assert isinstance(argument_name, str), "Parameter name must be a string." - argument = ast.arg(arg=hyphen_to_snake(argument_name), annotation=annotation) - - if param["in"] == "path": - args.append(argument) - else: - kwonlyargs.append(argument) - - arguments.kwonlyargs = kwonlyargs - arguments.args = args - arguments.kw_defaults = defaults - return arguments diff --git a/schemas/apis/api_client_generator/_private/export_client_module_to_file.py b/schemas/apis/api_client_generator/_private/export_client_module_to_file.py deleted file mode 100644 index a307c2140dad54673f0792d7cefcb38463c165b7..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/export_client_module_to_file.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import annotations - -import ast -from pathlib import Path -from typing import Literal - -from schemas.apis.api_client_generator._private.format_using_ruff import format_using_ruff - - -def export_module_to_file(module: ast.Module, mode: Literal["w", "a"] = "w", file_path: Path | None = None) -> None: - """ - Export an AST module to a Python file. Also formats the code using Black. - - Args: - module: The AST module to export. - mode: The file mode to use when writing the file. - file_path: The path to the file where the module will be saved. - If None, defaults to "cwd/generated_api_client.py". - """ - - ast.fix_missing_locations(module) - module_code = ast.unparse(module) - - formatted_module = format_using_ruff(module_code) - - if file_path is None: - file_path = Path.cwd() / "generated_api_client.py" - - with file_path.open(mode, encoding="utf-8") as f: - f.write(formatted_module) diff --git a/schemas/apis/api_client_generator/_private/format_using_ruff.py b/schemas/apis/api_client_generator/_private/format_using_ruff.py deleted file mode 100644 index 93d6ec640ac2a81b854bd2ffa4790074eb02953a..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/format_using_ruff.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import annotations - -import subprocess - -from ruff.__main__ import find_ruff_bin # type: ignore[import-untyped] - -from schemas.apis.api_client_generator._private.common.defaults import DEFAULT_LINE_LENGTH_FOR_RUFF - - -def format_using_ruff(code: str, line_length: int = DEFAULT_LINE_LENGTH_FOR_RUFF) -> str: - """Format the given code using Ruff.""" - - try: - ruff_bin = find_ruff_bin() - except FileNotFoundError: - ruff_bin = "ruff" - - try: - completed_process = subprocess.run( - [ - ruff_bin, - "format", - "--config", - f"line-length={line_length}", - "--stdin-filename", - "file.py", - "-", - ], - check=True, - capture_output=True, - text=True, - input=code, - ) - except subprocess.CalledProcessError: - return code - else: - return completed_process.stdout diff --git a/schemas/apis/api_client_generator/_private/json_rpc_tools/__init__.py b/schemas/apis/api_client_generator/_private/json_rpc_tools/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/schemas/apis/api_client_generator/_private/json_rpc_tools/api_name_tools.py b/schemas/apis/api_client_generator/_private/json_rpc_tools/api_name_tools.py deleted file mode 100644 index 734208d79dc515fb56733edaf4f4c3eed3b19676..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/json_rpc_tools/api_name_tools.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import annotations - -import re - -from schemas.apis.api_client_generator._private.common.models_aliased import ApiDescription -from schemas.apis.api_client_generator.exceptions import InvalidApiNameError - - -def get_api_name_from_description(api_description: ApiDescription) -> str: - """ - Extract the API name from the provided API description. - - Args: - api_description: The API description. - - Returns: - The name of the API. - """ - - return next(iter(api_description.keys())) - - -def validate_api_name(api_name: str) -> None: - """ - Validate the API name. - - Args: - api_name: The API name to validate. - - Raises: - ApiNameInvalidError: If the API name is not valid. - """ - is_valid = bool(re.match(r"^[a-z]+(_[a-z]+)*$", api_name)) - if not is_valid: - raise InvalidApiNameError(api_name) diff --git a/schemas/apis/api_client_generator/_private/json_rpc_tools/create_client_and_imports.py b/schemas/apis/api_client_generator/_private/json_rpc_tools/create_client_and_imports.py deleted file mode 100644 index 121fa466438c5bc96277f582ce7fe8bd92d54f52..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/json_rpc_tools/create_client_and_imports.py +++ /dev/null @@ -1,89 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Sequence - -from schemas.apis.api_client_generator._private.common.defaults import DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME -from schemas.apis.api_client_generator._private.common.generated_class import GeneratedClass -from schemas.apis.api_client_generator._private.common.models_aliased import ( - BaseApiClass, - ClientClassFactory, - EndpointsDescription, - Importable, - ensure_is_importable, -) -from schemas.apis.api_client_generator._private.resolve_needed_imports import ( - import_class, - import_classes, - import_params_types, - is_struct, -) -from schemas.apis.api_client_generator.exceptions import EndpointParamsIsNotMsgspecStructError - -if TYPE_CHECKING: - import ast - - -def create_client_and_imports( # NOQA: PLR0913 - api_name: str, - client_class_factory: ClientClassFactory, - endpoints: EndpointsDescription, - base_class: type[BaseApiClass] | str, - base_class_source: str | None = None, - endpoint_decorator: str = DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME, - additional_items_to_import: Sequence[Importable] | None = None, - already_imported: list[str] | None = None, - *, - asynchronous: bool = True, -) -> GeneratedClass: - """ - Create a client class and resolve the needed imports. - - Args: - api_name: The name of the API. - client_class_factory: The factory function to create the client class. - endpoints: The endpoints description for the API. - base_class: The base class for the API client. - base_class_source: The source of the base class. - endpoint_decorator: The name of the endpoint decorator to be used. - additional_items_to_import: Additional items to import. - already_imported: A list of already imported items. - asynchronous: If True, the endpoints will be created as asynchronous methods. - - Raises: - EndpointParamsIsNotDataclassError: If the endpoint parameters are not a dataclass. - """ - - needed_imports: list[ast.ImportFrom] = [] - if already_imported is None: - already_imported = [] - - needed_results = [ensure_is_importable(params["result"]) for params in endpoints.values() if params.get("result")] - needed_results_import = import_classes(needed_results, already_imported) - - needed_params_import = [] - - for params in endpoints.values(): - if params.get("params") is not None: - extracted_params = params.get("params") - - if extracted_params is not None and not is_struct(extracted_params): - raise EndpointParamsIsNotMsgspecStructError - - needed_params_import.extend(import_params_types(extracted_params, already_imported)) - - additional_imports = import_classes(additional_items_to_import or [], already_imported) - - needed_imports.extend(additional_imports + needed_results_import + needed_params_import) - - base_class_import = import_class(base_class, base_class_source) - - base_class_name = base_class if isinstance(base_class, str) else base_class.__name__ - - if base_class_import and base_class_name not in already_imported: - already_imported.append(base_class_name) - needed_imports.append(base_class_import) - - return GeneratedClass( - client_class_factory(api_name, endpoints, base_class, endpoint_decorator, asynchronous=asynchronous), - needed_imports, - ) diff --git a/schemas/apis/api_client_generator/_private/json_rpc_tools/create_collection_module.py b/schemas/apis/api_client_generator/_private/json_rpc_tools/create_collection_module.py deleted file mode 100644 index 412e784ff5c8213bd21c408c4063354b42d4c4e5..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/json_rpc_tools/create_collection_module.py +++ /dev/null @@ -1,77 +0,0 @@ -from __future__ import annotations - -import ast -from typing import Sequence - -from schemas.apis.api_client_generator._private.common.defaults import ( - DEFAULT_API_COLLECTION_NAME, - DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME, -) -from schemas.apis.api_client_generator._private.common.models_aliased import ( - ApiDescription, - BaseApiClass, - ClientClassFactory, - Importable, -) -from schemas.apis.api_client_generator._private.create_collection_class import create_collection_class -from schemas.apis.api_client_generator._private.json_rpc_tools.api_name_tools import validate_api_name -from schemas.apis.api_client_generator._private.json_rpc_tools.create_client_and_imports import ( - create_client_and_imports, -) - - -def create_collection_module( # NOQA: PLR0913 - api_descriptions: ApiDescription, - client_class_factory: ClientClassFactory, - base_class: type[BaseApiClass] | str, - base_class_source: str | None = None, - collection_name: str = DEFAULT_API_COLLECTION_NAME, - endpoint_decorator: str = DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME, - additional_items_to_import: Sequence[Importable] | None = None, - *, - asynchronous: bool = True, -) -> ast.Module: - """ - Generate an API client class based on the provided API descriptions. - - Args: - api_descriptions: The description of the APIs. - client_class_factory: The factory function to create api client class. - base_class: The base class for the API client. - base_class_source: The source of the base class. If None, a `__module__` will be used. - collection_name: The name of the collection class. - endpoint_decorator: The name of the endpoint decorator to be used. - additional_items_to_import: Additional things to import in the created module. - asynchronous: If True, the endpoints will be created as asynchronous methods. - - Raises: - InvalidApiNameError: If the API name is invalid. - """ - - generated_clients = [] - already_imported: list[str] = [] # List of already imported classes to avoid duplicates - imports: list[ast.ImportFrom] = [] - - for api_name, endpoints in api_descriptions.items(): - validate_api_name(api_name) - - created_client = create_client_and_imports( - api_name, - client_class_factory, - endpoints, - base_class, - base_class_source, - endpoint_decorator, - additional_items_to_import, - already_imported, - asynchronous=asynchronous, - ) - generated_clients.append(created_client.class_def) - imports.extend(created_client.imports) - - collection = create_collection_class(collection_name, generated_clients) - - return ast.Module( - body=[*imports, collection, *generated_clients], - type_ignores=[], - ) diff --git a/schemas/apis/api_client_generator/_private/json_rpc_tools/create_single_client_module.py b/schemas/apis/api_client_generator/_private/json_rpc_tools/create_single_client_module.py deleted file mode 100644 index 28baeb37b0dc8679713a0e4bb6b344a8a01924c7..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/json_rpc_tools/create_single_client_module.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import annotations - -import ast -from typing import Sequence - -from schemas.apis.api_client_generator._private.common.defaults import DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME -from schemas.apis.api_client_generator._private.common.models_aliased import ( - ApiDescription, - BaseApiClass, - ClientClassFactory, - Importable, -) -from schemas.apis.api_client_generator._private.json_rpc_tools.api_name_tools import ( - get_api_name_from_description, - validate_api_name, -) -from schemas.apis.api_client_generator._private.json_rpc_tools.create_client_and_imports import ( - create_client_and_imports, -) - - -def create_single_client_module( # NOQA: PLR0913 - api_description: ApiDescription, - client_class_factory: ClientClassFactory, - base_class: type[BaseApiClass] | str, - base_class_source: str | None = None, - endpoint_decorator: str = DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME, - additional_items_to_import: Sequence[Importable] | None = None, - *, - asynchronous: bool = True, -) -> ast.Module: - """ - Generate an API client class based on the provided API name, description, and type. - - Args: - api_description: The description of the API. - client_class_factory: The factory function to create api client class. - base_class: The base class for the API client. - base_class_source: The source of the base class. If None, a default source will be used. - endpoint_decorator: The name of the endpoint decorator to be used. - additional_items_to_import(: Additional things to import in the created module. - asynchronous: If True, the endpoints will be created as asynchronous methods. - - Raises: - AssertionError: If the API description does not contain endpoints. - InvalidApiNameError: If the API name is invalid. - """ - - api_name = get_api_name_from_description(api_description) - validate_api_name(api_name) - endpoints = api_description.get(api_name) - assert endpoints is not None, "API description must contain endpoints" - generated_client = create_client_and_imports( - api_name, - client_class_factory, - endpoints, - base_class, - base_class_source, - endpoint_decorator, - additional_items_to_import, - asynchronous=asynchronous, - ) - - return ast.Module( - body=[*generated_client.imports, generated_client.class_def], - type_ignores=[], - ) diff --git a/schemas/apis/api_client_generator/_private/resolve_needed_imports.py b/schemas/apis/api_client_generator/_private/resolve_needed_imports.py deleted file mode 100644 index 4d5068245e17f1cde542fc31b3a83b04866c2812..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/resolve_needed_imports.py +++ /dev/null @@ -1,181 +0,0 @@ -from __future__ import annotations - -import ast -from typing import TYPE_CHECKING, Any, Sequence, get_type_hints - -from msgspec import Struct - -from schemas.apis.api_client_generator._private.common.defaults import DEFAULT_IMPORT_LEVEL -from schemas.apis.api_client_generator._private.common.models_aliased import Importable -from schemas.apis.api_client_generator.exceptions import ( - ClassPassedByStrWithoutSourceError, - EndpointParamsIsNotMsgspecStructError, -) - -if TYPE_CHECKING: - from pathlib import Path - - -def is_struct(potential_struct: Any) -> bool: - """ - Check if the given parameter is a msgspec struct. - - Args: - potential_struct: The parameter to check. - Returns: - bool: True if the class is a msgspec struct, False otherwise. - """ - return issubclass(potential_struct, Struct) - - -def import_class( - class_: Importable | str, - class_source: str | None = None, -) -> ast.ImportFrom | None: - """ - Import a class from its module. - - Args: - class_: The class to import. - class_source: The source of the class. If None, uses the __module__. - - Raises: - AttributeError: If the module cannot be resolved. - - Returns: - ast.ImportFrom | None: The AST representation of the import statement. - Returns None if the class is from the builtins module. - - Notes: - Please note that the `class_` argument can be a string, but in this case class_source should be passed also. - """ - if not isinstance(class_, str) and class_.__module__ == "builtins": - return None - - if not isinstance(class_, str): - class_source = class_.__module__ - - if class_source is None: - raise ClassPassedByStrWithoutSourceError - - return ast.ImportFrom( - class_source, - [ast.alias(name=class_.__name__ if not isinstance(class_, str) else class_)], - DEFAULT_IMPORT_LEVEL, - ) - - -def import_classes( - classes: Sequence[Importable] | None, already_imported: list[str], sources: Sequence[str] | None = None -) -> list[ast.ImportFrom]: - """ - Import class from the given sequence of classes. - - Args: - classes: A sequence of classes to import. - already_imported: A list of already imported classes. - sources: A sequence of sources for the classes. If None, uses the __module__. - - Raises: - AssertionError: If the length of classes and sources do not match. - - Notes: - - If classes is None or empty, an empty list is returned. - - If sources is provided, it must match the length of classes. - """ - - classes_imports: list[ast.ImportFrom] = [] - - if not classes: - return classes_imports - - def add_import(class_: Importable, source: str | None = None) -> None: - if _should_be_imported(class_, already_imported): - already_imported.append(class_.__name__) - import_stmt = import_class(class_, source) - if import_stmt: - classes_imports.append(import_stmt) - - if sources is None: - for class_ in classes: - add_import(class_) - else: - assert len(classes) == len(sources), "Length of classes and sources must match" - for class_, source in zip(classes, sources): - add_import(class_, source) - - return classes_imports - - -def import_params_types(params: type[Struct] | None, already_imported: list[str]) -> list[ast.ImportFrom]: - """ - Import parameters types from the given dataclass of parameters. - - Args: - params: A msgspec struct with parameters to import. - already_imported: A list of already imported types. - - Notes: - - If params is None or empty, an empty list is returned. - - If a parameter is from the builtins or __main__ module, it is skipped. - - Raises: - EndpointParamsIsNotDataclassError: If params is not a dataclass. - """ - needed_imports: list[ast.ImportFrom] = [] - - def add_import(class_: Importable) -> None: - if _should_be_imported(class_, already_imported): - already_imported.append(class_.__name__) - import_stmt = import_class(class_) - if import_stmt: - needed_imports.append(import_stmt) - - if not params: - return [] - - if params is not None and not is_struct(params): - raise EndpointParamsIsNotMsgspecStructError - - for type_ in get_type_hints(params).values(): - add_import(type_) - - return needed_imports - - -def find_package_root(module_path: Path) -> Path: - """Find the top-level package directory (where `__init__.py` exists).""" - current = module_path.parent - root = None - while True: - init_file = current / "__init__.py" - if init_file.exists(): - root = current - current = current.parent - else: - break - return root if root is not None else module_path.parent - - -def compute_full_module_name(module_path: Path, root: Path) -> str: - """Compute the full dotted module name relative to the package root.""" - relative_path = module_path.relative_to(root) - - parts = relative_path.parts if relative_path.name == "__init__.py" else relative_path.with_suffix("").parts - relative_name = ".".join(parts) - - return f"{root.name}.{relative_name}" if relative_name else root.name - - -def _should_be_imported(class_: Importable, already_imported: list[str]) -> bool: - """ - Check if a class should be imported. - - Args: - class_: The class to check. - already_imported: A list of already imported classes. - - Returns: - bool: True if the class should be imported, False otherwise. - """ - return class_.__module__ != "builtins" and class_.__name__ not in already_imported diff --git a/schemas/apis/api_client_generator/_private/rest_api_tools/__init__.py b/schemas/apis/api_client_generator/_private/rest_api_tools/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/schemas/apis/api_client_generator/_private/rest_api_tools/create_client_and_imports.py b/schemas/apis/api_client_generator/_private/rest_api_tools/create_client_and_imports.py deleted file mode 100644 index ec4de08e073cfeee2ac93ae8116a496f11e9bfa9..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/rest_api_tools/create_client_and_imports.py +++ /dev/null @@ -1,110 +0,0 @@ -from __future__ import annotations - -import ast -from pathlib import Path -from typing import Sequence - -from schemas.apis.api_client_generator._private.common.converters import snake_to_camel -from schemas.apis.api_client_generator._private.common.defaults import ( - DEFAULT_ENDPOINT_REST_DECORATOR_NAME, - DEFAULT_IMPORT_LEVEL, -) -from schemas.apis.api_client_generator._private.common.generated_class import GeneratedClass -from schemas.apis.api_client_generator._private.common.models_aliased import ( - BaseApiClass, - Importable, -) -from schemas.apis.api_client_generator._private.resolve_needed_imports import ( - compute_full_module_name, - find_package_root, - import_class, - import_classes, -) -from schemas.apis.api_client_generator._private.rest_api_tools.models_aliased import CreatedEndpoints - - -def create_client_and_imports( # NOQA: PLR0913 - api_name: str, - server_url: str, - endpoints: CreatedEndpoints, - types_module_path: str | Path, - base_class: type[BaseApiClass] | str, - base_class_source: str | None = None, - endpoint_decorator: str = DEFAULT_ENDPOINT_REST_DECORATOR_NAME, - additional_items_to_import: Sequence[Importable] | None = None, - already_imported: list[str] | None = None, -) -> GeneratedClass: - """ - Create a client class and resolve the needed imports. - - Args: - api_name: The name of the API. - server_url: The server URL for the API. - types_module_path: The path to the module containing types. - endpoints: The endpoints description for the API. - base_class: The base class for the API client. - base_class_source: The source of the base class. - endpoint_decorator: The name of the endpoint decorator to be used. - additional_items_to_import: Additional items to import. - already_imported: A list of already imported items. - """ - - already_imported = already_imported or [] - - needed_imports: list[ast.ImportFrom] = [] - - base_class_import = import_class(base_class, base_class_source) - - if base_class_import is not None: - needed_imports.append(base_class_import) - - base_class_name = base_class if isinstance(base_class, str) else base_class.__name__ - already_imported.append(base_class_name) - - types_module_path = Path(types_module_path) - root = find_package_root(types_module_path) - full_module_name = compute_full_module_name(types_module_path, root) - - needed_imports.append( - ast.ImportFrom( - module=full_module_name, - names=[ast.alias(name="*")], - level=DEFAULT_IMPORT_LEVEL, - ) - ) - - additional_imports = import_classes(additional_items_to_import or [], already_imported) - needed_imports.extend(additional_imports) - - class_name = snake_to_camel(api_name) - - endpoint_decorator_assign = ast.Assign( # Assign endpoint decorator as class variable - targets=[ast.Name(id=endpoint_decorator)], - value=ast.Attribute( - value=ast.Name(id=base_class_name), - attr=f"{endpoint_decorator}()", # rest decorator is a class method of the base class - ), - ) - base_url_method = ast.FunctionDef( # type: ignore[call-overload] - name="base_path", - args=ast.arg(arg="self"), - returns=ast.Name(id="str"), - body=[ast.Return(value=ast.Constant(value="/" + server_url))], - decorator_list=[], - ) - - body: list[ast.stmt] = [endpoint_decorator_assign, base_url_method, *endpoints] - - class_def = ast.ClassDef( - name=class_name, - bases=[ast.Name(id=base_class_name)], - keywords=[], - body=body, - decorator_list=[], - type_params=[], - ) - - return GeneratedClass( - class_def, - needed_imports, - ) diff --git a/schemas/apis/api_client_generator/_private/rest_api_tools/create_endpoints_for_all_url_paths.py b/schemas/apis/api_client_generator/_private/rest_api_tools/create_endpoints_for_all_url_paths.py deleted file mode 100644 index 9502370155db2f3d02b52ac3c348a3ea5df7c2c2..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/rest_api_tools/create_endpoints_for_all_url_paths.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from schemas.apis.api_client_generator._private.common.converters import snake_to_camel -from schemas.apis.api_client_generator._private.common.models_aliased import SwaggerReadyForExtraction -from schemas.apis.api_client_generator._private.common.openapi_to_python_type import convert_openapi_type_to_python_type -from schemas.apis.api_client_generator._private.description_tools import ( - get_last_part_of_ref, - get_value_from_swagger_part_recursively, -) -from schemas.apis.api_client_generator._private.endpoints_factory.rest import create_endpoint -from schemas.apis.api_client_generator._private.rest_api_tools.create_method_name import create_method_name -from schemas.apis.api_client_generator._private.rest_api_tools.models_aliased import ( - CreatedEndpoints, - is_valid_rest_api_method_type, -) -from schemas.apis.api_client_generator._private.rest_api_tools.rest_method_model import RestApiMethod -from schemas.apis.api_client_generator.exceptions import UnsupportedHttpMethodError - -if TYPE_CHECKING: - import ast - - -def create_endpoints_for_all_url_paths( - swagger: SwaggerReadyForExtraction, *, asynchronous: bool = True -) -> CreatedEndpoints: - """ - Create endpoints for all URL paths defined in the Swagger/OpenAPI specification. - - Args: - swagger: The Swagger/OpenAPI specification as a dictionary. - asynchronous: If True, the endpoints will be created as asynchronous methods. - - Returns: - A list of endpoints created from the Swagger paths. - """ - - paths_from_swagger = swagger["paths"] - assert isinstance(paths_from_swagger, dict), f"Expected paths to be a dict, got {type(paths_from_swagger)}" - - url_paths = list(paths_from_swagger.keys()) # path is url like /name_of_endpoint/{some_param} - endpoints: list[ast.FunctionDef | ast.AsyncFunctionDef] = [] - - for url_path in url_paths: - method_name = create_method_name(url_path) - path = get_value_from_swagger_part_recursively(swagger, ("paths", url_path)) - assert isinstance(path, dict), f"Expected path to be a dict, got {type(path)} for {url_path}" - - method_types = path.keys() # e.g. ['get', 'post', 'put', 'delete'] - - for method_type in method_types: - if not is_valid_rest_api_method_type(method_type): - raise UnsupportedHttpMethodError(method_type) - - response_schema = get_value_from_swagger_part_recursively( - path, (method_type, "responses", "200", "content", "application/json", "schema") - ) - response: str | type - - if "$ref" in response_schema: - ref = response_schema["$ref"] - response = snake_to_camel(get_last_part_of_ref(ref).split(".")[1]) - else: - response = convert_openapi_type_to_python_type(response_schema["type"]) - - method = RestApiMethod(**path[method_type]) - - endpoints.append( - create_endpoint(method_name, url_path, method, response, method_type, asynchronous=asynchronous) - ) - - return endpoints diff --git a/schemas/apis/api_client_generator/_private/rest_api_tools/create_method_name.py b/schemas/apis/api_client_generator/_private/rest_api_tools/create_method_name.py deleted file mode 100644 index 0d513bec66c9abcb6b52811b586930e5d3053fcb..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/rest_api_tools/create_method_name.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import annotations - - -def create_method_name(url_path: str) -> str: - """ - Create a method name for a REST API client based on the URL path. - - Args: - url_path: The URL path of the endpoint, e.g., "/name_of_endpoint/{some_param}". - - Returns: - url_path: The constructed method name. - - Example: - my_url_path = "/name_of_endpoint/{some_param}/path_part" - create_method_name(my_url_path) - >>> "name_of_endpoint_path_part" - """ - split_path = url_path.split("/") - split_path = [part for part in split_path if part and not part.startswith("{") and not part.endswith("}")] - - return "_".join(split_path).replace("-", "_") diff --git a/schemas/apis/api_client_generator/_private/rest_api_tools/models_aliased.py b/schemas/apis/api_client_generator/_private/rest_api_tools/models_aliased.py deleted file mode 100644 index 3f2ea3117246afe9b9a0e264526756bf168e6354..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/rest_api_tools/models_aliased.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import annotations - -import ast -from typing import Literal, TypeGuard, get_args - -PathParam = ast.arg -QueryParam = ast.arg - -CreatedEndpoints = list[ast.FunctionDef | ast.AsyncFunctionDef] - -RestApiParameterType = Literal[ - "query", - "path", -] -RestApiMethodType = Literal[ - "get", - "post", - "put", - "patch", - "delete", -] -RestApiMethods: tuple[RestApiMethodType, ...] = get_args(RestApiMethodType) - - -def is_valid_rest_api_method_type(value: str) -> TypeGuard[RestApiMethodType]: - """ - Check if the given value is a valid REST API method type. - - Args: - value: The value to check. - - Returns: - True if the value is a valid REST API method type, False otherwise. - """ - return value in RestApiMethods diff --git a/schemas/apis/api_client_generator/_private/rest_api_tools/rest_method_model.py b/schemas/apis/api_client_generator/_private/rest_api_tools/rest_method_model.py deleted file mode 100644 index c9e2f88423e5ad5ec5b0777cf95c0e3c80fc5d63..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/_private/rest_api_tools/rest_method_model.py +++ /dev/null @@ -1,13 +0,0 @@ -from __future__ import annotations - -from schemas._preconfigured_base_model import PreconfiguredBaseModel -from schemas.apis.api_client_generator._private.common.models_aliased import AnyJson - - -class RestApiMethod(PreconfiguredBaseModel): - tags: list[str] - summary: str - description: str - operationId: str # NOQA: N815 - responses: AnyJson - parameters: list[AnyJson] | None = None diff --git a/schemas/apis/api_client_generator/exceptions.py b/schemas/apis/api_client_generator/exceptions.py deleted file mode 100644 index 0c74727ddbb3ef6c12f68c3318b249febbadf212..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/exceptions.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import annotations - - -class ApiClientGeneratorError(Exception): - """Base class for all exceptions raised by the ApiClientGenerator.""" - - -class InvalidApiNameError(ApiClientGeneratorError): - """Exception raised when the API name is invalid.""" - - def __init__(self, api_name: str) -> None: - self.message = f"Invalid API name: {api_name} provided." - self.api_name = api_name - super().__init__(self.message) - - -class InvalidApiDescriptionAmountError(ApiClientGeneratorError): - """Exception raised when more than one or none API description is passed to a single generator.""" - - def __init__(self) -> None: - self.message = "More than one or none API dscription passed to the single api client generator." - super().__init__(self.message) - - -class RunningScriptWithoutAppropriateFlagError(ApiClientGeneratorError): - def __init__(self) -> None: - self.message = ( - "Seems like you are trying to run the script without the -m flag. Please run your generation script like this:\n" - "python -m your_script_name.py" - ) - super().__init__(self.message) - - -class EndpointParamsIsNotMsgspecStructError(ApiClientGeneratorError): - """Exception raised when the endpoint parameters are not a msgspec struct.""" - - def __init__(self, endpoint_name: str = "any") -> None: - self.message = f"Params for {endpoint_name} endpoint must be a msgspec struct" - self.endpoint_name = endpoint_name - super().__init__(self.message) - - -class ClassPassedByStrWithoutSourceError(ApiClientGeneratorError): - """Exception raised when a class is passed by string without its source.""" - - def __init__(self) -> None: - self.message = "You've probably passed a class by string and not provided class source." - super().__init__(self.message) - - -class UnsupportedHttpMethodError(ApiClientGeneratorError): - """Exception raised when an unsupported HTTP method is used.""" - - def __init__(self, method: str) -> None: - self.message = f"Unsupported HTTP method: {method}." - self.method = method - super().__init__(self.message) diff --git a/schemas/apis/api_client_generator/generate_types_from_swagger.py b/schemas/apis/api_client_generator/generate_types_from_swagger.py deleted file mode 100644 index 4cdad90f9316b50fed0fba6aacc5ae4033fb3111..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/generate_types_from_swagger.py +++ /dev/null @@ -1,74 +0,0 @@ -from __future__ import annotations - -import re -from pathlib import Path - -from datamodel_code_generator import DataModelType, InputFileType, generate - -from schemas.apis.api_client_generator._private.resolve_needed_imports import ( - compute_full_module_name, - find_package_root, -) - - -def generate_types_from_swagger( - openapi_api_definition: str | Path, - output: str | Path, -) -> None: - """ - Generate types defined in Swagger. - - Args: - openapi_api_definition: The OpenAPI JSON definition file path. - output: The output file / package path where the generated types will be saved. - - Notes: - The generated types will be saved in the specified output directory, and relative imports will be fixed - to use absolute imports based on the package structure. - - Raises: - FileNotFoundError: If the OpenAPI definition file does not exist. - """ - openapi_file = openapi_api_definition if isinstance(openapi_api_definition, Path) else Path(openapi_api_definition) - output = output if isinstance(output, Path) else Path(output) - - if not openapi_file.exists(): - raise FileNotFoundError(f"File {openapi_file} does not exist.") - - generate( # generation of types available in the API definition - openapi_file, - output=output, - output_model_type=DataModelType.MsgspecStruct, - input_file_type=InputFileType.OpenAPI, - use_field_description=True, - use_standard_collections=True, - use_exact_imports=True, - ) - - package_root = find_package_root(output) - path_to_add_to_imports = compute_full_module_name(output, package_root) - - if path_to_add_to_imports.startswith( - "." - ): # There is just one dot which means that output is in the same directory as package root - path_to_add_to_imports = path_to_add_to_imports.replace(".", "", 1) - - fix_relative_imports(output, path_to_add_to_imports) - - -def fix_relative_imports(output_dir: Path, path_to_add: str) -> None: - """ - Replace relative imports (from .xyz import ...) with absolute imports using the path_to_add. - - Args: - output_dir: Directory with generated Python files. - path_to_add: Path to use in absolute imports. - """ - for py_file in output_dir.rglob("*.py"): - content = py_file.read_text(encoding="utf-8") - - fixed_content = re.sub( - r"^from \.(\w+) import (.+)$", rf"from {path_to_add}.\1 import \2", content, flags=re.MULTILINE - ) - - py_file.write_text(fixed_content, encoding="utf-8") diff --git a/schemas/apis/api_client_generator/json_rpc/__init__.py b/schemas/apis/api_client_generator/json_rpc/__init__.py deleted file mode 100644 index 2e4ee1f1c74fd61609e0a78d01210d06780fd93f..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/json_rpc/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import annotations - -from .generate_api_client import generate_api_client -from .generate_api_collection import generate_api_collection -from .generate_api_description import generate_api_description - -__all__ = [ - "generate_api_description", - "generate_api_client", - "generate_api_collection", -] diff --git a/schemas/apis/api_client_generator/json_rpc/generate_api_client.py b/schemas/apis/api_client_generator/json_rpc/generate_api_client.py deleted file mode 100644 index c220e1cf4161ca12979d779dac17cc437bc64794..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/json_rpc/generate_api_client.py +++ /dev/null @@ -1,91 +0,0 @@ -from __future__ import annotations - -from pathlib import Path -from typing import Sequence - -from schemas.apis.api_client_generator._private.check_whether_was_ran_as_script import check_whether_was_ran_as_script -from schemas.apis.api_client_generator._private.client_class_factory import create_json_rpc_api_client -from schemas.apis.api_client_generator._private.common.defaults import DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME -from schemas.apis.api_client_generator._private.common.models_aliased import ApiDescription, BaseApiClass, Importable -from schemas.apis.api_client_generator._private.export_client_module_to_file import export_module_to_file -from schemas.apis.api_client_generator._private.json_rpc_tools.api_name_tools import get_api_name_from_description -from schemas.apis.api_client_generator._private.json_rpc_tools.create_single_client_module import ( - create_single_client_module, -) -from schemas.apis.api_client_generator.exceptions import InvalidApiDescriptionAmountError - - -def generate_api_client( # NOQA: PLR0913 - api_description: ApiDescription, - base_class: type[BaseApiClass] | str, - base_class_source: str | None = None, - path: Path | None = None, - endpoint_decorator: str = DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME, - additional_items_to_import: Sequence[Importable] | None = None, - *, - asynchronous: bool = True, -) -> None: - """ - Generate an API client class based on the provided API name, description, and type and save it to a file. - - Args: - api_description: The description of the API. - base_class: The base class for the API client. - base_class_source: The source of the base class. If None, a default source will be used. - path: The path where the generated client should be saved. If None, a default path will be used. - endpoint_decorator: Name of the decorator to be used for the endpoint. - additional_items_to_import: Additional items to import in the module. - asynchronous: If True, the endpoints will be created as asynchronous methods. - - Notes: - Your script must be run with the `-m` flag to ensure that the module is executed as a script. - - Raises: - MoreThanOneApiPassedToSingleGeneratorError: If more than one or none API description is provided. If you want to generate a client for multiple APIs, - use `generate_api_collection` instead or pass your api descriptions one by one. - InvalidApiNameError: If the API name is invalid. - RunningScriptWithoutAppropriateFlagError: If the script is run without the appropriate (-m) flag. - - - Example: - from beekeepy import AbstractAsyncApi - - - @dataclass - class MyApiParameters: - account: str - - - @dataclass - class MyApiResult: - data: str - - - my_api_description = { - "my_api": { - "params": MyApiParameters, - "result": MyApiResult, - } - } - - generate_dapi_client(my_api_description, AbstractAsyncApi) - """ - check_whether_was_ran_as_script() - - if len(api_description.keys()) != 1: - raise InvalidApiDescriptionAmountError - - client_module = create_single_client_module( - api_description, - create_json_rpc_api_client, - base_class, - base_class_source, - endpoint_decorator, - additional_items_to_import, - asynchronous=asynchronous, - ) - - api_name = get_api_name_from_description(api_description) # Already validated in the `create_single_client_module` - - file_path = Path(f"{api_name}_client.py") if path is None else path - export_module_to_file(client_module, file_path=file_path) diff --git a/schemas/apis/api_client_generator/json_rpc/generate_api_collection.py b/schemas/apis/api_client_generator/json_rpc/generate_api_collection.py deleted file mode 100644 index 87935f8ec2345ed477453c7fc1aa0916d161e6be..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/json_rpc/generate_api_collection.py +++ /dev/null @@ -1,63 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Sequence - -from schemas.apis.api_client_generator._private.check_whether_was_ran_as_script import check_whether_was_ran_as_script -from schemas.apis.api_client_generator._private.client_class_factory import create_json_rpc_api_client -from schemas.apis.api_client_generator._private.common.defaults import ( - DEFAULT_API_COLLECTION_NAME, - DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME, -) -from schemas.apis.api_client_generator._private.common.models_aliased import ApiDescription, BaseApiClass, Importable -from schemas.apis.api_client_generator._private.export_client_module_to_file import export_module_to_file -from schemas.apis.api_client_generator._private.json_rpc_tools.create_collection_module import create_collection_module - -if TYPE_CHECKING: - from pathlib import Path - - -def generate_api_collection( # NOQA: PLR0913 - api_descriptions: ApiDescription, - base_class: type[BaseApiClass] | str, - base_class_source: str | None = None, - path: Path | None = None, - collection_name: str = DEFAULT_API_COLLECTION_NAME, - endpoint_decorator: str = DEFAULT_ENDPOINT_JSON_RPC_DECORATOR_NAME, - additional_items_to_import: Sequence[Importable] | None = None, - *, - asynchronous: bool = True, -) -> None: - """ - Generate an API client collection based on the provided API names, definition, and type and save it to a file. - - Args: - api_descriptions: Description of the APIs. - base_class: The base class for the API client. - base_class_source: The source of the base class. If None, a default source will be used. - path: The path where the generated client should be saved. If None, a default path will be used. - collection_name: Name of the collection. Will be used as the class name for the collection. - endpoint_decorator: Name of the decorator to be used for the endpoint. - additional_items_to_import: Additional items to import in the module. - asynchronous: If True, the endpoints will be created as asynchronous methods. - - Notes: - Your script must be run with the `-m` flag to ensure that the module is executed as a script. - - Raises: - InvalidApiNameError: If the API name is invalid. - RunningScriptWithoutAppropriateFlagError: If the script is run without the appropriate (-m) flag. - """ - check_whether_was_ran_as_script() - - collection_module = create_collection_module( - api_descriptions, - create_json_rpc_api_client, - base_class, - base_class_source, - collection_name, - endpoint_decorator, - additional_items_to_import, - asynchronous=asynchronous, - ) - - export_module_to_file(collection_module, file_path=path) diff --git a/schemas/apis/api_client_generator/json_rpc/generate_api_description.py b/schemas/apis/api_client_generator/json_rpc/generate_api_description.py deleted file mode 100644 index cb6d93c358c724c2611342a539724e72fada4a7c..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/json_rpc/generate_api_description.py +++ /dev/null @@ -1,120 +0,0 @@ -""" -Simple way to generate a JSON-RPC params-result structure to be used in the client generator. - -This script reads the OpenAPI JSON file, generates the API description, and creates a dictionary like that: - -api_description = { - "name_of_api": - { - "name_of_endpoint": { - - "params": ParamsClass, - "result": NameOfEndpointResponse, - "description": "Description of the endpoint if given", - }, - }, - "name_of_second_endpoint": - { - "name_of_endpoint": { - "params": ParamsClass, - "result": NameOfEndpointResponseItem, - "response_array": True, - "description": "Description of the endpoint if given", - }, - }, - } -""" - -from __future__ import annotations - -import json -from pathlib import Path -from typing import Container - -from schemas.apis.api_client_generator._private.common.converters import snake_to_camel -from schemas.apis.api_client_generator._private.common.models_aliased import ( - ApiDescriptionBeforeProcessing, - EndpointDescriptionBeforeProcessing, -) -from schemas.apis.api_client_generator._private.description_tools import ( - AliasToAssign, - create_api_description_module, - get_description_for_endpoint, - get_params_name_for_endpoint, - get_result_name_for_endpoint, - is_result_array, -) -from schemas.apis.api_client_generator._private.export_client_module_to_file import export_module_to_file -from schemas.apis.api_client_generator.generate_types_from_swagger import generate_types_from_swagger - - -def generate_api_description( - api_description_name: str, - openapi_api_definition: str | Path, - output_file: str | Path, - additional_aliases: tuple[AliasToAssign] | None = None, - apis_to_skip: Container[str] | None = None, -) -> None: - """ - Generate an API description based on the provided OpenAPI definition. - - Args: - api_description_name: The name of the API description to be generated. - openapi_api_definition: The OpenAPI JSON definition file path. - output_file: The file where the generated API description will be saved. - additional_aliases: Additional aliases to be used in the API description. - apis_to_skip: APIs to skip during the generation process. - - Raises: - FileNotFoundError: If the OpenAPI definition file does not exist. - """ - openapi_api_definition = ( - openapi_api_definition if isinstance(openapi_api_definition, Path) else Path(openapi_api_definition) - ) - output_file = output_file if isinstance(output_file, Path) else Path(output_file) - generate_types_from_swagger(openapi_api_definition, output_file) - - api_description: ApiDescriptionBeforeProcessing = {} - - openapi = json.loads(openapi_api_definition.read_text()) - - paths = list(openapi["paths"].keys()) # path is construct like name_of_api.name_of_endpoint - components = openapi["components"]["schemas"] - - for path in paths: - api_name, endpoint_name = path.split(".") - - if apis_to_skip and api_name in apis_to_skip: - continue - - if api_name not in api_description: - api_description[api_name] = {} - - endpoint_properties = openapi["paths"][path] - - params_name = get_params_name_for_endpoint(endpoint_properties) - result_name = get_result_name_for_endpoint( - endpoint_properties - ) # that's the name of the response class, in the snake case - - endpoint_description: EndpointDescriptionBeforeProcessing = { - "params": snake_to_camel(params_name) if params_name else "None", - "result": snake_to_camel(result_name), - "description": get_description_for_endpoint(endpoint_properties), - } - - if is_result_array(result_name, components): - endpoint_description["response_array"] = True - - assert isinstance(endpoint_description["result"], str), "Result must be a string at this point." - endpoint_description["result"] += "Item" # It will be typed as list[ClasNameResponseItem] - - api_description[api_name][endpoint_name] = endpoint_description - - description_module = create_api_description_module(api_description_name, api_description, additional_aliases) - - export_module_to_file( - description_module, - mode="a", - file_path=output_file, - ) diff --git a/schemas/apis/api_client_generator/rest/__init__.py b/schemas/apis/api_client_generator/rest/__init__.py deleted file mode 100644 index 62adb8eb9f47c2e0d9e5d554052c7ab1219701b4..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/rest/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - -from .generate_api_client_from_swagger import generate_api_client_from_swagger - -__all__ = ["generate_api_client_from_swagger"] diff --git a/schemas/apis/api_client_generator/rest/generate_api_client_from_swagger.py b/schemas/apis/api_client_generator/rest/generate_api_client_from_swagger.py deleted file mode 100644 index 2b91bcc80c884bd02f63958abe54574ebb92c010..0000000000000000000000000000000000000000 --- a/schemas/apis/api_client_generator/rest/generate_api_client_from_swagger.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations - -import ast -import json -from pathlib import Path - -from schemas.apis.api_client_generator._private.check_whether_was_ran_as_script import check_whether_was_ran_as_script -from schemas.apis.api_client_generator._private.common.converters import hyphen_to_snake -from schemas.apis.api_client_generator._private.common.defaults import DEFAULT_ENDPOINT_REST_DECORATOR_NAME -from schemas.apis.api_client_generator._private.common.models_aliased import BaseApiClass -from schemas.apis.api_client_generator._private.description_tools import ( - get_api_name_from_server_property, - get_types_name_from_components, -) -from schemas.apis.api_client_generator._private.export_client_module_to_file import export_module_to_file -from schemas.apis.api_client_generator._private.rest_api_tools.create_client_and_imports import ( - create_client_and_imports, -) -from schemas.apis.api_client_generator._private.rest_api_tools.create_endpoints_for_all_url_paths import ( - create_endpoints_for_all_url_paths, -) -from schemas.apis.api_client_generator.generate_types_from_swagger import generate_types_from_swagger - - -def generate_api_client_from_swagger( # NOQA: PLR0913 - openapi_api_definition: str | Path, - output_package: str | Path, - base_class: type[BaseApiClass] | str, - base_class_source: str | None = None, - endpoint_decorator: str = DEFAULT_ENDPOINT_REST_DECORATOR_NAME, - *, - asynchronous: bool = True, -) -> None: - """ - Generates a REST API client from an OpenAPI definition file. - - Args: - openapi_api_definition: The OpenAPI JSON definition file path. - output_package: The output package where the generated client will be saved. It should be a directory path. - base_class: The base class for the API client. - base_class_source: Optional source file for the base class, if it is not in the same module as the generated client. - endpoint_decorator: The name of the decorator to be used for the endpoints. - asynchronous: Whether to create asynchronous endpoints. - - Raises: - FileNotFoundError: If the OpenAPI definition file does not exist. - RunningScriptWithoutAppropriateFlagError: If the script is run without the appropriate (-m) flag. - """ - check_whether_was_ran_as_script() - - openapi_file = openapi_api_definition if isinstance(openapi_api_definition, Path) else Path(openapi_api_definition) - output_package = output_package if isinstance(output_package, Path) else Path(output_package) - - generate_types_from_swagger(openapi_api_definition, output_package) - - openapi = json.loads(openapi_file.read_text()) - - server_url = get_api_name_from_server_property(openapi) - api_name = hyphen_to_snake(server_url) - - types_module_name = get_types_name_from_components(openapi) - module_path = output_package / f"{types_module_name}.py" - - endpoints = create_endpoints_for_all_url_paths(openapi, asynchronous=asynchronous) - - class_and_imports = create_client_and_imports( - api_name, - server_url, - endpoints, - module_path, - base_class, - base_class_source, - endpoint_decorator, - ) - - client_module = ast.Module(body=[*class_and_imports.imports, class_and_imports.class_def], type_ignores=[]) - - output_client_file = output_package / f"{api_name}_client.py" - - export_module_to_file(client_module, mode="w", file_path=output_client_file) diff --git a/tests/test_api_generator/__init__.py b/tests/test_api_generator/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/tests/test_api_generator/base_api_classes.py b/tests/test_api_generator/base_api_classes.py deleted file mode 100644 index 5fe68e9c65cab57a0f156337afb0b02a08c3c929..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/base_api_classes.py +++ /dev/null @@ -1,68 +0,0 @@ -from __future__ import annotations - -from functools import wraps -from typing import Any, Awaitable, Callable, Final, Self - -VALID_RETURN_VALUE: Final[str] = "valid_return_value" - - -class MockAsyncJsonRpcApiBase: - """Base class for test generating async api.""" - - @classmethod - def endpoint_jsonrpc(cls, wrapped_function: Callable[..., Awaitable[str]]) -> Callable[..., Awaitable[str]]: - @wraps(wrapped_function) - async def impl(*args: Any, **kwargs: Any) -> str: # NOQA: ARG001 - return VALID_RETURN_VALUE - - return impl - - -class MockSyncJsonRpcApiBase: - """Base class for test generating async api.""" - - @classmethod - def endpoint_jsonrpc(cls, wrapped_function: Callable[..., str]) -> Callable[..., str]: - @wraps(wrapped_function) - def impl(*args: Any, **kwargs: Any) -> str: # NOQA: ARG001 - return VALID_RETURN_VALUE - - return impl - - -class MockAsyncRestApiBase: - """Base class for test generating async rest api.""" - - @classmethod - def endpoint_rest(cls) -> Self: - return cls() - - @classmethod - def get(cls, path: str) -> Callable[[Callable[..., Awaitable[str]]], Callable[..., Awaitable[str]]]: # NOQA: ARG003 - def decorator(func: Callable[..., Awaitable[str]]) -> Callable[..., Awaitable[str]]: - @wraps(func) - async def impl(*args: Any, **kwargs: Any) -> str: # NOQA: ARG001 - return VALID_RETURN_VALUE - - return impl - - return decorator - - -class MockSyncRestApiBase: - """Base class for test generating sync rest api.""" - - @classmethod - def endpoint_rest(cls) -> Self: - return cls() - - @classmethod - def get(cls, path: str) -> Callable[[Callable[..., str]], Callable[..., str]]: # NOQA: ARG003 - def decorator(func: Callable[..., str]) -> Callable[..., str]: - @wraps(func) - def impl(*args: Any, **kwargs: Any) -> str: # NOQA: ARG001 - return VALID_RETURN_VALUE - - return impl - - return decorator diff --git a/tests/test_api_generator/conftest.py b/tests/test_api_generator/conftest.py deleted file mode 100644 index 3682b2323290c5bf1cf724d70d24ae67e5ddb686..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/conftest.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -import pytest - - -@pytest.fixture(scope="session", autouse=True) -def generate_needed_modules() -> None: - from .generate_clients_and_collections import generate_api_description_from_swagger - - generate_api_description_from_swagger() - - from .generate_clients_and_collections import generate_clients_and_collections - - generate_clients_and_collections() diff --git a/tests/test_api_generator/generate_clients_and_collections.py b/tests/test_api_generator/generate_clients_and_collections.py deleted file mode 100644 index bc630f5a6fc095d48df0611e742c28d83eb9d07e..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/generate_clients_and_collections.py +++ /dev/null @@ -1,101 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -from schemas.apis.api_client_generator.json_rpc import ( - generate_api_client, - generate_api_collection, - generate_api_description, -) -from schemas.apis.api_client_generator.rest import generate_api_client_from_swagger -from tests.test_api_generator.base_api_classes import ( - MockAsyncJsonRpcApiBase, - MockAsyncRestApiBase, - MockSyncJsonRpcApiBase, - MockSyncRestApiBase, -) -from tests.test_api_generator.manual_definition.input import ( - GENERATOR_TEST_API_COLLECTION, - GENERATOR_TEST_SINGLE_API, -) - -SYNC_API_COLLECTION_NAME = "GeneratedSyncApiCollection" -ASYNC_API_COLLECTION_NAME = "GeneratedAsyncApiCollection" - -SINGLE_ASYNC_API_DESTINATION = Path(__file__).parent / "manual_definition" / "generated_async_single_api.py" -SINGLE_SYNC_API_DESTINATION = Path(__file__).parent / "manual_definition" / "generated_sync_single_api.py" -COLLECTION_ASYNC_API_DESTINATION = Path(__file__).parent / "manual_definition" / "generated_async_api_collection.py" -COLLECTION_SYNC_API_DESTINATION = Path(__file__).parent / "manual_definition" / "generated_sync_api_collection.py" - -OPENAPI_JSON_RPC_DEFINITION_DESTINATION = Path(__file__).parent / "swagger" / "json_rpc" / "openapi.json" -SYNC_JSON_RPC_API_FROM_SWAGGER_DESTINATION = Path(__file__).parent / "swagger" / "json_rpc" / "generated_sync_api.py" -JSON_RPC_DESCRIPTION_OUTPUT_FILE = Path(__file__).parent / "swagger" / "json_rpc" / "api_description.py" -ASYNC_JSON_RPC_API_FROM_SWAGGER_DESTINATION = Path(__file__).parent / "swagger" / "json_rpc" / "generated_async_api.py" - -OPENAPI_REST_DEFINITION_DESTINATION = Path(__file__).parent / "swagger" / "rest" / "openapi.json" -OUTPUT_SYNC_REST_API_CLIENT_DESTINATION = Path(__file__).parent / "swagger" / "rest" / "generated_sync" -OUTPUT_ASYNC_REST_API_CLIENT_DESTINATION = Path(__file__).parent / "swagger" / "rest" / "generated_async" - - -def generate_api_description_from_swagger() -> None: - generate_api_description( - "test_api_description", OPENAPI_JSON_RPC_DEFINITION_DESTINATION, JSON_RPC_DESCRIPTION_OUTPUT_FILE - ) - - -def generate_clients_and_collections() -> None: - from .swagger.json_rpc.api_description import test_api_description # type: ignore[import-untyped] - - generate_api_client_from_swagger( - OPENAPI_REST_DEFINITION_DESTINATION, - OUTPUT_SYNC_REST_API_CLIENT_DESTINATION, - base_class=MockSyncRestApiBase, # type: ignore[arg-type] - asynchronous=False, - ) - - generate_api_client_from_swagger( - OPENAPI_REST_DEFINITION_DESTINATION, - OUTPUT_ASYNC_REST_API_CLIENT_DESTINATION, - base_class=MockAsyncRestApiBase, # type: ignore[arg-type] - ) - - generate_api_client( - test_api_description, - MockSyncJsonRpcApiBase, # type: ignore[arg-type] - path=SYNC_JSON_RPC_API_FROM_SWAGGER_DESTINATION, - asynchronous=False, - ) - - generate_api_client( - test_api_description, - MockAsyncJsonRpcApiBase, # type: ignore[arg-type] - path=ASYNC_JSON_RPC_API_FROM_SWAGGER_DESTINATION, - ) - - generate_api_client( - GENERATOR_TEST_SINGLE_API, # type: ignore[arg-type] - MockSyncJsonRpcApiBase, # type: ignore[arg-type] - path=SINGLE_SYNC_API_DESTINATION, - asynchronous=False, - ) - - generate_api_client( - GENERATOR_TEST_SINGLE_API, # type: ignore[arg-type] - MockAsyncJsonRpcApiBase, # type: ignore[arg-type] - path=SINGLE_ASYNC_API_DESTINATION, - ) - - generate_api_collection( - GENERATOR_TEST_API_COLLECTION, - MockSyncJsonRpcApiBase, # type: ignore[arg-type] - collection_name=SYNC_API_COLLECTION_NAME, - path=COLLECTION_SYNC_API_DESTINATION, - asynchronous=False, - ) - - generate_api_collection( - GENERATOR_TEST_API_COLLECTION, - MockAsyncJsonRpcApiBase, # type: ignore[arg-type] - collection_name=ASYNC_API_COLLECTION_NAME, - path=COLLECTION_ASYNC_API_DESTINATION, - ) diff --git a/tests/test_api_generator/manual_definition/__init__.py b/tests/test_api_generator/manual_definition/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/tests/test_api_generator/manual_definition/input.py b/tests/test_api_generator/manual_definition/input.py deleted file mode 100644 index f8dd56bbdb061b1803f69eca206c61870fe324d4..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/manual_definition/input.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -from msgspec import Struct - - -class TestCustomType(Struct): ... - - -class TestApiParams(Struct): - some_custom_type: TestCustomType - some_string: str = "" - some_int: int = 0 - - -TestApiResult = str - - -GENERATOR_TEST_SINGLE_API = { - "test_api": { - "first_endpoint": { - "params": TestApiParams, - "result": TestApiResult, - }, - "second_endpoint": { - "params": TestApiParams, - "result": TestApiResult, - }, - "third_endpoint": { - "params": TestApiParams, - "result": TestApiResult, - "description": "This is a test endpoint", - "response_array": True, - }, - } -} - -GENERATOR_TEST_API_COLLECTION = { - "first_test_api": { - "first_endpoint": { - "params": TestApiParams, - "result": TestApiResult, - }, - "second_endpoint": { - "params": TestApiParams, - "result": TestApiResult, - }, - }, - "second_test_api": { - "first_endpoint": { - "params": TestApiParams, - "result": TestApiResult, - }, - }, -} diff --git a/tests/test_api_generator/manual_definition/output.py b/tests/test_api_generator/manual_definition/output.py deleted file mode 100644 index dcf72862b81b1a151a4dead5a22cc26e3a6e36b6..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/manual_definition/output.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import annotations - -from typing import Any - -from .input import TestCustomType - -VALID_PARAMS_FOR_FIRST_AND_SECOND_ENDPOINT: dict[str, Any] = { - "return": str, - "some_custom_type": TestCustomType, - "some_string": str, - "some_int": int, -} - -VALID_PARAMS_FOR_THIRD_ENDPOINT: dict[str, Any] = { - "return": list[str], - "some_custom_type": TestCustomType, - "some_string": str, - "some_int": int, -} diff --git a/tests/test_api_generator/manual_definition/test_collection_generator.py b/tests/test_api_generator/manual_definition/test_collection_generator.py deleted file mode 100644 index dc298385afe9c8a0093bf83048435a255349698b..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/manual_definition/test_collection_generator.py +++ /dev/null @@ -1,121 +0,0 @@ -from __future__ import annotations - -from typing import get_type_hints - -import pytest - -from tests.test_api_generator.base_api_classes import VALID_RETURN_VALUE -from tests.test_api_generator.generate_clients_and_collections import ( - COLLECTION_ASYNC_API_DESTINATION, - COLLECTION_SYNC_API_DESTINATION, -) -from tests.test_api_generator.manual_definition.output import VALID_PARAMS_FOR_FIRST_AND_SECOND_ENDPOINT -from tests.test_api_generator.messages import ( - API_NOT_GENERATED_MESSAGE, - ENDPOINT_IS_NOT_CALLABLE_MESSAGE, - ENDPOINT_NOT_GENERATED_MESSAGE, -) - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_is_collection_generated(api_type: str) -> None: - # ARRANGE - api_destination = COLLECTION_SYNC_API_DESTINATION if api_type == "sync" else COLLECTION_ASYNC_API_DESTINATION - - # ASSERT - assert api_destination.exists(), "API collection file was not created" - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_endpoint_methods_created_and_are_callable(api_type: str) -> None: - # ARRANGE & ACT - if api_type == "async": - from tests.test_api_generator.manual_definition.generated_async_api_collection import ( # type: ignore[import-untyped] - GeneratedAsyncApiCollection as GeneratedCollection, - ) - else: - from tests.test_api_generator.manual_definition.generated_sync_api_collection import ( # type: ignore[import-untyped] - GeneratedSyncApiCollection as GeneratedCollection, - ) - - api_collection = GeneratedCollection() - - # ASSERT - assert hasattr(api_collection, "first_test_api"), API_NOT_GENERATED_MESSAGE - assert hasattr(api_collection, "second_test_api"), API_NOT_GENERATED_MESSAGE - - assert hasattr(api_collection.first_test_api, "first_endpoint"), ENDPOINT_NOT_GENERATED_MESSAGE - assert hasattr(api_collection.first_test_api, "second_endpoint"), ENDPOINT_NOT_GENERATED_MESSAGE - assert hasattr(api_collection.second_test_api, "first_endpoint"), ENDPOINT_NOT_GENERATED_MESSAGE - - assert callable(api_collection.first_test_api.first_endpoint), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - assert callable(api_collection.first_test_api.second_endpoint), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - - assert callable(api_collection.second_test_api.first_endpoint), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_api_methods_signature(api_type: str) -> None: - # ARRANGE & ACT - if api_type == "async": - from tests.test_api_generator.manual_definition.generated_async_api_collection import ( - GeneratedAsyncApiCollection as GeneratedCollection, - ) - else: - from tests.test_api_generator.manual_definition.generated_sync_api_collection import ( - GeneratedSyncApiCollection as GeneratedCollection, - ) - - api_collection = GeneratedCollection() - - # ASSERT - assert ( - get_type_hints(api_collection.first_test_api.first_endpoint) == VALID_PARAMS_FOR_FIRST_AND_SECOND_ENDPOINT - ), "First test endpoint signature is invalid" - assert ( - get_type_hints(api_collection.first_test_api.second_endpoint) == VALID_PARAMS_FOR_FIRST_AND_SECOND_ENDPOINT - ), "Second test endpoint signature is invalid" - - assert ( - get_type_hints(api_collection.second_test_api.first_endpoint) == VALID_PARAMS_FOR_FIRST_AND_SECOND_ENDPOINT - ), "First test endpoint signature is invalid" - - -def test_sync_api_return_values() -> None: - # ARRANGE & ACT - from tests.test_api_generator.manual_definition.generated_sync_api_collection import ( - GeneratedSyncApiCollection, - ) - - api_collection = GeneratedSyncApiCollection() - - # ASSERT - assert ( - api_collection.first_test_api.first_endpoint() == VALID_RETURN_VALUE - ), "First test endpoint returned invalid value" - assert ( - api_collection.first_test_api.second_endpoint() == VALID_RETURN_VALUE - ), "Second test endpoint returned invalid value" - - assert ( - api_collection.second_test_api.first_endpoint() == VALID_RETURN_VALUE - ), "First test endpoint returned invalid value" - - -async def test_async_api_return_values() -> None: - # ARRANGE & ACT - from tests.test_api_generator.manual_definition.generated_async_api_collection import GeneratedAsyncApiCollection - - api_collection = GeneratedAsyncApiCollection() - - # ASSERT - assert ( - await api_collection.first_test_api.first_endpoint() == VALID_RETURN_VALUE - ), "First test endpoint returned invalid value" - assert ( - await api_collection.first_test_api.second_endpoint() == VALID_RETURN_VALUE - ), "Second test endpoint returned invalid value" - - assert ( - await api_collection.second_test_api.first_endpoint() == VALID_RETURN_VALUE - ), "First test endpoint returned invalid value" diff --git a/tests/test_api_generator/manual_definition/test_single_class_generator.py b/tests/test_api_generator/manual_definition/test_single_class_generator.py deleted file mode 100644 index e408206706ba98e620aad8a6a3fd90e35acbecdd..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/manual_definition/test_single_class_generator.py +++ /dev/null @@ -1,96 +0,0 @@ -from __future__ import annotations - -from typing import get_type_hints - -import pytest - -from tests.test_api_generator.base_api_classes import VALID_RETURN_VALUE -from tests.test_api_generator.generate_clients_and_collections import ( - SINGLE_ASYNC_API_DESTINATION, - SINGLE_SYNC_API_DESTINATION, -) -from tests.test_api_generator.manual_definition.output import ( - VALID_PARAMS_FOR_FIRST_AND_SECOND_ENDPOINT, - VALID_PARAMS_FOR_THIRD_ENDPOINT, -) -from tests.test_api_generator.messages import ENDPOINT_IS_NOT_CALLABLE_MESSAGE, ENDPOINT_NOT_GENERATED_MESSAGE - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_is_api_file_created(api_type: str) -> None: - # ARRANGE - api_destination = SINGLE_SYNC_API_DESTINATION if api_type == "sync" else SINGLE_ASYNC_API_DESTINATION - - # ASSERT - assert api_destination.exists(), "API file was not created" - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_endpoint_methods_created(api_type: str) -> None: - # ARRANGE - if api_type == "async": - from tests.test_api_generator.manual_definition.generated_async_single_api import ( # type: ignore[import-untyped] - TestApi, - ) - - else: - from tests.test_api_generator.manual_definition.generated_sync_single_api import ( # type: ignore[import-untyped] - TestApi, - ) - - # ASSERT - assert hasattr(TestApi, "first_endpoint"), ENDPOINT_NOT_GENERATED_MESSAGE - assert hasattr(TestApi, "second_endpoint"), ENDPOINT_NOT_GENERATED_MESSAGE - assert hasattr(TestApi, "third_endpoint"), ENDPOINT_NOT_GENERATED_MESSAGE - - assert callable(TestApi.first_endpoint), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - assert callable(TestApi.second_endpoint), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - assert callable(TestApi.third_endpoint), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_api_methods_signature(api_type: str) -> None: - # ARRANGE & ACT - if api_type == "async": - from tests.test_api_generator.manual_definition.generated_async_single_api import TestApi - else: - from tests.test_api_generator.manual_definition.generated_sync_single_api import TestApi - - test_api_instance = TestApi() - - # ASSERT - assert ( - get_type_hints(test_api_instance.first_endpoint) == VALID_PARAMS_FOR_FIRST_AND_SECOND_ENDPOINT - ), "First test endpoint signature is invalid" - assert ( - get_type_hints(test_api_instance.second_endpoint) == VALID_PARAMS_FOR_FIRST_AND_SECOND_ENDPOINT - ), "Second test endpoint signature is invalid" - assert ( - get_type_hints(test_api_instance.third_endpoint) == VALID_PARAMS_FOR_THIRD_ENDPOINT - ), "Third test endpoint signature is invalid" - - -def test_sync_api_return_values() -> None: - # ARRANGE & ACT - from tests.test_api_generator.manual_definition.generated_sync_single_api import TestApi - - test_api_instance = TestApi() - - # ASSERT - assert test_api_instance.first_endpoint() == VALID_RETURN_VALUE, "First test endpoint returned invalid value" - assert test_api_instance.second_endpoint() == VALID_RETURN_VALUE, "Second test endpoint returned invalid value" - assert test_api_instance.third_endpoint() == VALID_RETURN_VALUE, "Third test endpoint returned invalid value" - - -async def test_async_api_return_values() -> None: - # ARRANGE & ACT - from tests.test_api_generator.manual_definition.generated_async_single_api import TestApi - - test_api_instance = TestApi() - - # ASSERT - assert await test_api_instance.first_endpoint() == VALID_RETURN_VALUE, "First test endpoint returned invalid value" - assert ( - await test_api_instance.second_endpoint() == VALID_RETURN_VALUE - ), "Second test endpoint returned invalid value" - assert await test_api_instance.third_endpoint() == VALID_RETURN_VALUE, "Third test endpoint returned invalid value" diff --git a/tests/test_api_generator/messages.py b/tests/test_api_generator/messages.py deleted file mode 100644 index 0469f8fb1ebe55159a5802745ba4a1facbbe637b..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/messages.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import annotations - -from typing import Final - -API_NOT_GENERATED_MESSAGE: Final[str] = "One of the APIs were not created" -ENDPOINT_NOT_GENERATED_MESSAGE: Final[str] = "One of the API endpoints was not created" -ENDPOINT_IS_NOT_CALLABLE_MESSAGE: Final[str] = "The endpoint is not callable" diff --git a/tests/test_api_generator/swagger/__init__.py b/tests/test_api_generator/swagger/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/tests/test_api_generator/swagger/json_rpc/__init__.py b/tests/test_api_generator/swagger/json_rpc/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/tests/test_api_generator/swagger/json_rpc/openapi.json b/tests/test_api_generator/swagger/json_rpc/openapi.json deleted file mode 100644 index 827208fe930713f7a87853060fcf4996defaa7ab..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/swagger/json_rpc/openapi.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "components": { - "schemas": { - "first_endpoint": { - "properties": { - "some_another_string": { - "description": "Third param", - "example": "Tralala", - "type": "string" - }, - "some_integer": { - "description": "Second param", - "example": 123, - "type": "integer" - }, - "some_string": { - "description": "First param", - "example": "Test test test", - "type": "string" - } - }, - "required": [ - "some_string", - "some_integer", - "some_another_string" - ], - "type": "object" - }, - "first_endpoint_response": { - "type": "string" - }, - "second_endpoint": { - "properties": { - "some_another_string": { - "description": "Third param", - "example": "Tralala", - "type": "string" - }, - "some_integer": { - "description": "Second param", - "example": 123, - "type": "integer" - }, - "some_string": { - "description": "First param", - "example": "Test test test", - "type": "string" - } - }, - "required": [ - "some_string", - "some_integer", - "some_another_string" - ], - "type": "object" - }, - "second_endpoint_response": { - "items": { - "properties": { - "some_bool": { - "description": "Some boolean", - "type": "boolean" - }, - "some_string": { - "description": "Some string", - "example": "Lalala", - "type": "string" - } - }, - "type": "object" - }, - "type": "array" - } - } - }, - "info": { - "description": "Simple api description for testing purposes", - "title": "Test api", - "version": "1.2.1" - }, - "openapi": "3.0.3", - "paths": { - "test_api.first_endpoint": { - "post": { - "description": "First endpoint description", - "operationId": "first_endpoint", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/first_endpoint" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/first_endpoint_response" - } - } - }, - "description": "Successful operation" - } - }, - "summary": "Test api", - "tags": [ - "first_endpoint" - ] - } - }, - "test_api.second_endpoint": { - "post": { - "description": "Sample second_endpoint description", - "operationId": "second_endpoint", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/second_endpoint" - } - } - }, - "required": true - }, - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/second_endpoint_response" - } - } - }, - "description": "Successful operation" - } - }, - "summary": "Second endpoint api", - "tags": [ - "second_endpoint" - ] - } - } - } -} diff --git a/tests/test_api_generator/swagger/json_rpc/test_generation_from_swagger.py b/tests/test_api_generator/swagger/json_rpc/test_generation_from_swagger.py deleted file mode 100644 index b6bdd7deb6684d6ce11bd568c6299d7fc7c48da4..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/swagger/json_rpc/test_generation_from_swagger.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import annotations - -from typing import get_type_hints - -import pytest - -from tests.test_api_generator.generate_clients_and_collections import ( - ASYNC_JSON_RPC_API_FROM_SWAGGER_DESTINATION, - JSON_RPC_DESCRIPTION_OUTPUT_FILE, - SYNC_JSON_RPC_API_FROM_SWAGGER_DESTINATION, -) -from tests.test_api_generator.messages import ENDPOINT_IS_NOT_CALLABLE_MESSAGE, ENDPOINT_NOT_GENERATED_MESSAGE -from tests.test_api_generator.swagger.json_rpc.valid_output import ( - VALID_PARAMS_FOR_FIRST_ENDPOINT, - get_valid_params_for_second_endpoint, -) - - -def test_is_api_description_created() -> None: - # ASSERT - assert JSON_RPC_DESCRIPTION_OUTPUT_FILE.exists(), "json rpc API description from swagger was not created" - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_is_api_file_created(api_type: str) -> None: - # ARRANGE - api_destination = ( - SYNC_JSON_RPC_API_FROM_SWAGGER_DESTINATION - if api_type == "sync" - else ASYNC_JSON_RPC_API_FROM_SWAGGER_DESTINATION - ) - - # ASSERT - assert api_destination.exists(), "API file was not created" - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_endpoint_methods_created(api_type: str) -> None: - # ARRANGE - if api_type == "async": - from tests.test_api_generator.swagger.json_rpc.generated_async_api import ( # type: ignore[import-untyped] - TestApi, - ) - else: - from tests.test_api_generator.swagger.json_rpc.generated_sync_api import TestApi # type: ignore[import-untyped] - - # ASSERT - assert hasattr(TestApi, "first_endpoint"), ENDPOINT_NOT_GENERATED_MESSAGE - assert hasattr(TestApi, "second_endpoint"), ENDPOINT_NOT_GENERATED_MESSAGE - - assert callable(TestApi.first_endpoint), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - assert callable(TestApi.second_endpoint), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_api_methods_signature(api_type: str) -> None: - # ARRANGE & ACT - if api_type == "async": - from tests.test_api_generator.swagger.json_rpc.generated_async_api import ( - TestApi, - ) - else: - from tests.test_api_generator.swagger.json_rpc.generated_sync_api import TestApi - - test_api_instance = TestApi() - - # ASSERT - assert ( - get_type_hints(test_api_instance.first_endpoint) == VALID_PARAMS_FOR_FIRST_ENDPOINT - ), "First test endpoint generated from swagger signature is invalid" - - second_endpoint_type_hints = get_type_hints(test_api_instance.second_endpoint) - - assert ( - second_endpoint_type_hints == get_valid_params_for_second_endpoint() - ), "Second test endpoint generated from swagger signature is invalid" diff --git a/tests/test_api_generator/swagger/json_rpc/valid_output.py b/tests/test_api_generator/swagger/json_rpc/valid_output.py deleted file mode 100644 index 070c7139dbffa4bbecf0b16fe92f3ae1c954eff7..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/swagger/json_rpc/valid_output.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import annotations - -from typing import Any - - -def get_valid_params_for_second_endpoint() -> dict[str, type[str] | type[int] | type[list[Any]]]: - """Get valid params for the second endpoint generated from the swagger.""" - from .api_description import SecondEndpointResponseItem # type: ignore[import-untyped] - - return { - "return": list[SecondEndpointResponseItem], - "some_string": str, - "some_integer": int, - "some_another_string": str, - } - - -VALID_PARAMS_FOR_FIRST_ENDPOINT: dict[str, Any] = { - "return": str, - "some_string": str, - "some_integer": int, - "some_another_string": str, -} diff --git a/tests/test_api_generator/swagger/rest/__init__.py b/tests/test_api_generator/swagger/rest/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/tests/test_api_generator/swagger/rest/openapi.json b/tests/test_api_generator/swagger/rest/openapi.json deleted file mode 100644 index b5dd37070d0126e5b14cd2520ec4d52bb29b8eb8..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/swagger/rest/openapi.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "components": { - "schemas": { - "test_api.balance": { - "properties": { - "hbd_balance": { - "description": "number of HIVE backed dollars the account has", - "type": "integer", - "x-sql-datatype": "BIGINT" - }, - "hive_balance": { - "description": "account's HIVE balance", - "type": "integer", - "x-sql-datatype": "BIGINT" - }, - "vesting_shares": { - "description": "account's VEST balance", - "type": "string" - } - }, - "type": "object" - }, - "test_api.granularity": { - "enum": [ - "first", - "second", - "third" - ], - "type": "string" - }, - "test_api.sort_direction": { - "enum": [ - "asc", - "desc" - ], - "type": "string" - } - } - }, - "externalDocs": { - "description": "Balance tracker gitlab repository", - "url": "https://gitlab.syncad.com/hive/balance_tracker" - }, - "info": { - "description": "Simple api description for testing purposes", - "license": { - "name": "MIT License", - "url": "https://opensource.org/license/mit" - }, - "title": "Test API", - "version": "0.0.0" - }, - "openapi": "3.1.0", - "paths": { - "/test-2": { - "get": { - "description": "...", - "operationId": "....", - "parameters": [ - { - "description": "...", - "in": "query", - "name": "test-name-3", - "required": false, - "schema": { - "$ref": "#/components/schemas/test_api.balance" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "example": "c2fed8958584511ef1a66dab3dbac8c40f3518f0", - "schema": { - "type": "string" - } - } - }, - "description": "..." - }, - "404": { - "description": "..." - } - }, - "summary": "...", - "tags": [ - "Test-tag" - ] - } - }, - "/test/{test-name}/balances": { - "get": { - "description": "...", - "operationId": "...", - "parameters": [ - { - "description": "...", - "in": "path", - "name": "test-name", - "required": true, - "schema": { - "type": "string" - } - }, - { - "description": "...", - "in": "query", - "name": "test-name-2", - "required": false, - "schema": { - "$ref": "#/components/schemas/test_api.sort_direction" - } - } - ], - "responses": { - "200": { - "content": { - "application/json": { - "schema": { - "type": "string" - } - } - }, - "description": "..." - }, - "404": { - "description": "..." - } - }, - "summary": "Test balances", - "tags": [ - "Accounts" - ] - } - } - }, - "servers": [ - { - "url": "/test-api" - } - ], - "tags": [ - { - "name": "Test-tag" - } - ] -} diff --git a/tests/test_api_generator/swagger/rest/test_generation_from_swagger.py b/tests/test_api_generator/swagger/rest/test_generation_from_swagger.py deleted file mode 100644 index 585e3cd1247a0f60bdcbe301d7de8a1c6a4c5364..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/swagger/rest/test_generation_from_swagger.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations - -from typing import get_type_hints - -import pytest - -from tests.test_api_generator.generate_clients_and_collections import ( - OUTPUT_ASYNC_REST_API_CLIENT_DESTINATION, - OUTPUT_SYNC_REST_API_CLIENT_DESTINATION, -) -from tests.test_api_generator.messages import ENDPOINT_IS_NOT_CALLABLE_MESSAGE, ENDPOINT_NOT_GENERATED_MESSAGE -from tests.test_api_generator.swagger.rest.valid_output import ( - get_valid_params_for_async_balances_endpoint, - get_valid_params_for_sync_balances_endpoint, - get_valid_params_for_test_2_async_endpoint, - get_valid_params_for_test_2_sync_endpoint, -) - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_is_api_package_created(api_type: str) -> None: - # ARRANGE - api_destination = ( - OUTPUT_SYNC_REST_API_CLIENT_DESTINATION if api_type == "sync" else OUTPUT_ASYNC_REST_API_CLIENT_DESTINATION - ) - - # ASSERT - assert api_destination.exists(), "API file was not created" - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_endpoint_methods_created(api_type: str) -> None: - # ARRANGE - if api_type == "async": - from tests.test_api_generator.swagger.rest.generated_async.test_api_client import ( # type: ignore[import-untyped] - TestApi, - ) - else: - from tests.test_api_generator.swagger.rest.generated_sync.test_api_client import ( # type: ignore[import-untyped] - TestApi, - ) - - # ASSERT - assert hasattr(TestApi, "test_balances"), ENDPOINT_NOT_GENERATED_MESSAGE - assert hasattr(TestApi, "test_2"), ENDPOINT_NOT_GENERATED_MESSAGE - - assert callable(TestApi.test_balances), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - assert callable(TestApi.test_2), ENDPOINT_IS_NOT_CALLABLE_MESSAGE - - -@pytest.mark.parametrize("api_type", ["sync", "async"]) -def test_api_methods_signature(api_type: str) -> None: - # ARRANGE & ACT - if api_type == "async": - from tests.test_api_generator.swagger.rest.generated_async.test_api_client import ( - TestApi, - ) - - valid_params_for_balances_endpoint = get_valid_params_for_async_balances_endpoint() - valid_params_for_test_2_endpoint = get_valid_params_for_test_2_async_endpoint() - - else: - from tests.test_api_generator.swagger.rest.generated_sync.test_api_client import TestApi - - valid_params_for_balances_endpoint = get_valid_params_for_sync_balances_endpoint() - valid_params_for_test_2_endpoint = get_valid_params_for_test_2_sync_endpoint() - - test_api_instance = TestApi() - - test_2_endpoint_type_hints = get_type_hints(test_api_instance.test_2) - test_balances_endpoint_type_hints = get_type_hints(test_api_instance.test_balances) - - # ASSERT - assert ( - test_balances_endpoint_type_hints == valid_params_for_balances_endpoint - ), "Test balances endpoint generated from swagger signature is invalid" - - assert ( - test_2_endpoint_type_hints == valid_params_for_test_2_endpoint - ), "Test 2 endpoint generated from swagger signature is invalid" diff --git a/tests/test_api_generator/swagger/rest/valid_output.py b/tests/test_api_generator/swagger/rest/valid_output.py deleted file mode 100644 index dd9d48b4d9f70d0001be7c1bcadefebb672ee0a9..0000000000000000000000000000000000000000 --- a/tests/test_api_generator/swagger/rest/valid_output.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import annotations - - -def get_valid_params_for_sync_balances_endpoint() -> dict[str, type]: - from .generated_sync.test_api import SortDirection # type: ignore[import-untyped] - - return { - "test_name": str, - "test_name_2": SortDirection | None, - "return": str, - } - - -def get_valid_params_for_async_balances_endpoint() -> dict[str, type]: - from .generated_async.test_api import SortDirection # type: ignore[import-untyped] - - return { - "test_name": str, - "test_name_2": SortDirection | None, - "return": str, - } - - -def get_valid_params_for_test_2_sync_endpoint() -> dict[str, type]: - from .generated_sync.test_api import Balance - - return { - "test_name_3": Balance | None, - "return": str, - } - - -def get_valid_params_for_test_2_async_endpoint() -> dict[str, type]: - from .generated_async.test_api import Balance - - return { - "test_name_3": Balance | None, - "return": str, - }